aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/CodingGuidelines5
-rw-r--r--Documentation/RelNotes/2.51.0.adoc61
-rw-r--r--Documentation/config/core.adoc6
-rw-r--r--Documentation/config/log.adoc4
-rw-r--r--Documentation/diff-context-options.adoc10
-rw-r--r--Documentation/diff-options.adoc28
-rw-r--r--Documentation/for-each-ref-options.adoc88
-rw-r--r--Documentation/git-add.adoc2
-rw-r--r--Documentation/git-checkout.adoc2
-rw-r--r--Documentation/git-clone.adoc2
-rw-r--r--Documentation/git-commit.adoc2
-rw-r--r--Documentation/git-fast-import.adoc2
-rw-r--r--Documentation/git-for-each-ref.adoc90
-rw-r--r--Documentation/git-reflog.adoc96
-rw-r--r--Documentation/git-refs.adoc16
-rw-r--r--Documentation/git-reset.adoc2
-rw-r--r--Documentation/git-restore.adoc4
-rw-r--r--Documentation/git-stash.adoc2
-rw-r--r--Documentation/git-submodule.adoc7
-rw-r--r--Documentation/git-switch.adoc2
-rw-r--r--Documentation/user-manual.adoc2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile1
-rw-r--r--add-interactive.c45
-rw-r--r--add-interactive.h17
-rw-r--r--add-patch.c14
-rw-r--r--apply.c17
-rw-r--r--archive-tar.c2
-rw-r--r--archive-zip.c22
-rw-r--r--archive.c4
-rw-r--r--branch.c10
-rw-r--r--builtin/add.c22
-rw-r--r--builtin/am.c10
-rw-r--r--builtin/blame.c19
-rw-r--r--builtin/branch.c8
-rw-r--r--builtin/cat-file.c4
-rw-r--r--builtin/check-attr.c2
-rw-r--r--builtin/check-ignore.c3
-rw-r--r--builtin/check-mailmap.c3
-rw-r--r--builtin/checkout--worker.c3
-rw-r--r--builtin/checkout-index.c1
-rw-r--r--builtin/checkout.c37
-rw-r--r--builtin/clean.c77
-rw-r--r--builtin/clone.c26
-rw-r--r--builtin/column.c4
-rw-r--r--builtin/commit-graph.c5
-rw-r--r--builtin/commit-tree.c3
-rw-r--r--builtin/commit.c20
-rw-r--r--builtin/config.c60
-rw-r--r--builtin/count-objects.c5
-rw-r--r--builtin/credential-cache--daemon.c2
-rw-r--r--builtin/credential-store.c2
-rw-r--r--builtin/credential.c3
-rw-r--r--builtin/describe.c89
-rw-r--r--builtin/diff-files.c2
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c2
-rw-r--r--builtin/diff.c17
-rw-r--r--builtin/fast-export.c3
-rw-r--r--builtin/fast-import.c16
-rw-r--r--builtin/fetch.c10
-rw-r--r--builtin/fmt-merge-msg.c6
-rw-r--r--builtin/for-each-ref.c43
-rw-r--r--builtin/fsck.c27
-rw-r--r--builtin/fsmonitor--daemon.c3
-rw-r--r--builtin/gc.c83
-rw-r--r--builtin/grep.c5
-rw-r--r--builtin/hash-object.c3
-rw-r--r--builtin/help.c5
-rw-r--r--builtin/hook.c3
-rw-r--r--builtin/index-pack.c4
-rw-r--r--builtin/interpret-trailers.c3
-rw-r--r--builtin/log.c24
-rw-r--r--builtin/ls-files.c1
-rw-r--r--builtin/ls-tree.c3
-rw-r--r--builtin/merge-base.c3
-rw-r--r--builtin/merge-file.c5
-rw-r--r--builtin/merge-recursive.c3
-rw-r--r--builtin/merge-tree.c33
-rw-r--r--builtin/merge.c7
-rw-r--r--builtin/mktag.c4
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/multi-pack-index.c5
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/notes.c30
-rw-r--r--builtin/pack-objects.c43
-rw-r--r--builtin/pack-refs.c1
-rw-r--r--builtin/patch-id.c3
-rw-r--r--builtin/prune.c2
-rw-r--r--builtin/pull.c9
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/range-diff.c2
-rw-r--r--builtin/read-tree.c3
-rw-r--r--builtin/rebase.c46
-rw-r--r--builtin/receive-pack.c6
-rw-r--r--builtin/reflog.c105
-rw-r--r--builtin/refs.c16
-rw-r--r--builtin/remote.c412
-rw-r--r--builtin/repack.c12
-rw-r--r--builtin/replace.c6
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/reset.c19
-rw-r--r--builtin/rev-list.c2
-rw-r--r--builtin/rev-parse.c4
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/rm.c3
-rw-r--r--builtin/send-pack.c1
-rw-r--r--builtin/shortlog.c2
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/show-ref.c3
-rw-r--r--builtin/sparse-checkout.c2
-rw-r--r--builtin/stash.c66
-rw-r--r--builtin/stripspace.c2
-rw-r--r--builtin/submodule--helper.c102
-rw-r--r--builtin/symbolic-ref.c3
-rw-r--r--builtin/tag.c6
-rw-r--r--builtin/unpack-file.c3
-rw-r--r--builtin/unpack-objects.c17
-rw-r--r--builtin/update-index.c2
-rw-r--r--builtin/update-ref.c3
-rw-r--r--builtin/update-server-info.c1
-rw-r--r--builtin/var.c7
-rw-r--r--builtin/verify-commit.c1
-rw-r--r--builtin/verify-pack.c3
-rw-r--r--builtin/verify-tag.c1
-rw-r--r--builtin/worktree.c8
-rw-r--r--builtin/write-tree.c3
-rw-r--r--bulk-checkin.c2
-rw-r--r--cache-tree.c5
-rw-r--r--checkout.c2
-rw-r--r--combine-diff.c2
-rw-r--r--commit-graph.c1
-rw-r--r--commit.c7
-rw-r--r--commit.h3
-rw-r--r--compat/mingw.c93
-rw-r--r--compat/precompose_utf8.c6
-rw-r--r--config.c578
-rw-r--r--config.h139
-rw-r--r--connect.c8
-rw-r--r--contrib/coccinelle/config_fn_ctx.pending.cocci2
-rwxr-xr-xcontrib/git-jump/git-jump2
-rw-r--r--convert.c2
-rw-r--r--daemon.c2
-rw-r--r--diff-lib.c5
-rw-r--r--diff.c108
-rw-r--r--diff.h10
-rw-r--r--dir.c6
-rw-r--r--editor.c2
-rw-r--r--environment.c532
-rw-r--r--environment.h3
-rw-r--r--fetch-pack.c18
-rw-r--r--fmt-merge-msg.c10
-rw-r--r--fmt-merge-msg.h1
-rw-r--r--for-each-ref.h26
-rw-r--r--fsck.c1
-rw-r--r--fsck.h2
-rw-r--r--fsmonitor.c2
-rw-r--r--git-gui/.gitignore2
-rw-r--r--git-gui/GIT-GUI-BUILD-OPTIONS.in1
-rw-r--r--git-gui/Makefile61
-rwxr-xr-xgit-gui/generate-macos-app.sh30
-rwxr-xr-xgit-gui/generate-macos-wrapper.sh35
-rwxr-xr-xgit-gui/generate-script.sh22
-rwxr-xr-xgit-gui/git-gui--askpass.sh (renamed from git-gui/git-gui--askpass)0
-rwxr-xr-xgit-gui/git-gui.sh58
-rw-r--r--git-gui/lib/blame.tcl9
-rw-r--r--git-gui/lib/branch.tcl4
-rw-r--r--git-gui/lib/browser.tcl2
-rw-r--r--git-gui/lib/checkout_op.tcl2
-rw-r--r--git-gui/lib/choose_rev.tcl4
-rw-r--r--git-gui/lib/commit.tcl83
-rw-r--r--git-gui/lib/diff.tcl3
-rw-r--r--git-gui/lib/index.tcl3
-rw-r--r--git-gui/lib/mergetool.tcl4
-rw-r--r--git-gui/lib/remote_branch_delete.tcl1
-rw-r--r--git-gui/lib/shortcut.tcl52
-rw-r--r--git-gui/lib/spellcheck.tcl1
-rw-r--r--git-gui/lib/themed.tcl8
-rw-r--r--git-gui/macosx/AppMain.tcl29
-rw-r--r--git-gui/macosx/Info.plist30
-rw-r--r--git-gui/macosx/git-gui.icnsbin28866 -> 0 bytes
-rw-r--r--git-gui/meson.build79
-rw-r--r--git-gui/po/bg.po714
-rwxr-xr-xgit-gui/windows/git-gui.sh12
-rw-r--r--git.c4
-rwxr-xr-xgitk-git/gitk185
-rw-r--r--gitk-git/po/bg.po375
-rw-r--r--gpg-interface.c2
-rw-r--r--help.c6
-rw-r--r--http-backend.c6
-rw-r--r--http-fetch.c3
-rw-r--r--http.c7
-rw-r--r--ident.c2
-rw-r--r--ident.h2
-rw-r--r--imap-send.c3
-rw-r--r--list-objects-filter-options.c6
-rw-r--r--loose.c16
-rw-r--r--loose.h4
-rw-r--r--ls-refs.c2
-rw-r--r--mailinfo.c1
-rw-r--r--match-trees.c2
-rw-r--r--merge-ll.c2
-rw-r--r--merge-ort.c80
-rw-r--r--meson.build11
-rw-r--r--midx-write.c24
-rw-r--r--midx.c36
-rw-r--r--midx.h5
-rw-r--r--notes-cache.c3
-rw-r--r--notes-utils.c2
-rw-r--r--notes.c20
-rw-r--r--object-file.c306
-rw-r--r--object-file.h65
-rw-r--r--object-name.c25
-rw-r--r--odb.c10
-rw-r--r--odb.h54
-rw-r--r--pack-bitmap.c21
-rw-r--r--pack-write.c16
-rw-r--r--pack.h3
-rw-r--r--packfile.c86
-rw-r--r--packfile.h3
-rw-r--r--parallel-checkout.c4
-rw-r--r--parse-options.c32
-rw-r--r--parse-options.h2
-rw-r--r--pathspec.c3
-rw-r--r--pretty.c2
-rw-r--r--promisor-remote.c8
-rw-r--r--prompt.c8
-rw-r--r--protocol.c4
-rw-r--r--prune-packed.c2
-rw-r--r--reachable.c4
-rw-r--r--read-cache.c6
-rw-r--r--rebase-interactive.c2
-rw-r--r--ref-filter.c121
-rw-r--r--ref-filter.h1
-rw-r--r--reflog-walk.c7
-rw-r--r--reflog.c4
-rw-r--r--reflog.h3
-rw-r--r--refs.c118
-rw-r--r--refs.h192
-rw-r--r--refs/debug.c12
-rw-r--r--refs/files-backend.c87
-rw-r--r--refs/iterator.c26
-rw-r--r--refs/packed-backend.c19
-rw-r--r--refs/ref-cache.c101
-rw-r--r--refs/ref-cache.h7
-rw-r--r--refs/refs-internal.h155
-rw-r--r--refs/reftable-backend.c51
-rw-r--r--remote.c32
-rw-r--r--rerere.c9
-rw-r--r--revision.c47
-rw-r--r--run-command.c6
-rw-r--r--scalar.c18
-rw-r--r--sequencer.c37
-rw-r--r--setup.c47
-rw-r--r--sideband.c6
-rw-r--r--string-list.c120
-rw-r--r--string-list.h33
-rw-r--r--sub-process.c15
-rw-r--r--submodule-config.c2
-rw-r--r--submodule.c2
-rw-r--r--t/for-each-ref-tests.sh2141
-rw-r--r--t/helper/test-advise.c3
-rw-r--r--t/helper/test-config.c20
-rw-r--r--t/helper/test-delta.c77
-rw-r--r--t/helper/test-hashmap.c9
-rw-r--r--t/helper/test-json-writer.c4
-rw-r--r--t/helper/test-path-utils.c3
-rw-r--r--t/helper/test-read-cache.c3
-rw-r--r--t/helper/test-ref-store.c5
-rw-r--r--t/helper/test-truncate.c3
-rw-r--r--t/helper/test-userdiff.c2
-rw-r--r--t/meson.build7
-rw-r--r--t/t0450/adoc-help-mismatches1
-rwxr-xr-xt/t1421-reflog-write.sh126
-rwxr-xr-xt/t1460-refs-migrate.sh22
-rwxr-xr-xt/t1461-refs-list.sh8
-rwxr-xr-xt/t1517-outside-repo.sh11
-rwxr-xr-xt/t3404-rebase-interactive.sh1
-rwxr-xr-xt/t3415-rebase-autosquash.sh10
-rwxr-xr-xt/t3701-add-interactive.sh119
-rwxr-xr-xt/t4013-diff-various.sh13
-rwxr-xr-xt/t4015-diff-whitespace.sh8
-rwxr-xr-xt/t4053-diff-no-index.sh17
-rwxr-xr-xt/t4055-diff-context.sh42
-rwxr-xr-xt/t4072-diff-max-depth.sh116
-rwxr-xr-xt/t4216-log-bloom.sh31
-rw-r--r--t/t4256/1/mailinfo.c2
-rw-r--r--t/t4256/1/mailinfo.c.orig2
-rwxr-xr-xt/t5505-remote.sh73
-rwxr-xr-xt/t5516-fetch-push.sh54
-rwxr-xr-xt/t6137-pathspec-wildcards-literal.sh12
-rwxr-xr-xt/t6300-for-each-ref.sh2140
-rwxr-xr-xt/t6302-for-each-ref-filter.sh213
-rwxr-xr-xt/t6423-merge-rename-directories.sh519
-rwxr-xr-xt/t7400-submodule-basic.sh23
-rwxr-xr-xt/t7413-submodule-is-active.sh15
-rwxr-xr-xt/t7450-bad-git-dotfiles.sh2
-rwxr-xr-xt/t7510-signed-commit.sh12
-rwxr-xr-xt/t9350-fast-export.sh215
-rwxr-xr-xt/t9902-completion.sh2
-rw-r--r--t/unit-tests/clar/clar.c2
-rw-r--r--t/unit-tests/u-dir.c47
-rw-r--r--t/unit-tests/u-string-list.c95
-rw-r--r--t/unit-tests/unit-test.h7
-rw-r--r--tmp-objdir.c2
-rw-r--r--trace2/tr2_cfg.c80
-rw-r--r--trailer.c4
-rw-r--r--transport.c14
-rw-r--r--tree-diff.c78
-rw-r--r--upload-pack.c2
-rw-r--r--usage.c3
-rw-r--r--versioncmp.c4
-rw-r--r--worktree.c8
-rw-r--r--wt-status.c37
-rw-r--r--xdiff-interface.c1
-rw-r--r--xdiff-interface.h6
317 files changed, 7708 insertions, 6624 deletions
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index f474120425..224f0978a8 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -624,8 +624,9 @@ For C programs:
- `S_init()` initializes a structure without allocating the
structure itself.
- - `S_release()` releases a structure's contents without freeing the
- structure.
+ - `S_release()` releases a structure's contents without reinitializing
+ the structure for immediate reuse, and without freeing the structure
+ itself.
- `S_clear()` is equivalent to `S_release()` followed by `S_init()`
such that the structure is directly usable after clearing it. When
diff --git a/Documentation/RelNotes/2.51.0.adoc b/Documentation/RelNotes/2.51.0.adoc
index 5e254541b5..a73ea3e808 100644
--- a/Documentation/RelNotes/2.51.0.adoc
+++ b/Documentation/RelNotes/2.51.0.adoc
@@ -61,6 +61,17 @@ UI, Workflows & Features
* "git pull" learned to pay attention to pull.autostash configuration
variable, which overrides rebase/merge.autostash.
+ * "git for-each-ref" learns "--start-after" option to help
+ applications that want to page its output.
+
+ * "git switch" and "git restore" are declared to be no longer
+ experimental.
+
+ * "git -c alias.foo=bar foo -h baz" reported "'foo' is aliased to
+ 'bar'" and then went on to run "git foo -h baz", which was
+ unexpected. Tighten the rule so that alias expansion is reported
+ only when "-h" is the sole option.
+
Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
@@ -86,8 +97,8 @@ Performance, Internal Implementation, Development Support etc.
* "git push" and "git fetch" are taught to update refs in batches to
gain performance.
- * Some code paths in the "git prune" used to ignore passed in
- repository object and used the_repository singleton instance
+ * Some code paths in "git prune" used to ignore the passed-in
+ repository object and used the `the_repository` singleton instance
instead, which has been corrected.
* Update ".clang-format" and ".editorconfig" to match our style guide
@@ -125,6 +136,14 @@ Performance, Internal Implementation, Development Support etc.
* The reftable unit tests are now ported to the "clar" unit testing
framework.
+ * Redefine where the multi-pack-index sits in the object subsystem,
+ which recently was restructured to allow multiple backends that
+ support a single object source that belongs to one repository. A
+ MIDX does span multiple "object sources".
+
+ * Reduce implicit assumption and dependence on the_repository in the
+ object-file subsystem.
+
Fixes since v2.50
-----------------
@@ -252,6 +271,36 @@ including security updates, are included in this release.
core.commentstring is set to 'auto'.
(merge 92b7c7c9f5 ac/auto-comment-char-fix later to maint).
+ * "git rebase -i" with bogus rebase.instructionFormat configuration
+ failed to produce the todo file after recording the state files,
+ leading to confused "git status"; this has been corrected.
+ (merge ade14bffd7 ow/rebase-verify-insn-fmt-before-initializing-state later to maint).
+
+ * A few file descriptors left unclosed upon program completion in a
+ few test helper programs are now closed.
+ (merge 0f1b33815b hl/test-helper-fd-close later to maint).
+
+ * Interactive prompt code did not correctly strip CRLF from the end
+ of line on Windows.
+ (merge 711a20827b js/prompt-crlf-fix later to maint).
+
+ * The config API had a set of convenience wrapper functions that
+ implicitly use the_repository instance; they have been removed and
+ inlined at the calling sites.
+
+ * "git add/etc -p" now honor the diff.context configuration variable,
+ and also they learn to honor the -U<n> command-line option.
+ (merge 2b3ae04011 lm/add-p-context later to maint).
+
+ * The case where a new submodule takes a path where there used to be a
+ completely different subproject is now dealt with a bit better than
+ before.
+ (merge 5ed8c5b465 kj/renamed-submodule later to maint).
+
+ * The deflate codepath in "git archive --format=zip" had a
+ longstanding bug coming from misuse of zlib API, which has been
+ corrected.
+
* Other code cleanup, docfix, build fix, etc.
(merge b257adb571 lo/my-first-ow-doc-update later to maint).
(merge 8b34b6a220 ly/sequencer-update-squash-is-fixup-only later to maint).
@@ -282,3 +331,11 @@ including security updates, are included in this release.
(merge 26552cb62a jk/unleak-reflog-expire-entry later to maint).
(merge 339d95fda9 jc/ci-print-test-failures-fix later to maint).
(merge 8c3add51a8 cb/meson-avoid-broken-macos-pcre2 later to maint).
+ (merge 5247da07b8 ps/meson-clar-decls-fix later to maint).
+ (merge f3ef347bb2 ch/t7450-recursive-clone-test-fix later to maint).
+ (merge 4ac3302a1a jc/doc-release-vs-clear later to maint).
+ (merge 3bdd897413 ms/meson-with-ancient-git-wo-ls-files-dedup later to maint).
+ (merge cca758d324 kh/doc-fast-import-historical later to maint).
+ (merge 9b0781196a jc/test-hashmap-is-still-here later to maint).
+ (merge 1bad05bacc jk/revert-squelch-compiler-warning later to maint).
+ (merge 3a7e783d9c dl/squelch-maybe-uninitialized later to maint).
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 9fde1ab63a..3fbe83eef1 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -696,12 +696,6 @@ core.unsetenvvars::
Defaults to `PERL5LIB` to account for the fact that Git for
Windows insists on using its own Perl interpreter.
-core.restrictinheritedhandles::
- Windows-only: override whether spawned processes inherit only standard
- file handles (`stdin`, `stdout` and `stderr`) or all handles. Can be
- `auto`, `true` or `false`. Defaults to `auto`, which means `true` on
- Windows 7 and later, and `false` on older Windows versions.
-
core.createObject::
You can set this to 'link', in which case a hardlink followed by
a delete of the source are used to make sure that object creation
diff --git a/Documentation/config/log.adoc b/Documentation/config/log.adoc
index 16e00e8d29..f20cc25cd7 100644
--- a/Documentation/config/log.adoc
+++ b/Documentation/config/log.adoc
@@ -23,14 +23,14 @@ be used.
Print out the ref names of any commits that are shown by the log
command. Possible values are:
+
-----
+--
`short`;; the ref name prefixes `refs/heads/`, `refs/tags/` and
`refs/remotes/` are not printed.
`full`;; the full ref name (including prefix) are printed.
`auto`;; if the output is going to a terminal,
the ref names are shown as if `short` were given, otherwise no ref
names are shown.
-----
+--
+
This is the same as the `--decorate` option of the `git log`.
diff --git a/Documentation/diff-context-options.adoc b/Documentation/diff-context-options.adoc
new file mode 100644
index 0000000000..e161260358
--- /dev/null
+++ b/Documentation/diff-context-options.adoc
@@ -0,0 +1,10 @@
+`-U<n>`::
+`--unified=<n>`::
+ Generate diffs with _<n>_ lines of context. Defaults to `diff.context`
+ or 3 if the config option is unset.
+
+`--inter-hunk-context=<n>`::
+ Show the context between diff hunks, up to the specified _<number>_
+ of lines, thereby fusing hunks that are close to each other.
+ Defaults to `diff.interHunkContext` or 0 if the config option
+ is unset.
diff --git a/Documentation/diff-options.adoc b/Documentation/diff-options.adoc
index f3a35d8141..b4cbbd4290 100644
--- a/Documentation/diff-options.adoc
+++ b/Documentation/diff-options.adoc
@@ -893,5 +893,33 @@ endif::git-format-patch[]
reverted with `--ita-visible-in-index`. Both options are
experimental and could be removed in future.
+--max-depth=<depth>::
+ For each pathspec given on command line, descend at most `<depth>`
+ levels of directories. A value of `-1` means no limit.
+ Cannot be combined with wildcards in the pathspec.
+ Given a tree containing `foo/bar/baz`, the following list shows the
+ matches generated by each set of options:
++
+--
+ - `--max-depth=0 -- foo`: `foo`
+
+ - `--max-depth=1 -- foo`: `foo/bar`
+
+ - `--max-depth=1 -- foo/bar`: `foo/bar/baz`
+
+ - `--max-depth=1 -- foo foo/bar`: `foo/bar/baz`
+
+ - `--max-depth=2 -- foo`: `foo/bar/baz`
+--
++
+If no pathspec is given, the depth is measured as if all
+top-level entries were specified. Note that this is different
+than measuring from the root, in that `--max-depth=0` would
+still return `foo`. This allows you to still limit depth while
+asking for a subset of the top-level entries.
++
+Note that this option is only supported for diffs between tree objects,
+not against the index or working tree.
+
For more detailed explanation on these common options, see also
linkgit:gitdiffcore[7].
diff --git a/Documentation/for-each-ref-options.adoc b/Documentation/for-each-ref-options.adoc
new file mode 100644
index 0000000000..4a033d3e16
--- /dev/null
+++ b/Documentation/for-each-ref-options.adoc
@@ -0,0 +1,88 @@
+<pattern>...::
+ If one or more patterns are given, only refs are shown that
+ match against at least one pattern, either using fnmatch(3) or
+ literally, in the latter case matching completely or from the
+ beginning up to a slash.
+
+--stdin::
+ If `--stdin` is supplied, then the list of patterns is read from
+ standard input instead of from the argument list.
+
+--count=<count>::
+ By default the command shows all refs that match
+ `<pattern>`. This option makes it stop after showing
+ that many refs.
+
+--sort=<key>::
+ A field name to sort on. Prefix `-` to sort in
+ descending order of the value. When unspecified,
+ `refname` is used. You may use the --sort=<key> option
+ multiple times, in which case the last key becomes the primary
+ key.
+
+--format=<format>::
+ A string that interpolates `%(fieldname)` from a ref being shown and
+ the object it points at. In addition, the string literal `%%`
+ renders as `%` and `%xx` - where `xx` are hex digits - renders as
+ the character with hex code `xx`. For example, `%00` interpolates to
+ `\0` (NUL), `%09` to `\t` (TAB), and `%0a` to `\n` (LF).
++
+When unspecified, `<format>` defaults to `%(objectname) SPC %(objecttype)
+TAB %(refname)`.
+
+--color[=<when>]::
+ Respect any colors specified in the `--format` option. The
+ `<when>` field must be one of `always`, `never`, or `auto` (if
+ `<when>` is absent, behave as if `always` was given).
+
+--shell::
+--perl::
+--python::
+--tcl::
+ If given, strings that substitute `%(fieldname)`
+ placeholders are quoted as string literals suitable for
+ the specified host language. This is meant to produce
+ a scriptlet that can directly be `eval`ed.
+
+--points-at=<object>::
+ Only list refs which points at the given object.
+
+--merged[=<object>]::
+ Only list refs whose tips are reachable from the
+ specified commit (HEAD if not specified).
+
+--no-merged[=<object>]::
+ Only list refs whose tips are not reachable from the
+ specified commit (HEAD if not specified).
+
+--contains[=<object>]::
+ Only list refs which contain the specified commit (HEAD if not
+ specified).
+
+--no-contains[=<object>]::
+ Only list refs which don't contain the specified commit (HEAD
+ if not specified).
+
+--ignore-case::
+ Sorting and filtering refs are case insensitive.
+
+--omit-empty::
+ Do not print a newline after formatted refs where the format expands
+ to the empty string.
+
+--exclude=<pattern>::
+ If one or more patterns are given, only refs which do not match
+ any excluded pattern(s) are shown. Matching is done using the
+ same rules as `<pattern>` above.
+
+--include-root-refs::
+ List root refs (HEAD and pseudorefs) apart from regular refs.
+
+--start-after=<marker>::
+ Allows paginating the output by skipping references up to and including the
+ specified marker. When paging, it should be noted that references may be
+ deleted, modified or added between invocations. Output will only yield those
+ references which follow the marker lexicographically. Output begins from the
+ first reference that would come after the marker alphabetically. Cannot be
+ used with `--sort=<key>` or `--stdin` options, or the _<pattern>_ argument(s)
+ to limit the refs.
diff --git a/Documentation/git-add.adoc b/Documentation/git-add.adoc
index eba0b419ce..b7a735824d 100644
--- a/Documentation/git-add.adoc
+++ b/Documentation/git-add.adoc
@@ -104,6 +104,8 @@ This effectively runs `add --interactive`, but bypasses the
initial command menu and directly jumps to the `patch` subcommand.
See ``Interactive mode'' for details.
+include::diff-context-options.adoc[]
+
`-e`::
`--edit`::
Open the diff vs. the index in an editor and let the user
diff --git a/Documentation/git-checkout.adoc b/Documentation/git-checkout.adoc
index ee83b6d9ba..40e02cfd65 100644
--- a/Documentation/git-checkout.adoc
+++ b/Documentation/git-checkout.adoc
@@ -289,6 +289,8 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
Note that this option uses the no overlay mode by default (see also
`--overlay`), and currently doesn't support overlay mode.
+include::diff-context-options.adoc[]
+
`--ignore-other-worktrees`::
`git checkout` refuses when the wanted branch is already checked
out or otherwise in use by another worktree. This option makes
diff --git a/Documentation/git-clone.adoc b/Documentation/git-clone.adoc
index 222d558290..d829206d1b 100644
--- a/Documentation/git-clone.adoc
+++ b/Documentation/git-clone.adoc
@@ -16,7 +16,7 @@ git clone [--template=<template-directory>]
[--depth <depth>] [--[no-]single-branch] [--[no-]tags]
[--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
[--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
- [--filter=<filter-spec>] [--also-filter-submodules]] [--] <repository>
+ [--filter=<filter-spec> [--also-filter-submodules]] [--] <repository>
[<directory>]
DESCRIPTION
diff --git a/Documentation/git-commit.adoc b/Documentation/git-commit.adoc
index dc219025f1..ae988a883b 100644
--- a/Documentation/git-commit.adoc
+++ b/Documentation/git-commit.adoc
@@ -76,6 +76,8 @@ OPTIONS
which changes to commit. See linkgit:git-add[1] for
details.
+include::diff-context-options.adoc[]
+
`-C <commit>`::
`--reuse-message=<commit>`::
Take an existing _<commit>_ object, and reuse the log message
diff --git a/Documentation/git-fast-import.adoc b/Documentation/git-fast-import.adoc
index d232784200..6f9763c11b 100644
--- a/Documentation/git-fast-import.adoc
+++ b/Documentation/git-fast-import.adoc
@@ -182,7 +182,7 @@ amount of memory usage and processing time. Assuming the frontend
is able to keep up with fast-import and feed it a constant stream of data,
import times for projects holding 10+ years of history and containing
100,000+ individual commits are generally completed in just 1-2
-hours on quite modest (~$2,000 USD) hardware.
+hours on quite modest hardware (~$2,000 USD in 2007).
Most bottlenecks appear to be in foreign source data access (the
source just cannot extract revisions fast enough) or disk IO (fast-import
diff --git a/Documentation/git-for-each-ref.adoc b/Documentation/git-for-each-ref.adoc
index 5ef89fc0fe..130d452de0 100644
--- a/Documentation/git-for-each-ref.adoc
+++ b/Documentation/git-for-each-ref.adoc
@@ -7,14 +7,14 @@ git-for-each-ref - Output information on each ref
SYNOPSIS
--------
-[verse]
-'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
+[synopsis]
+git for-each-ref [--count=<count>] [--shell|--perl|--python|--tcl]
[(--sort=<key>)...] [--format=<format>]
- [--include-root-refs] [ --stdin | <pattern>... ]
- [--points-at=<object>]
+ [--include-root-refs] [--points-at=<object>]
[--merged[=<object>]] [--no-merged[=<object>]]
[--contains[=<object>]] [--no-contains[=<object>]]
- [--exclude=<pattern> ...]
+ [(--exclude=<pattern>)...] [--start-after=<marker>]
+ [ --stdin | <pattern>... ]
DESCRIPTION
-----------
@@ -28,85 +28,7 @@ host language allowing their direct evaluation in that language.
OPTIONS
-------
-<pattern>...::
- If one or more patterns are given, only refs are shown that
- match against at least one pattern, either using fnmatch(3) or
- literally, in the latter case matching completely or from the
- beginning up to a slash.
-
---stdin::
- If `--stdin` is supplied, then the list of patterns is read from
- standard input instead of from the argument list.
-
---count=<count>::
- By default the command shows all refs that match
- `<pattern>`. This option makes it stop after showing
- that many refs.
-
---sort=<key>::
- A field name to sort on. Prefix `-` to sort in
- descending order of the value. When unspecified,
- `refname` is used. You may use the --sort=<key> option
- multiple times, in which case the last key becomes the primary
- key.
-
---format=<format>::
- A string that interpolates `%(fieldname)` from a ref being shown and
- the object it points at. In addition, the string literal `%%`
- renders as `%` and `%xx` - where `xx` are hex digits - renders as
- the character with hex code `xx`. For example, `%00` interpolates to
- `\0` (NUL), `%09` to `\t` (TAB), and `%0a` to `\n` (LF).
-+
-When unspecified, `<format>` defaults to `%(objectname) SPC %(objecttype)
-TAB %(refname)`.
-
---color[=<when>]::
- Respect any colors specified in the `--format` option. The
- `<when>` field must be one of `always`, `never`, or `auto` (if
- `<when>` is absent, behave as if `always` was given).
-
---shell::
---perl::
---python::
---tcl::
- If given, strings that substitute `%(fieldname)`
- placeholders are quoted as string literals suitable for
- the specified host language. This is meant to produce
- a scriptlet that can directly be `eval`ed.
-
---points-at=<object>::
- Only list refs which points at the given object.
-
---merged[=<object>]::
- Only list refs whose tips are reachable from the
- specified commit (HEAD if not specified).
-
---no-merged[=<object>]::
- Only list refs whose tips are not reachable from the
- specified commit (HEAD if not specified).
-
---contains[=<object>]::
- Only list refs which contain the specified commit (HEAD if not
- specified).
-
---no-contains[=<object>]::
- Only list refs which don't contain the specified commit (HEAD
- if not specified).
-
---ignore-case::
- Sorting and filtering refs are case insensitive.
-
---omit-empty::
- Do not print a newline after formatted refs where the format expands
- to the empty string.
-
---exclude=<pattern>::
- If one or more patterns are given, only refs which do not match
- any excluded pattern(s) are shown. Matching is done using the
- same rules as `<pattern>` above.
-
---include-root-refs::
- List root refs (HEAD and pseudorefs) apart from regular refs.
+include::for-each-ref-options.adoc[]
FIELD NAMES
-----------
diff --git a/Documentation/git-reflog.adoc b/Documentation/git-reflog.adoc
index 412f06b8fe..38af0c977a 100644
--- a/Documentation/git-reflog.adoc
+++ b/Documentation/git-reflog.adoc
@@ -8,16 +8,17 @@ git-reflog - Manage reflog information
SYNOPSIS
--------
-[verse]
-'git reflog' [show] [<log-options>] [<ref>]
-'git reflog list'
-'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
+[synopsis]
+git reflog [show] [<log-options>] [<ref>]
+git reflog list
+git reflog exists <ref>
+git reflog write <ref> <old-oid> <new-oid> <message>
+git reflog delete [--rewrite] [--updateref]
+ [--dry-run | -n] [--verbose] <ref>@{<specifier>}...
+git reflog drop [--all [--single-worktree] | <refs>...]
+git reflog expire [--expire=<time>] [--expire-unreachable=<time>]
[--rewrite] [--updateref] [--stale-fix]
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
-'git reflog delete' [--rewrite] [--updateref]
- [--dry-run | -n] [--verbose] <ref>@{<specifier>}...
-'git reflog drop' [--all [--single-worktree] | <refs>...]
-'git reflog exists' <ref>
DESCRIPTION
-----------
@@ -43,11 +44,15 @@ actions, and in addition the `HEAD` reflog records branch switching.
The "list" subcommand lists all refs which have a corresponding reflog.
-The "expire" subcommand prunes older reflog entries. Entries older
-than `expire` time, or entries older than `expire-unreachable` time
-and not reachable from the current tip, are removed from the reflog.
-This is typically not used directly by end users -- instead, see
-linkgit:git-gc[1].
+The "exists" subcommand checks whether a ref has a reflog. It exits
+with zero status if the reflog exists, and non-zero status if it does
+not.
+
+The "write" subcommand writes a single entry to the reflog of a given
+reference. This new entry is appended to the reflog and will thus become
+the most recent entry. The reference name must be fully qualified. Both the old
+and new object IDs must not be abbreviated and must point to existing objects.
+The reflog message gets normalized.
The "delete" subcommand deletes single entries from the reflog, but
not the reflog itself. Its argument must be an _exact_ entry (e.g. "`git
@@ -58,9 +63,11 @@ The "drop" subcommand completely removes the reflog for the specified
references. This is in contrast to "expire" and "delete", both of which
can be used to delete reflog entries, but not the reflog itself.
-The "exists" subcommand checks whether a ref has a reflog. It exits
-with zero status if the reflog exists, and non-zero status if it does
-not.
+The "expire" subcommand prunes older reflog entries. Entries older
+than `expire` time, or entries older than `expire-unreachable` time
+and not reachable from the current tip, are removed from the reflog.
+This is typically not used directly by end users -- instead, see
+linkgit:git-gc[1].
OPTIONS
-------
@@ -71,18 +78,37 @@ Options for `show`
`git reflog show` accepts any of the options accepted by `git log`.
+Options for `delete`
+~~~~~~~~~~~~~~~~~~~~
+
+`git reflog delete` accepts options `--updateref`, `--rewrite`, `-n`,
+`--dry-run`, and `--verbose`, with the same meanings as when they are
+used with `expire`.
+
+Options for `drop`
+~~~~~~~~~~~~~~~~~~
+
+`--all`::
+ Drop the reflogs of all references from all worktrees.
+
+`--single-worktree`::
+ By default when `--all` is specified, reflogs from all working
+ trees are dropped. This option limits the processing to reflogs
+ from the current working tree only.
+
+
Options for `expire`
~~~~~~~~~~~~~~~~~~~~
---all::
+`--all`::
Process the reflogs of all references.
---single-worktree::
+`--single-worktree`::
By default when `--all` is specified, reflogs from all working
trees are processed. This option limits the processing to reflogs
from the current working tree only.
---expire=<time>::
+`--expire=<time>`::
Prune entries older than the specified time. If this option is
not specified, the expiration time is taken from the
configuration setting `gc.reflogExpire`, which in turn
@@ -90,7 +116,7 @@ Options for `expire`
of their age; `--expire=never` turns off pruning of reachable
entries (but see `--expire-unreachable`).
---expire-unreachable=<time>::
+`--expire-unreachable=<time>`::
Prune entries older than `<time>` that are not reachable from
the current tip of the branch. If this option is not
specified, the expiration time is taken from the configuration
@@ -100,17 +126,17 @@ Options for `expire`
turns off early pruning of unreachable entries (but see
`--expire`).
---updateref::
+`--updateref`::
Update the reference to the value of the top reflog entry (i.e.
<ref>@\{0\}) if the previous top entry was pruned. (This
option is ignored for symbolic references.)
---rewrite::
+`--rewrite`::
If a reflog entry's predecessor is pruned, adjust its "old"
SHA-1 to be equal to the "new" SHA-1 field of the entry that
now precedes it.
---stale-fix::
+`--stale-fix`::
Prune any reflog entries that point to "broken commits". A
broken commit is a commit that is not reachable from any of
the reference tips and that refers, directly or indirectly, to
@@ -121,33 +147,15 @@ has the same cost as 'git prune'. It is primarily intended to fix
corruption caused by garbage collecting using older versions of Git,
which didn't protect objects referred to by reflogs.
--n::
---dry-run::
+`-n`::
+`--dry-run`::
Do not actually prune any entries; just show what would have
been pruned.
---verbose::
+`--verbose`::
Print extra information on screen.
-Options for `delete`
-~~~~~~~~~~~~~~~~~~~~
-
-`git reflog delete` accepts options `--updateref`, `--rewrite`, `-n`,
-`--dry-run`, and `--verbose`, with the same meanings as when they are
-used with `expire`.
-
-Options for `drop`
-~~~~~~~~~~~~~~~~~~
-
---all::
- Drop the reflogs of all references from all worktrees.
-
---single-worktree::
- By default when `--all` is specified, reflogs from all working
- trees are dropped. This option limits the processing to reflogs
- from the current working tree only.
-
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc
index 4d6dc994f9..e608980711 100644
--- a/Documentation/git-refs.adoc
+++ b/Documentation/git-refs.adoc
@@ -11,6 +11,13 @@ SYNOPSIS
[synopsis]
git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]
git refs verify [--strict] [--verbose]
+git refs list [--count=<count>] [--shell|--perl|--python|--tcl]
+ [(--sort=<key>)...] [--format=<format>]
+ [--include-root-refs] [--points-at=<object>]
+ [--merged[=<object>]] [--no-merged[=<object>]]
+ [--contains[=<object>]] [--no-contains[=<object>]]
+ [(--exclude=<pattern>)...] [--start-after=<marker>]
+ [ --stdin | <pattern>... ]
DESCRIPTION
-----------
@@ -26,6 +33,11 @@ migrate::
verify::
Verify reference database consistency.
+list::
+ List references in the repository with support for filtering,
+ formatting, and sorting. This subcommand is an alias for
+ linkgit:git-for-each-ref[1] and offers identical functionality.
+
OPTIONS
-------
@@ -57,6 +69,10 @@ The following options are specific to 'git refs verify':
--verbose::
When verifying the reference database consistency, be chatty.
+The following options are specific to 'git refs list':
+
+include::for-each-ref-options.adoc[]
+
KNOWN LIMITATIONS
-----------------
diff --git a/Documentation/git-reset.adoc b/Documentation/git-reset.adoc
index 53ab88c545..50e8a0ba6f 100644
--- a/Documentation/git-reset.adoc
+++ b/Documentation/git-reset.adoc
@@ -125,6 +125,8 @@ OPTIONS
separated with _NUL_ character and all other characters are taken
literally (including newlines and quotes).
+include::diff-context-options.adoc[]
+
`--`::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-restore.adoc b/Documentation/git-restore.adoc
index 877b7772e6..961eef0137 100644
--- a/Documentation/git-restore.adoc
+++ b/Documentation/git-restore.adoc
@@ -28,8 +28,6 @@ otherwise from the index. Use `--source` to restore from a different commit.
See "Reset, restore and revert" in linkgit:git[1] for the differences
between the three commands.
-THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
-
OPTIONS
-------
`-s <tree>`::
@@ -52,6 +50,8 @@ leave out at most one of _<rev-A>__ and _<rev-B>_, in which case it defaults to
Mode" section of linkgit:git-add[1] to learn how to operate
the `--patch` mode.
+include::diff-context-options.adoc[]
+
`-W`::
`--worktree`::
`-S`::
diff --git a/Documentation/git-stash.adoc b/Documentation/git-stash.adoc
index e5e6c9d37f..e2300a19a2 100644
--- a/Documentation/git-stash.adoc
+++ b/Documentation/git-stash.adoc
@@ -222,6 +222,8 @@ to learn how to operate the `--patch` mode.
The `--patch` option implies `--keep-index`. You can use
`--no-keep-index` to override this.
+include::diff-context-options.adoc[]
+
-S::
--staged::
This option is only valid for `push` and `save` commands.
diff --git a/Documentation/git-submodule.adoc b/Documentation/git-submodule.adoc
index 87d8e0f0c5..503c84a200 100644
--- a/Documentation/git-submodule.adoc
+++ b/Documentation/git-submodule.adoc
@@ -307,6 +307,13 @@ OPTIONS
--force::
This option is only valid for add, deinit and update commands.
When running add, allow adding an otherwise ignored submodule path.
+ This option is also used to bypass a check that the submodule's name
+ is not already in use. By default, 'git submodule add' will fail if
+ the proposed name (which is derived from the path) is already registered
+ for another submodule in the repository. Using '--force' allows the command
+ to proceed by automatically generating a unique name by appending a number
+ to the conflicting name (e.g., if a submodule named 'child' exists, it will
+ try 'child1', and so on).
When running deinit the submodule working trees will be removed even
if they contain local changes.
When running update (only effective with the checkout procedure),
diff --git a/Documentation/git-switch.adoc b/Documentation/git-switch.adoc
index 9f62abf9e2..87707e9265 100644
--- a/Documentation/git-switch.adoc
+++ b/Documentation/git-switch.adoc
@@ -29,8 +29,6 @@ Switching branches does not require a clean index and working tree
however if the operation leads to loss of local changes, unless told
otherwise with `--discard-changes` or `--merge`.
-THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
-
OPTIONS
-------
_<branch>_::
diff --git a/Documentation/user-manual.adoc b/Documentation/user-manual.adoc
index 8d00a9e822..7696987117 100644
--- a/Documentation/user-manual.adoc
+++ b/Documentation/user-manual.adoc
@@ -4270,7 +4270,7 @@ So, look into `builtin/cat-file.c`, search for `cmd_cat_file()` and look what
it does.
------------------------------------------------------------------
- git_config(git_default_config);
+ repo_config(the_repository, git_default_config);
if (argc != 3)
usage("git cat-file [-t|-s|-e|-p|<type>] <sha1>");
if (get_sha1(argv[2], sha1))
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 63463c8773..be801415bd 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,6 +1,6 @@
#!/bin/sh
-DEF_VER=v2.50.GIT
+DEF_VER=v2.51.0-rc2
LF='
'
diff --git a/Makefile b/Makefile
index e11340c1ae..8d403301d9 100644
--- a/Makefile
+++ b/Makefile
@@ -1354,6 +1354,7 @@ THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/%
THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
CLAR_TEST_SUITES += u-ctype
+CLAR_TEST_SUITES += u-dir
CLAR_TEST_SUITES += u-example-decorate
CLAR_TEST_SUITES += u-hash
CLAR_TEST_SUITES += u-hashmap
diff --git a/add-interactive.c b/add-interactive.c
index 97ff35b6f1..3e692b47ec 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -36,11 +36,14 @@ static void init_color(struct repository *r, struct add_i_state *s,
free(key);
}
-void init_add_i_state(struct add_i_state *s, struct repository *r)
+void init_add_i_state(struct add_i_state *s, struct repository *r,
+ struct add_p_opt *add_p_opt)
{
const char *value;
s->r = r;
+ s->context = -1;
+ s->interhunkcontext = -1;
if (repo_config_get_value(r, "color.interactive", &value))
s->use_color = -1;
@@ -78,9 +81,27 @@ void init_add_i_state(struct add_i_state *s, struct repository *r)
repo_config_get_string(r, "diff.algorithm",
&s->interactive_diff_algorithm);
+ if (!repo_config_get_int(r, "diff.context", &s->context))
+ if (s->context < 0)
+ die(_("%s cannot be negative"), "diff.context");
+ if (!repo_config_get_int(r, "diff.interHunkContext", &s->interhunkcontext))
+ if (s->interhunkcontext < 0)
+ die(_("%s cannot be negative"), "diff.interHunkContext");
+
repo_config_get_bool(r, "interactive.singlekey", &s->use_single_key);
if (s->use_single_key)
setbuf(stdin, NULL);
+
+ if (add_p_opt->context != -1) {
+ if (add_p_opt->context < 0)
+ die(_("%s cannot be negative"), "--unified");
+ s->context = add_p_opt->context;
+ }
+ if (add_p_opt->interhunkcontext != -1) {
+ if (add_p_opt->interhunkcontext < 0)
+ die(_("%s cannot be negative"), "--inter-hunk-context");
+ s->interhunkcontext = add_p_opt->interhunkcontext;
+ }
}
void clear_add_i_state(struct add_i_state *s)
@@ -969,6 +990,10 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
opts->prompt = N_("Patch update");
count = list_and_choose(s, files, opts);
if (count > 0) {
+ struct add_p_opt add_p_opt = {
+ .context = s->context,
+ .interhunkcontext = s->interhunkcontext,
+ };
struct strvec args = STRVEC_INIT;
struct pathspec ps_selected = { 0 };
@@ -979,7 +1004,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
parse_pathspec(&ps_selected,
PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
PATHSPEC_LITERAL_PATH, "", args.v);
- res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected);
+ res = run_add_p(s->r, ADD_P_ADD, &add_p_opt, NULL, &ps_selected);
strvec_clear(&args);
clear_pathspec(&ps_selected);
}
@@ -1014,10 +1039,13 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
if (count > 0) {
struct child_process cmd = CHILD_PROCESS_INIT;
- strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached",
- oid_to_hex(!is_initial ? &oid :
- s->r->hash_algo->empty_tree),
- "--", NULL);
+ strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached", NULL);
+ if (s->context != -1)
+ strvec_pushf(&cmd.args, "--unified=%i", s->context);
+ if (s->interhunkcontext != -1)
+ strvec_pushf(&cmd.args, "--inter-hunk-context=%i", s->interhunkcontext);
+ strvec_pushl(&cmd.args, oid_to_hex(!is_initial ? &oid :
+ s->r->hash_algo->empty_tree), "--", NULL);
for (i = 0; i < files->items.nr; i++)
if (files->selected[i])
strvec_push(&cmd.args,
@@ -1110,7 +1138,8 @@ static void command_prompt_help(struct add_i_state *s)
_("(empty) select nothing"));
}
-int run_add_i(struct repository *r, const struct pathspec *ps)
+int run_add_i(struct repository *r, const struct pathspec *ps,
+ struct add_p_opt *add_p_opt)
{
struct add_i_state s = { NULL };
struct print_command_item_data data = { "[", "]" };
@@ -1153,7 +1182,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
->util = util;
}
- init_add_i_state(&s, r);
+ init_add_i_state(&s, r, add_p_opt);
/*
* When color was asked for, use the prompt color for
diff --git a/add-interactive.h b/add-interactive.h
index 693f125e8e..4213dcd67b 100644
--- a/add-interactive.h
+++ b/add-interactive.h
@@ -3,6 +3,13 @@
#include "color.h"
+struct add_p_opt {
+ int context;
+ int interhunkcontext;
+};
+
+#define ADD_P_OPT_INIT { .context = -1, .interhunkcontext = -1 }
+
struct add_i_state {
struct repository *r;
int use_color;
@@ -18,14 +25,17 @@ struct add_i_state {
int use_single_key;
char *interactive_diff_filter, *interactive_diff_algorithm;
+ int context, interhunkcontext;
};
-void init_add_i_state(struct add_i_state *s, struct repository *r);
+void init_add_i_state(struct add_i_state *s, struct repository *r,
+ struct add_p_opt *add_p_opt);
void clear_add_i_state(struct add_i_state *s);
struct repository;
struct pathspec;
-int run_add_i(struct repository *r, const struct pathspec *ps);
+int run_add_i(struct repository *r, const struct pathspec *ps,
+ struct add_p_opt *add_p_opt);
enum add_p_mode {
ADD_P_ADD,
@@ -36,6 +46,7 @@ enum add_p_mode {
};
int run_add_p(struct repository *r, enum add_p_mode mode,
- const char *revision, const struct pathspec *ps);
+ struct add_p_opt *o, const char *revision,
+ const struct pathspec *ps);
#endif
diff --git a/add-patch.c b/add-patch.c
index 95c67d8c80..302e6ba7d9 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -414,7 +414,6 @@ static int normalize_marker(const char *p)
static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
{
struct strvec args = STRVEC_INIT;
- const char *diff_algorithm = s->s.interactive_diff_algorithm;
struct strbuf *plain = &s->plain, *colored = NULL;
struct child_process cp = CHILD_PROCESS_INIT;
char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0';
@@ -424,8 +423,12 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
int res;
strvec_pushv(&args, s->mode->diff_cmd);
- if (diff_algorithm)
- strvec_pushf(&args, "--diff-algorithm=%s", diff_algorithm);
+ if (s->s.context != -1)
+ strvec_pushf(&args, "--unified=%i", s->s.context);
+ if (s->s.interhunkcontext != -1)
+ strvec_pushf(&args, "--inter-hunk-context=%i", s->s.interhunkcontext);
+ if (s->s.interactive_diff_algorithm)
+ strvec_pushf(&args, "--diff-algorithm=%s", s->s.interactive_diff_algorithm);
if (s->revision) {
struct object_id oid;
strvec_push(&args,
@@ -1760,14 +1763,15 @@ soft_increment:
}
int run_add_p(struct repository *r, enum add_p_mode mode,
- const char *revision, const struct pathspec *ps)
+ struct add_p_opt *o, const char *revision,
+ const struct pathspec *ps)
{
struct add_p_state s = {
{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
};
size_t i, binary_count = 0;
- init_add_i_state(&s.s, r);
+ init_add_i_state(&s.s, r, o);
if (mode == ADD_P_STASH)
s.mode = &patch_mode_stash;
diff --git a/apply.c b/apply.c
index a3804316fb..a2ceb3fb40 100644
--- a/apply.c
+++ b/apply.c
@@ -48,9 +48,9 @@ struct gitdiff_data {
static void git_apply_config(void)
{
- git_config_get_string("apply.whitespace", &apply_default_whitespace);
- git_config_get_string("apply.ignorewhitespace", &apply_default_ignorewhitespace);
- git_config(git_xmerge_config, NULL);
+ repo_config_get_string(the_repository, "apply.whitespace", &apply_default_whitespace);
+ repo_config_get_string(the_repository, "apply.ignorewhitespace", &apply_default_ignorewhitespace);
+ repo_config(the_repository, git_xmerge_config, NULL);
}
static int parse_whitespace_option(struct apply_state *state, const char *option)
@@ -3621,7 +3621,7 @@ static int try_threeway(struct apply_state *state,
/* Preimage the patch was prepared for */
if (patch->is_new)
- write_object_file("", 0, OBJ_BLOB, &pre_oid);
+ odb_write_object(the_repository->objects, "", 0, OBJ_BLOB, &pre_oid);
else if (repo_get_oid(the_repository, patch->old_oid_prefix, &pre_oid) ||
read_blob_object(&buf, &pre_oid, patch->old_mode))
return error(_("repository lacks the necessary blob to perform 3-way merge."));
@@ -3637,7 +3637,8 @@ static int try_threeway(struct apply_state *state,
return -1;
}
/* post_oid is theirs */
- write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &post_oid);
+ odb_write_object(the_repository->objects, tmp_image.buf.buf,
+ tmp_image.buf.len, OBJ_BLOB, &post_oid);
image_clear(&tmp_image);
/* our_oid is ours */
@@ -3650,7 +3651,8 @@ static int try_threeway(struct apply_state *state,
return error(_("cannot read the current contents of '%s'"),
patch->old_name);
}
- write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &our_oid);
+ odb_write_object(the_repository->objects, tmp_image.buf.buf,
+ tmp_image.buf.len, OBJ_BLOB, &our_oid);
image_clear(&tmp_image);
/* in-core three-way merge between post and our using pre as base */
@@ -4360,7 +4362,8 @@ static int add_index_file(struct apply_state *state,
}
fill_stat_cache_info(state->repo->index, ce, &st);
}
- if (write_object_file(buf, size, OBJ_BLOB, &ce->oid) < 0) {
+ if (odb_write_object(the_repository->objects, buf, size,
+ OBJ_BLOB, &ce->oid) < 0) {
discard_cache_entry(ce);
return error(_("unable to create backing store "
"for newly created file %s"), path);
diff --git a/archive-tar.c b/archive-tar.c
index 249164ea77..73b63ddc41 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -537,7 +537,7 @@ void init_tar_archiver(void)
tar_filter_config("tar.tgz.remote", "true", NULL);
tar_filter_config("tar.tar.gz.command", internal_gzip_command, NULL);
tar_filter_config("tar.tar.gz.remote", "true", NULL);
- git_config(git_tar_config, NULL);
+ repo_config(the_repository, git_tar_config, NULL);
for (i = 0; i < nr_tar_filters; i++) {
/* omit any filters that never had a command configured */
if (tar_filters[i]->filter_command)
diff --git a/archive-zip.c b/archive-zip.c
index df8866d5ba..bea5bdd43d 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -492,14 +492,22 @@ static int write_zip_entry(struct archiver_args *args,
zstream.next_in = buf;
zstream.avail_in = 0;
- result = git_deflate(&zstream, Z_FINISH);
- if (result != Z_STREAM_END)
- die("deflate error (%d)", result);
+
+ do {
+ result = git_deflate(&zstream, Z_FINISH);
+ if (result != Z_OK && result != Z_STREAM_END)
+ die("deflate error (%d)", result);
+
+ out_len = zstream.next_out - compressed;
+ if (out_len > 0) {
+ write_or_die(1, compressed, out_len);
+ compressed_size += out_len;
+ zstream.next_out = compressed;
+ zstream.avail_out = sizeof(compressed);
+ }
+ } while (result != Z_STREAM_END);
git_deflate_end(&zstream);
- out_len = zstream.next_out - compressed;
- write_or_die(1, compressed, out_len);
- compressed_size += out_len;
zip_offset += compressed_size;
write_zip_data_desc(size, compressed_size, crc);
@@ -632,7 +640,7 @@ static int write_zip_archive(const struct archiver *ar UNUSED,
{
int err;
- git_config(archive_zip_config, NULL);
+ repo_config(the_repository, archive_zip_config, NULL);
dos_time(&args->time, &zip_date, &zip_time);
diff --git a/archive.c b/archive.c
index f5a9d45c8d..310672b479 100644
--- a/archive.c
+++ b/archive.c
@@ -760,8 +760,8 @@ int write_archive(int argc, const char **argv, const char *prefix,
const char **argv_copy;
int rc;
- git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
- git_config(git_default_config, NULL);
+ repo_config_get_bool(the_repository, "uploadarchive.allowunreachable", &remote_allow_unreachable);
+ repo_config(the_repository, git_default_config, NULL);
describe_status.max_invocations = 1;
ctx.date_mode.type = DATE_NORMAL;
diff --git a/branch.c b/branch.c
index 93f5b4e8dd..26be358347 100644
--- a/branch.c
+++ b/branch.c
@@ -116,7 +116,7 @@ static int install_branch_config_multiple_remotes(int flag, const char *local,
}
strbuf_addf(&key, "branch.%s.remote", local);
- if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
+ if (repo_config_set_gently(the_repository, key.buf, origin ? origin : ".") < 0)
goto out_err;
strbuf_reset(&key);
@@ -127,16 +127,16 @@ static int install_branch_config_multiple_remotes(int flag, const char *local,
* more than one is provided, use CONFIG_REGEX_NONE to preserve what
* we've written so far.
*/
- if (git_config_set_gently(key.buf, NULL) < 0)
+ if (repo_config_set_gently(the_repository, key.buf, NULL) < 0)
goto out_err;
for_each_string_list_item(item, remotes)
- if (git_config_set_multivar_gently(key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0)
+ if (repo_config_set_multivar_gently(the_repository, key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0)
goto out_err;
if (rebasing) {
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.rebase", local);
- if (git_config_set_gently(key.buf, "true") < 0)
+ if (repo_config_set_gently(the_repository, key.buf, "true") < 0)
goto out_err;
}
strbuf_release(&key);
@@ -355,7 +355,7 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name)
char *v = NULL;
struct strbuf name = STRBUF_INIT;
strbuf_addf(&name, "branch.%s.description", branch_name);
- if (git_config_get_string(name.buf, &v)) {
+ if (repo_config_get_string(the_repository, name.buf, &v)) {
strbuf_release(&name);
return -1;
}
diff --git a/builtin/add.c b/builtin/add.c
index 7c292ffdc6..0235854f80 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -7,6 +7,7 @@
#include "builtin.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "lockfile.h"
#include "editor.h"
#include "dir.h"
@@ -29,6 +30,7 @@ static const char * const builtin_add_usage[] = {
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
+static struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
static int take_worktree_changes;
static int add_renormalize;
static int pathspec_file_nul;
@@ -157,7 +159,7 @@ static int refresh(struct repository *repo, int verbose, const struct pathspec *
int interactive_add(struct repository *repo,
const char **argv,
const char *prefix,
- int patch)
+ int patch, struct add_p_opt *add_p_opt)
{
struct pathspec pathspec;
int ret;
@@ -169,9 +171,9 @@ int interactive_add(struct repository *repo,
prefix, argv);
if (patch)
- ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec);
+ ret = !!run_add_p(repo, ADD_P_ADD, add_p_opt, NULL, &pathspec);
else
- ret = !!run_add_i(repo, &pathspec);
+ ret = !!run_add_i(repo, &pathspec, add_p_opt);
clear_pathspec(&pathspec);
return ret;
@@ -253,6 +255,8 @@ static struct option builtin_add_options[] = {
OPT_GROUP(""),
OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0),
OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
@@ -394,6 +398,11 @@ int cmd_add(int argc,
prepare_repo_settings(repo);
repo->settings.command_requires_full_index = 0;
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
if (patch_interactive)
add_interactive = 1;
if (add_interactive) {
@@ -401,7 +410,12 @@ int cmd_add(int argc,
die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch");
if (pathspec_from_file)
die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
- exit(interactive_add(repo, argv + 1, prefix, patch_interactive));
+ exit(interactive_add(repo, argv + 1, prefix, patch_interactive, &add_p_opt));
+ } else {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch");
}
if (edit_interactive) {
diff --git a/builtin/am.c b/builtin/am.c
index c9d925f7b9..6073d64ae9 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -162,18 +162,18 @@ static void am_state_init(struct am_state *state)
state->prec = 4;
- git_config_get_bool("am.threeway", &state->threeway);
+ repo_config_get_bool(the_repository, "am.threeway", &state->threeway);
state->utf8 = 1;
- git_config_get_bool("am.messageid", &state->message_id);
+ repo_config_get_bool(the_repository, "am.messageid", &state->message_id);
state->scissors = SCISSORS_UNSET;
state->quoted_cr = quoted_cr_unset;
strvec_init(&state->git_apply_opts);
- if (!git_config_get_bool("commit.gpgsign", &gpgsign))
+ if (!repo_config_get_bool(the_repository, "commit.gpgsign", &gpgsign))
state->sign_commit = gpgsign ? "" : NULL;
}
@@ -965,7 +965,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
{
if (keep_cr < 0) {
keep_cr = 0;
- git_config_get_bool("am.keepcr", &keep_cr);
+ repo_config_get_bool(the_repository, "am.keepcr", &keep_cr);
}
switch (patch_format) {
@@ -2445,7 +2445,7 @@ int cmd_am(int argc,
show_usage_with_options_if_asked(argc, argv, usage, options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
am_state_init(&state);
diff --git a/builtin/blame.c b/builtin/blame.c
index 91586e6852..2703820258 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -197,9 +197,7 @@ static void commit_info_destroy(struct commit_info *ci)
strbuf_release(&ci->summary);
}
-static void get_commit_info(struct commit *commit,
- struct commit_info *ret,
- int detailed)
+static void get_commit_info(struct commit *commit, struct commit_info *ret)
{
int len;
const char *subject, *encoding;
@@ -211,11 +209,6 @@ static void get_commit_info(struct commit *commit,
&ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
- if (!detailed) {
- repo_unuse_commit_buffer(the_repository, commit, message);
- return;
- }
-
get_ac_line(message, "\ncommitter ",
&ret->committer, &ret->committer_mail,
&ret->committer_time, &ret->committer_tz);
@@ -263,7 +256,7 @@ static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat)
return 0;
suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
+ get_commit_info(suspect->commit, &ci);
printf("author %s\n", ci.author.buf);
printf("author-mail %s\n", ci.author_mail.buf);
printf("author-time %"PRItime"\n", ci.author_time);
@@ -420,7 +413,7 @@ static void parse_color_fields(const char *s)
colorfield_nr = 0;
/* Ideally this would be stripped and split at the same time? */
- string_list_split(&l, s, ',', -1);
+ string_list_split(&l, s, ",", -1);
ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
for_each_string_list_item(item, &l) {
@@ -471,7 +464,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
const char *default_color = NULL, *color = NULL, *reset = NULL;
- get_commit_info(suspect->commit, &ci, 1);
+ get_commit_info(suspect->commit, &ci);
oid_to_hex_r(hex, &suspect->commit->object.oid);
cp = blame_nth_line(sb, ent->lno);
@@ -665,7 +658,7 @@ static void find_alignment(struct blame_scoreboard *sb, int *option)
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
struct commit_info ci = COMMIT_INFO_INIT;
suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
+ get_commit_info(suspect->commit, &ci);
if (*option & OUTPUT_SHOW_EMAIL)
num = utf8_strwidth(ci.author_mail.buf);
else
@@ -947,7 +940,7 @@ int cmd_blame(int argc,
const char *const *opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
setup_default_color_by_age();
- git_config(git_blame_config, &output_option);
+ repo_config(the_repository, git_blame_config, &output_option);
repo_init_revisions(the_repository, &revs, NULL);
revs.date_mode = blame_date_mode;
revs.diffopt.flags.allow_textconv = 1;
diff --git a/builtin/branch.c b/builtin/branch.c
index c150131bd9..fa5ced452e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -699,7 +699,7 @@ static int edit_branch_description(const char *branch_name)
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
- git_config_set(name.buf, buf.len ? buf.buf : NULL);
+ repo_config_set(the_repository, name.buf, buf.len ? buf.buf : NULL);
strbuf_release(&name);
strbuf_release(&buf);
@@ -791,7 +791,7 @@ int cmd_branch(int argc,
* Try to set sort keys from config. If config does not set any,
* fall back on default (refname) sorting.
*/
- git_config(git_branch_config, &sorting_options);
+ repo_config(the_repository, git_branch_config, &sorting_options);
if (!sorting_options.nr)
string_list_append(&sorting_options, "refname");
@@ -987,10 +987,10 @@ int cmd_branch(int argc,
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", branch->name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.merge", branch->name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_release(&buf);
} else if (!noncreate_actions && argc > 0 && argc <= 2) {
const char *branch_name = argv[0];
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 2492a0b6f3..fce0b06451 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -848,7 +848,7 @@ static void batch_each_object(struct batch_options *opt,
};
struct bitmap_index *bitmap = prepare_bitmap_git(the_repository);
- for_each_loose_object(batch_one_object_loose, &payload, 0);
+ for_each_loose_object(the_repository->objects, batch_one_object_loose, &payload, 0);
if (bitmap && !for_each_bitmapped_object(bitmap, &opt->objects_filter,
batch_one_object_bitmapped, &payload)) {
@@ -1095,7 +1095,7 @@ int cmd_cat_file(int argc,
OPT_END()
};
- git_config(git_cat_file_config, NULL);
+ repo_config(the_repository, git_cat_file_config, NULL);
batch.buffer_output = -1;
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 7cf275b893..51ed48ce43 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -119,7 +119,7 @@ int cmd_check_attr(int argc,
if (!is_bare_repository())
setup_work_tree();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, check_attr_options,
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 7b7831d13a..644c9a414f 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "quote.h"
#include "pathspec.h"
@@ -159,7 +160,7 @@ int cmd_check_ignore(int argc,
int num_ignored;
struct dir_struct dir = DIR_INIT;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, check_ignore_options,
check_ignore_usage, 0);
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index be2cebe121..9cc5c59830 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "ident.h"
#include "mailmap.h"
@@ -56,7 +57,7 @@ int cmd_check_mailmap(int argc,
int i;
struct string_list mailmap = STRING_LIST_INIT_NODUP;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, check_mailmap_options,
check_mailmap_usage, 0);
if (argc == 0 && !use_stdin)
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index da9345a44b..e0772b718b 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -4,6 +4,7 @@
#include "builtin.h"
#include "config.h"
#include "entry.h"
+#include "environment.h"
#include "gettext.h"
#include "parallel-checkout.h"
#include "parse-options.h"
@@ -132,7 +133,7 @@ int cmd_checkout__worker(int argc,
checkout_worker_usage,
checkout_worker_options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, checkout_worker_options,
checkout_worker_usage, 0);
if (argc > 0)
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 7f74bc702f..188128aebd 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "lockfile.h"
#include "quote.h"
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0a90b86a72..f9453473fe 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -61,6 +61,8 @@ static const char * const restore_usage[] = {
struct checkout_opts {
int patch_mode;
+ int patch_context;
+ int patch_interhunk_context;
int quiet;
int merge;
int force;
@@ -104,7 +106,12 @@ struct checkout_opts {
struct tree *source_tree;
};
-#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 }
+#define CHECKOUT_OPTS_INIT { \
+ .conflict_style = -1, \
+ .merge = -1, \
+ .patch_context = -1, \
+ .patch_interhunk_context = -1, \
+}
struct branch_info {
char *name; /* The short name used */
@@ -291,7 +298,7 @@ static int checkout_merged(int pos, const struct checkout *state,
read_mmblob(&ours, &threeway[1]);
read_mmblob(&theirs, &threeway[2]);
- git_config_get_bool("merge.renormalize", &renormalize);
+ repo_config_get_bool(the_repository, "merge.renormalize", &renormalize);
ll_opts.renormalize = renormalize;
ll_opts.conflict_style = conflict_style;
merge_status = ll_merge(&result_buf, path, &ancestor, "base",
@@ -320,7 +327,7 @@ static int checkout_merged(int pos, const struct checkout *state,
* (it also writes the merge result to the object database even
* when it may contain conflicts).
*/
- if (write_object_file(result_buf.ptr, result_buf.size, OBJ_BLOB, &oid))
+ if (odb_write_object(the_repository->objects, result_buf.ptr, result_buf.size, OBJ_BLOB, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
ce = make_transient_cache_entry(mode, &oid, path, 2, ce_mem_pool);
@@ -539,6 +546,10 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->patch_mode) {
enum add_p_mode patch_mode;
+ struct add_p_opt add_p_opt = {
+ .context = opts->patch_context,
+ .interhunkcontext = opts->patch_interhunk_context,
+ };
const char *rev = new_branch_info->name;
char rev_oid[GIT_MAX_HEXSZ + 1];
@@ -564,8 +575,8 @@ static int checkout_paths(const struct checkout_opts *opts,
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return !!run_add_p(the_repository, patch_mode, rev,
- &opts->pathspec);
+ return !!run_add_p(the_repository, patch_mode, &add_p_opt,
+ rev, &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -1738,6 +1749,8 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,
N_("checkout their version for unmerged files"),
3, PARSE_OPT_NONEG),
OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")),
+ OPT_DIFF_UNIFIED(&opts->patch_context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&opts->patch_interhunk_context),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file),
@@ -1764,7 +1777,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->prefix = prefix;
opts->show_progress = -1;
- git_config(git_checkout_config, opts);
+ repo_config(the_repository, git_checkout_config, opts);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -1780,6 +1793,18 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
argc = parse_options(argc, argv, prefix, options,
usagestr, parseopt_flags);
+ if (opts->patch_context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (opts->patch_interhunk_context < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
+ if (!opts->patch_mode) {
+ if (opts->patch_context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (opts->patch_interhunk_context != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
+ }
+
if (opts->show_progress < 0) {
if (opts->quiet)
opts->show_progress = 0;
diff --git a/builtin/clean.c b/builtin/clean.c
index 053c94fc6b..38b67923a6 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -13,6 +13,7 @@
#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "path.h"
@@ -477,43 +478,39 @@ static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
*/
static int parse_choice(struct menu_stuff *menu_stuff,
int is_single,
- struct strbuf input,
+ char *input,
int **chosen)
{
- struct strbuf **choice_list, **ptr;
+ struct string_list choice = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
int nr = 0;
int i;
- if (is_single) {
- choice_list = strbuf_split_max(&input, '\n', 0);
- } else {
- char *p = input.buf;
- do {
- if (*p == ',')
- *p = ' ';
- } while (*p++);
- choice_list = strbuf_split_max(&input, ' ', 0);
- }
+ string_list_split_in_place_f(&choice, input,
+ is_single ? "\n" : ", ", -1,
+ STRING_LIST_SPLIT_TRIM);
- for (ptr = choice_list; *ptr; ptr++) {
- char *p;
- int choose = 1;
+ for_each_string_list_item(item, &choice) {
+ const char *string;
+ int choose;
int bottom = 0, top = 0;
int is_range, is_number;
- strbuf_trim(*ptr);
- if (!(*ptr)->len)
+ string = item->string;
+ if (!*string)
continue;
/* Input that begins with '-'; unchoose */
- if (*(*ptr)->buf == '-') {
+ if (string[0] == '-') {
choose = 0;
- strbuf_remove((*ptr), 0, 1);
+ string++;
+ } else {
+ choose = 1;
}
is_range = 0;
is_number = 1;
- for (p = (*ptr)->buf; *p; p++) {
+ for (const char *p = string; *p; p++) {
if ('-' == *p) {
if (!is_range) {
is_range = 1;
@@ -531,27 +528,27 @@ static int parse_choice(struct menu_stuff *menu_stuff,
}
if (is_number) {
- bottom = atoi((*ptr)->buf);
+ bottom = atoi(string);
top = bottom;
} else if (is_range) {
- bottom = atoi((*ptr)->buf);
+ bottom = atoi(string);
/* a range can be specified like 5-7 or 5- */
- if (!*(strchr((*ptr)->buf, '-') + 1))
+ if (!*(strchr(string, '-') + 1))
top = menu_stuff->nr;
else
- top = atoi(strchr((*ptr)->buf, '-') + 1);
- } else if (!strcmp((*ptr)->buf, "*")) {
+ top = atoi(strchr(string, '-') + 1);
+ } else if (!strcmp(string, "*")) {
bottom = 1;
top = menu_stuff->nr;
} else {
- bottom = find_unique((*ptr)->buf, menu_stuff);
+ bottom = find_unique(string, menu_stuff);
top = bottom;
}
if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||
(is_single && bottom != top)) {
clean_print_color(CLEAN_COLOR_ERROR);
- printf(_("Huh (%s)?\n"), (*ptr)->buf);
+ printf(_("Huh (%s)?\n"), string);
clean_print_color(CLEAN_COLOR_RESET);
continue;
}
@@ -560,7 +557,7 @@ static int parse_choice(struct menu_stuff *menu_stuff,
(*chosen)[i-1] = choose;
}
- strbuf_list_free(choice_list);
+ string_list_clear(&choice, 0);
for (i = 0; i < menu_stuff->nr; i++)
nr += (*chosen)[i];
@@ -630,7 +627,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
nr = parse_choice(stuff,
opts->flags & MENU_OPTS_SINGLETON,
- choice,
+ choice.buf,
&chosen);
if (opts->flags & MENU_OPTS_SINGLETON) {
@@ -678,12 +675,13 @@ static int filter_by_patterns_cmd(void)
{
struct dir_struct dir = DIR_INIT;
struct strbuf confirm = STRBUF_INIT;
- struct strbuf **ignore_list;
- struct string_list_item *item;
struct pattern_list *pl;
int changed = -1, i;
for (;;) {
+ struct string_list ignore_list = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
+
if (!del_list.nr)
break;
@@ -701,14 +699,15 @@ static int filter_by_patterns_cmd(void)
break;
pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
- ignore_list = strbuf_split_max(&confirm, ' ', 0);
- for (i = 0; ignore_list[i]; i++) {
- strbuf_trim(ignore_list[i]);
- if (!ignore_list[i]->len)
- continue;
+ string_list_split_in_place_f(&ignore_list, confirm.buf, " ", -1,
+ STRING_LIST_SPLIT_TRIM);
- add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1));
+ for (i = 0; i < ignore_list.nr; i++) {
+ item = &ignore_list.items[i];
+ if (!*item->string)
+ continue;
+ add_pattern(item->string, "", 0, pl, -(i+1));
}
changed = 0;
@@ -729,7 +728,7 @@ static int filter_by_patterns_cmd(void)
clean_print_color(CLEAN_COLOR_RESET);
}
- strbuf_list_free(ignore_list);
+ string_list_clear(&ignore_list, 0);
dir_clear(&dir);
}
@@ -949,7 +948,7 @@ int cmd_clean(int argc,
OPT_END()
};
- git_config(git_clean_config, NULL);
+ repo_config(the_repository, git_clean_config, NULL);
argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
0);
diff --git a/builtin/clone.c b/builtin/clone.c
index 6d08abed37..c990f398ef 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -762,16 +762,16 @@ static int write_one_config(const char *key, const char *value,
{
/*
* give git_clone_config a chance to write config values back to the
- * environment, since git_config_set_multivar_gently only deals with
+ * environment, since repo_config_set_multivar_gently only deals with
* config-file writes
*/
int apply_failed = git_clone_config(key, value, ctx, data);
if (apply_failed)
return apply_failed;
- return git_config_set_multivar_gently(key,
- value ? value : "true",
- CONFIG_REGEX_NONE, 0);
+ return repo_config_set_multivar_gently(the_repository, key,
+ value ? value : "true",
+ CONFIG_REGEX_NONE, 0);
}
static void write_config(struct string_list *config)
@@ -822,12 +822,12 @@ static void write_refspec_config(const char *src_ref_prefix,
/* Configure the remote */
if (value.len) {
strbuf_addf(&key, "remote.%s.fetch", remote_name);
- git_config_set_multivar(key.buf, value.buf, "^$", 0);
+ repo_config_set_multivar(the_repository, key.buf, value.buf, "^$", 0);
strbuf_reset(&key);
if (option_mirror) {
strbuf_addf(&key, "remote.%s.mirror", remote_name);
- git_config_set(key.buf, "true");
+ repo_config_set(the_repository, key.buf, "true");
strbuf_reset(&key);
}
}
@@ -1001,7 +1001,7 @@ int cmd_clone(int argc,
packet_trace_identity("clone");
- git_config(git_clone_config, NULL);
+ repo_config(the_repository, git_clone_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
@@ -1150,7 +1150,7 @@ int cmd_clone(int argc,
strbuf_reset(&sb);
}
- if (!git_config_get_bool("submodule.stickyRecursiveClone", &val) &&
+ if (!repo_config_get_bool(the_repository, "submodule.stickyRecursiveClone", &val) &&
val)
string_list_append(&option_config, "submodule.recurse=true");
@@ -1242,7 +1242,7 @@ int cmd_clone(int argc,
* re-read config after init_db and write_config to pick up any config
* injected by --template and --config, respectively.
*/
- git_config(git_clone_config, NULL);
+ repo_config(the_repository, git_clone_config, NULL);
/*
* If option_reject_shallow is specified from CLI option,
@@ -1294,18 +1294,18 @@ int cmd_clone(int argc,
src_ref_prefix = "refs/";
strbuf_addstr(&branch_top, src_ref_prefix);
- git_config_set("core.bare", "true");
+ repo_config_set(the_repository, "core.bare", "true");
} else if (!option_rev) {
strbuf_addf(&branch_top, "refs/remotes/%s/", remote_name);
}
strbuf_addf(&key, "remote.%s.url", remote_name);
- git_config_set(key.buf, repo);
+ repo_config_set(the_repository, key.buf, repo);
strbuf_reset(&key);
if (!option_tags) {
strbuf_addf(&key, "remote.%s.tagOpt", remote_name);
- git_config_set(key.buf, "--no-tags");
+ repo_config_set(the_repository, key.buf, "--no-tags");
strbuf_reset(&key);
}
@@ -1467,7 +1467,7 @@ int cmd_clone(int argc,
warning(_("failed to fetch objects from bundle URI '%s'"),
bundle_uri);
else if (has_heuristic)
- git_config_set_gently("fetch.bundleuri", bundle_uri);
+ repo_config_set_gently(the_repository, "fetch.bundleuri", bundle_uri);
remote_state_clear(the_repository->remote_state);
free(the_repository->remote_state);
diff --git a/builtin/column.c b/builtin/column.c
index ce6443d5fa..87dce3c6e5 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -42,9 +42,9 @@ int cmd_column(int argc,
/* This one is special and must be the first one */
if (argc > 1 && starts_with(argv[1], "--command=")) {
command = argv[1] + 10;
- git_config(column_config, (void *)command);
+ repo_config(the_repository, column_config, (void *)command);
} else
- git_config(column_config, NULL);
+ repo_config(the_repository, column_config, NULL);
memset(&copts, 0, sizeof(copts));
copts.padding = 1;
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 25018a0b9d..4992ac146e 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "commit.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "parse-options.h"
@@ -265,7 +266,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
trace2_cmd_mode("write");
- git_config(git_commit_graph_write_config, &opts);
+ repo_config(the_repository, git_commit_graph_write_config, &opts);
argc = parse_options(argc, argv, prefix,
options,
@@ -347,7 +348,7 @@ int cmd_commit_graph(int argc,
};
struct option *options = parse_options_concat(builtin_commit_graph_options, common_opts);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
disable_replace_refs();
save_commit_buffer = 0;
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 31cfd9bd15..5189e685a7 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -6,6 +6,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-name.h"
@@ -125,7 +126,7 @@ int cmd_commit_tree(int argc,
};
int ret;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
show_usage_with_options_if_asked(argc, argv,
commit_tree_usage, options);
diff --git a/builtin/commit.c b/builtin/commit.c
index 63e7158e98..b5b9608813 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -19,6 +19,7 @@
#include "environment.h"
#include "diff.h"
#include "commit.h"
+#include "add-interactive.h"
#include "gettext.h"
#include "revision.h"
#include "wt-status.h"
@@ -122,6 +123,7 @@ static const char *edit_message, *use_message;
static char *fixup_message, *fixup_commit, *squash_message;
static const char *fixup_prefix;
static int all, also, interactive, patch_interactive, only, amend, signoff;
+static struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
@@ -207,9 +209,9 @@ static void status_init_config(struct wt_status *s, config_fn_t fn)
{
wt_status_prepare(the_repository, s);
init_diff_ui_defaults();
- git_config(fn, s);
+ repo_config(the_repository, fn, s);
determine_whence(s);
- s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after git_config() */
+ s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after repo_config() */
}
static void rollback_index_files(void)
@@ -354,6 +356,11 @@ static const char *prepare_index(const char **argv, const char *prefix,
const char *ret;
char *path = NULL;
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
if (is_status)
refresh_flags |= REFRESH_UNMERGED;
parse_pathspec(&pathspec, 0,
@@ -400,7 +407,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0)
+ if (interactive_add(the_repository, argv, prefix, patch_interactive, &add_p_opt) != 0)
die(_("interactive add failed"));
the_repository->index_file = old_repo_index_file;
@@ -424,6 +431,11 @@ static const char *prepare_index(const char **argv, const char *prefix,
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
goto out;
+ } else {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch");
}
/*
@@ -1726,6 +1738,8 @@ int cmd_commit(int argc,
OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")),
OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT_BOOL('o', "only", &only, N_("commit only specified files")),
OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit and commit-msg hooks")),
OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")),
diff --git a/builtin/config.c b/builtin/config.c
index 5efe273010..59fb113b07 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -966,12 +966,12 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix,
value = normalize_value(argv[0], argv[1], type, &default_kvi);
if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) {
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value, value_pattern,
- comment, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value, value_pattern,
+ comment, flags);
} else {
- ret = git_config_set_in_file_gently(location_opts.source.file,
- argv[0], comment, value);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
@@ -1010,12 +1010,12 @@ static int cmd_config_unset(int argc, const char **argv, const char *prefix,
check_write(&location_opts.source);
if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], NULL, value_pattern,
- NULL, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, value_pattern,
+ NULL, flags);
else
- ret = git_config_set_in_file_gently(location_opts.source.file, argv[0],
- NULL, NULL);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, argv[0],
+ NULL, NULL);
location_options_release(&location_opts);
return ret;
@@ -1091,7 +1091,7 @@ static int show_editor(struct config_location_options *opts)
die(_("editing stdin is not supported"));
if (opts->source.blob)
die(_("editing blobs is not supported"));
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
config_file = opts->source.file ?
xstrdup(opts->source.file) :
repo_git_path(the_repository, "config");
@@ -1296,7 +1296,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
check_write(&location_opts.source);
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
@@ -1305,26 +1305,26 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
check_write(&location_opts.source);
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value, argv[2],
- comment, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value, argv[2],
+ comment, flags);
}
else if (actions == ACTION_ADD) {
check_write(&location_opts.source);
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value,
- CONFIG_REGEX_NONE,
- comment, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value,
+ CONFIG_REGEX_NONE,
+ comment, flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write(&location_opts.source);
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value, argv[2],
- comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value, argv[2],
+ comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -1350,19 +1350,19 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
check_write(&location_opts.source);
check_argc(argc, 1, 2);
if (argc == 2)
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], NULL, argv[1],
- NULL, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags);
else
- ret = git_config_set_in_file_gently(location_opts.source.file,
- argv[0], NULL, NULL);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_write(&location_opts.source);
check_argc(argc, 1, 2);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], NULL, argv[1],
- NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
check_write(&location_opts.source);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index f687647931..a61d3b46aa 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -7,6 +7,7 @@
#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "path.h"
#include "parse-options.h"
@@ -106,7 +107,7 @@ int cmd_count_objects(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0);
/* we do not take arguments other than flags for now */
@@ -117,7 +118,7 @@ int cmd_count_objects(int argc,
report_linked_checkout_garbage(the_repository);
}
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ for_each_loose_file_in_source(the_repository->objects->sources,
count_loose, count_cruft, NULL, NULL);
if (verbose) {
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 5065ff4660..65cc619bec 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -307,7 +307,7 @@ int cmd_credential_cache_daemon(int argc,
OPT_END()
};
- git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
+ repo_config_get_bool(the_repository, "credentialcache.ignoresighup", &ignore_sighup);
argc = parse_options(argc, argv, prefix, options, usage, 0);
socket_path = argv[0];
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index e669e99dbf..b74e06cc93 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -66,7 +66,7 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
{
int timeout_ms = 1000;
- git_config_get_int("credentialstore.locktimeoutms", &timeout_ms);
+ repo_config_get_int(the_repository, "credentialstore.locktimeoutms", &timeout_ms);
if (hold_lock_file_for_update_timeout(&credential_lock, fn, 0, timeout_ms) < 0)
die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms);
if (extra)
diff --git a/builtin/credential.c b/builtin/credential.c
index 2e11b15dde..a295c80b36 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -3,6 +3,7 @@
#include "git-compat-util.h"
#include "credential.h"
#include "builtin.h"
+#include "environment.h"
#include "config.h"
static const char usage_msg[] =
@@ -16,7 +17,7 @@ int cmd_credential(int argc,
const char *op;
struct credential c = CREDENTIAL_INIT;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
show_usage_if_asked(argc, argv, usage_msg);
if (argc != 2)
diff --git a/builtin/describe.c b/builtin/describe.c
index fbf305d762..0540976210 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -23,6 +23,7 @@
#include "list-objects.h"
#include "commit-slab.h"
#include "wildmatch.h"
+#include "prio-queue.h"
#define MAX_TAGS (FLAG_BITS - 1)
#define DEFAULT_CANDIDATES 10
@@ -249,24 +250,62 @@ static int compare_pt(const void *a_, const void *b_)
return 0;
}
-static unsigned long finish_depth_computation(
- struct commit_list **list,
- struct possible_tag *best)
+struct lazy_queue {
+ struct prio_queue queue;
+ bool get_pending;
+};
+
+#define LAZY_QUEUE_INIT { { compare_commits_by_commit_date }, false }
+
+static void *lazy_queue_get(struct lazy_queue *queue)
+{
+ if (queue->get_pending)
+ prio_queue_get(&queue->queue);
+ else
+ queue->get_pending = true;
+ return prio_queue_peek(&queue->queue);
+}
+
+static void lazy_queue_put(struct lazy_queue *queue, void *thing)
+{
+ if (queue->get_pending)
+ prio_queue_replace(&queue->queue, thing);
+ else
+ prio_queue_put(&queue->queue, thing);
+ queue->get_pending = false;
+}
+
+static bool lazy_queue_empty(const struct lazy_queue *queue)
+{
+ return queue->queue.nr == (queue->get_pending ? 1 : 0);
+}
+
+static void lazy_queue_clear(struct lazy_queue *queue)
+{
+ clear_prio_queue(&queue->queue);
+ queue->get_pending = false;
+}
+
+static bool all_have_flag(const struct lazy_queue *queue, unsigned flag)
+{
+ for (size_t i = queue->get_pending ? 1 : 0; i < queue->queue.nr; i++) {
+ struct commit *commit = queue->queue.array[i].data;
+ if (!(commit->object.flags & flag))
+ return false;
+ }
+ return true;
+}
+
+static unsigned long finish_depth_computation(struct lazy_queue *queue,
+ struct possible_tag *best)
{
unsigned long seen_commits = 0;
- while (*list) {
- struct commit *c = pop_commit(list);
+ while (!lazy_queue_empty(queue)) {
+ struct commit *c = lazy_queue_get(queue);
struct commit_list *parents = c->parents;
seen_commits++;
if (c->object.flags & best->flag_within) {
- struct commit_list *a = *list;
- while (a) {
- struct commit *i = a->item;
- if (!(i->object.flags & best->flag_within))
- break;
- a = a->next;
- }
- if (!a)
+ if (all_have_flag(queue, best->flag_within))
break;
} else
best->depth++;
@@ -274,7 +313,7 @@ static unsigned long finish_depth_computation(
struct commit *p = parents->item;
repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
- commit_list_insert_by_date(p, list);
+ lazy_queue_put(queue, p);
p->object.flags |= c->object.flags;
parents = parents->next;
}
@@ -316,7 +355,7 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf
static void describe_commit(struct object_id *oid, struct strbuf *dst)
{
struct commit *cmit, *gave_up_on = NULL;
- struct commit_list *list;
+ struct lazy_queue queue = LAZY_QUEUE_INIT;
struct commit_name *n;
struct possible_tag all_matches[MAX_TAGS];
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
@@ -359,11 +398,10 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
have_util = 1;
}
- list = NULL;
cmit->object.flags = SEEN;
- commit_list_insert(cmit, &list);
- while (list) {
- struct commit *c = pop_commit(&list);
+ lazy_queue_put(&queue, cmit);
+ while (!lazy_queue_empty(&queue)) {
+ struct commit *c = lazy_queue_get(&queue);
struct commit_list *parents = c->parents;
struct commit_name **slot;
@@ -397,7 +435,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
t->depth++;
}
/* Stop if last remaining path already covered by best candidate(s) */
- if (annotated_cnt && !list) {
+ if (annotated_cnt && lazy_queue_empty(&queue)) {
int best_depth = INT_MAX;
unsigned best_within = 0;
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
@@ -420,7 +458,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit *p = parents->item;
repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
- commit_list_insert_by_date(p, &list);
+ lazy_queue_put(&queue, p);
p->object.flags |= c->object.flags;
parents = parents->next;
@@ -435,6 +473,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
if (suffix)
strbuf_addstr(dst, suffix);
+ lazy_queue_clear(&queue);
return;
}
if (unannotated_cnt)
@@ -450,11 +489,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
QSORT(all_matches, match_cnt, compare_pt);
if (gave_up_on) {
- commit_list_insert_by_date(gave_up_on, &list);
+ lazy_queue_put(&queue, gave_up_on);
seen_commits--;
}
- seen_commits += finish_depth_computation(&list, &all_matches[0]);
- free_commit_list(list);
+ seen_commits += finish_depth_computation(&queue, &all_matches[0]);
+ lazy_queue_clear(&queue);
if (debug) {
static int label_width = -1;
@@ -623,7 +662,7 @@ int cmd_describe(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
if (abbrev < 0)
abbrev = DEFAULT_ABBREV;
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 99b1749723..ea91347ce2 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -31,7 +31,7 @@ int cmd_diff_files(int argc,
show_usage_if_asked(argc, argv, diff_files_usage);
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 81c0bc8ed7..522dacfc4c 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -28,7 +28,7 @@ int cmd_diff_index(int argc,
show_usage_if_asked(argc, argv, diff_cache_usage);
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index e31cc797fe..49dd4d00eb 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -124,7 +124,7 @@ int cmd_diff_tree(int argc,
show_usage_if_asked(argc, argv, diff_tree_usage);
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/diff.c b/builtin/diff.c
index eebffe36cc..0b23c41456 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -486,7 +486,22 @@ int cmd_diff(int argc,
repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
init_diff_ui_defaults();
- git_config(git_diff_ui_config, NULL);
+ repo_config(the_repository, git_diff_ui_config, NULL);
+
+ /*
+ * If we are ignoring the fact that our current directory may
+ * be part of a working tree controlled by a Git repository to
+ * pretend to be a "better GNU diff", we should undo the
+ * effect of the setup code that did a chdir() to the top of
+ * the working tree. Where we came from is recorded in the
+ * prefix.
+ */
+ if (no_index && prefix) {
+ if (chdir(prefix))
+ die(_("cannot come back to cwd"));
+ prefix = NULL;
+ }
+
prefix = precompose_argv_prefix(argc, argv, prefix);
repo_init_revisions(the_repository, &rev, prefix);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index f4169dc5f3..c06ee0b213 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
@@ -1361,7 +1362,7 @@ int cmd_fast_export(int argc,
usage_with_options (fast_export_usage, options);
/* we handle encodings */
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
repo_init_revisions(the_repository, &revs, prefix);
init_revision_sources(&revision_sources);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 6e7d0c3449..2c35f9345d 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -822,11 +822,11 @@ static char *keep_pack(const char *curr_index_name)
die_errno("failed to write keep file");
odb_pack_name(pack_data->repo, &name, pack_data->hash, "pack");
- if (finalize_object_file(pack_data->pack_name, name.buf))
+ if (finalize_object_file(pack_data->repo, pack_data->pack_name, name.buf))
die("cannot store pack file");
odb_pack_name(pack_data->repo, &name, pack_data->hash, "idx");
- if (finalize_object_file(curr_index_name, name.buf))
+ if (finalize_object_file(pack_data->repo, curr_index_name, name.buf))
die("cannot store index file");
free((void *)curr_index_name);
return strbuf_detach(&name, NULL);
@@ -3592,25 +3592,25 @@ static void git_pack_config(void)
int limit;
unsigned long packsizelimit_value;
- if (!git_config_get_ulong("pack.depth", &max_depth)) {
+ if (!repo_config_get_ulong(the_repository, "pack.depth", &max_depth)) {
if (max_depth > MAX_DEPTH)
max_depth = MAX_DEPTH;
}
- if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
+ if (!repo_config_get_int(the_repository, "pack.indexversion", &indexversion_value)) {
pack_idx_opts.version = indexversion_value;
if (pack_idx_opts.version > 2)
git_die_config(the_repository, "pack.indexversion",
"bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
}
- if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
+ if (!repo_config_get_ulong(the_repository, "pack.packsizelimit", &packsizelimit_value))
max_packsize = packsizelimit_value;
- if (!git_config_get_int("fastimport.unpacklimit", &limit))
+ if (!repo_config_get_int(the_repository, "fastimport.unpacklimit", &limit))
unpack_limit = limit;
- else if (!git_config_get_int("transfer.unpacklimit", &limit))
+ else if (!repo_config_get_int(the_repository, "transfer.unpacklimit", &limit))
unpack_limit = limit;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
}
static const char fast_import_usage[] =
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 87a0cca799..24645c4653 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1995,7 +1995,7 @@ static int add_remote_or_group(const char *name, struct string_list *list)
struct remote_group_data g;
g.name = name; g.list = list;
- git_config(get_remote_group, &g);
+ repo_config(the_repository, get_remote_group, &g);
if (list->nr == prev_nr) {
struct remote *remote = remote_get(name);
if (!remote_is_configured(remote, 0))
@@ -2417,7 +2417,7 @@ int cmd_fetch(int argc,
free(anon);
}
- git_config(git_fetch_config, &config);
+ repo_config(the_repository, git_fetch_config, &config);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -2508,7 +2508,7 @@ int cmd_fetch(int argc,
if (!max_jobs)
max_jobs = online_cpus();
- if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+ if (!repo_config_get_string_tmp(the_repository, "fetch.bundleuri", &bundle_uri) &&
fetch_bundle_uri(the_repository, bundle_uri, NULL))
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
@@ -2683,12 +2683,12 @@ int cmd_fetch(int argc,
* but respect config settings disabling it.
*/
int opt_val;
- if (git_config_get_int("gc.autopacklimit", &opt_val))
+ if (repo_config_get_int(the_repository, "gc.autopacklimit", &opt_val))
opt_val = -1;
if (opt_val != 0)
git_config_push_parameter("gc.autoPackLimit=1");
- if (git_config_get_int("maintenance.incremental-repack.auto", &opt_val))
+ if (repo_config_get_int(the_repository, "maintenance.incremental-repack.auto", &opt_val))
opt_val = -1;
if (opt_val != 0)
git_config_push_parameter("maintenance.incremental-repack.auto=-1");
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 3b6aac2cf7..cf4273a52c 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "fmt-merge-msg.h"
@@ -13,12 +12,13 @@ static const char * const fmt_merge_msg_usage[] = {
int cmd_fmt_merge_msg(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
char *inpath = NULL;
const char *message = NULL;
char *into_name = NULL;
int shortlog_len = -1;
+ int merge_log_config = -1;
struct option options[] = {
{
.type = OPTION_INTEGER,
@@ -53,7 +53,7 @@ int cmd_fmt_merge_msg(int argc,
int ret;
struct fmt_merge_msg_opts opts;
- git_config(fmt_merge_msg_config, NULL);
+ repo_config(repo, fmt_merge_msg_config, &merge_log_config);
argc = parse_options(argc, argv, prefix, options, fmt_merge_msg_usage,
0);
if (argc > 0)
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3d2207ec77..4a2fc421db 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "commit.h"
#include "config.h"
+#include "environment.h"
+#include "for-each-ref.h"
#include "gettext.h"
#include "object.h"
#include "parse-options.h"
@@ -8,18 +10,7 @@
#include "strbuf.h"
#include "strvec.h"
-static char const * const for_each_ref_usage[] = {
- N_("git for-each-ref [<options>] [<pattern>]"),
- N_("git for-each-ref [--points-at <object>]"),
- N_("git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"),
- N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"),
- NULL
-};
-
-int cmd_for_each_ref(int argc,
- const char **argv,
- const char *prefix,
- struct repository *repo)
+int for_each_ref_core(int argc, const char **argv, const char *prefix, struct repository *repo, const char *const *usage)
{
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
@@ -44,6 +35,7 @@ int cmd_for_each_ref(int argc,
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+ OPT_STRING( 0 , "start-after", &filter.start_after, N_("marker"), N_("start iteration after the provided marker")),
OPT__COLOR(&format.use_color, N_("respect format colors")),
OPT_REF_FILTER_EXCLUDE(&filter),
OPT_REF_SORT(&sorting_options),
@@ -67,17 +59,20 @@ int cmd_for_each_ref(int argc,
/* Set default (refname) sorting */
string_list_append(&sorting_options, "refname");
- parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
+ parse_options(argc, argv, prefix, opts, usage, 0);
if (format.array_opts.max_count < 0) {
error("invalid --count argument: `%d'", format.array_opts.max_count);
- usage_with_options(for_each_ref_usage, opts);
+ usage_with_options(usage, opts);
}
if (HAS_MULTI_BITS(format.quote_style)) {
error("more than one quoting style?");
- usage_with_options(for_each_ref_usage, opts);
+ usage_with_options(usage, opts);
}
if (verify_ref_format(&format))
- usage_with_options(for_each_ref_usage, opts);
+ usage_with_options(usage, opts);
+
+ if (filter.start_after && sorting_options.nr > 1)
+ die(_("cannot use --start-after with custom sort options"));
sorting = ref_sorting_options(&sorting_options);
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
@@ -100,6 +95,9 @@ int cmd_for_each_ref(int argc,
filter.name_patterns = argv;
}
+ if (filter.start_after && filter.name_patterns && filter.name_patterns[0])
+ die(_("cannot use --start-after with patterns"));
+
if (include_root_refs)
flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD;
@@ -111,3 +109,16 @@ int cmd_for_each_ref(int argc,
strvec_clear(&vec);
return 0;
}
+
+int cmd_for_each_ref(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo)
+{
+ static char const * const for_each_ref_usage[] = {
+ N_("git for-each-ref " COMMON_USAGE_FOR_EACH_REF),
+ NULL
+ };
+
+ return for_each_ref_core(argc, argv, prefix, repo, for_each_ref_usage);
+}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 0084cf7400..d2eb9d4fbe 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -393,7 +393,8 @@ static void check_connectivity(void)
* and ignore any that weren't present in our earlier
* traversal.
*/
- for_each_loose_object(mark_loose_unreachable_referents, NULL, 0);
+ for_each_loose_object(the_repository->objects,
+ mark_loose_unreachable_referents, NULL, 0);
for_each_packed_object(the_repository,
mark_packed_unreachable_referents,
NULL,
@@ -502,13 +503,12 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
}
}
-static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,
+static int fsck_handle_reflog_ent(const char *refname,
+ struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED,
- const char *message UNUSED, void *cb_data)
+ const char *message UNUSED, void *cb_data UNUSED)
{
- const char *refname = cb_data;
-
if (verbose)
fprintf_ln(stderr, _("Checking reflog %s->%s"),
oid_to_hex(ooid), oid_to_hex(noid));
@@ -525,7 +525,7 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
strbuf_worktree_ref(cb_data, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(the_repository),
refname.buf, fsck_handle_reflog_ent,
- refname.buf);
+ NULL);
strbuf_release(&refname);
return 0;
}
@@ -632,7 +632,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,
oi.sizep = &size;
oi.typep = &type;
- if (read_loose_object(path, oid, &real_oid, &contents, &oi) < 0) {
+ if (read_loose_object(the_repository, path, oid, &real_oid, &contents, &oi) < 0) {
if (contents && !oideq(&real_oid, oid))
err = error(_("%s: hash-path mismatch, found at: %s"),
oid_to_hex(&real_oid), path);
@@ -687,7 +687,7 @@ static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
return 0;
}
-static void fsck_object_dir(const char *path)
+static void fsck_source(struct odb_source *source)
{
struct progress *progress = NULL;
struct for_each_loose_cb cb_data = {
@@ -701,8 +701,8 @@ static void fsck_object_dir(const char *path)
progress = start_progress(the_repository,
_("Checking object directories"), 256);
- for_each_loose_file_in_objdir(path, fsck_loose, fsck_cruft, fsck_subdir,
- &cb_data);
+ for_each_loose_file_in_source(source, fsck_loose,
+ fsck_cruft, fsck_subdir, &cb_data);
display_progress(progress, 256);
stop_progress(&progress);
}
@@ -987,20 +987,21 @@ int cmd_fsck(int argc,
if (name_objects)
fsck_enable_object_names(&fsck_walk_options);
- git_config(git_fsck_config, &fsck_obj_options);
+ repo_config(the_repository, git_fsck_config, &fsck_obj_options);
prepare_repo_settings(the_repository);
if (check_references)
fsck_refs(the_repository);
if (connectivity_only) {
- for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
+ for_each_loose_object(the_repository->objects,
+ mark_loose_for_connectivity, NULL, 0);
for_each_packed_object(the_repository,
mark_packed_for_connectivity, NULL, 0);
} else {
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next)
- fsck_object_dir(source->path);
+ fsck_source(source);
if (check_full) {
struct packed_git *p;
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0820e524f1..242c594646 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -5,6 +5,7 @@
#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "fsmonitor-ll.h"
@@ -1547,7 +1548,7 @@ int cmd_fsmonitor__daemon(int argc,
OPT_END()
};
- git_config(fsmonitor_config, NULL);
+ repo_config(the_repository, fsmonitor_config, NULL);
argc = parse_options(argc, argv, prefix, options,
builtin_fsmonitor__daemon_usage, 0);
diff --git a/builtin/gc.c b/builtin/gc.c
index a02d6b7806..03ae4926b2 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -114,7 +114,7 @@ static int gc_config_is_timestamp_never(const char *var)
const char *value;
timestamp_t expire;
- if (!git_config_get_value(var, &value) && value) {
+ if (!repo_config_get_value(the_repository, var, &value) && value) {
if (parse_expiry_date(value, &expire))
die(_("failed to parse '%s' value '%s'"), var, value);
return expire == 0;
@@ -178,7 +178,7 @@ static void gc_config(struct gc_config *cfg)
char *owned = NULL;
unsigned long ulongval;
- if (!git_config_get_value("gc.packrefs", &value)) {
+ if (!repo_config_get_value(the_repository, "gc.packrefs", &value)) {
if (value && !strcmp(value, "notbare"))
cfg->pack_refs = -1;
else
@@ -189,13 +189,13 @@ static void gc_config(struct gc_config *cfg)
gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
cfg->prune_reflogs = 0;
- git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window);
- git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth);
- git_config_get_int("gc.auto", &cfg->gc_auto_threshold);
- git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit);
- git_config_get_bool("gc.autodetach", &cfg->detach_auto);
- git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs);
- git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size);
+ repo_config_get_int(the_repository, "gc.aggressivewindow", &cfg->aggressive_window);
+ repo_config_get_int(the_repository, "gc.aggressivedepth", &cfg->aggressive_depth);
+ repo_config_get_int(the_repository, "gc.auto", &cfg->gc_auto_threshold);
+ repo_config_get_int(the_repository, "gc.autopacklimit", &cfg->gc_auto_pack_limit);
+ repo_config_get_bool(the_repository, "gc.autodetach", &cfg->detach_auto);
+ repo_config_get_bool(the_repository, "gc.cruftpacks", &cfg->cruft_packs);
+ repo_config_get_ulong(the_repository, "gc.maxcruftsize", &cfg->max_cruft_size);
if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) {
free(cfg->prune_expire);
@@ -212,23 +212,23 @@ static void gc_config(struct gc_config *cfg)
cfg->gc_log_expire = owned;
}
- git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
- git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
+ repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &cfg->big_pack_threshold);
+ repo_config_get_ulong(the_repository, "pack.deltacachesize", &cfg->max_delta_cache_size);
- if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval))
+ if (!repo_config_get_ulong(the_repository, "core.deltabasecachelimit", &ulongval))
cfg->delta_base_cache_limit = ulongval;
- if (!git_config_get_string("gc.repackfilter", &owned)) {
+ if (!repo_config_get_string(the_repository, "gc.repackfilter", &owned)) {
free(cfg->repack_filter);
cfg->repack_filter = owned;
}
- if (!git_config_get_string("gc.repackfilterto", &owned)) {
+ if (!repo_config_get_string(the_repository, "gc.repackfilterto", &owned)) {
free(cfg->repack_filter_to);
cfg->repack_filter_to = owned;
}
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
}
enum schedule_priority {
@@ -312,7 +312,8 @@ struct count_reflog_entries_data {
size_t limit;
};
-static int count_reflog_entries(struct object_id *old_oid, struct object_id *new_oid,
+static int count_reflog_entries(const char *refname UNUSED,
+ struct object_id *old_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data)
{
@@ -332,7 +333,7 @@ static int reflog_expire_condition(struct gc_config *cfg UNUSED)
};
int limit = 100;
- git_config_get_int("maintenance.reflog-expire.auto", &limit);
+ repo_config_get_int(the_repository, "maintenance.reflog-expire.auto", &limit);
if (!limit)
return 0;
if (limit < 0)
@@ -379,7 +380,7 @@ static int worktree_prune_condition(struct gc_config *cfg)
struct dirent *d;
DIR *dir = NULL;
- git_config_get_int("maintenance.worktree-prune.auto", &limit);
+ repo_config_get_int(the_repository, "maintenance.worktree-prune.auto", &limit);
if (limit <= 0) {
should_prune = limit < 0;
goto out;
@@ -424,7 +425,7 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
int should_gc = 0, limit = 1;
DIR *dir = NULL;
- git_config_get_int("maintenance.rerere-gc.auto", &limit);
+ repo_config_get_int(the_repository, "maintenance.rerere-gc.auto", &limit);
if (limit <= 0) {
should_gc = limit < 0;
goto out;
@@ -1162,8 +1163,8 @@ static int should_write_commit_graph(struct gc_config *cfg UNUSED)
data.num_not_in_graph = 0;
data.limit = 100;
- git_config_get_int("maintenance.commit-graph.auto",
- &data.limit);
+ repo_config_get_int(the_repository, "maintenance.commit-graph.auto",
+ &data.limit);
if (!data.limit)
return 0;
@@ -1301,15 +1302,15 @@ static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
{
int count = 0;
- git_config_get_int("maintenance.loose-objects.auto",
- &loose_object_auto_limit);
+ repo_config_get_int(the_repository, "maintenance.loose-objects.auto",
+ &loose_object_auto_limit);
if (!loose_object_auto_limit)
return 0;
if (loose_object_auto_limit < 0)
return 1;
- return for_each_loose_file_in_objdir(the_repository->objects->sources->path,
+ return for_each_loose_file_in_source(the_repository->objects->sources,
loose_object_count,
NULL, NULL, &count);
}
@@ -1344,7 +1345,7 @@ static int pack_loose(struct maintenance_run_opts *opts)
* Do not start pack-objects process
* if there are no loose objects.
*/
- if (!for_each_loose_file_in_objdir(r->objects->sources->path,
+ if (!for_each_loose_file_in_source(r->objects->sources,
bail_on_loose,
NULL, NULL, NULL))
return 0;
@@ -1384,11 +1385,9 @@ static int pack_loose(struct maintenance_run_opts *opts)
else if (data.batch_size > 0)
data.batch_size--; /* Decrease for equality on limit. */
- for_each_loose_file_in_objdir(r->objects->sources->path,
+ for_each_loose_file_in_source(r->objects->sources,
write_loose_object_to_stdin,
- NULL,
- NULL,
- &data);
+ NULL, NULL, &data);
fclose(data.in);
@@ -1416,8 +1415,8 @@ static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
if (!the_repository->settings.core_multi_pack_index)
return 0;
- git_config_get_int("maintenance.incremental-repack.auto",
- &incremental_repack_auto_limit);
+ repo_config_get_int(the_repository, "maintenance.incremental-repack.auto",
+ &incremental_repack_auto_limit);
if (!incremental_repack_auto_limit)
return 0;
@@ -1766,7 +1765,7 @@ static void initialize_task_config(struct maintenance_run_opts *opts,
if (opts->schedule) {
strategy = none_strategy;
- if (!git_config_get_string_tmp("maintenance.strategy", &config_str)) {
+ if (!repo_config_get_string_tmp(the_repository, "maintenance.strategy", &config_str)) {
if (!strcasecmp(config_str, "incremental"))
strategy = incremental_strategy;
}
@@ -1780,7 +1779,7 @@ static void initialize_task_config(struct maintenance_run_opts *opts,
strbuf_reset(&config_name);
strbuf_addf(&config_name, "maintenance.%s.enabled",
tasks[i].name);
- if (!git_config_get_bool(config_name.buf, &config_value))
+ if (!repo_config_get_bool(the_repository, config_name.buf, &config_value))
strategy.tasks[i].enabled = config_value;
if (!strategy.tasks[i].enabled)
continue;
@@ -1789,7 +1788,7 @@ static void initialize_task_config(struct maintenance_run_opts *opts,
strbuf_reset(&config_name);
strbuf_addf(&config_name, "maintenance.%s.schedule",
tasks[i].name);
- if (!git_config_get_string_tmp(config_name.buf, &config_str))
+ if (!repo_config_get_string_tmp(the_repository, config_name.buf, &config_str))
strategy.tasks[i].schedule = parse_schedule(config_str);
if (strategy.tasks[i].schedule < opts->schedule)
continue;
@@ -1914,13 +1913,13 @@ static int maintenance_register(int argc, const char **argv, const char *prefix,
options);
/* Disable foreground maintenance */
- git_config_set("maintenance.auto", "false");
+ repo_config_set(the_repository, "maintenance.auto", "false");
/* Set maintenance strategy, if unset */
- if (git_config_get("maintenance.strategy"))
- git_config_set("maintenance.strategy", "incremental");
+ if (repo_config_get(the_repository, "maintenance.strategy"))
+ repo_config_set(the_repository, "maintenance.strategy", "incremental");
- if (!git_config_get_string_multi(key, &list)) {
+ if (!repo_config_get_string_multi(the_repository, key, &list)) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
@@ -1939,7 +1938,7 @@ static int maintenance_register(int argc, const char **argv, const char *prefix,
}
if (!config_file)
die(_("$HOME not set"));
- rc = git_config_set_multivar_in_file_gently(
+ rc = repo_config_set_multivar_in_file_gently(the_repository,
config_file, "maintenance.repo", maintpath,
CONFIG_REGEX_NONE, NULL, 0);
free(global_config_file);
@@ -1989,7 +1988,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
}
if (!(config_file
? git_configset_get_string_multi(&cs, key, &list)
- : git_config_get_string_multi(key, &list))) {
+ : repo_config_get_string_multi(the_repository, key, &list))) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
@@ -2008,7 +2007,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
}
if (!config_file)
die(_("$HOME not set"));
- rc = git_config_set_multivar_in_file_gently(
+ rc = repo_config_set_multivar_in_file_gently(the_repository,
config_file, key, NULL, maintpath, NULL,
CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
free(global_config_file);
@@ -2345,7 +2344,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
die(_("failed to create directories for '%s'"), filename);
if ((long)lock_file_timeout_ms < 0 &&
- git_config_get_ulong("gc.launchctlplistlocktimeoutms",
+ repo_config_get_ulong(the_repository, "gc.launchctlplistlocktimeoutms",
&lock_file_timeout_ms))
lock_file_timeout_ms = 150;
diff --git a/builtin/grep.c b/builtin/grep.c
index 39273d9c0f..5df6537333 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "abspath.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "config.h"
@@ -1035,7 +1036,7 @@ int cmd_grep(int argc,
grep_prefix = prefix;
grep_init(&opt, the_repository);
- git_config(grep_cmd_config, &opt);
+ repo_config(the_repository, grep_cmd_config, &opt);
/*
* If there is no -- then the paths must exist in the working
@@ -1058,7 +1059,7 @@ int cmd_grep(int argc,
if (use_index && !startup_info->have_repository) {
int fallback = 0;
- git_config_get_bool("grep.fallbacktonoindex", &fallback);
+ repo_config_get_bool(the_repository, "grep.fallbacktonoindex", &fallback);
if (fallback)
use_index = 0;
else
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index ddf281413a..5d900a6b8c 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -8,6 +8,7 @@
#include "builtin.h"
#include "abspath.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-file.h"
@@ -111,7 +112,7 @@ int cmd_hash_object(int argc,
vpath = vpath_free;
}
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
if (stdin_paths) {
if (hashstdin)
diff --git a/builtin/help.c b/builtin/help.c
index c257079ceb..c09cbc8912 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -6,6 +6,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "pager.h"
@@ -210,7 +211,7 @@ static enum help_format parse_help_format(const char *format)
if (!strcmp(format, "web") || !strcmp(format, "html"))
return HELP_FORMAT_WEB;
/*
- * Please update _git_config() in git-completion.bash when you
+ * Please update _repo_config() in git-completion.bash when you
* add new help formats.
*/
die(_("unrecognized help format '%s'"), format);
@@ -706,7 +707,7 @@ int cmd_help(int argc,
}
setup_git_directory_gently(&nongit);
- git_config(git_help_config, NULL);
+ repo_config(the_repository, git_help_config, NULL);
if (parsed_help_format != HELP_FORMAT_NONE)
help_format = parsed_help_format;
diff --git a/builtin/hook.c b/builtin/hook.c
index 672d2e37e8..7afec380d2 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hook.h"
#include "parse-options.h"
@@ -55,7 +56,7 @@ static int run(int argc, const char **argv, const char *prefix,
strvec_push(&opt.args, argv[i]);
/* Need to take into account core.hooksPath */
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
hook_name = argv[0];
if (!ignore_missing)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0a5c8a1ac8..f91c301bba 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1598,7 +1598,7 @@ static void rename_tmp_packfile(const char **final_name,
if (!*final_name || strcmp(*final_name, curr_name)) {
if (!*final_name)
*final_name = odb_pack_name(the_repository, name, hash, ext);
- if (finalize_object_file(curr_name, *final_name))
+ if (finalize_object_file(the_repository, curr_name, *final_name))
die(_("unable to rename temporary '*.%s' file to '%s'"),
ext, *final_name);
} else if (make_read_only_if_same) {
@@ -1917,7 +1917,7 @@ int cmd_index_pack(int argc,
reset_pack_idx_option(&opts);
opts.flags |= WRITE_REV;
- git_config(git_index_pack_config, &opts);
+ repo_config(the_repository, git_index_pack_config, &opts);
if (prefix && chdir(prefix))
die(_("Cannot come back to cwd"));
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 44d8ccddc9..41b0750e5a 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -6,6 +6,7 @@
*/
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "string-list.h"
@@ -220,7 +221,7 @@ int cmd_interpret_trailers(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options,
git_interpret_trailers_usage, 0);
diff --git a/builtin/log.c b/builtin/log.c
index fb42e094af..c2f8bbf863 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -221,7 +221,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
struct string_list *include = decoration_filter->include_ref_pattern;
const struct string_list *config_exclude;
- if (!git_config_get_string_multi("log.excludeDecoration",
+ if (!repo_config_get_string_multi(the_repository, "log.excludeDecoration",
&config_exclude)) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
@@ -235,7 +235,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
* since the command-line takes precedent.
*/
if (use_default_decoration_filter &&
- !git_config_get_string("log.initialdecorationset", &value) &&
+ !repo_config_get_string(the_repository, "log.initialdecorationset", &value) &&
!strcmp("all", value))
use_default_decoration_filter = 0;
free(value);
@@ -530,10 +530,10 @@ int cmd_whatchanged(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.diff = 1;
rev.simplify_history = 0;
@@ -661,7 +661,7 @@ int cmd_show(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
@@ -670,7 +670,7 @@ int cmd_show(int argc,
memset(&match_all, 0, sizeof(match_all));
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.diff = 1;
rev.always_show_header = 1;
@@ -778,11 +778,11 @@ int cmd_log_reflog(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
@@ -823,10 +823,10 @@ int cmd_log(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.always_show_header = 1;
memset(&opt, 0, sizeof(opt));
@@ -2029,9 +2029,9 @@ int cmd_format_patch(int argc,
format_config_init(&cfg);
init_diff_ui_defaults();
init_display_notes(&cfg.notes_opt);
- git_config(git_format_config, &cfg);
+ repo_config(the_repository, git_format_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.show_notes = cfg.show_notes;
memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index ff975e7be0..c06a6f33e4 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -11,6 +11,7 @@
#include "builtin.h"
#include "config.h"
#include "convert.h"
+#include "environment.h"
#include "quote.h"
#include "dir.h"
#include "gettext.h"
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 4d616dd528..5d55731ca3 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -7,6 +7,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-name.h"
@@ -375,7 +376,7 @@ int cmd_ls_tree(int argc,
struct object_context obj_context = {0};
int ret;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, ls_tree_options,
ls_tree_usage, 0);
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 123c81515e..3f82781245 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "config.h"
#include "commit.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-name.h"
@@ -167,7 +168,7 @@ int cmd_merge_base(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
if (cmdmode == 'a') {
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 9464f27562..46775d0c79 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -97,7 +97,7 @@ int cmd_merge_file(int argc,
if (startup_info->have_repository) {
/* Read the configuration file */
- git_config(git_xmerge_config, NULL);
+ repo_config(the_repository, git_xmerge_config, NULL);
if (0 <= git_xmerge_style)
xmp.style = git_xmerge_style;
}
@@ -155,7 +155,8 @@ int cmd_merge_file(int argc,
if (object_id && !to_stdout) {
struct object_id oid;
if (result.size) {
- if (write_object_file(result.ptr, result.size, OBJ_BLOB, &oid) < 0)
+ if (odb_write_object(the_repository->objects, result.ptr,
+ result.size, OBJ_BLOB, &oid) < 0)
ret = error(_("Could not write object file"));
} else {
oidcpy(&oid, the_hash_algo->empty_blob);
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 03b5100cfa..17aa4db37a 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -38,7 +38,8 @@ int cmd_merge_recursive(int argc,
if (argv[0] && ends_with(argv[0], "-subtree"))
o.subtree_shift = "";
- if (argc == 2 && !strcmp(argv[1], "-h")) {
+ if (argc == 2 && (!strcmp(argv[1], "-h") ||
+ !strcmp(argv[1], "--help-all"))) {
struct strbuf msg = STRBUF_INIT;
strbuf_addf(&msg, builtin_merge_recursive_usage, argv[0]);
show_usage_if_asked(argc, argv, msg.buf);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index cf8b06cadc..1c063d9a41 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "environment.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "help.h"
@@ -618,32 +619,34 @@ int cmd_merge_tree(int argc,
"--merge-base", "--stdin");
line_termination = '\0';
while (strbuf_getline_lf(&buf, stdin) != EOF) {
- struct strbuf **split;
+ struct string_list split = STRING_LIST_INIT_NODUP;
const char *input_merge_base = NULL;
- split = strbuf_split(&buf, ' ');
- if (!split[0] || !split[1])
+ string_list_split_in_place_f(&split, buf.buf, " ", -1,
+ STRING_LIST_SPLIT_TRIM);
+
+ if (split.nr < 2)
die(_("malformed input line: '%s'."), buf.buf);
- strbuf_rtrim(split[0]);
- strbuf_rtrim(split[1]);
/* parse the merge-base */
- if (!strcmp(split[1]->buf, "--")) {
- input_merge_base = split[0]->buf;
+ if (!strcmp(split.items[1].string, "--")) {
+ input_merge_base = split.items[0].string;
}
- if (input_merge_base && split[2] && split[3] && !split[4]) {
- strbuf_rtrim(split[2]);
- strbuf_rtrim(split[3]);
- real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
- } else if (!input_merge_base && !split[2]) {
- real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+ if (input_merge_base && split.nr == 4) {
+ real_merge(&o, input_merge_base,
+ split.items[2].string, split.items[3].string,
+ prefix);
+ } else if (!input_merge_base && split.nr == 2) {
+ real_merge(&o, NULL,
+ split.items[0].string, split.items[1].string,
+ prefix);
} else {
die(_("malformed input line: '%s'."), buf.buf);
}
maybe_flush_or_die(stdout, "stdout");
- strbuf_list_free(split);
+ string_list_clear(&split, 0);
}
strbuf_release(&buf);
@@ -683,7 +686,7 @@ int cmd_merge_tree(int argc,
if (argc != expected_remaining_argc)
usage_with_options(merge_tree_usage, mt_options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
diff --git a/builtin/merge.c b/builtin/merge.c
index 18b22c0a26..783ca66377 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -264,7 +264,7 @@ static struct option builtin_merge_options[] = {
OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")),
OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
- OPT_CALLBACK_F(0, "compact-summary", &show_diffstat, N_("compact-summary"),
+ OPT_CALLBACK_F(0, "compact-summary", &show_diffstat, NULL,
N_("show a compact-summary at the end of the merge"),
PARSE_OPT_NOARG,
option_parse_compact_summary),
@@ -875,7 +875,7 @@ static void add_strategies(const char *string, unsigned attr)
if (string) {
struct string_list list = STRING_LIST_INIT_DUP;
struct string_list_item *item;
- string_list_split(&list, string, ' ', -1);
+ string_list_split(&list, string, " ", -1);
for_each_string_list_item(item, &list)
append_strategy(get_strategy(item->string));
string_list_clear(&list, 0);
@@ -1374,6 +1374,7 @@ int cmd_merge(int argc,
struct commit_list *remoteheads = NULL, *p;
void *branch_to_free;
int orig_argc = argc;
+ int merge_log_config = -1;
show_usage_with_options_if_asked(argc, argv,
builtin_merge_usage, builtin_merge_options);
@@ -1392,7 +1393,7 @@ int cmd_merge(int argc,
skip_prefix(branch, "refs/heads/", &branch);
init_diff_ui_defaults();
- git_config(git_merge_config, NULL);
+ repo_config(the_repository, git_merge_config, &merge_log_config);
if (!branch || is_null_oid(&head_oid))
head_commit = NULL;
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 27e649736c..7cf6e1230a 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -98,7 +98,7 @@ int cmd_mktag(int argc,
fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,
FSCK_WARN);
/* config might set fsck.extraHeaderEntry=* again */
- git_config(git_fsck_config, &fsck_options);
+ repo_config(the_repository, git_fsck_config, &fsck_options);
if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options,
&tagged_oid, &tagged_type))
die(_("tag on stdin did not pass our strict fsck check"));
@@ -106,7 +106,7 @@ int cmd_mktag(int argc,
if (verify_object_in_tag(&tagged_oid, &tagged_type) < 0)
die(_("tag on stdin did not refer to a valid object"));
- if (write_object_file(buf.buf, buf.len, OBJ_TAG, &result) < 0)
+ if (odb_write_object(the_repository->objects, buf.buf, buf.len, OBJ_TAG, &result) < 0)
die(_("unable to write tag file"));
strbuf_release(&buf);
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 81df7f6099..12772303f5 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -63,7 +63,7 @@ static void write_tree(struct object_id *oid)
strbuf_add(&buf, ent->oid.hash, the_hash_algo->rawsz);
}
- write_object_file(buf.buf, buf.len, OBJ_TREE, oid);
+ odb_write_object(the_repository->objects, buf.buf, buf.len, OBJ_TREE, oid);
strbuf_release(&buf);
}
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index aa25b06f9d..d3b9e98be3 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "abspath.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "midx.h"
@@ -143,7 +144,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
- git_config(git_multi_pack_index_write_config, NULL);
+ repo_config(the_repository, git_multi_pack_index_write_config, NULL);
options = add_common_options(builtin_multi_pack_index_write_options);
@@ -290,7 +291,7 @@ int cmd_multi_pack_index(int argc,
disable_replace_refs();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
if (the_repository &&
the_repository->objects &&
diff --git a/builtin/mv.c b/builtin/mv.c
index 07548fe96a..d43925097b 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -239,7 +239,7 @@ int cmd_mv(int argc,
struct strbuf pathbuf = STRBUF_INIT;
int ret;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_mv_options,
builtin_mv_usage, 0);
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index ff199638de..74512e54a3 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -600,7 +600,7 @@ int cmd_name_rev(int argc,
mem_pool_init(&string_pool, 0);
init_commit_rev_name(&rev_names);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
#ifndef WITH_BREAKING_CHANGES
diff --git a/builtin/notes.c b/builtin/notes.c
index a9529b1696..9af602bdd7 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -229,7 +229,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
static void write_note_data(struct note_data *d, struct object_id *oid)
{
- if (write_object_file(d->buf.buf, d->buf.len, OBJ_BLOB, oid)) {
+ if (odb_write_object(the_repository->objects, d->buf.buf,
+ d->buf.len, OBJ_BLOB, oid)) {
int status = die_message(_("unable to write note object"));
if (d->edit_path)
@@ -375,18 +376,19 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
while (strbuf_getline_lf(&buf, stdin) != EOF) {
struct object_id from_obj, to_obj;
- struct strbuf **split;
+ struct string_list split = STRING_LIST_INIT_NODUP;
int err;
- split = strbuf_split(&buf, ' ');
- if (!split[0] || !split[1])
+ string_list_split_in_place_f(&split, buf.buf, " ", -1,
+ STRING_LIST_SPLIT_TRIM);
+ if (split.nr < 2)
die(_("malformed input line: '%s'."), buf.buf);
- strbuf_rtrim(split[0]);
- strbuf_rtrim(split[1]);
- if (repo_get_oid(the_repository, split[0]->buf, &from_obj))
- die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
- if (repo_get_oid(the_repository, split[1]->buf, &to_obj))
- die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
+ if (repo_get_oid(the_repository, split.items[0].string, &from_obj))
+ die(_("failed to resolve '%s' as a valid ref."),
+ split.items[0].string);
+ if (repo_get_oid(the_repository, split.items[1].string, &to_obj))
+ die(_("failed to resolve '%s' as a valid ref."),
+ split.items[1].string);
if (rewrite_cmd)
err = copy_note_for_rewrite(c, &from_obj, &to_obj);
@@ -396,11 +398,11 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
if (err) {
error(_("failed to copy notes from '%s' to '%s'"),
- split[0]->buf, split[1]->buf);
+ split.items[0].string, split.items[1].string);
ret = 1;
}
- strbuf_list_free(split);
+ string_list_clear(&split, 0);
}
if (!rewrite_cmd) {
@@ -873,7 +875,7 @@ static int git_config_get_notes_strategy(const char *key,
{
char *value;
- if (git_config_get_string(key, &value))
+ if (repo_config_get_string(the_repository, key, &value))
return 1;
if (parse_notes_merge_strategy(value, strategy))
git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value);
@@ -1145,7 +1147,7 @@ int cmd_notes(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_notes_usage,
PARSE_OPT_SUBCOMMAND_OPTIONAL);
if (!fn) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 067b9e322a..53a2256250 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1455,7 +1455,7 @@ static void write_pack_file(void)
strbuf_setlen(&tmpname, tmpname_len);
}
- rename_tmp_packfile_idx(&tmpname, &idx_tmp_name);
+ rename_tmp_packfile_idx(the_repository, &tmpname, &idx_tmp_name);
free(idx_tmp_name);
strbuf_release(&tmpname);
@@ -1706,11 +1706,19 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
uint32_t found_mtime)
{
int want;
+ struct odb_source *source;
struct list_head *pos;
- struct multi_pack_index *m;
- if (!exclude && local && has_loose_object_nonlocal(oid))
- return 0;
+ if (!exclude && local) {
+ /*
+ * Note that we start iterating at `sources->next` so that we
+ * skip the local object source.
+ */
+ struct odb_source *source = the_repository->objects->sources->next;
+ for (; source; source = source->next)
+ if (has_loose_object(source, oid))
+ return 0;
+ }
/*
* If we already know the pack object lives in, start checks from that
@@ -1727,9 +1735,13 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
*found_offset = 0;
}
- for (m = get_multi_pack_index(the_repository); m; m = m->next) {
+ odb_prepare_alternates(the_repository->objects);
+
+ for (source = the_repository->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
struct pack_entry e;
- if (fill_midx_entry(the_repository, oid, &e, m)) {
+
+ if (m && fill_midx_entry(the_repository, oid, &e, m)) {
want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime);
if (want != -1)
return want;
@@ -3962,7 +3974,14 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
} else {
if (!want_object_in_pack_mtime(oid, 0, &pack, &offset, mtime))
return;
- if (!pack && type == OBJ_BLOB && !has_loose_object(oid)) {
+ if (!pack && type == OBJ_BLOB) {
+ struct odb_source *source = the_repository->objects->sources;
+ int found = 0;
+
+ for (; !found && source; source = source->next)
+ if (has_loose_object(source, oid))
+ found = 1;
+
/*
* If a traversed tree has a missing blob then we want
* to avoid adding that missing object to our pack.
@@ -3976,7 +3995,8 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
* limited to "ensure non-tip blobs which don't exist in
* packs do exist via loose objects". Confused?
*/
- return;
+ if (!found)
+ return;
}
entry = create_object_entry(oid, type, pack_name_hash_fn(name),
@@ -4364,7 +4384,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
*/
static void add_unreachable_loose_objects(struct rev_info *revs)
{
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ for_each_loose_file_in_source(the_repository->objects->sources,
add_loose_object, NULL, NULL, revs);
}
@@ -4433,7 +4453,8 @@ static void loosen_unused_packed_objects(void)
if (!packlist_find(&to_pack, &oid) &&
!has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime)) {
- if (force_object_loose(&oid, p->mtime))
+ if (force_object_loose(the_repository->objects->sources,
+ &oid, p->mtime))
die(_("unable to force loose object"));
loosened_objects_nr++;
}
@@ -4981,7 +5002,7 @@ int cmd_pack_objects(int argc,
reset_pack_idx_option(&pack_idx_opts);
pack_idx_opts.flags |= WRITE_REV;
- git_config(git_pack_config, NULL);
+ repo_config(the_repository, git_pack_config, NULL);
if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
pack_idx_opts.flags &= ~WRITE_REV;
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index e47bae1c80..5e28d0f9e8 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "refs.h"
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 26f04b0335..d26e9d0c1e 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -3,6 +3,7 @@
#include "builtin.h"
#include "config.h"
#include "diff.h"
+#include "environment.h"
#include "gettext.h"
#include "hash.h"
#include "hex.h"
@@ -235,7 +236,7 @@ int cmd_patch_id(int argc,
OPT_END()
};
- git_config(git_patch_id_config, &config);
+ repo_config(the_repository, git_patch_id_config, &config);
/* verbatim implies stable */
if (config.verbatim)
diff --git a/builtin/prune.c b/builtin/prune.c
index d1c0ee1419..55635a891f 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -198,7 +198,7 @@ int cmd_prune(int argc,
revs.exclude_promisor_objects = 1;
}
- for_each_loose_file_in_objdir(repo_get_object_directory(repo),
+ for_each_loose_file_in_source(repo->objects->sources,
prune_object, prune_cruft, prune_subdir, &revs);
prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
diff --git a/builtin/pull.c b/builtin/pull.c
index 2a6c2e4a37..5ebd529620 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -11,6 +11,7 @@
#include "builtin.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "merge.h"
@@ -313,7 +314,7 @@ static const char *config_get_ff(void)
{
const char *value;
- if (git_config_get_value("pull.ff", &value))
+ if (repo_config_get_value(the_repository, "pull.ff", &value))
return NULL;
switch (git_parse_maybe_bool(value)) {
@@ -344,7 +345,7 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
if (curr_branch) {
char *key = xstrfmt("branch.%s.rebase", curr_branch->name);
- if (!git_config_get_value(key, &value)) {
+ if (!repo_config_get_value(the_repository, key, &value)) {
enum rebase_type ret = parse_config_rebase(key, value, 1);
free(key);
return ret;
@@ -353,7 +354,7 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
free(key);
}
- if (!git_config_get_value("pull.rebase", &value))
+ if (!repo_config_get_value(the_repository, "pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
*rebase_unspecified = 1;
@@ -1011,7 +1012,7 @@ int cmd_pull(int argc,
if (!getenv("GIT_REFLOG_ACTION"))
set_reflog_message(argc, argv);
- git_config(git_pull_config, NULL);
+ repo_config(the_repository, git_pull_config, NULL);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/push.c b/builtin/push.c
index 92d530e5c4..d0794b7b30 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -598,7 +598,7 @@ int cmd_push(int argc,
};
packet_trace_identity("push");
- git_config(git_push_config, &flags);
+ repo_config(the_repository, git_push_config, &flags);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
push_options = (push_options_cmdline.nr
? &push_options_cmdline
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index 32ddb6613f..a563abff5f 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -54,7 +54,7 @@ int cmd_range_diff(int argc,
struct object_id oid;
const char *three_dots = NULL;
- git_config(git_diff_ui_config, NULL);
+ repo_config(the_repository, git_diff_ui_config, NULL);
repo_diff_setup(the_repository, &diffopt);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index a8f352f7cd..34f7a59f38 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -6,6 +6,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
@@ -168,7 +169,7 @@ int cmd_read_tree(int argc,
opts.src_index = the_repository->index;
opts.dst_index = the_repository->index;
- git_config(git_read_tree_config, NULL);
+ repo_config(the_repository, git_read_tree_config, NULL);
argc = parse_options(argc, argv, cmd_prefix, read_tree_options,
read_tree_usage, 0);
diff --git a/builtin/rebase.c b/builtin/rebase.c
index e90562a3b8..3c85768d29 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -293,15 +293,6 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
&revisions, &shortrevisions))
goto cleanup;
- if (init_basic_state(&replay,
- opts->head_name ? opts->head_name : "detached HEAD",
- opts->onto, &opts->orig_head->object.oid))
- goto cleanup;
-
- if (!opts->upstream && opts->squash_onto)
- write_file(path_squash_onto(), "%s\n",
- oid_to_hex(opts->squash_onto));
-
strvec_pushl(&make_script_args, "", revisions, NULL);
if (opts->restrict_revision)
strvec_pushf(&make_script_args, "^%s",
@@ -310,21 +301,30 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
ret = sequencer_make_script(the_repository, &todo_list.buf,
make_script_args.nr, make_script_args.v,
flags);
-
- if (ret)
+ if (ret) {
error(_("could not generate todo list"));
- else {
- discard_index(the_repository->index);
- if (todo_list_parse_insn_buffer(the_repository, &replay,
- todo_list.buf.buf, &todo_list))
- BUG("unusable todo list");
-
- ret = complete_action(the_repository, &replay, flags,
- shortrevisions, opts->onto_name, opts->onto,
- &opts->orig_head->object.oid, &opts->exec,
- opts->autosquash, opts->update_refs, &todo_list);
+ goto cleanup;
}
+ if (init_basic_state(&replay,
+ opts->head_name ? opts->head_name : "detached HEAD",
+ opts->onto, &opts->orig_head->object.oid))
+ goto cleanup;
+
+ if (!opts->upstream && opts->squash_onto)
+ write_file(path_squash_onto(), "%s\n",
+ oid_to_hex(opts->squash_onto));
+
+ discard_index(the_repository->index);
+ if (todo_list_parse_insn_buffer(the_repository, &replay,
+ todo_list.buf.buf, &todo_list))
+ BUG("unusable todo list");
+
+ ret = complete_action(the_repository, &replay, flags,
+ shortrevisions, opts->onto_name, opts->onto,
+ &opts->orig_head->object.oid, &opts->exec,
+ opts->autosquash, opts->update_refs, &todo_list);
+
cleanup:
replay_opts_release(&replay);
free(revisions);
@@ -340,7 +340,7 @@ static int run_sequencer_rebase(struct rebase_options *opts)
unsigned flags = 0;
int abbreviate_commands = 0, ret = 0;
- git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
+ repo_config_get_bool(the_repository, "rebase.abbreviatecommands", &abbreviate_commands);
flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
@@ -1245,7 +1245,7 @@ int cmd_rebase(int argc,
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- git_config(rebase_config, &options);
+ repo_config(the_repository, rebase_config, &options);
/* options.gpg_sign_opt will be either "-S" or NULL */
gpg_sign = options.gpg_sign_opt ? "" : NULL;
FREE_AND_NULL(options.gpg_sign_opt);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 7974d157eb..1113137a6f 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -760,8 +760,8 @@ static void prepare_push_cert_sha1(struct child_process *proc)
int bogs /* beginning_of_gpg_sig */;
already_done = 1;
- if (write_object_file(push_cert.buf, push_cert.len, OBJ_BLOB,
- &push_cert_oid))
+ if (odb_write_object(the_repository->objects, push_cert.buf,
+ push_cert.len, OBJ_BLOB, &push_cert_oid))
oidclr(&push_cert_oid, the_repository->hash_algo);
memset(&sigcheck, '\0', sizeof(sigcheck));
@@ -2613,7 +2613,7 @@ int cmd_receive_pack(int argc,
if (!enter_repo(service_dir, 0))
die("'%s' does not appear to be a git repository", service_dir);
- git_config(receive_pack_config, NULL);
+ repo_config(the_repository, receive_pack_config, NULL);
if (cert_nonce_seed)
push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
diff --git a/builtin/reflog.c b/builtin/reflog.c
index d4da41aaea..c8f6b93d60 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -3,6 +3,8 @@
#include "builtin.h"
#include "config.h"
#include "gettext.h"
+#include "hex.h"
+#include "odb.h"
#include "revision.h"
#include "reachable.h"
#include "wildmatch.h"
@@ -17,21 +19,24 @@
#define BUILTIN_REFLOG_LIST_USAGE \
N_("git reflog list")
-#define BUILTIN_REFLOG_EXPIRE_USAGE \
- N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
- " [--rewrite] [--updateref] [--stale-fix]\n" \
- " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
+#define BUILTIN_REFLOG_EXISTS_USAGE \
+ N_("git reflog exists <ref>")
+
+#define BUILTIN_REFLOG_WRITE_USAGE \
+ N_("git reflog write <ref> <old-oid> <new-oid> <message>")
#define BUILTIN_REFLOG_DELETE_USAGE \
N_("git reflog delete [--rewrite] [--updateref]\n" \
" [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
-#define BUILTIN_REFLOG_EXISTS_USAGE \
- N_("git reflog exists <ref>")
-
#define BUILTIN_REFLOG_DROP_USAGE \
N_("git reflog drop [--all [--single-worktree] | <refs>...]")
+#define BUILTIN_REFLOG_EXPIRE_USAGE \
+ N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
+ " [--rewrite] [--updateref] [--stale-fix]\n" \
+ " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
+
static const char *const reflog_show_usage[] = {
BUILTIN_REFLOG_SHOW_USAGE,
NULL,
@@ -42,9 +47,14 @@ static const char *const reflog_list_usage[] = {
NULL,
};
-static const char *const reflog_expire_usage[] = {
- BUILTIN_REFLOG_EXPIRE_USAGE,
- NULL
+static const char *const reflog_exists_usage[] = {
+ BUILTIN_REFLOG_EXISTS_USAGE,
+ NULL,
+};
+
+static const char *const reflog_write_usage[] = {
+ BUILTIN_REFLOG_WRITE_USAGE,
+ NULL,
};
static const char *const reflog_delete_usage[] = {
@@ -52,23 +62,24 @@ static const char *const reflog_delete_usage[] = {
NULL
};
-static const char *const reflog_exists_usage[] = {
- BUILTIN_REFLOG_EXISTS_USAGE,
- NULL,
-};
-
static const char *const reflog_drop_usage[] = {
BUILTIN_REFLOG_DROP_USAGE,
NULL,
};
+static const char *const reflog_expire_usage[] = {
+ BUILTIN_REFLOG_EXPIRE_USAGE,
+ NULL
+};
+
static const char *const reflog_usage[] = {
BUILTIN_REFLOG_SHOW_USAGE,
BUILTIN_REFLOG_LIST_USAGE,
- BUILTIN_REFLOG_EXPIRE_USAGE,
+ BUILTIN_REFLOG_EXISTS_USAGE,
+ BUILTIN_REFLOG_WRITE_USAGE,
BUILTIN_REFLOG_DELETE_USAGE,
BUILTIN_REFLOG_DROP_USAGE,
- BUILTIN_REFLOG_EXISTS_USAGE,
+ BUILTIN_REFLOG_EXPIRE_USAGE,
NULL
};
@@ -202,7 +213,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
OPT_END()
};
- git_config(reflog_expire_config, &opts);
+ repo_config(the_repository, reflog_expire_config, &opts);
save_commit_buffer = 0;
do_all = status = 0;
@@ -395,6 +406,59 @@ static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
return ret;
}
+static int cmd_reflog_write(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ const struct option options[] = {
+ OPT_END()
+ };
+ struct object_id old_oid, new_oid;
+ struct strbuf err = STRBUF_INIT;
+ struct ref_transaction *tx;
+ const char *ref, *message;
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, options, reflog_write_usage, 0);
+ if (argc != 4)
+ usage_with_options(reflog_write_usage, options);
+
+ ref = argv[0];
+ if (!is_root_ref(ref) && check_refname_format(ref, 0))
+ die(_("invalid reference name: %s"), ref);
+
+ ret = get_oid_hex_algop(argv[1], &old_oid, repo->hash_algo);
+ if (ret)
+ die(_("invalid old object ID: '%s'"), argv[1]);
+ if (!is_null_oid(&old_oid) && !odb_has_object(repo->objects, &old_oid, 0))
+ die(_("old object '%s' does not exist"), argv[1]);
+
+ ret = get_oid_hex_algop(argv[2], &new_oid, repo->hash_algo);
+ if (ret)
+ die(_("invalid new object ID: '%s'"), argv[2]);
+ if (!is_null_oid(&new_oid) && !odb_has_object(repo->objects, &new_oid, 0))
+ die(_("new object '%s' does not exist"), argv[2]);
+
+ message = argv[3];
+
+ tx = ref_store_transaction_begin(get_main_ref_store(repo), 0, &err);
+ if (!tx)
+ die(_("cannot start transaction: %s"), err.buf);
+
+ ret = ref_transaction_update_reflog(tx, ref, &new_oid, &old_oid,
+ git_committer_info(0),
+ message, 0, &err);
+ if (ret)
+ die(_("cannot queue reflog update: %s"), err.buf);
+
+ ret = ref_transaction_commit(tx, &err);
+ if (ret)
+ die(_("cannot commit reflog update: %s"), err.buf);
+
+ ref_transaction_free(tx);
+ strbuf_release(&err);
+ return 0;
+}
+
/*
* main "reflog"
*/
@@ -407,10 +471,11 @@ int cmd_reflog(int argc,
struct option options[] = {
OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
- OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
- OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
+ OPT_SUBCOMMAND("write", &fn, cmd_reflog_write),
+ OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
OPT_SUBCOMMAND("drop", &fn, cmd_reflog_drop),
+ OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
OPT_END()
};
diff --git a/builtin/refs.c b/builtin/refs.c
index 998d2a2c1c..76224feba4 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -6,6 +6,7 @@
#include "refs.h"
#include "strbuf.h"
#include "worktree.h"
+#include "for-each-ref.h"
#define REFS_MIGRATE_USAGE \
N_("git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]")
@@ -88,7 +89,7 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
if (argc)
usage(_("'git refs verify' takes no arguments"));
- git_config(git_fsck_config, &fsck_refs_options);
+ repo_config(the_repository, git_fsck_config, &fsck_refs_options);
prepare_repo_settings(the_repository);
worktrees = get_worktrees_without_reading_head();
@@ -101,6 +102,17 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
return ret;
}
+static int cmd_refs_list(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ static char const * const refs_list_usage[] = {
+ N_("git refs list " COMMON_USAGE_FOR_EACH_REF),
+ NULL
+ };
+
+ return for_each_ref_core(argc, argv, prefix, repo, refs_list_usage);
+}
+
int cmd_refs(int argc,
const char **argv,
const char *prefix,
@@ -109,12 +121,14 @@ int cmd_refs(int argc,
const char * const refs_usage[] = {
REFS_MIGRATE_USAGE,
REFS_VERIFY_USAGE,
+ "git refs list " COMMON_USAGE_FOR_EACH_REF,
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_SUBCOMMAND("list", &fn, cmd_refs_list),
OPT_END(),
};
diff --git a/builtin/remote.c b/builtin/remote.c
index 5dd6cbbaee..8a7ed4299a 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,9 +1,11 @@
#define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "date.h"
#include "gettext.h"
+#include "ident.h"
#include "parse-options.h"
#include "path.h"
#include "transport.h"
@@ -132,7 +134,7 @@ static void add_branch(const char *key, const char *branchname,
else
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
branchname, remotename, branchname);
- git_config_set_multivar(key, tmp->buf, "^$", 0);
+ repo_config_set_multivar(the_repository, key, tmp->buf, "^$", 0);
}
static const char mirror_advice[] =
@@ -182,7 +184,6 @@ static int add(int argc, const char **argv, const char *prefix,
struct remote *remote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url;
- int i;
int result = 0;
struct option options[] = {
@@ -226,14 +227,14 @@ static int add(int argc, const char **argv, const char *prefix,
for_each_remote(check_remote_collision, (void *)name);
strbuf_addf(&buf, "remote.%s.url", name);
- git_config_set(buf.buf, url);
+ repo_config_set(the_repository, buf.buf, url);
if (!mirror || mirror & MIRROR_FETCH) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", name);
if (track.nr == 0)
string_list_append(&track, "*");
- for (i = 0; i < track.nr; i++) {
+ for (size_t i = 0; i < track.nr; i++) {
add_branch(buf.buf, track.items[i].string,
name, mirror, &buf2);
}
@@ -242,14 +243,14 @@ static int add(int argc, const char **argv, const char *prefix,
if (mirror & MIRROR_PUSH) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.mirror", name);
- git_config_set(buf.buf, "true");
+ repo_config_set(the_repository, buf.buf, "true");
}
if (fetch_tags != TAGS_DEFAULT) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.tagOpt", name);
- git_config_set(buf.buf,
- fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
+ repo_config_set(the_repository, buf.buf,
+ fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
}
if (fetch && fetch_remote(name)) {
@@ -370,7 +371,7 @@ static void read_branches(void)
{
if (branch_list.nr)
return;
- git_config(config_read_branches, NULL);
+ repo_config(the_repository, config_read_branches, NULL);
}
struct ref_states {
@@ -612,54 +613,170 @@ static int add_branch_for_removal(const char *refname,
struct rename_info {
const char *old_name;
const char *new_name;
- struct string_list *remote_branches;
- uint32_t symrefs_nr;
+ struct ref_transaction *transaction;
+ struct progress *progress;
+ struct strbuf *err;
+ uint32_t progress_nr;
+ uint64_t index;
};
-static int read_remote_branches(const char *refname, const char *referent UNUSED,
- const struct object_id *oid UNUSED,
- int flags UNUSED, void *cb_data)
+static void compute_renamed_ref(struct rename_info *rename,
+ const char *refname,
+ struct strbuf *out)
+{
+ strbuf_reset(out);
+ strbuf_addstr(out, refname);
+ strbuf_splice(out, strlen("refs/remotes/"), strlen(rename->old_name),
+ rename->new_name, strlen(rename->new_name));
+}
+
+static int rename_one_reflog_entry(const char *old_refname,
+ struct object_id *old_oid,
+ struct object_id *new_oid,
+ const char *committer,
+ timestamp_t timestamp, int tz,
+ const char *msg, void *cb_data)
{
struct rename_info *rename = cb_data;
- struct strbuf buf = STRBUF_INIT;
- struct string_list_item *item;
- int flag;
- const char *symref;
-
- strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
- if (starts_with(refname, buf.buf)) {
- item = string_list_append(rename->remote_branches, refname);
- symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
- refname, RESOLVE_REF_READING,
- NULL, &flag);
- if (symref && (flag & REF_ISSYMREF)) {
- item->util = xstrdup(symref);
- rename->symrefs_nr++;
- } else {
- item->util = NULL;
- }
+ struct strbuf new_refname = STRBUF_INIT;
+ struct strbuf identity = STRBUF_INIT;
+ struct strbuf name = STRBUF_INIT;
+ struct strbuf mail = STRBUF_INIT;
+ struct ident_split ident;
+ const char *date;
+ int error;
+
+ compute_renamed_ref(rename, old_refname, &new_refname);
+
+ if (split_ident_line(&ident, committer, strlen(committer)) < 0) {
+ error = -1;
+ goto out;
}
- strbuf_release(&buf);
- return 0;
+ strbuf_add(&name, ident.name_begin, ident.name_end - ident.name_begin);
+ strbuf_add(&mail, ident.mail_begin, ident.mail_end - ident.mail_begin);
+
+ date = show_date(timestamp, tz, DATE_MODE(NORMAL));
+ strbuf_addstr(&identity, fmt_ident(name.buf, mail.buf,
+ WANT_BLANK_IDENT, date, 0));
+
+ error = ref_transaction_update_reflog(rename->transaction, new_refname.buf,
+ new_oid, old_oid, identity.buf, msg,
+ rename->index++, rename->err);
+
+out:
+ strbuf_release(&new_refname);
+ strbuf_release(&identity);
+ strbuf_release(&name);
+ strbuf_release(&mail);
+ return error;
+}
+
+static int rename_one_reflog(const char *old_refname,
+ const struct object_id *old_oid,
+ struct rename_info *rename)
+{
+ struct strbuf new_refname = STRBUF_INIT;
+ struct strbuf message = STRBUF_INIT;
+ int error;
+
+ if (!refs_reflog_exists(get_main_ref_store(the_repository), old_refname))
+ return 0;
+
+ error = refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ old_refname, rename_one_reflog_entry, rename);
+ if (error < 0)
+ goto out;
+
+ compute_renamed_ref(rename, old_refname, &new_refname);
+
+ /*
+ * Manually write the reflog entry for the now-renamed ref. We cannot
+ * rely on `rename_one_ref()` to do this for us as that would screw
+ * over order in which reflog entries are being written.
+ *
+ * Furthermore, we only append the entry in case the reference
+ * resolves. Missing references shouldn't have reflogs anyway.
+ */
+ strbuf_addf(&message, "remote: renamed %s to %s", old_refname,
+ new_refname.buf);
+
+ error = ref_transaction_update_reflog(rename->transaction, new_refname.buf,
+ old_oid, old_oid, git_committer_info(0),
+ message.buf, rename->index++, rename->err);
+ if (error < 0)
+ return error;
+
+out:
+ strbuf_release(&new_refname);
+ strbuf_release(&message);
+ return error;
+}
+
+static int rename_one_ref(const char *old_refname, const char *referent,
+ const struct object_id *oid,
+ int flags, void *cb_data)
+{
+ struct strbuf new_referent = STRBUF_INIT;
+ struct strbuf new_refname = STRBUF_INIT;
+ struct rename_info *rename = cb_data;
+ int error;
+
+ compute_renamed_ref(rename, old_refname, &new_refname);
+
+ if (flags & REF_ISSYMREF) {
+ /*
+ * Stupidly enough `referent` is not pointing to the immediate
+ * target of a symref, but it's the recursively resolved value.
+ * So symrefs pointing to symrefs would be misresolved, and
+ * unborn symrefs don't have any value for the `referent` at all.
+ */
+ referent = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ old_refname, RESOLVE_REF_NO_RECURSE,
+ NULL, NULL);
+ compute_renamed_ref(rename, referent, &new_referent);
+ oid = NULL;
+ }
+
+ error = ref_transaction_delete(rename->transaction, old_refname,
+ oid, referent, REF_NO_DEREF, NULL, rename->err);
+ if (error < 0)
+ goto out;
+
+ error = ref_transaction_update(rename->transaction, new_refname.buf, oid, null_oid(the_hash_algo),
+ (flags & REF_ISSYMREF) ? new_referent.buf : NULL, NULL,
+ REF_SKIP_CREATE_REFLOG | REF_NO_DEREF | REF_SKIP_OID_VERIFICATION,
+ NULL, rename->err);
+ if (error < 0)
+ goto out;
+
+ error = rename_one_reflog(old_refname, oid, rename);
+ if (error < 0)
+ goto out;
+
+ display_progress(rename->progress, ++rename->progress_nr);
+
+out:
+ strbuf_release(&new_referent);
+ strbuf_release(&new_refname);
+ return error;
}
static int migrate_file(struct remote *remote)
{
struct strbuf buf = STRBUF_INIT;
- int i;
strbuf_addf(&buf, "remote.%s.url", remote->name);
- for (i = 0; i < remote->url.nr; i++)
- git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0);
+ for (size_t i = 0; i < remote->url.nr; i++)
+ repo_config_set_multivar(the_repository, buf.buf, remote->url.v[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name);
- for (i = 0; i < remote->push.nr; i++)
- git_config_set_multivar(buf.buf, remote->push.items[i].raw, "^$", 0);
+ for (int i = 0; i < remote->push.nr; i++)
+ repo_config_set_multivar(the_repository, buf.buf, remote->push.items[i].raw, "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
- for (i = 0; i < remote->fetch.nr; i++)
- git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0);
+ for (int i = 0; i < remote->fetch.nr; i++)
+ repo_config_set_multivar(the_repository, buf.buf, remote->fetch.items[i].raw, "^$", 0);
#ifndef WITH_BREAKING_CHANGES
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(repo_git_path_replace(the_repository, &buf,
@@ -707,12 +824,12 @@ static void handle_push_default(const char* old_name, const char* new_name)
.origin = STRBUF_INIT,
.linenr = -1,
};
- git_config(config_read_push_default, &push_default);
+ repo_config(the_repository, config_read_push_default, &push_default);
if (push_default.scope >= CONFIG_SCOPE_COMMAND)
; /* pass */
else if (push_default.scope >= CONFIG_SCOPE_LOCAL) {
- int result = git_config_set_gently("remote.pushDefault",
- new_name);
+ int result = repo_config_set_gently(the_repository, "remote.pushDefault",
+ new_name);
if (new_name && result && result != CONFIG_NOTHING_SET)
die(_("could not set '%s'"), "remote.pushDefault");
else if (!new_name && result && result != CONFIG_NOTHING_SET)
@@ -730,6 +847,14 @@ static void handle_push_default(const char* old_name, const char* new_name)
strbuf_release(&push_default.origin);
}
+static const char conflicting_remote_refs_advice[] = N_(
+ "The remote you are trying to rename has conflicting references in the\n"
+ "new target refspec. This is most likely caused by you trying to nest\n"
+ "a remote into itself, e.g. by renaming 'parent' into 'parent/child'\n"
+ "or by unnesting a remote, e.g. the other way round.\n"
+ "\n"
+ "If that is the case, you can address this by first renaming the\n"
+ "remote to a different name.\n");
static int mv(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
@@ -741,11 +866,11 @@ static int mv(int argc, const char **argv, const char *prefix,
};
struct remote *oldremote, *newremote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT,
- old_remote_context = STRBUF_INIT;
- struct string_list remote_branches = STRING_LIST_INIT_DUP;
- struct rename_info rename;
- int i, refs_renamed_nr = 0, refspec_updated = 0;
- struct progress *progress = NULL;
+ old_remote_context = STRBUF_INIT, err = STRBUF_INIT;
+ struct rename_info rename = {
+ .err = &err,
+ };
+ int refspecs_need_update = 0;
int result = 0;
argc = parse_options(argc, argv, prefix, options,
@@ -756,8 +881,6 @@ static int mv(int argc, const char **argv, const char *prefix,
rename.old_name = argv[0];
rename.new_name = argv[1];
- rename.remote_branches = &remote_branches;
- rename.symrefs_nr = 0;
oldremote = remote_get(rename.old_name);
if (!remote_is_configured(oldremote, 1)) {
@@ -785,19 +908,50 @@ static int mv(int argc, const char **argv, const char *prefix,
goto out;
}
+ strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
+
+ for (int i = 0; i < oldremote->fetch.nr && !refspecs_need_update; i++)
+ refspecs_need_update = !!strstr(oldremote->fetch.items[i].raw,
+ old_remote_context.buf);
+
+ if (refspecs_need_update) {
+ rename.transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
+ if (!rename.transaction)
+ goto out;
+
+ if (show_progress)
+ rename.progress = start_delayed_progress(the_repository,
+ _("Renaming remote references"), 0);
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "refs/remotes/%s/", rename.old_name);
+
+ result = refs_for_each_rawref_in(get_main_ref_store(the_repository), buf.buf,
+ rename_one_ref, &rename);
+ if (result < 0)
+ die(_("queueing remote ref renames failed: %s"), rename.err->buf);
+
+ result = ref_transaction_prepare(rename.transaction, &err);
+ if (result < 0) {
+ error("renaming remote references failed: %s", err.buf);
+ if (result == REF_TRANSACTION_ERROR_NAME_CONFLICT)
+ advise(conflicting_remote_refs_advice);
+ die(NULL);
+ }
+ }
+
if (oldremote->fetch.nr) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
- strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
- for (i = 0; i < oldremote->fetch.nr; i++) {
+ repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ for (int i = 0; i < oldremote->fetch.nr; i++) {
char *ptr;
strbuf_reset(&buf2);
strbuf_addstr(&buf2, oldremote->fetch.items[i].raw);
ptr = strstr(buf2.buf, old_remote_context.buf);
if (ptr) {
- refspec_updated = 1;
strbuf_splice(&buf2,
ptr-buf2.buf + strlen(":refs/remotes/"),
strlen(rename.old_name), rename.new_name,
@@ -808,103 +962,43 @@ static int mv(int argc, const char **argv, const char *prefix,
"\tPlease update the configuration manually if necessary."),
buf2.buf);
- git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+ repo_config_set_multivar(the_repository, buf.buf, buf2.buf, "^$", 0);
}
}
read_branches();
- for (i = 0; i < branch_list.nr; i++) {
+ for (size_t i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util;
if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", item->string);
- git_config_set(buf.buf, rename.new_name);
+ repo_config_set(the_repository, buf.buf, rename.new_name);
}
if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.pushRemote", item->string);
- git_config_set(buf.buf, rename.new_name);
+ repo_config_set(the_repository, buf.buf, rename.new_name);
}
}
- if (!refspec_updated)
- goto out;
+ if (refspecs_need_update) {
+ result = ref_transaction_commit(rename.transaction, &err);
+ if (result < 0)
+ die(_("renaming remote refs failed: %s"), rename.err->buf);
- /*
- * First remove symrefs, then rename the rest, finally create
- * the new symrefs.
- */
- refs_for_each_ref(get_main_ref_store(the_repository),
- read_remote_branches, &rename);
- if (show_progress) {
- /*
- * Count symrefs twice, since "renaming" them is done by
- * deleting and recreating them in two separate passes.
- */
- progress = start_progress(the_repository,
- _("Renaming remote references"),
- rename.remote_branches->nr + rename.symrefs_nr);
- }
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
- struct strbuf referent = STRBUF_INIT;
-
- if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
- &referent))
- continue;
- if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
- die(_("deleting '%s' failed"), item->string);
+ stop_progress(&rename.progress);
- strbuf_release(&referent);
- display_progress(progress, ++refs_renamed_nr);
+ handle_push_default(rename.old_name, rename.new_name);
}
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
-
- if (item->util)
- continue;
- strbuf_reset(&buf);
- strbuf_addstr(&buf, item->string);
- strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
- rename.new_name, strlen(rename.new_name));
- strbuf_reset(&buf2);
- strbuf_addf(&buf2, "remote: renamed %s to %s",
- item->string, buf.buf);
- if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
- die(_("renaming '%s' failed"), item->string);
- display_progress(progress, ++refs_renamed_nr);
- }
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
-
- if (!item->util)
- continue;
- strbuf_reset(&buf);
- strbuf_addstr(&buf, item->string);
- strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
- rename.new_name, strlen(rename.new_name));
- strbuf_reset(&buf2);
- strbuf_addstr(&buf2, item->util);
- strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old_name),
- rename.new_name, strlen(rename.new_name));
- strbuf_reset(&buf3);
- strbuf_addf(&buf3, "remote: renamed %s to %s",
- item->string, buf.buf);
- if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
- die(_("creating '%s' failed"), buf.buf);
- display_progress(progress, ++refs_renamed_nr);
- }
- stop_progress(&progress);
-
- handle_push_default(rename.old_name, rename.new_name);
out:
- string_list_clear(&remote_branches, 1);
+ ref_transaction_free(rename.transaction);
strbuf_release(&old_remote_context);
strbuf_release(&buf);
strbuf_release(&buf2);
strbuf_release(&buf3);
+ strbuf_release(&err);
return result;
}
@@ -920,7 +1014,7 @@ static int rm(int argc, const char **argv, const char *prefix,
struct string_list branches = STRING_LIST_INIT_DUP;
struct string_list skipped = STRING_LIST_INIT_DUP;
struct branches_for_remote cb_data;
- int i, result;
+ int result;
memset(&cb_data, 0, sizeof(cb_data));
cb_data.branches = &branches;
@@ -942,7 +1036,7 @@ static int rm(int argc, const char **argv, const char *prefix,
for_each_remote(add_known_remote, &known_remotes);
read_branches();
- for (i = 0; i < branch_list.nr; i++) {
+ for (size_t i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util;
if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
@@ -951,7 +1045,7 @@ static int rm(int argc, const char **argv, const char *prefix,
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.%s",
item->string, *k);
- result = git_config_set_gently(buf.buf, NULL);
+ result = repo_config_set_gently(the_repository, buf.buf, NULL);
if (result && result != CONFIG_NOTHING_SET)
die(_("could not unset '%s'"), buf.buf);
}
@@ -959,7 +1053,7 @@ static int rm(int argc, const char **argv, const char *prefix,
if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.pushremote", item->string);
- result = git_config_set_gently(buf.buf, NULL);
+ result = repo_config_set_gently(the_repository, buf.buf, NULL);
if (result && result != CONFIG_NOTHING_SET)
die(_("could not unset '%s'"), buf.buf);
}
@@ -988,7 +1082,7 @@ static int rm(int argc, const char **argv, const char *prefix,
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:",
skipped.nr));
- for (i = 0; i < skipped.nr; i++)
+ for (size_t i = 0; i < skipped.nr; i++)
fprintf(stderr, " git branch -d %s\n",
skipped.items[i].string);
}
@@ -1166,7 +1260,6 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
struct branch_info *branch_info = item->util;
struct string_list *merge = &branch_info->merge;
int width = show_info->width + 4;
- int i;
if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
@@ -1192,7 +1285,7 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
} else {
printf_ln(_("merges with remote %s"), merge->items[0].string);
}
- for (i = 1; i < merge->nr; i++)
+ for (size_t i = 1; i < merge->nr; i++)
printf(_("%-*s and with remote %s\n"), width, "",
merge->items[i].string);
@@ -1277,7 +1370,6 @@ static int get_one_entry(struct remote *remote, void *priv)
struct string_list *list = priv;
struct strbuf remote_info_buf = STRBUF_INIT;
struct strvec *url;
- int i;
if (remote->url.nr > 0) {
struct strbuf promisor_config = STRBUF_INIT;
@@ -1285,7 +1377,7 @@ static int get_one_entry(struct remote *remote, void *priv)
strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name);
strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]);
- if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter))
+ if (!repo_config_get_string_tmp(the_repository, promisor_config.buf, &partial_clone_filter))
strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter);
strbuf_release(&promisor_config);
@@ -1294,8 +1386,7 @@ static int get_one_entry(struct remote *remote, void *priv)
} else
string_list_append(list, remote->name)->util = NULL;
url = push_url_of_remote(remote);
- for (i = 0; i < url->nr; i++)
- {
+ for (size_t i = 0; i < url->nr; i++) {
strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]);
string_list_append(list, remote->name)->util =
strbuf_detach(&remote_info_buf, NULL);
@@ -1312,10 +1403,8 @@ static int show_all(void)
result = for_each_remote(get_one_entry, &list);
if (!result) {
- int i;
-
string_list_sort(&list);
- for (i = 0; i < list.nr; i++) {
+ for (size_t i = 0; i < list.nr; i++) {
struct string_list_item *item = list.items + i;
if (verbose)
printf("%s\t%s\n", item->string,
@@ -1352,7 +1441,7 @@ static int show(int argc, const char **argv, const char *prefix,
query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);
for (; argc; argc--, argv++) {
- int i;
+ size_t i;
struct strvec *url;
get_remote_ref_states(*argv, &info.states, query_flag);
@@ -1458,7 +1547,7 @@ static void report_set_head_auto(const char *remote, const char *head_name,
static int set_head(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, opt_a = 0, opt_d = 0, result = 0, was_detached;
+ int opt_a = 0, opt_d = 0, result = 0, was_detached;
struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
b_local_head = STRBUF_INIT;
char *head_name = NULL;
@@ -1474,10 +1563,13 @@ static int set_head(int argc, const char **argv, const char *prefix,
};
argc = parse_options(argc, argv, prefix, options,
builtin_remote_sethead_usage, 0);
- if (argc) {
- strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
- remote = remote_get(argv[0]);
- }
+
+ /* All modes require at least a remote name. */
+ if (!argc)
+ usage_with_options(builtin_remote_sethead_usage, options);
+
+ strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
+ remote = remote_get(argv[0]);
if (!opt_a && !opt_d && argc == 2) {
head_name = xstrdup(argv[1]);
@@ -1489,7 +1581,7 @@ static int set_head(int argc, const char **argv, const char *prefix,
else if (states.heads.nr > 1) {
result |= error(_("Multiple remote HEAD branches. "
"Please choose one explicitly with:"));
- for (i = 0; i < states.heads.nr; i++)
+ for (size_t i = 0; i < states.heads.nr; i++)
fprintf(stderr, " git remote set-head %s %s\n",
argv[0], states.heads.items[i].string);
} else
@@ -1520,7 +1612,7 @@ static int set_head(int argc, const char **argv, const char *prefix,
struct strbuf config_name = STRBUF_INIT;
strbuf_addf(&config_name,
"remote.%s.followremotehead", remote->name);
- git_config_set(config_name.buf, "warn");
+ repo_config_set(the_repository, config_name.buf, "warn");
strbuf_release(&config_name);
}
@@ -1637,7 +1729,7 @@ static int update(int argc, const char **argv, const char *prefix,
strvec_push(&cmd.args, argv[i]);
if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) {
- git_config(get_remote_default, &default_defined);
+ repo_config(the_repository, get_remote_default, &default_defined);
if (!default_defined) {
strvec_pop(&cmd.args);
strvec_push(&cmd.args, "--all");
@@ -1650,8 +1742,8 @@ static int update(int argc, const char **argv, const char *prefix,
static int remove_all_fetch_refspecs(const char *key)
{
- return git_config_set_multivar_gently(key, NULL, NULL,
- CONFIG_FLAGS_MULTI_REPLACE);
+ return repo_config_set_multivar_gently(the_repository, key, NULL, NULL,
+ CONFIG_FLAGS_MULTI_REPLACE);
}
static void add_branches(struct remote *remote, const char **branches,
@@ -1714,7 +1806,7 @@ static int set_branches(int argc, const char **argv, const char *prefix,
static int get_url(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, push_mode = 0, all_mode = 0;
+ int push_mode = 0, all_mode = 0;
const char *remotename = NULL;
struct remote *remote;
struct strvec *url;
@@ -1742,7 +1834,7 @@ static int get_url(int argc, const char **argv, const char *prefix,
url = push_mode ? push_url_of_remote(remote) : &remote->url;
if (all_mode) {
- for (i = 0; i < url->nr; i++)
+ for (size_t i = 0; i < url->nr; i++)
printf_ln("%s", url->v[i]);
} else {
printf_ln("%s", url->v[0]);
@@ -1754,7 +1846,7 @@ static int get_url(int argc, const char **argv, const char *prefix,
static int set_url(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, push_mode = 0, add_mode = 0, delete_mode = 0;
+ int push_mode = 0, add_mode = 0, delete_mode = 0;
int matches = 0, negative_matches = 0;
const char *remotename = NULL;
const char *newurl = NULL;
@@ -1807,10 +1899,10 @@ static int set_url(int argc, const char **argv, const char *prefix,
/* Special cases that add new entry. */
if ((!oldurl && !delete_mode) || add_mode) {
if (add_mode)
- git_config_set_multivar(name_buf.buf, newurl,
+ repo_config_set_multivar(the_repository, name_buf.buf, newurl,
"^$", 0);
else
- git_config_set(name_buf.buf, newurl);
+ repo_config_set(the_repository, name_buf.buf, newurl);
goto out;
}
@@ -1818,7 +1910,7 @@ static int set_url(int argc, const char **argv, const char *prefix,
if (regcomp(&old_regex, oldurl, REG_EXTENDED))
die(_("Invalid old URL pattern: %s"), oldurl);
- for (i = 0; i < urlset->nr; i++)
+ for (size_t i = 0; i < urlset->nr; i++)
if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0))
matches++;
else
@@ -1831,10 +1923,10 @@ static int set_url(int argc, const char **argv, const char *prefix,
regfree(&old_regex);
if (!delete_mode)
- git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
+ repo_config_set_multivar(the_repository, name_buf.buf, newurl, oldurl, 0);
else
- git_config_set_multivar(name_buf.buf, NULL, oldurl,
- CONFIG_FLAGS_MULTI_REPLACE);
+ repo_config_set_multivar(the_repository, name_buf.buf, NULL, oldurl,
+ CONFIG_FLAGS_MULTI_REPLACE);
out:
strbuf_release(&name_buf);
return 0;
diff --git a/builtin/repack.c b/builtin/repack.c
index 75158d7776..a4def39197 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -223,9 +223,9 @@ static void mark_packs_for_deletion(struct existing_packs *existing,
static void remove_redundant_pack(const char *dir_name, const char *base_name)
{
struct strbuf buf = STRBUF_INIT;
- struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+ struct multi_pack_index *m = get_multi_pack_index(the_repository->objects->sources);
strbuf_addf(&buf, "%s.pack", base_name);
- if (m && midx_contains_pack(m, buf.buf))
+ if (m && m->local && midx_contains_pack(m, buf.buf))
clear_midx_file(the_repository);
strbuf_insertf(&buf, 0, "%s/", dir_name);
unlink_pack_path(buf.buf, 1);
@@ -1340,7 +1340,7 @@ int cmd_repack(int argc,
list_objects_filter_init(&po_args.filter_options);
- git_config(repack_config, &cruft_po_args);
+ repo_config(the_repository, repack_config, &cruft_po_args);
argc = parse_options(argc, argv, prefix, builtin_repack_options,
git_repack_usage, 0);
@@ -1531,7 +1531,7 @@ int cmd_repack(int argc,
* midx_has_unknown_packs() will make the decision for
* us.
*/
- if (!get_local_multi_pack_index(the_repository))
+ if (!get_multi_pack_index(the_repository->objects->sources))
midx_must_contain_cruft = 1;
}
@@ -1614,9 +1614,9 @@ int cmd_repack(int argc,
string_list_sort(&names);
- if (get_local_multi_pack_index(the_repository)) {
+ if (get_multi_pack_index(the_repository->objects->sources)) {
struct multi_pack_index *m =
- get_local_multi_pack_index(the_repository);
+ get_multi_pack_index(the_repository->objects->sources);
ALLOC_ARRAY(midx_pack_names,
m->num_packs + m->num_packs_in_base);
diff --git a/builtin/replace.c b/builtin/replace.c
index 5ff2ab723c..900b560a77 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -11,6 +11,7 @@
#include "builtin.h"
#include "config.h"
#include "editor.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
@@ -488,7 +489,8 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
return -1;
}
- if (write_object_file(buf.buf, buf.len, OBJ_COMMIT, &new_oid)) {
+ if (odb_write_object(the_repository->objects, buf.buf,
+ buf.len, OBJ_COMMIT, &new_oid)) {
strbuf_release(&buf);
return error(_("could not write replacement commit for: '%s'"),
old_ref);
@@ -574,7 +576,7 @@ int cmd_replace(int argc,
};
disable_replace_refs();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 1312e79d89..a056cb791b 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -66,7 +66,7 @@ int cmd_rerere(int argc,
argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
- git_config(git_xmerge_config, NULL);
+ repo_config(the_repository, git_xmerge_config, NULL);
if (autoupdate == 1)
flags = RERERE_AUTOUPDATE;
diff --git a/builtin/reset.c b/builtin/reset.c
index dc50ffc1ac..ed35802af1 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -346,6 +346,7 @@ int cmd_reset(int argc,
struct object_id oid;
struct pathspec pathspec;
int intent_to_add = 0;
+ struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_BOOL(0, "no-refresh", &no_refresh,
@@ -370,6 +371,8 @@ int cmd_reset(int argc,
PARSE_OPT_OPTARG,
option_parse_recurse_submodules_worktree_updater),
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT_BOOL('N', "intent-to-add", &intent_to_add,
N_("record only the fact that removed paths will be added later")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
@@ -377,7 +380,7 @@ int cmd_reset(int argc,
OPT_END()
};
- git_config(git_reset_config, NULL);
+ repo_config(the_repository, git_reset_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
@@ -420,6 +423,11 @@ int cmd_reset(int argc,
oidcpy(&oid, &tree->object.oid);
}
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -427,9 +435,14 @@ int cmd_reset(int argc,
if (reset_type != NONE)
die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
trace2_cmd_mode("patch-interactive");
- update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
- &pathspec);
+ update_ref_status = !!run_add_p(the_repository, ADD_P_RESET,
+ &add_p_opt, rev, &pathspec);
goto cleanup;
+ } else {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
}
/* git reset tree [--] paths... can be used to
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 97a3af36ec..99f876ba85 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -644,7 +644,7 @@ int cmd_rev_list(int argc,
show_usage_if_asked(argc, argv, rev_list_usage);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
repo_init_revisions(the_repository, &revs, prefix);
revs.abbrev = DEFAULT_ABBREV;
revs.commit_format = CMIT_FMT_UNSPECIFIED;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 490da33bec..44ff1b8342 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -734,7 +734,7 @@ int cmd_rev_parse(int argc,
/* No options; just report on whether we're in a git repo or not. */
if (argc == 1) {
setup_git_directory();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
return 0;
}
@@ -769,7 +769,7 @@ int cmd_rev_parse(int argc,
/* The rest of the options require a git repository. */
if (!did_repo_setup) {
prefix = setup_git_directory();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
did_repo_setup = 1;
prepare_repo_settings(the_repository);
diff --git a/builtin/revert.c b/builtin/revert.c
index e07c2217fe..c3f92b585d 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -111,7 +111,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
- const char sentinel_value;
+ const char sentinel_value = 0; /* value not important */
const char *strategy = &sentinel_value;
const char *gpg_sign = &sentinel_value;
enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
diff --git a/builtin/rm.c b/builtin/rm.c
index a6565a69cf..05d89e98c3 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "lockfile.h"
#include "dir.h"
#include "gettext.h"
@@ -271,7 +272,7 @@ int cmd_rm(int argc,
struct pathspec pathspec;
char *seen;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_rm_options,
builtin_rm_usage, 0);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 28b69d26b4..8b81c8a848 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "hex.h"
#include "pkt-line.h"
#include "run-command.h"
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 60adc5e7a5..b91acf45c8 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -421,7 +421,7 @@ int cmd_shortlog(int argc,
if (nongit && !the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
shortlog_init(&log);
repo_init_revisions(the_repository, &rev, prefix);
parse_options_start(&ctx, argc, argv, prefix, options,
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 525b231d87..1ab7db9d2c 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -710,7 +710,7 @@ int cmd_show_branch(int ac,
init_commit_name_slab(&name_slab);
- git_config(git_show_branch_config, NULL);
+ repo_config(the_repository, git_show_branch_config, NULL);
/* If nothing is specified, try the default first */
if (ac == 1 && default_args.nr) {
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 117709cb07..0b6f9edf86 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs/refs-internal.h"
@@ -324,7 +325,7 @@ struct repository *repo UNUSED)
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, show_ref_options,
show_ref_usage, 0);
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 1bf01591b2..8c333b3e2e 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1082,7 +1082,7 @@ int cmd_sparse_checkout(int argc,
builtin_sparse_checkout_options,
builtin_sparse_checkout_usage, 0);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/stash.c b/builtin/stash.c
index e2f95cc2eb..f5ddee5c7f 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -738,7 +738,8 @@ cleanup:
return ret;
}
-static int reject_reflog_ent(struct object_id *ooid UNUSED,
+static int reject_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid UNUSED,
struct object_id *noid UNUSED,
const char *email UNUSED,
timestamp_t timestamp UNUSED,
@@ -979,7 +980,7 @@ static int show_stash(int argc, const char **argv, const char *prefix,
int do_usage = 0;
init_diff_ui_defaults();
- git_config(git_diff_ui_config, NULL);
+ repo_config(the_repository, git_diff_ui_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
@@ -1301,7 +1302,8 @@ done:
}
static int stash_patch(struct stash_info *info, const struct pathspec *ps,
- struct strbuf *out_patch, int quiet)
+ struct strbuf *out_patch, int quiet,
+ struct add_p_opt *add_p_opt)
{
int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
@@ -1326,7 +1328,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
+ ret = !!run_add_p(the_repository, ADD_P_STASH, add_p_opt, NULL, ps);
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
@@ -1421,8 +1423,8 @@ done:
}
static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf,
- int include_untracked, int patch_mode, int only_staged,
- struct stash_info *info, struct strbuf *patch,
+ int include_untracked, int patch_mode, struct add_p_opt *add_p_opt,
+ int only_staged, struct stash_info *info, struct strbuf *patch,
int quiet)
{
int ret = 0;
@@ -1503,7 +1505,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
untracked_commit_option = 1;
}
if (patch_mode) {
- ret = stash_patch(info, ps, patch, quiet);
+ ret = stash_patch(info, ps, patch, quiet, add_p_opt);
if (ret < 0) {
if (!quiet)
fprintf_ln(stderr, _("Cannot save the current "
@@ -1578,7 +1580,7 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,
if (!check_changes_tracked_files(&ps))
return 0;
- ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info,
+ ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, NULL, 0, &info,
NULL, 0);
if (!ret)
printf_ln("%s", oid_to_hex(&info.w_commit));
@@ -1589,7 +1591,8 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,
}
static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet,
- int keep_index, int patch_mode, int include_untracked, int only_staged)
+ int keep_index, int patch_mode, struct add_p_opt *add_p_opt,
+ int include_untracked, int only_staged)
{
int ret = 0;
struct stash_info info = STASH_INFO_INIT;
@@ -1659,8 +1662,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
if (stash_msg)
strbuf_addstr(&stash_msg_buf, stash_msg);
- if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged,
- &info, &patch, quiet)) {
+ if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode,
+ add_p_opt, only_staged, &info, &patch, quiet)) {
ret = -1;
goto done;
}
@@ -1833,6 +1836,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
const char *stash_msg = NULL;
char *pathspec_from_file = NULL;
struct pathspec ps;
+ struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
@@ -1840,6 +1844,8 @@ static int push_stash(int argc, const char **argv, const char *prefix,
N_("stash staged changes only")),
OPT_BOOL('p', "patch", &patch_mode,
N_("stash in patch mode")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT__QUIET(&quiet, N_("quiet mode")),
OPT_BOOL('u', "include-untracked", &include_untracked,
N_("include untracked files in stash")),
@@ -1895,8 +1901,20 @@ static int push_stash(int argc, const char **argv, const char *prefix,
die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
+ if (!patch_mode) {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
+ }
+
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
- include_untracked, only_staged);
+ &add_p_opt, include_untracked, only_staged);
clear_pathspec(&ps);
free(pathspec_from_file);
@@ -1921,6 +1939,7 @@ static int save_stash(int argc, const char **argv, const char *prefix,
const char *stash_msg = NULL;
struct pathspec ps;
struct strbuf stash_msg_buf = STRBUF_INIT;
+ struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
@@ -1928,6 +1947,8 @@ static int save_stash(int argc, const char **argv, const char *prefix,
N_("stash staged changes only")),
OPT_BOOL('p', "patch", &patch_mode,
N_("stash in patch mode")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT__QUIET(&quiet, N_("quiet mode")),
OPT_BOOL('u', "include-untracked", &include_untracked,
N_("include untracked files in stash")),
@@ -1946,8 +1967,22 @@ static int save_stash(int argc, const char **argv, const char *prefix,
stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' ');
memset(&ps, 0, sizeof(ps));
+
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
+ if (!patch_mode) {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
+ }
+
ret = do_push_stash(&ps, stash_msg, quiet, keep_index,
- patch_mode, include_untracked, only_staged);
+ patch_mode, &add_p_opt, include_untracked,
+ only_staged);
strbuf_release(&stash_msg_buf);
return ret;
@@ -2173,7 +2208,8 @@ struct stash_entry_data {
size_t count;
};
-static int collect_stash_entries(struct object_id *old_oid UNUSED,
+static int collect_stash_entries(const char *refname UNUSED,
+ struct object_id *old_oid UNUSED,
struct object_id *new_oid,
const char *committer UNUSED,
timestamp_t timestamp UNUSED,
@@ -2358,7 +2394,7 @@ int cmd_stash(int argc,
const char **args_copy;
int ret;
- git_config(git_stash_config, NULL);
+ repo_config(the_repository, git_stash_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_stash_usage,
PARSE_OPT_SUBCOMMAND_OPTIONAL |
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index e147f3ff92..4a566cbc5d 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -55,7 +55,7 @@ int cmd_stripspace(int argc,
if (mode == STRIP_COMMENTS || mode == COMMENT_LINES) {
setup_git_directory_gently(&nongit);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
}
if (strbuf_read(&buf, 0, 1024) < 0)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index d8a6fa47e5..07a1935cbe 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -32,6 +32,8 @@
#include "advice.h"
#include "branch.h"
#include "list-objects-filter-options.h"
+#include "wildmatch.h"
+#include "strbuf.h"
#define OPT_QUIET (1 << 0)
#define OPT_CACHED (1 << 1)
@@ -53,7 +55,7 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
struct strbuf remotesb = STRBUF_INIT;
strbuf_addf(&remotesb, "remote.%s.url", remote);
- if (git_config_get_string(remotesb.buf, &remoteurl)) {
+ if (repo_config_get_string(the_repository, remotesb.buf, &remoteurl)) {
if (!quiet)
warning(_("could not look up configuration '%s'. "
"Assuming this repository is its own "
@@ -458,7 +460,7 @@ static void init_submodule(const char *path, const char *prefix,
*/
if (!is_submodule_active(the_repository, path)) {
strbuf_addf(&sb, "submodule.%s.active", sub->name);
- git_config_set_gently(sb.buf, "true");
+ repo_config_set_gently(the_repository, sb.buf, "true");
strbuf_reset(&sb);
}
@@ -468,7 +470,7 @@ static void init_submodule(const char *path, const char *prefix,
* .gitmodules, so look it up directly.
*/
strbuf_addf(&sb, "submodule.%s.url", sub->name);
- if (git_config_get_string(sb.buf, &url)) {
+ if (repo_config_get_string(the_repository, sb.buf, &url)) {
if (!sub->url)
die(_("No url found for submodule path '%s' in .gitmodules"),
displaypath);
@@ -484,7 +486,7 @@ static void init_submodule(const char *path, const char *prefix,
free(oldurl);
}
- if (git_config_set_gently(sb.buf, url))
+ if (repo_config_set_gently(the_repository, sb.buf, url))
die(_("Failed to register url for submodule path '%s'"),
displaypath);
if (!(flags & OPT_QUIET))
@@ -496,7 +498,7 @@ static void init_submodule(const char *path, const char *prefix,
/* Copy "update" setting when it is not set yet */
strbuf_addf(&sb, "submodule.%s.update", sub->name);
- if (git_config_get_string_tmp(sb.buf, &upd) &&
+ if (repo_config_get_string_tmp(the_repository, sb.buf, &upd) &&
sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
fprintf(stderr, _("warning: command update mode suggested for submodule '%s'\n"),
@@ -506,7 +508,7 @@ static void init_submodule(const char *path, const char *prefix,
upd = submodule_update_type_to_string(sub->update_strategy.type);
}
- if (git_config_set_gently(sb.buf, upd))
+ if (repo_config_set_gently(the_repository, sb.buf, upd))
die(_("Failed to register update mode for submodule path '%s'"), displaypath);
}
strbuf_release(&sb);
@@ -549,7 +551,7 @@ static int module_init(int argc, const char **argv, const char *prefix,
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && !git_config_get("submodule.active"))
+ if (!argc && !repo_config_get(the_repository, "submodule.active"))
module_list_active(&list);
info.prefix = prefix;
@@ -649,7 +651,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
"--ignore-submodules=dirty", "--quiet", "--",
path, NULL);
- git_config(git_diff_basic_config, NULL);
+ repo_config(the_repository, git_diff_basic_config, NULL);
repo_init_revisions(the_repository, &rev, NULL);
rev.abbrev = 0;
@@ -1034,7 +1036,7 @@ static void prepare_submodule_summary(struct summary_cb *info,
config_key = xstrfmt("submodule.%s.ignore",
sub->name);
- if (!git_config_get_string_tmp(config_key, &value))
+ if (!repo_config_get_string_tmp(the_repository, config_key, &value))
ignore_all = !strcmp(value, "all");
else if (sub->ignore)
ignore_all = !strcmp(sub->ignore, "all");
@@ -1108,7 +1110,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
if (info->argc)
strvec_pushv(&diff_args, info->argv);
- git_config(git_diff_basic_config, NULL);
+ repo_config(the_repository, git_diff_basic_config, NULL);
repo_init_revisions(the_repository, &rev, info->prefix);
rev.abbrev = 0;
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
@@ -1262,7 +1264,7 @@ static void sync_submodule(const char *path, const char *prefix,
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
- if (git_config_set_gently(sb.buf, super_config_url))
+ if (repo_config_set_gently(the_repository, sb.buf, super_config_url))
die(_("failed to register url for submodule path '%s'"),
displaypath);
@@ -1280,7 +1282,7 @@ static void sync_submodule(const char *path, const char *prefix,
submodule_to_gitdir(the_repository, &sb, path);
strbuf_addstr(&sb, "/config");
- if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
+ if (repo_config_set_in_file_gently(the_repository, sb.buf, remote_key, NULL, sub_origin_url))
die(_("failed to update remote for submodule '%s'"),
path);
@@ -1623,11 +1625,11 @@ static void prepare_possible_alternates(const char *sm_name,
char *sm_alternate = NULL, *error_strategy = NULL;
struct submodule_alternate_setup sas = SUBMODULE_ALTERNATE_SETUP_INIT;
- git_config_get_string("submodule.alternateLocation", &sm_alternate);
+ repo_config_get_string(the_repository, "submodule.alternateLocation", &sm_alternate);
if (!sm_alternate)
return;
- git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+ repo_config_get_string(the_repository, "submodule.alternateErrorStrategy", &error_strategy);
if (!error_strategy)
error_strategy = xstrdup("die");
@@ -1808,14 +1810,14 @@ static int clone_submodule(const struct module_clone_data *clone_data,
die(_("could not get submodule directory for '%s'"), clone_data_path);
/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
- git_config_get_string("submodule.alternateLocation", &sm_alternate);
+ repo_config_get_string(the_repository, "submodule.alternateLocation", &sm_alternate);
if (sm_alternate)
- git_config_set_in_file(p, "submodule.alternateLocation",
- sm_alternate);
- git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+ repo_config_set_in_file(the_repository, p, "submodule.alternateLocation",
+ sm_alternate);
+ repo_config_get_string(the_repository, "submodule.alternateErrorStrategy", &error_strategy);
if (error_strategy)
- git_config_set_in_file(p, "submodule.alternateErrorStrategy",
- error_strategy);
+ repo_config_set_in_file(the_repository, p, "submodule.alternateErrorStrategy",
+ error_strategy);
free(sm_alternate);
free(error_strategy);
@@ -2522,7 +2524,7 @@ static int ensure_core_worktree(const char *path)
abs_path = absolute_pathdup(path);
rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
- git_config_set_in_file(cfg_file, "core.worktree", rel_path);
+ repo_config_set_in_file(the_repository, cfg_file, "core.worktree", rel_path);
free(cfg_file);
free(abs_path);
@@ -2830,7 +2832,7 @@ static int module_update(int argc, const char **argv, const char *prefix,
};
update_clone_config_from_gitmodules(&opt.max_jobs);
- git_config(git_update_clone_config, &opt.max_jobs);
+ repo_config(the_repository, git_update_clone_config, &opt.max_jobs);
argc = parse_options(argc, argv, prefix, module_update_options,
git_submodule_helper_usage, 0);
@@ -2878,7 +2880,7 @@ static int module_update(int argc, const char **argv, const char *prefix,
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && !git_config_get("submodule.active"))
+ if (!argc && !repo_config_get(the_repository, "submodule.active"))
module_list_active(&list);
info.prefix = opt.prefix;
@@ -3128,7 +3130,7 @@ static int module_create_branch(int argc, const char **argv, const char *prefix,
NULL
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
track = git_branch_track;
argc = parse_options(argc, argv, prefix, options, usage, 0);
@@ -3307,9 +3309,11 @@ static void configure_added_submodule(struct add_data *add_data)
char *key;
struct child_process add_submod = CHILD_PROCESS_INIT;
struct child_process add_gitmodules = CHILD_PROCESS_INIT;
+ const struct string_list *values;
+ int matched = 0;
key = xstrfmt("submodule.%s.url", add_data->sm_name);
- git_config_set_gently(key, add_data->realrepo);
+ repo_config_set_gently(the_repository, key, add_data->realrepo);
free(key);
add_submod.git_cmd = 1;
@@ -3349,20 +3353,28 @@ static void configure_added_submodule(struct add_data *add_data)
* is_submodule_active(), since that function needs to find
* out the value of "submodule.active" again anyway.
*/
- if (!git_config_get("submodule.active")) {
+ if (repo_config_get(the_repository, "submodule.active") || /* key absent */
+ repo_config_get_string_multi(the_repository, "submodule.active", &values)) {
/*
* If the submodule being added isn't already covered by the
* current configured pathspec, set the submodule's active flag
*/
- if (!is_submodule_active(the_repository, add_data->sm_path)) {
+ key = xstrfmt("submodule.%s.active", add_data->sm_name);
+ repo_config_set_gently(the_repository, key, "true");
+ free(key);
+ } else {
+ for (size_t i = 0; i < values->nr; i++) {
+ const char *pat = values->items[i].string;
+ if (!wildmatch(pat, add_data->sm_path, 0)) { /* match found */
+ matched = 1;
+ break;
+ }
+ }
+ if (!matched) { /* no pattern matched -> force-enable */
key = xstrfmt("submodule.%s.active", add_data->sm_name);
- git_config_set_gently(key, "true");
+ repo_config_set_gently(the_repository, key, "true");
free(key);
}
- } else {
- key = xstrfmt("submodule.%s.active", add_data->sm_name);
- git_config_set_gently(key, "true");
- free(key);
}
}
@@ -3423,6 +3435,9 @@ static int module_add(int argc, const char **argv, const char *prefix,
struct add_data add_data = ADD_DATA_INIT;
const char *ref_storage_format = NULL;
char *to_free = NULL;
+ const struct submodule *existing;
+ struct strbuf buf = STRBUF_INIT;
+ char *sm_name_to_free = NULL;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
N_("branch of repository to add as submodule")),
@@ -3525,6 +3540,28 @@ static int module_add(int argc, const char **argv, const char *prefix,
if(!add_data.sm_name)
add_data.sm_name = add_data.sm_path;
+ existing = submodule_from_name(the_repository,
+ null_oid(the_hash_algo),
+ add_data.sm_name);
+
+ if (existing && strcmp(existing->path, add_data.sm_path)) {
+ if (!force) {
+ die(_("submodule name '%s' already used for path '%s'"),
+ add_data.sm_name, existing->path);
+ }
+ /* --force: build <name><n> until unique */
+ for (int i = 1; ; i++) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s%d", add_data.sm_name, i);
+ if (!submodule_from_name(the_repository,
+ null_oid(the_hash_algo),
+ buf.buf)) {
+ break;
+ }
+ }
+ add_data.sm_name = sm_name_to_free = strbuf_detach(&buf, NULL);
+ }
+
if (check_submodule_name(add_data.sm_name))
die(_("'%s' is not a valid submodule name"), add_data.sm_name);
@@ -3540,6 +3577,7 @@ static int module_add(int argc, const char **argv, const char *prefix,
ret = 0;
cleanup:
+ free(sm_name_to_free);
free(add_data.sm_path);
free(to_free);
strbuf_release(&sb);
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 299d23d76a..231e41e715 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "refs.h"
#include "parse-options.h"
@@ -59,7 +60,7 @@ int cmd_symbolic_ref(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options,
git_symbolic_ref_usage, 0);
if (msg && !*msg)
diff --git a/builtin/tag.c b/builtin/tag.c
index 46cbf892e3..f0665af3ac 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -271,8 +271,8 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
struct object_id *compat_oid = NULL, compat_oid_buf;
if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0)
return error(_("unable to sign the tag"));
- if (write_object_file_flags(buf->buf, buf->len, OBJ_TAG, result,
- compat_oid, 0) < 0)
+ if (odb_write_object_ext(the_repository->objects, buf->buf,
+ buf->len, OBJ_TAG, result, compat_oid, 0) < 0)
return error(_("unable to write tag file"));
return 0;
}
@@ -546,7 +546,7 @@ int cmd_tag(int argc,
* Try to set sort keys from config. If config does not set any,
* fall back on default (refname) sorting.
*/
- git_config(git_tag_config, &sorting_options);
+ repo_config(the_repository, git_tag_config, &sorting_options);
if (!sorting_options.nr)
string_list_append(&sorting_options, "refname");
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 4360872ae0..87877a9fab 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "hex.h"
#include "object-file.h"
#include "object-name.h"
@@ -43,7 +44,7 @@ int cmd_unpack_file(int argc,
if (repo_get_oid(the_repository, argv[1], &oid))
die("Not a valid object name %s", argv[1]);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
puts(create_temp_file(&oid));
return 0;
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index a69d59eb50..7ae7c82b6c 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -204,8 +204,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
{
struct object_id oid;
- if (write_object_file(obj_buf->buffer, obj_buf->size,
- obj->type, &oid) < 0)
+ if (odb_write_object(the_repository->objects, obj_buf->buffer, obj_buf->size,
+ obj->type, &oid) < 0)
die("failed to write object %s", oid_to_hex(&obj->oid));
obj->flags |= FLAG_WRITTEN;
}
@@ -272,16 +272,16 @@ static void write_object(unsigned nr, enum object_type type,
void *buf, unsigned long size)
{
if (!strict) {
- if (write_object_file(buf, size, type,
- &obj_list[nr].oid) < 0)
+ if (odb_write_object(the_repository->objects, buf, size, type,
+ &obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
free(buf);
obj_list[nr].obj = NULL;
} else if (type == OBJ_BLOB) {
struct blob *blob;
- if (write_object_file(buf, size, type,
- &obj_list[nr].oid) < 0)
+ if (odb_write_object(the_repository->objects, buf, size, type,
+ &obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
free(buf);
@@ -403,7 +403,8 @@ static void stream_blob(unsigned long size, unsigned nr)
data.zstream = &zstream;
git_inflate_init(&zstream);
- if (stream_loose_object(&in_stream, size, &info->oid))
+ if (stream_loose_object(the_repository->objects->sources,
+ &in_stream, size, &info->oid))
die(_("failed to write object in stream"));
if (data.status != Z_STREAM_END)
@@ -621,7 +622,7 @@ int cmd_unpack_objects(int argc,
disable_replace_refs();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
quiet = !isatty(2);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 0c1d4ed55b..2380f3ccd6 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -1103,7 +1103,7 @@ int cmd_update_index(int argc,
show_usage_with_options_if_asked(argc, argv,
update_index_usage, options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
prepare_repo_settings(r);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 1e6131e04a..195437e7c6 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -3,6 +3,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hash.h"
#include "hex.h"
@@ -769,7 +770,7 @@ int cmd_update_ref(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_update_ref_usage,
0);
if (msg && !*msg)
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index ba702d30ef..4c12968a83 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "server-info.h"
diff --git a/builtin/var.c b/builtin/var.c
index ada642a9fe..cc3a43cde2 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -11,6 +11,7 @@
#include "attr.h"
#include "config.h"
#include "editor.h"
+#include "environment.h"
#include "ident.h"
#include "pager.h"
#include "refs.h"
@@ -181,7 +182,7 @@ static void list_vars(void)
if (ptr->multivalued && *val) {
struct string_list list = STRING_LIST_INIT_DUP;
- string_list_split(&list, val, '\n', -1);
+ string_list_split(&list, val, "\n", -1);
for (size_t i = 0; i < list.nr; i++)
printf("%s=%s\n", ptr->name, list.items[i].string);
string_list_clear(&list, 0);
@@ -226,11 +227,11 @@ int cmd_var(int argc,
usage(var_usage);
if (strcmp(argv[1], "-l") == 0) {
- git_config(show_config, NULL);
+ repo_config(the_repository, show_config, NULL);
list_vars();
return 0;
}
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
git_var = get_git_var(argv[1]);
if (!git_var)
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 5f749a30da..62398acd72 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -7,6 +7,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "object-name.h"
#include "commit.h"
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 34e4ed715f..65fd6629a0 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
@@ -81,7 +82,7 @@ int cmd_verify_pack(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, verify_pack_options,
verify_pack_usage, 0);
if (argc < 1)
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index ed1c40338f..cd6bc11095 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -7,6 +7,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "tag.h"
#include "object-name.h"
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 2dceeeed8b..812774a5ca 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -379,13 +379,13 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
bare &&
- git_config_set_multivar_in_file_gently(
+ repo_config_set_multivar_in_file_gently(the_repository,
to_file, "core.bare", NULL, "true", NULL, 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
if (!git_configset_get(&cs, "core.worktree") &&
- git_config_set_in_file_gently(to_file,
- "core.worktree", NULL, NULL))
+ repo_config_set_in_file_gently(the_repository, to_file,
+ "core.worktree", NULL, NULL))
error(_("failed to unset '%s' in '%s'"),
"core.worktree", to_file);
@@ -1448,7 +1448,7 @@ int cmd_worktree(int ac,
OPT_END()
};
- git_config(git_worktree_config, NULL);
+ repo_config(the_repository, git_worktree_config, NULL);
if (!prefix)
prefix = "";
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index cfec044710..e3bd1a40db 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -6,6 +6,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "tree.h"
@@ -43,7 +44,7 @@ int cmd_write_tree(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
write_tree_usage, 0);
diff --git a/bulk-checkin.c b/bulk-checkin.c
index 16df86c0ba..b2809ab039 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -46,7 +46,7 @@ static void finish_tmp_packfile(struct strbuf *basename,
stage_tmp_packfiles(the_repository, basename, pack_tmp_name,
written_list, nr_written, NULL, pack_idx_opts, hash,
&idx_tmp_name);
- rename_tmp_packfile_idx(basename, &idx_tmp_name);
+ rename_tmp_packfile_idx(the_repository, basename, &idx_tmp_name);
free(idx_tmp_name);
}
diff --git a/cache-tree.c b/cache-tree.c
index a4bc14ad15..66ef2becbe 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -456,9 +456,8 @@ static int update_one(struct cache_tree *it,
} else if (dryrun) {
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
OBJ_TREE, &it->oid);
- } else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE,
- &it->oid, NULL, flags & WRITE_TREE_SILENT
- ? WRITE_OBJECT_FILE_SILENT : 0)) {
+ } else if (odb_write_object_ext(the_repository->objects, buffer.buf, buffer.len, OBJ_TREE,
+ &it->oid, NULL, flags & WRITE_TREE_SILENT ? WRITE_OBJECT_SILENT : 0)) {
strbuf_release(&buffer);
return -1;
}
diff --git a/checkout.c b/checkout.c
index 0b1cf8b40b..1588b116ee 100644
--- a/checkout.c
+++ b/checkout.c
@@ -52,7 +52,7 @@ char *unique_tracking_name(const char *name, struct object_id *oid,
{
struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
const char *default_remote = NULL;
- if (!git_config_get_string_tmp("checkout.defaultremote", &default_remote))
+ if (!repo_config_get_string_tmp(the_repository, "checkout.defaultremote", &default_remote))
cb_data.default_remote = default_remote;
cb_data.src_ref = xstrfmt("refs/heads/%s", name);
cb_data.dst_oid = oid;
diff --git a/combine-diff.c b/combine-diff.c
index 4ea2dc93c4..3878faabe7 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1315,7 +1315,7 @@ static struct diff_filepair *combined_pair(struct combine_diff_path *p,
struct diff_filepair *pair;
struct diff_filespec *pool;
- pair = xmalloc(sizeof(*pair));
+ CALLOC_ARRAY(pair, 1);
CALLOC_ARRAY(pool, st_add(num_parent, 1));
pair->one = pool + 1;
pair->two = pool;
diff --git a/commit-graph.c b/commit-graph.c
index bd7b6f5338..e0d92b816f 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -4,6 +4,7 @@
#include "git-compat-util.h"
#include "config.h"
#include "csum-file.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
diff --git a/commit.c b/commit.c
index ea84c8e7f6..16d91b2bfc 100644
--- a/commit.c
+++ b/commit.c
@@ -1039,7 +1039,8 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
commit->object.flags |= TMP_MARK;
}
-static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+static int collect_one_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid, struct object_id *noid,
const char *ident UNUSED,
timestamp_t timestamp UNUSED, int tz UNUSED,
const char *message UNUSED, void *cbdata)
@@ -1805,8 +1806,8 @@ int commit_tree_extended(const char *msg, size_t msg_len,
compat_oid = &compat_oid_buf;
}
- result = write_object_file_flags(buffer.buf, buffer.len, OBJ_COMMIT,
- ret, compat_oid, 0);
+ result = odb_write_object_ext(the_repository->objects, buffer.buf, buffer.len,
+ OBJ_COMMIT, ret, compat_oid, 0);
out:
free(parent_buf);
strbuf_release(&buffer);
diff --git a/commit.h b/commit.h
index 9630c076d6..1d6e0c7518 100644
--- a/commit.h
+++ b/commit.h
@@ -2,6 +2,7 @@
#define COMMIT_H
#include "object.h"
+#include "add-interactive.h"
struct signature_check;
struct strbuf;
@@ -257,7 +258,7 @@ int for_each_commit_graft(each_commit_graft_fn, void *);
int interactive_add(struct repository *repo,
const char **argv,
const char *prefix,
- int patch);
+ int patch, struct add_p_opt *add_p_opt);
struct commit_extra_header {
struct commit_extra_header *next;
diff --git a/compat/mingw.c b/compat/mingw.c
index 5d69ae32f4..8538e3d172 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -244,7 +244,6 @@ enum hide_dotfiles_type {
HIDE_DOTFILES_DOTGITONLY
};
-static int core_restrict_inherited_handles = -1;
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
static char *unset_environment_variables;
@@ -268,15 +267,6 @@ int mingw_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.restrictinheritedhandles")) {
- if (value && !strcasecmp(value, "auto"))
- core_restrict_inherited_handles = -1;
- else
- core_restrict_inherited_handles =
- git_config_bool(var, value);
- return 0;
- }
-
return 0;
}
@@ -588,13 +578,24 @@ static int mingw_open_existing(const wchar_t *filename, int oflags, ...)
&security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ DWORD attrs = GetFileAttributesW(filename);
+ if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
+ handle = CreateFileW(filename, access,
+ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+ &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL| FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
- /* See `mingw_open_append()` for why we have this conversion. */
- if (err == ERROR_INVALID_PARAMETER)
- err = ERROR_PATH_NOT_FOUND;
+ if (handle == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
- errno = err_win_to_posix(err);
- return -1;
+ /* See `mingw_open_append()` for why we have this conversion. */
+ if (err == ERROR_INVALID_PARAMETER)
+ err = ERROR_PATH_NOT_FOUND;
+
+ errno = err_win_to_posix(err);
+ return -1;
+ }
}
fd = _open_osfhandle((intptr_t)handle, oflags | O_BINARY);
@@ -1656,7 +1657,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
const char *dir,
int prepend_cmd, int fhin, int fhout, int fherr)
{
- static int restrict_handle_inheritance = -1;
STARTUPINFOEXW si;
PROCESS_INFORMATION pi;
LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
@@ -1676,16 +1676,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
/* Make sure to override previous errors, if any */
errno = 0;
- if (restrict_handle_inheritance < 0)
- restrict_handle_inheritance = core_restrict_inherited_handles;
- /*
- * The following code to restrict which handles are inherited seems
- * to work properly only on Windows 7 and later, so let's disable it
- * on Windows Vista and 2008.
- */
- if (restrict_handle_inheritance < 0)
- restrict_handle_inheritance = GetVersion() >> 16 >= 7601;
-
do_unset_environment_variables();
/* Determine whether or not we are associated to a console */
@@ -1787,7 +1777,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
wenvblk = make_environment_block(deltaenv);
memset(&pi, 0, sizeof(pi));
- if (restrict_handle_inheritance && stdhandles_count &&
+ if (stdhandles_count &&
(InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
(attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
@@ -1808,52 +1798,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
&si.StartupInfo, &pi);
/*
- * On Windows 2008 R2, it seems that specifying certain types of handles
- * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
- * error. Rather than playing finicky and fragile games, let's just try
- * to detect this situation and simply try again without restricting any
- * handle inheritance. This is still better than failing to create
- * processes.
+ * On the off-chance that something with the file handle restriction
+ * went wrong, silently fall back to trying without it.
*/
- if (!ret && restrict_handle_inheritance && stdhandles_count) {
+ if (!ret && stdhandles_count) {
DWORD err = GetLastError();
struct strbuf buf = STRBUF_INIT;
- if (err != ERROR_NO_SYSTEM_RESOURCES &&
- /*
- * On Windows 7 and earlier, handles on pipes and character
- * devices are inherited automatically, and cannot be
- * specified in the thread handle list. Rather than trying
- * to catch each and every corner case (and running the
- * chance of *still* forgetting a few), let's just fall
- * back to creating the process without trying to limit the
- * handle inheritance.
- */
- !(err == ERROR_INVALID_PARAMETER &&
- GetVersion() >> 16 < 9200) &&
- !getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) {
- DWORD fl = 0;
- int i;
-
- setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1);
-
- for (i = 0; i < stdhandles_count; i++) {
- HANDLE h = stdhandles[i];
- strbuf_addf(&buf, "handle #%d: %p (type %lx, "
- "handle info (%d) %lx\n", i, h,
- GetFileType(h),
- GetHandleInformation(h, &fl),
- fl);
- }
- strbuf_addstr(&buf, "\nThis is a bug; please report it "
- "at\nhttps://github.com/git-for-windows/"
- "git/issues/new\n\n"
- "To suppress this warning, please set "
- "the environment variable\n\n"
- "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
- "\n");
- }
- restrict_handle_inheritance = 0;
flags &= ~EXTENDED_STARTUPINFO_PRESENT;
ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
TRUE, flags, wenvblk, dir ? wdir : NULL,
@@ -2326,7 +2277,9 @@ repeat:
* current system doesn't support FileRenameInfoEx. Keep us
* from using it in future calls and retry.
*/
- if (gle == ERROR_INVALID_PARAMETER) {
+ if (gle == ERROR_INVALID_PARAMETER ||
+ gle == ERROR_NOT_SUPPORTED ||
+ gle == ERROR_INVALID_FUNCTION) {
supports_file_rename_info_ex = 0;
goto repeat;
}
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 12e38e0ea3..43b3be0114 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -56,8 +56,8 @@ void probe_utf8_pathname_composition(void)
close(output_fd);
repo_git_path_replace(the_repository, &path, "%s", auml_nfd);
precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
- git_config_set("core.precomposeunicode",
- precomposed_unicode ? "true" : "false");
+ repo_config_set(the_repository, "core.precomposeunicode",
+ precomposed_unicode ? "true" : "false");
repo_git_path_replace(the_repository, &path, "%s", auml_nfc);
if (unlink(path.buf))
die_errno(_("failed to unlink '%s'"), path.buf);
@@ -75,7 +75,7 @@ const char *precompose_string_if_needed(const char *in)
iconv_t ic_prec;
char *out;
if (precomposed_unicode < 0)
- git_config_get_bool("core.precomposeunicode", &precomposed_unicode);
+ repo_config_get_bool(the_repository, "core.precomposeunicode", &precomposed_unicode);
if (precomposed_unicode != 1)
return in;
ic_prec = iconv_open(repo_encoding, path_encoding);
diff --git a/config.c b/config.c
index 8a2d0b7916..e0ff35d426 100644
--- a/config.c
+++ b/config.c
@@ -6,12 +6,8 @@
*
*/
-#define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
-
#include "git-compat-util.h"
#include "abspath.h"
-#include "advice.h"
#include "date.h"
#include "branch.h"
#include "config.h"
@@ -20,11 +16,8 @@
#include "environment.h"
#include "gettext.h"
#include "git-zlib.h"
-#include "ident.h"
#include "repository.h"
#include "lockfile.h"
-#include "mailmap.h"
-#include "attr.h"
#include "exec-cmd.h"
#include "strbuf.h"
#include "quote.h"
@@ -32,7 +25,6 @@
#include "string-list.h"
#include "object-name.h"
#include "odb.h"
-#include "pager.h"
#include "path.h"
#include "utf8.h"
#include "color.h"
@@ -41,7 +33,6 @@
#include "strvec.h"
#include "trace2.h"
#include "wildmatch.h"
-#include "ws.h"
#include "write-or-die.h"
struct config_source {
@@ -70,9 +61,6 @@ struct config_source {
};
#define CONFIG_SOURCE_INIT { 0 }
-static int pack_compression_seen;
-static int zlib_compression_seen;
-
/*
* Config that comes from trusted scopes, namely:
* - CONFIG_SCOPE_SYSTEM (e.g. /etc/gitconfig)
@@ -207,11 +195,12 @@ static void add_trailing_starstar_for_dir(struct strbuf *pat)
}
static int prepare_include_condition_pattern(const struct key_value_info *kvi,
- struct strbuf *pat)
+ struct strbuf *pat,
+ size_t *out)
{
struct strbuf path = STRBUF_INIT;
char *expanded;
- int prefix = 0;
+ size_t prefix = 0;
expanded = interpolate_path(pat->buf, 1);
if (expanded) {
@@ -238,8 +227,10 @@ static int prepare_include_condition_pattern(const struct key_value_info *kvi,
add_trailing_starstar_for_dir(pat);
+ *out = prefix;
+
strbuf_release(&path);
- return prefix;
+ return 0;
}
static int include_by_gitdir(const struct key_value_info *kvi,
@@ -248,7 +239,8 @@ static int include_by_gitdir(const struct key_value_info *kvi,
{
struct strbuf text = STRBUF_INIT;
struct strbuf pattern = STRBUF_INIT;
- int ret = 0, prefix;
+ size_t prefix;
+ int ret = 0;
const char *git_dir;
int already_tried_absolute = 0;
@@ -259,12 +251,11 @@ static int include_by_gitdir(const struct key_value_info *kvi,
strbuf_realpath(&text, git_dir, 1);
strbuf_add(&pattern, cond, cond_len);
- prefix = prepare_include_condition_pattern(kvi, &pattern);
-
-again:
- if (prefix < 0)
+ ret = prepare_include_condition_pattern(kvi, &pattern, &prefix);
+ if (ret < 0)
goto done;
+again:
if (prefix > 0) {
/*
* perform literal matching on the prefix part so that
@@ -638,31 +629,28 @@ int git_config_parse_parameter(const char *text,
config_fn_t fn, void *data)
{
const char *value;
- struct strbuf **pair;
+ struct string_list pair = STRING_LIST_INIT_DUP;
int ret;
struct key_value_info kvi = KVI_INIT;
kvi_from_param(&kvi);
- pair = strbuf_split_str(text, '=', 2);
- if (!pair[0])
+ string_list_split(&pair, text, "=", 1);
+ if (!pair.nr)
return error(_("bogus config parameter: %s"), text);
- if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
- strbuf_setlen(pair[0], pair[0]->len - 1);
- value = pair[1] ? pair[1]->buf : "";
- } else {
+ if (pair.nr == 1)
value = NULL;
- }
+ else
+ value = pair.items[1].string;
- strbuf_trim(pair[0]);
- if (!pair[0]->len) {
- strbuf_list_free(pair);
+ if (!*pair.items[0].string) {
+ string_list_clear(&pair, 0);
return error(_("bogus config parameter: %s"), text);
}
- ret = config_parse_pair(pair[0]->buf, value, &kvi, fn, data);
- strbuf_list_free(pair);
+ ret = config_parse_pair(pair.items[0].string, value, &kvi, fn, data);
+ string_list_clear(&pair, 0);
return ret;
}
@@ -732,7 +720,6 @@ int git_config_from_parameters(config_fn_t fn, void *data)
if (env) {
unsigned long count;
char *endp;
- int i;
count = strtoul(env, &endp, 10);
if (*endp) {
@@ -744,10 +731,10 @@ int git_config_from_parameters(config_fn_t fn, void *data)
goto out;
}
- for (i = 0; i < count; i++) {
+ for (unsigned long i = 0; i < count; i++) {
const char *key, *value;
- strbuf_addf(&envvar, "GIT_CONFIG_KEY_%d", i);
+ strbuf_addf(&envvar, "GIT_CONFIG_KEY_%lu", i);
key = getenv_safe(&to_free, envvar.buf);
if (!key) {
ret = error(_("missing config key %s"), envvar.buf);
@@ -755,7 +742,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)
}
strbuf_reset(&envvar);
- strbuf_addf(&envvar, "GIT_CONFIG_VALUE_%d", i);
+ strbuf_addf(&envvar, "GIT_CONFIG_VALUE_%lu", i);
value = getenv_safe(&to_free, envvar.buf);
if (!value) {
ret = error(_("missing config value %s"), envvar.buf);
@@ -1259,80 +1246,6 @@ double git_config_double(const char *name, const char *value,
return ret;
}
-static const struct fsync_component_name {
- const char *name;
- enum fsync_component component_bits;
-} fsync_component_names[] = {
- { "loose-object", FSYNC_COMPONENT_LOOSE_OBJECT },
- { "pack", FSYNC_COMPONENT_PACK },
- { "pack-metadata", FSYNC_COMPONENT_PACK_METADATA },
- { "commit-graph", FSYNC_COMPONENT_COMMIT_GRAPH },
- { "index", FSYNC_COMPONENT_INDEX },
- { "objects", FSYNC_COMPONENTS_OBJECTS },
- { "reference", FSYNC_COMPONENT_REFERENCE },
- { "derived-metadata", FSYNC_COMPONENTS_DERIVED_METADATA },
- { "committed", FSYNC_COMPONENTS_COMMITTED },
- { "added", FSYNC_COMPONENTS_ADDED },
- { "all", FSYNC_COMPONENTS_ALL },
-};
-
-static enum fsync_component parse_fsync_components(const char *var, const char *string)
-{
- enum fsync_component current = FSYNC_COMPONENTS_PLATFORM_DEFAULT;
- enum fsync_component positive = 0, negative = 0;
-
- while (string) {
- int i;
- size_t len;
- const char *ep;
- int negated = 0;
- int found = 0;
-
- string = string + strspn(string, ", \t\n\r");
- ep = strchrnul(string, ',');
- len = ep - string;
- if (!strcmp(string, "none")) {
- current = FSYNC_COMPONENT_NONE;
- goto next_name;
- }
-
- if (*string == '-') {
- negated = 1;
- string++;
- len--;
- if (!len)
- warning(_("invalid value for variable %s"), var);
- }
-
- if (!len)
- break;
-
- for (i = 0; i < ARRAY_SIZE(fsync_component_names); ++i) {
- const struct fsync_component_name *n = &fsync_component_names[i];
-
- if (strncmp(n->name, string, len))
- continue;
-
- found = 1;
- if (negated)
- negative |= n->component_bits;
- else
- positive |= n->component_bits;
- }
-
- if (!found) {
- char *component = xstrndup(string, len);
- warning(_("ignoring unknown core.fsync component '%s'"), component);
- free(component);
- }
-
-next_name:
- string = ep;
- }
-
- return (current & ~negative) | positive;
-}
-
int git_config_bool_or_int(const char *name, const char *value,
const struct key_value_info *kvi, int *is_bool)
{
@@ -1390,435 +1303,6 @@ int git_config_color(char *dest, const char *var, const char *value)
return 0;
}
-static int git_default_core_config(const char *var, const char *value,
- const struct config_context *ctx, void *cb)
-{
- /* This needs a better name */
- if (!strcmp(var, "core.filemode")) {
- trust_executable_bit = git_config_bool(var, value);
- return 0;
- }
- if (!strcmp(var, "core.trustctime")) {
- trust_ctime = git_config_bool(var, value);
- return 0;
- }
- if (!strcmp(var, "core.checkstat")) {
- if (!value)
- return config_error_nonbool(var);
- if (!strcasecmp(value, "default"))
- check_stat = 1;
- else if (!strcasecmp(value, "minimal"))
- check_stat = 0;
- else
- return error(_("invalid value for '%s': '%s'"),
- var, value);
- }
-
- if (!strcmp(var, "core.quotepath")) {
- quote_path_fully = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.symlinks")) {
- has_symlinks = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.ignorecase")) {
- ignore_case = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.attributesfile")) {
- FREE_AND_NULL(git_attributes_file);
- return git_config_pathname(&git_attributes_file, var, value);
- }
-
- if (!strcmp(var, "core.bare")) {
- is_bare_repository_cfg = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.ignorestat")) {
- assume_unchanged = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.abbrev")) {
- if (!value)
- return config_error_nonbool(var);
- if (!strcasecmp(value, "auto"))
- default_abbrev = -1;
- else if (!git_parse_maybe_bool_text(value))
- default_abbrev = GIT_MAX_HEXSZ;
- else {
- int abbrev = git_config_int(var, value, ctx->kvi);
- if (abbrev < minimum_abbrev)
- return error(_("abbrev length out of range: %d"), abbrev);
- default_abbrev = abbrev;
- }
- return 0;
- }
-
- if (!strcmp(var, "core.disambiguate"))
- return set_disambiguate_hint_config(var, value);
-
- if (!strcmp(var, "core.loosecompression")) {
- int level = git_config_int(var, value, ctx->kvi);
- if (level == -1)
- level = Z_DEFAULT_COMPRESSION;
- else if (level < 0 || level > Z_BEST_COMPRESSION)
- die(_("bad zlib compression level %d"), level);
- zlib_compression_level = level;
- zlib_compression_seen = 1;
- return 0;
- }
-
- if (!strcmp(var, "core.compression")) {
- int level = git_config_int(var, value, ctx->kvi);
- if (level == -1)
- level = Z_DEFAULT_COMPRESSION;
- else if (level < 0 || level > Z_BEST_COMPRESSION)
- die(_("bad zlib compression level %d"), level);
- if (!zlib_compression_seen)
- zlib_compression_level = level;
- if (!pack_compression_seen)
- pack_compression_level = level;
- return 0;
- }
-
- if (!strcmp(var, "core.autocrlf")) {
- if (value && !strcasecmp(value, "input")) {
- auto_crlf = AUTO_CRLF_INPUT;
- return 0;
- }
- auto_crlf = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.safecrlf")) {
- int eol_rndtrp_die;
- if (value && !strcasecmp(value, "warn")) {
- global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
- return 0;
- }
- eol_rndtrp_die = git_config_bool(var, value);
- global_conv_flags_eol = eol_rndtrp_die ?
- CONV_EOL_RNDTRP_DIE : 0;
- return 0;
- }
-
- if (!strcmp(var, "core.eol")) {
- if (value && !strcasecmp(value, "lf"))
- core_eol = EOL_LF;
- else if (value && !strcasecmp(value, "crlf"))
- core_eol = EOL_CRLF;
- else if (value && !strcasecmp(value, "native"))
- core_eol = EOL_NATIVE;
- else
- core_eol = EOL_UNSET;
- return 0;
- }
-
- if (!strcmp(var, "core.checkroundtripencoding")) {
- FREE_AND_NULL(check_roundtrip_encoding);
- return git_config_string(&check_roundtrip_encoding, var, value);
- }
-
- if (!strcmp(var, "core.editor")) {
- FREE_AND_NULL(editor_program);
- return git_config_string(&editor_program, var, value);
- }
-
- if (!strcmp(var, "core.commentchar") ||
- !strcmp(var, "core.commentstring")) {
- if (!value)
- return config_error_nonbool(var);
- else if (!strcasecmp(value, "auto")) {
- auto_comment_line_char = 1;
- FREE_AND_NULL(comment_line_str_to_free);
- comment_line_str = "#";
- } else if (value[0]) {
- if (strchr(value, '\n'))
- return error(_("%s cannot contain newline"), var);
- 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);
- return 0;
- }
-
- if (!strcmp(var, "core.askpass")) {
- FREE_AND_NULL(askpass_program);
- return git_config_string(&askpass_program, var, value);
- }
-
- if (!strcmp(var, "core.excludesfile")) {
- FREE_AND_NULL(excludes_file);
- return git_config_pathname(&excludes_file, var, value);
- }
-
- if (!strcmp(var, "core.whitespace")) {
- if (!value)
- return config_error_nonbool(var);
- whitespace_rule_cfg = parse_whitespace_rule(value);
- return 0;
- }
-
- if (!strcmp(var, "core.fsync")) {
- if (!value)
- return config_error_nonbool(var);
- fsync_components = parse_fsync_components(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.fsyncmethod")) {
- if (!value)
- return config_error_nonbool(var);
- if (!strcmp(value, "fsync"))
- fsync_method = FSYNC_METHOD_FSYNC;
- else if (!strcmp(value, "writeout-only"))
- fsync_method = FSYNC_METHOD_WRITEOUT_ONLY;
- else if (!strcmp(value, "batch"))
- fsync_method = FSYNC_METHOD_BATCH;
- else
- warning(_("ignoring unknown core.fsyncMethod value '%s'"), value);
-
- }
-
- if (!strcmp(var, "core.fsyncobjectfiles")) {
- if (fsync_object_files < 0)
- warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead"));
- fsync_object_files = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.createobject")) {
- if (!value)
- return config_error_nonbool(var);
- if (!strcmp(value, "rename"))
- object_creation_mode = OBJECT_CREATION_USES_RENAMES;
- else if (!strcmp(value, "link"))
- object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
- else
- die(_("invalid mode for object creation: %s"), value);
- return 0;
- }
-
- if (!strcmp(var, "core.sparsecheckout")) {
- core_apply_sparse_checkout = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.sparsecheckoutcone")) {
- core_sparse_checkout_cone = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.precomposeunicode")) {
- precomposed_unicode = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.protecthfs")) {
- protect_hfs = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.protectntfs")) {
- protect_ntfs = git_config_bool(var, value);
- return 0;
- }
-
- if (!strcmp(var, "core.maxtreedepth")) {
- max_allowed_tree_depth = git_config_int(var, value, ctx->kvi);
- return 0;
- }
-
- /* Add other config variables here and to Documentation/config.adoc. */
- return platform_core_config(var, value, ctx, cb);
-}
-
-static int git_default_sparse_config(const char *var, const char *value)
-{
- if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) {
- sparse_expect_files_outside_of_patterns = git_config_bool(var, value);
- return 0;
- }
-
- /* Add other config variables here and to Documentation/config/sparse.adoc. */
- return 0;
-}
-
-static int git_default_i18n_config(const char *var, const char *value)
-{
- if (!strcmp(var, "i18n.commitencoding")) {
- FREE_AND_NULL(git_commit_encoding);
- return git_config_string(&git_commit_encoding, var, value);
- }
-
- if (!strcmp(var, "i18n.logoutputencoding")) {
- FREE_AND_NULL(git_log_output_encoding);
- return git_config_string(&git_log_output_encoding, var, value);
- }
-
- /* Add other config variables here and to Documentation/config.adoc. */
- return 0;
-}
-
-static int git_default_branch_config(const char *var, const char *value)
-{
- if (!strcmp(var, "branch.autosetupmerge")) {
- if (value && !strcmp(value, "always")) {
- git_branch_track = BRANCH_TRACK_ALWAYS;
- return 0;
- } else if (value && !strcmp(value, "inherit")) {
- git_branch_track = BRANCH_TRACK_INHERIT;
- return 0;
- } else if (value && !strcmp(value, "simple")) {
- git_branch_track = BRANCH_TRACK_SIMPLE;
- return 0;
- }
- git_branch_track = git_config_bool(var, value);
- return 0;
- }
- if (!strcmp(var, "branch.autosetuprebase")) {
- if (!value)
- return config_error_nonbool(var);
- else if (!strcmp(value, "never"))
- autorebase = AUTOREBASE_NEVER;
- else if (!strcmp(value, "local"))
- autorebase = AUTOREBASE_LOCAL;
- else if (!strcmp(value, "remote"))
- autorebase = AUTOREBASE_REMOTE;
- else if (!strcmp(value, "always"))
- autorebase = AUTOREBASE_ALWAYS;
- else
- return error(_("malformed value for %s"), var);
- return 0;
- }
-
- /* Add other config variables here and to Documentation/config.adoc. */
- return 0;
-}
-
-static int git_default_push_config(const char *var, const char *value)
-{
- if (!strcmp(var, "push.default")) {
- if (!value)
- return config_error_nonbool(var);
- else if (!strcmp(value, "nothing"))
- push_default = PUSH_DEFAULT_NOTHING;
- else if (!strcmp(value, "matching"))
- push_default = PUSH_DEFAULT_MATCHING;
- else if (!strcmp(value, "simple"))
- push_default = PUSH_DEFAULT_SIMPLE;
- else if (!strcmp(value, "upstream"))
- push_default = PUSH_DEFAULT_UPSTREAM;
- else if (!strcmp(value, "tracking")) /* deprecated */
- push_default = PUSH_DEFAULT_UPSTREAM;
- else if (!strcmp(value, "current"))
- push_default = PUSH_DEFAULT_CURRENT;
- else {
- error(_("malformed value for %s: %s"), var, value);
- return error(_("must be one of nothing, matching, simple, "
- "upstream or current"));
- }
- return 0;
- }
-
- /* Add other config variables here and to Documentation/config.adoc. */
- return 0;
-}
-
-static int git_default_mailmap_config(const char *var, const char *value)
-{
- if (!strcmp(var, "mailmap.file")) {
- FREE_AND_NULL(git_mailmap_file);
- return git_config_pathname(&git_mailmap_file, var, value);
- }
-
- if (!strcmp(var, "mailmap.blob")) {
- FREE_AND_NULL(git_mailmap_blob);
- return git_config_string(&git_mailmap_blob, var, value);
- }
-
- /* Add other config variables here and to Documentation/config.adoc. */
- return 0;
-}
-
-static int git_default_attr_config(const char *var, const char *value)
-{
- if (!strcmp(var, "attr.tree")) {
- FREE_AND_NULL(git_attr_tree);
- return git_config_string(&git_attr_tree, var, value);
- }
-
- /*
- * Add other attribute related config variables here and to
- * Documentation/config/attr.adoc.
- */
- return 0;
-}
-
-int git_default_config(const char *var, const char *value,
- const struct config_context *ctx, void *cb)
-{
- if (starts_with(var, "core."))
- return git_default_core_config(var, value, ctx, cb);
-
- if (starts_with(var, "user.") ||
- starts_with(var, "author.") ||
- starts_with(var, "committer."))
- return git_ident_config(var, value, ctx, cb);
-
- if (starts_with(var, "i18n."))
- return git_default_i18n_config(var, value);
-
- if (starts_with(var, "branch."))
- return git_default_branch_config(var, value);
-
- if (starts_with(var, "push."))
- return git_default_push_config(var, value);
-
- if (starts_with(var, "mailmap."))
- return git_default_mailmap_config(var, value);
-
- if (starts_with(var, "attr."))
- return git_default_attr_config(var, value);
-
- if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
- return git_default_advice_config(var, value);
-
- if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
- pager_use_color = git_config_bool(var,value);
- return 0;
- }
-
- if (!strcmp(var, "pack.packsizelimit")) {
- pack_size_limit_cfg = git_config_ulong(var, value, ctx->kvi);
- return 0;
- }
-
- if (!strcmp(var, "pack.compression")) {
- int level = git_config_int(var, value, ctx->kvi);
- if (level == -1)
- level = Z_DEFAULT_COMPRESSION;
- else if (level < 0 || level > Z_BEST_COMPRESSION)
- die(_("bad pack compression level %d"), level);
- pack_compression_level = level;
- pack_compression_seen = 1;
- return 0;
- }
-
- if (starts_with(var, "sparse."))
- return git_default_sparse_config(var, value);
-
- /* Add other config variables here and to Documentation/config.adoc. */
- return 0;
-}
-
/*
* All source specific fields in the union, die_on_error, name and the callbacks
* fgetc, ungetc, ftell of top need to be initialized before calling
@@ -2125,13 +1609,13 @@ int config_with_options(config_fn_t fn, void *data,
static void configset_iter(struct config_set *set, config_fn_t fn, void *data)
{
- int i, value_index;
+ int value_index;
struct string_list *values;
struct config_set_element *entry;
struct configset_list *list = &set->list;
struct config_context ctx = CONFIG_CONTEXT_INIT;
- for (i = 0; i < list->nr; i++) {
+ for (size_t i = 0; i < list->nr; i++) {
entry = list->items[i].e;
value_index = list->items[i].value_index;
values = &entry->value_list;
@@ -2748,7 +2232,7 @@ void git_die_config(struct repository *r, const char *key, const char *err, ...)
}
/*
- * Find all the stuff for git_config_set() below.
+ * Find all the stuff for repo_config_set() below.
*/
struct config_store_data {
@@ -2981,10 +2465,11 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
*/
static void maybe_remove_section(struct config_store_data *store,
size_t *begin_offset, size_t *end_offset,
- int *seen_ptr)
+ unsigned *seen_ptr)
{
size_t begin;
- int i, seen, section_seen = 0;
+ int section_seen = 0;
+ unsigned int i, seen;
/*
* First, ensure that this is the first key, and that there are no
@@ -3227,7 +2712,8 @@ int repo_config_set_multivar_in_file_gently(struct repository *r,
} else {
struct stat st;
size_t copy_begin, copy_end;
- int i, new_line = 0;
+ unsigned i;
+ int new_line = 0;
struct config_options opts;
if (!value_pattern)
diff --git a/config.h b/config.h
index cbb0f4fddc..19c87fc0bc 100644
--- a/config.h
+++ b/config.h
@@ -163,9 +163,6 @@ struct config_context {
typedef int (*config_fn_t)(const char *, const char *,
const struct config_context *, void *);
-int git_default_config(const char *, const char *,
- const struct config_context *, void *);
-
/**
* Read a specific file in git-config format.
* This function takes the same callback and data parameters as `repo_config`.
@@ -716,140 +713,4 @@ 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 e77287f426..8352b71faf 100644
--- a/connect.c
+++ b/connect.c
@@ -407,7 +407,7 @@ static int process_ref_v2(struct packet_reader *reader, struct ref ***list,
* name. Subsequent fields (symref-target and peeled) are optional and
* don't have a particular order.
*/
- if (string_list_split(&line_sections, line, ' ', -1) < 2) {
+ if (string_list_split(&line_sections, line, " ", -1) < 2) {
ret = 0;
goto out;
}
@@ -1028,7 +1028,7 @@ static int git_proxy_command_options(const char *var, const char *value,
static int git_use_proxy(const char *host)
{
git_proxy_command = getenv("GIT_PROXY_COMMAND");
- git_config(git_proxy_command_options, (void*)host);
+ repo_config(the_repository, git_proxy_command_options, (void*)host);
return (git_proxy_command && *git_proxy_command);
}
@@ -1154,7 +1154,7 @@ static const char *get_ssh_command(void)
if ((ssh = getenv("GIT_SSH_COMMAND")))
return ssh;
- if (!git_config_get_string_tmp("core.sshcommand", &ssh))
+ if (!repo_config_get_string_tmp(the_repository, "core.sshcommand", &ssh))
return ssh;
return NULL;
@@ -1173,7 +1173,7 @@ static void override_ssh_variant(enum ssh_variant *ssh_variant)
{
const char *variant = getenv("GIT_SSH_VARIANT");
- if (!variant && git_config_get_string_tmp("ssh.variant", &variant))
+ if (!variant && repo_config_get_string_tmp(the_repository, "ssh.variant", &variant))
return;
if (!strcmp(variant, "auto"))
diff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/contrib/coccinelle/config_fn_ctx.pending.cocci
index 6d3d1000a9..54f09fcbcd 100644
--- a/contrib/coccinelle/config_fn_ctx.pending.cocci
+++ b/contrib/coccinelle/config_fn_ctx.pending.cocci
@@ -83,7 +83,7 @@ int fn(const char *C1, const char *C2,
// The previous rules don't catch all callbacks, especially if they're defined
-// in a separate file from the git_config() call. Fix these manually.
+// in a separate file from the repo_config() call. Fix these manually.
@@
identifier C1, C2, D;
attribute name UNUSED;
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 3f69675961..8d1d5d79a6 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -44,7 +44,7 @@ open_editor() {
mode_diff() {
git diff --no-prefix --relative "$@" |
perl -ne '
- if (m{^\+\+\+ (.*)}) { $file = $1 eq "/dev/null" ? undef : $1; next }
+ if (m{^\+\+\+ (.*?)\t?$}) { $file = $1 eq "/dev/null" ? undef : $1; next }
defined($file) or next;
if (m/^@@ .*?\+(\d+)/) { $line = $1; next }
defined($line) or next;
diff --git a/convert.c b/convert.c
index b5f7cf6306..c7d6a85c22 100644
--- a/convert.c
+++ b/convert.c
@@ -1326,7 +1326,7 @@ void convert_attrs(struct index_state *istate,
"eol", "text", "working-tree-encoding",
NULL);
user_convert_tail = &user_convert;
- git_config(read_convert_config, NULL);
+ repo_config(the_repository, read_convert_config, NULL);
}
git_check_attr(istate, path, check);
diff --git a/daemon.c b/daemon.c
index 1f3e23b6a8..0a7b1aae44 100644
--- a/daemon.c
+++ b/daemon.c
@@ -402,7 +402,7 @@ static int run_service(const char *dir, struct daemon_service *service,
if (service->overridable) {
strbuf_addf(&var, "daemon.%s", service->config_name);
- git_config_get_bool(var.buf, &enabled);
+ repo_config_get_bool(the_repository, var.buf, &enabled);
strbuf_release(&var);
}
if (!enabled) {
diff --git a/diff-lib.c b/diff-lib.c
index 244468dd1a..b8f8f3bc31 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -115,6 +115,9 @@ void run_diff_files(struct rev_info *revs, unsigned int option)
uint64_t start = getnanotime();
struct index_state *istate = revs->diffopt.repo->index;
+ if (revs->diffopt.max_depth_valid)
+ die(_("max-depth is not supported for worktree diffs"));
+
diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
refresh_fsmonitor(istate);
@@ -560,6 +563,8 @@ static int diff_cache(struct rev_info *revs,
opts.dst_index = NULL;
opts.pathspec = &revs->diffopt.pathspec;
opts.pathspec->recursive = 1;
+ if (revs->diffopt.max_depth_valid)
+ die(_("max-depth is not supported for index diffs"));
init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
return unpack_trees(1, &t, &opts);
diff --git a/diff.c b/diff.c
index dca87e164f..51603117a9 100644
--- a/diff.c
+++ b/diff.c
@@ -327,29 +327,23 @@ static unsigned parse_color_moved_ws(const char *arg)
struct string_list l = STRING_LIST_INIT_DUP;
struct string_list_item *i;
- string_list_split(&l, arg, ',', -1);
+ string_list_split_f(&l, arg, ",", -1, STRING_LIST_SPLIT_TRIM);
for_each_string_list_item(i, &l) {
- struct strbuf sb = STRBUF_INIT;
- strbuf_addstr(&sb, i->string);
- strbuf_trim(&sb);
-
- if (!strcmp(sb.buf, "no"))
+ if (!strcmp(i->string, "no"))
ret = 0;
- else if (!strcmp(sb.buf, "ignore-space-change"))
+ else if (!strcmp(i->string, "ignore-space-change"))
ret |= XDF_IGNORE_WHITESPACE_CHANGE;
- else if (!strcmp(sb.buf, "ignore-space-at-eol"))
+ else if (!strcmp(i->string, "ignore-space-at-eol"))
ret |= XDF_IGNORE_WHITESPACE_AT_EOL;
- else if (!strcmp(sb.buf, "ignore-all-space"))
+ else if (!strcmp(i->string, "ignore-all-space"))
ret |= XDF_IGNORE_WHITESPACE;
- else if (!strcmp(sb.buf, "allow-indentation-change"))
+ else if (!strcmp(i->string, "allow-indentation-change"))
ret |= COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE;
else {
ret |= COLOR_MOVED_WS_ERROR;
- error(_("unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', 'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"), sb.buf);
+ error(_("unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', 'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"), i->string);
}
-
- strbuf_release(&sb);
}
if ((ret & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) &&
@@ -2444,6 +2438,15 @@ static int fn_out_consume(void *priv, char *line, unsigned long len)
return 0;
}
+static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED)
+{
+ struct emit_callback *ecbdata = priv;
+ struct diff_options *o = ecbdata->opt;
+
+ o->found_changes = 1;
+ return 1;
+}
+
static void pprint_rename(struct strbuf *name, const char *a, const char *b)
{
const char *old_name = a;
@@ -3759,8 +3762,21 @@ static void builtin_diff(const char *name_a,
if (o->word_diff)
init_diff_words_data(&ecbdata, o, one, two);
- if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
- &ecbdata, &xpp, &xecfg))
+ if (o->dry_run) {
+ /*
+ * Unlike the !dry_run case, we need to ignore the
+ * return value from xdi_diff_outf() here, because
+ * xdi_diff_outf() takes non-zero return from its
+ * callback function as a sign of error and returns
+ * early (which is why we return non-zero from our
+ * callback, quick_consume()). Unfortunately,
+ * xdi_diff_outf() signals an error by returning
+ * non-zero.
+ */
+ xdi_diff_outf(&mf1, &mf2, NULL, quick_consume,
+ &ecbdata, &xpp, &xecfg);
+ } else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
+ &ecbdata, &xpp, &xecfg))
die("unable to generate diff for %s", one->path);
if (o->word_diff)
free_diff_words_data(&ecbdata);
@@ -4988,6 +5004,9 @@ void diff_setup_done(struct diff_options *options)
options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON];
options->filter &= ~options->filter_not;
}
+
+ if (options->pathspec.has_wildcard && options->max_depth_valid)
+ die("max-depth cannot be used with wildcard pathspecs");
}
int parse_long_opt(const char *opt, const char **argv,
@@ -5622,6 +5641,23 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns
return 0;
}
+static int diff_opt_max_depth(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct diff_options *options = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
+ if (!git_parse_int(arg, &options->max_depth))
+ return error(_("invalid value for '%s': '%s'"),
+ "--max-depth", arg);
+
+ options->flags.recursive = 1;
+ options->max_depth_valid = options->max_depth >= 0;
+
+ return 0;
+}
+
/*
* Consider adding new flags to __git_diff_common_options
* in contrib/completion/git-completion.bash
@@ -5894,6 +5930,10 @@ struct option *add_diff_options(const struct option *opts,
OPT_CALLBACK_F(0, "diff-filter", options, N_("[(A|C|D|M|R|T|U|X|B)...[*]]"),
N_("select files by diff type"),
PARSE_OPT_NONEG, diff_opt_diff_filter),
+ OPT_CALLBACK_F(0, "max-depth", options, N_("<depth>"),
+ N_("maximum tree depth to recurse"),
+ PARSE_OPT_NONEG, diff_opt_max_depth),
+
{
.type = OPTION_CALLBACK,
.long_name = "output",
@@ -6150,6 +6190,22 @@ static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
run_diff(p, o);
}
+/* return 1 if any change is found; otherwise, return 0 */
+static int diff_flush_patch_quietly(struct diff_filepair *p, struct diff_options *o)
+{
+ int saved_dry_run = o->dry_run;
+ int saved_found_changes = o->found_changes;
+ int ret;
+
+ o->dry_run = 1;
+ o->found_changes = 0;
+ diff_flush_patch(p, o);
+ ret = o->found_changes;
+ o->dry_run = saved_dry_run;
+ o->found_changes |= saved_found_changes;
+ return ret;
+}
+
static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o,
struct diffstat_t *diffstat)
{
@@ -6778,8 +6834,15 @@ void diff_flush(struct diff_options *options)
DIFF_FORMAT_CHECKDIFF)) {
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- if (check_pair_status(p))
- flush_one_pair(p, options);
+
+ if (!check_pair_status(p))
+ continue;
+
+ if (options->flags.diff_from_contents &&
+ !diff_flush_patch_quietly(p, options))
+ continue;
+
+ flush_one_pair(p, options);
}
separator++;
}
@@ -6831,19 +6894,10 @@ void diff_flush(struct diff_options *options)
if (output_format & DIFF_FORMAT_NO_OUTPUT &&
options->flags.exit_with_status &&
options->flags.diff_from_contents) {
- /*
- * run diff_flush_patch for the exit status. setting
- * options->file to /dev/null should be safe, because we
- * aren't supposed to produce any output anyway.
- */
- diff_free_file(options);
- options->file = xfopen("/dev/null", "w");
- options->close_file = 1;
- options->color_moved = 0;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (check_pair_status(p))
- diff_flush_patch(p, options);
+ diff_flush_patch_quietly(p, options);
if (options->found_changes)
break;
}
diff --git a/diff.h b/diff.h
index 62e5768a9a..9bb939a4f1 100644
--- a/diff.h
+++ b/diff.h
@@ -400,10 +400,20 @@ struct diff_options {
#define COLOR_MOVED_WS_ERROR (1<<0)
unsigned color_moved_ws_handling;
+ bool dry_run;
+
struct repository *repo;
struct strmap *additional_path_headers;
int no_free;
+
+ /*
+ * The value '0' is a valid max-depth (for no recursion), and value '-1'
+ * also (for unlimited recursion), so the extra "valid" flag is used to
+ * determined whether the user specified option --max-depth.
+ */
+ int max_depth;
+ int max_depth_valid;
};
unsigned diff_filter_bit(char status);
diff --git a/dir.c b/dir.c
index 02873f59ea..71108ac79b 100644
--- a/dir.c
+++ b/dir.c
@@ -277,7 +277,7 @@ int within_depth(const char *name, int namelen,
if (depth > max_depth)
return 0;
}
- return 1;
+ return depth <= max_depth;
}
/*
@@ -4091,8 +4091,8 @@ void connect_work_tree_and_git_dir(const char *work_tree_,
write_file(gitfile_sb.buf, "gitdir: %s",
relative_path(git_dir, work_tree, &rel_path));
/* Update core.worktree setting */
- git_config_set_in_file(cfg_sb.buf, "core.worktree",
- relative_path(work_tree, git_dir, &rel_path));
+ repo_config_set_in_file(the_repository, cfg_sb.buf, "core.worktree",
+ relative_path(work_tree, git_dir, &rel_path));
strbuf_release(&gitfile_sb);
strbuf_release(&cfg_sb);
diff --git a/editor.c b/editor.c
index b79d97b0e7..fd174e6a03 100644
--- a/editor.c
+++ b/editor.c
@@ -50,7 +50,7 @@ const char *git_sequence_editor(void)
const char *editor = getenv("GIT_SEQUENCE_EDITOR");
if (!editor)
- git_config_get_string_tmp("sequence.editor", &editor);
+ repo_config_get_string_tmp(the_repository, "sequence.editor", &editor);
if (!editor)
editor = git_editor();
diff --git a/environment.c b/environment.c
index 7c2480b22e..0e72fdac85 100644
--- a/environment.c
+++ b/environment.c
@@ -12,22 +12,34 @@
#include "git-compat-util.h"
#include "abspath.h"
+#include "advice.h"
+#include "attr.h"
#include "branch.h"
+#include "color.h"
#include "convert.h"
#include "environment.h"
#include "gettext.h"
#include "git-zlib.h"
+#include "ident.h"
+#include "mailmap.h"
+#include "object-name.h"
#include "repository.h"
#include "config.h"
#include "refs.h"
#include "fmt-merge-msg.h"
#include "commit.h"
#include "strvec.h"
+#include "pager.h"
#include "path.h"
+#include "quote.h"
#include "chdir-notify.h"
#include "setup.h"
+#include "ws.h"
#include "write-or-die.h"
+static int pack_compression_seen;
+static int zlib_compression_seen;
+
int trust_executable_bit = 1;
int trust_ctime = 1;
int check_stat = 1;
@@ -66,7 +78,6 @@ int grafts_keep_true_parents;
int core_apply_sparse_checkout;
int core_sparse_checkout_cone;
int sparse_expect_files_outside_of_patterns;
-int merge_log_config = -1;
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
unsigned long pack_size_limit_cfg;
int max_allowed_tree_depth =
@@ -163,10 +174,10 @@ int have_git_dir(void)
const char *get_git_namespace(void)
{
static const char *namespace;
-
struct strbuf buf = STRBUF_INIT;
- struct strbuf **components, **c;
const char *raw_namespace;
+ struct string_list components = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
if (namespace)
return namespace;
@@ -178,12 +189,17 @@ const char *get_git_namespace(void)
}
strbuf_addstr(&buf, raw_namespace);
- components = strbuf_split(&buf, '/');
+
+ string_list_split(&components, buf.buf, "/", -1);
strbuf_reset(&buf);
- for (c = components; *c; c++)
- if (strcmp((*c)->buf, "/") != 0)
- strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
- strbuf_list_free(components);
+
+ for_each_string_list_item(item, &components) {
+ if (item->string[0])
+ strbuf_addf(&buf, "refs/namespaces/%s/", item->string);
+ }
+ string_list_clear(&components, 0);
+
+ strbuf_trim_trailing_dir_sep(&buf);
if (check_refname_format(buf.buf, 0))
die(_("bad git namespace path \"%s\""), raw_namespace);
strbuf_addch(&buf, '/');
@@ -231,3 +247,503 @@ int print_sha1_ellipsis(void)
}
return cached_result;
}
+
+static const struct fsync_component_name {
+ const char *name;
+ enum fsync_component component_bits;
+} fsync_component_names[] = {
+ { "loose-object", FSYNC_COMPONENT_LOOSE_OBJECT },
+ { "pack", FSYNC_COMPONENT_PACK },
+ { "pack-metadata", FSYNC_COMPONENT_PACK_METADATA },
+ { "commit-graph", FSYNC_COMPONENT_COMMIT_GRAPH },
+ { "index", FSYNC_COMPONENT_INDEX },
+ { "objects", FSYNC_COMPONENTS_OBJECTS },
+ { "reference", FSYNC_COMPONENT_REFERENCE },
+ { "derived-metadata", FSYNC_COMPONENTS_DERIVED_METADATA },
+ { "committed", FSYNC_COMPONENTS_COMMITTED },
+ { "added", FSYNC_COMPONENTS_ADDED },
+ { "all", FSYNC_COMPONENTS_ALL },
+};
+
+static enum fsync_component parse_fsync_components(const char *var, const char *string)
+{
+ enum fsync_component current = FSYNC_COMPONENTS_PLATFORM_DEFAULT;
+ enum fsync_component positive = 0, negative = 0;
+
+ while (string) {
+ size_t len;
+ const char *ep;
+ int negated = 0;
+ int found = 0;
+
+ string = string + strspn(string, ", \t\n\r");
+ ep = strchrnul(string, ',');
+ len = ep - string;
+ if (!strcmp(string, "none")) {
+ current = FSYNC_COMPONENT_NONE;
+ goto next_name;
+ }
+
+ if (*string == '-') {
+ negated = 1;
+ string++;
+ len--;
+ if (!len)
+ warning(_("invalid value for variable %s"), var);
+ }
+
+ if (!len)
+ break;
+
+ for (size_t i = 0; i < ARRAY_SIZE(fsync_component_names); ++i) {
+ const struct fsync_component_name *n = &fsync_component_names[i];
+
+ if (strncmp(n->name, string, len))
+ continue;
+
+ found = 1;
+ if (negated)
+ negative |= n->component_bits;
+ else
+ positive |= n->component_bits;
+ }
+
+ if (!found) {
+ char *component = xstrndup(string, len);
+ warning(_("ignoring unknown core.fsync component '%s'"), component);
+ free(component);
+ }
+
+next_name:
+ string = ep;
+ }
+
+ return (current & ~negative) | positive;
+}
+
+static int git_default_core_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
+{
+ /* This needs a better name */
+ if (!strcmp(var, "core.filemode")) {
+ trust_executable_bit = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "core.trustctime")) {
+ trust_ctime = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "core.checkstat")) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (!strcasecmp(value, "default"))
+ check_stat = 1;
+ else if (!strcasecmp(value, "minimal"))
+ check_stat = 0;
+ else
+ return error(_("invalid value for '%s': '%s'"),
+ var, value);
+ }
+
+ if (!strcmp(var, "core.quotepath")) {
+ quote_path_fully = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.symlinks")) {
+ has_symlinks = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.ignorecase")) {
+ ignore_case = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.attributesfile")) {
+ FREE_AND_NULL(git_attributes_file);
+ return git_config_pathname(&git_attributes_file, var, value);
+ }
+
+ if (!strcmp(var, "core.bare")) {
+ is_bare_repository_cfg = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.ignorestat")) {
+ assume_unchanged = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.abbrev")) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (!strcasecmp(value, "auto"))
+ default_abbrev = -1;
+ else if (!git_parse_maybe_bool_text(value))
+ default_abbrev = GIT_MAX_HEXSZ;
+ else {
+ int abbrev = git_config_int(var, value, ctx->kvi);
+ if (abbrev < minimum_abbrev)
+ return error(_("abbrev length out of range: %d"), abbrev);
+ default_abbrev = abbrev;
+ }
+ return 0;
+ }
+
+ if (!strcmp(var, "core.disambiguate"))
+ return set_disambiguate_hint_config(var, value);
+
+ if (!strcmp(var, "core.loosecompression")) {
+ int level = git_config_int(var, value, ctx->kvi);
+ if (level == -1)
+ level = Z_DEFAULT_COMPRESSION;
+ else if (level < 0 || level > Z_BEST_COMPRESSION)
+ die(_("bad zlib compression level %d"), level);
+ zlib_compression_level = level;
+ zlib_compression_seen = 1;
+ return 0;
+ }
+
+ if (!strcmp(var, "core.compression")) {
+ int level = git_config_int(var, value, ctx->kvi);
+ if (level == -1)
+ level = Z_DEFAULT_COMPRESSION;
+ else if (level < 0 || level > Z_BEST_COMPRESSION)
+ die(_("bad zlib compression level %d"), level);
+ if (!zlib_compression_seen)
+ zlib_compression_level = level;
+ if (!pack_compression_seen)
+ pack_compression_level = level;
+ return 0;
+ }
+
+ if (!strcmp(var, "core.autocrlf")) {
+ if (value && !strcasecmp(value, "input")) {
+ auto_crlf = AUTO_CRLF_INPUT;
+ return 0;
+ }
+ auto_crlf = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.safecrlf")) {
+ int eol_rndtrp_die;
+ if (value && !strcasecmp(value, "warn")) {
+ global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
+ return 0;
+ }
+ eol_rndtrp_die = git_config_bool(var, value);
+ global_conv_flags_eol = eol_rndtrp_die ?
+ CONV_EOL_RNDTRP_DIE : 0;
+ return 0;
+ }
+
+ if (!strcmp(var, "core.eol")) {
+ if (value && !strcasecmp(value, "lf"))
+ core_eol = EOL_LF;
+ else if (value && !strcasecmp(value, "crlf"))
+ core_eol = EOL_CRLF;
+ else if (value && !strcasecmp(value, "native"))
+ core_eol = EOL_NATIVE;
+ else
+ core_eol = EOL_UNSET;
+ return 0;
+ }
+
+ if (!strcmp(var, "core.checkroundtripencoding")) {
+ FREE_AND_NULL(check_roundtrip_encoding);
+ return git_config_string(&check_roundtrip_encoding, var, value);
+ }
+
+ if (!strcmp(var, "core.editor")) {
+ FREE_AND_NULL(editor_program);
+ return git_config_string(&editor_program, var, value);
+ }
+
+ if (!strcmp(var, "core.commentchar") ||
+ !strcmp(var, "core.commentstring")) {
+ if (!value)
+ return config_error_nonbool(var);
+ else if (!strcasecmp(value, "auto"))
+ auto_comment_line_char = 1;
+ else if (value[0]) {
+ if (strchr(value, '\n'))
+ return error(_("%s cannot contain newline"), var);
+ 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);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.askpass")) {
+ FREE_AND_NULL(askpass_program);
+ return git_config_string(&askpass_program, var, value);
+ }
+
+ if (!strcmp(var, "core.excludesfile")) {
+ FREE_AND_NULL(excludes_file);
+ return git_config_pathname(&excludes_file, var, value);
+ }
+
+ if (!strcmp(var, "core.whitespace")) {
+ if (!value)
+ return config_error_nonbool(var);
+ whitespace_rule_cfg = parse_whitespace_rule(value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.fsync")) {
+ if (!value)
+ return config_error_nonbool(var);
+ fsync_components = parse_fsync_components(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.fsyncmethod")) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (!strcmp(value, "fsync"))
+ fsync_method = FSYNC_METHOD_FSYNC;
+ else if (!strcmp(value, "writeout-only"))
+ fsync_method = FSYNC_METHOD_WRITEOUT_ONLY;
+ else if (!strcmp(value, "batch"))
+ fsync_method = FSYNC_METHOD_BATCH;
+ else
+ warning(_("ignoring unknown core.fsyncMethod value '%s'"), value);
+
+ }
+
+ if (!strcmp(var, "core.fsyncobjectfiles")) {
+ if (fsync_object_files < 0)
+ warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead"));
+ fsync_object_files = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.createobject")) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (!strcmp(value, "rename"))
+ object_creation_mode = OBJECT_CREATION_USES_RENAMES;
+ else if (!strcmp(value, "link"))
+ object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
+ else
+ die(_("invalid mode for object creation: %s"), value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.sparsecheckout")) {
+ core_apply_sparse_checkout = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.sparsecheckoutcone")) {
+ core_sparse_checkout_cone = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.precomposeunicode")) {
+ precomposed_unicode = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.protecthfs")) {
+ protect_hfs = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.protectntfs")) {
+ protect_ntfs = git_config_bool(var, value);
+ return 0;
+ }
+
+ if (!strcmp(var, "core.maxtreedepth")) {
+ max_allowed_tree_depth = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+
+ /* Add other config variables here and to Documentation/config.adoc. */
+ return platform_core_config(var, value, ctx, cb);
+}
+
+static int git_default_sparse_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) {
+ sparse_expect_files_outside_of_patterns = git_config_bool(var, value);
+ return 0;
+ }
+
+ /* Add other config variables here and to Documentation/config/sparse.adoc. */
+ return 0;
+}
+
+static int git_default_i18n_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "i18n.commitencoding")) {
+ FREE_AND_NULL(git_commit_encoding);
+ return git_config_string(&git_commit_encoding, var, value);
+ }
+
+ if (!strcmp(var, "i18n.logoutputencoding")) {
+ FREE_AND_NULL(git_log_output_encoding);
+ return git_config_string(&git_log_output_encoding, var, value);
+ }
+
+ /* Add other config variables here and to Documentation/config.adoc. */
+ return 0;
+}
+
+static int git_default_branch_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "branch.autosetupmerge")) {
+ if (value && !strcmp(value, "always")) {
+ git_branch_track = BRANCH_TRACK_ALWAYS;
+ return 0;
+ } else if (value && !strcmp(value, "inherit")) {
+ git_branch_track = BRANCH_TRACK_INHERIT;
+ return 0;
+ } else if (value && !strcmp(value, "simple")) {
+ git_branch_track = BRANCH_TRACK_SIMPLE;
+ return 0;
+ }
+ git_branch_track = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "branch.autosetuprebase")) {
+ if (!value)
+ return config_error_nonbool(var);
+ else if (!strcmp(value, "never"))
+ autorebase = AUTOREBASE_NEVER;
+ else if (!strcmp(value, "local"))
+ autorebase = AUTOREBASE_LOCAL;
+ else if (!strcmp(value, "remote"))
+ autorebase = AUTOREBASE_REMOTE;
+ else if (!strcmp(value, "always"))
+ autorebase = AUTOREBASE_ALWAYS;
+ else
+ return error(_("malformed value for %s"), var);
+ return 0;
+ }
+
+ /* Add other config variables here and to Documentation/config.adoc. */
+ return 0;
+}
+
+static int git_default_push_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "push.default")) {
+ if (!value)
+ return config_error_nonbool(var);
+ else if (!strcmp(value, "nothing"))
+ push_default = PUSH_DEFAULT_NOTHING;
+ else if (!strcmp(value, "matching"))
+ push_default = PUSH_DEFAULT_MATCHING;
+ else if (!strcmp(value, "simple"))
+ push_default = PUSH_DEFAULT_SIMPLE;
+ else if (!strcmp(value, "upstream"))
+ push_default = PUSH_DEFAULT_UPSTREAM;
+ else if (!strcmp(value, "tracking")) /* deprecated */
+ push_default = PUSH_DEFAULT_UPSTREAM;
+ else if (!strcmp(value, "current"))
+ push_default = PUSH_DEFAULT_CURRENT;
+ else {
+ error(_("malformed value for %s: %s"), var, value);
+ return error(_("must be one of nothing, matching, simple, "
+ "upstream or current"));
+ }
+ return 0;
+ }
+
+ /* Add other config variables here and to Documentation/config.adoc. */
+ return 0;
+}
+
+static int git_default_mailmap_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "mailmap.file")) {
+ FREE_AND_NULL(git_mailmap_file);
+ return git_config_pathname(&git_mailmap_file, var, value);
+ }
+
+ if (!strcmp(var, "mailmap.blob")) {
+ FREE_AND_NULL(git_mailmap_blob);
+ return git_config_string(&git_mailmap_blob, var, value);
+ }
+
+ /* Add other config variables here and to Documentation/config.adoc. */
+ return 0;
+}
+
+static int git_default_attr_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "attr.tree")) {
+ FREE_AND_NULL(git_attr_tree);
+ return git_config_string(&git_attr_tree, var, value);
+ }
+
+ /*
+ * Add other attribute related config variables here and to
+ * Documentation/config/attr.adoc.
+ */
+ return 0;
+}
+
+int git_default_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
+{
+ if (starts_with(var, "core."))
+ return git_default_core_config(var, value, ctx, cb);
+
+ if (starts_with(var, "user.") ||
+ starts_with(var, "author.") ||
+ starts_with(var, "committer."))
+ return git_ident_config(var, value, ctx, cb);
+
+ if (starts_with(var, "i18n."))
+ return git_default_i18n_config(var, value);
+
+ if (starts_with(var, "branch."))
+ return git_default_branch_config(var, value);
+
+ if (starts_with(var, "push."))
+ return git_default_push_config(var, value);
+
+ if (starts_with(var, "mailmap."))
+ return git_default_mailmap_config(var, value);
+
+ if (starts_with(var, "attr."))
+ return git_default_attr_config(var, value);
+
+ if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
+ return git_default_advice_config(var, value);
+
+ if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
+ pager_use_color = git_config_bool(var,value);
+ return 0;
+ }
+
+ if (!strcmp(var, "pack.packsizelimit")) {
+ pack_size_limit_cfg = git_config_ulong(var, value, ctx->kvi);
+ return 0;
+ }
+
+ if (!strcmp(var, "pack.compression")) {
+ int level = git_config_int(var, value, ctx->kvi);
+ if (level == -1)
+ level = Z_DEFAULT_COMPRESSION;
+ else if (level < 0 || level > Z_BEST_COMPRESSION)
+ die(_("bad pack compression level %d"), level);
+ pack_compression_level = level;
+ pack_compression_seen = 1;
+ return 0;
+ }
+
+ if (starts_with(var, "sparse."))
+ return git_default_sparse_config(var, value);
+
+ /* Add other config variables here and to Documentation/config.adoc. */
+ return 0;
+}
diff --git a/environment.h b/environment.h
index 3d806ced6e..8cfce41015 100644
--- a/environment.h
+++ b/environment.h
@@ -104,6 +104,9 @@ int use_optional_locks(void);
const char *get_git_namespace(void);
const char *strip_namespace(const char *namespaced_ref);
+int git_default_config(const char *, const char *,
+ const struct config_context *, void *);
+
/*
* TODO: All the below state either explicitly or implicitly relies on
* `the_repository`. We should eventually get rid of these and make the
diff --git a/fetch-pack.c b/fetch-pack.c
index c1be9b76eb..20e5533b21 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1904,22 +1904,22 @@ static int fetch_pack_config_cb(const char *var, const char *value,
static void fetch_pack_config(void)
{
- git_config_get_int("fetch.unpacklimit", &fetch_unpack_limit);
- git_config_get_int("transfer.unpacklimit", &transfer_unpack_limit);
- git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
- git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
- git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
- git_config_get_bool("transfer.advertisesid", &advertise_sid);
+ repo_config_get_int(the_repository, "fetch.unpacklimit", &fetch_unpack_limit);
+ repo_config_get_int(the_repository, "transfer.unpacklimit", &transfer_unpack_limit);
+ repo_config_get_bool(the_repository, "repack.usedeltabaseoffset", &prefer_ofs_delta);
+ repo_config_get_bool(the_repository, "fetch.fsckobjects", &fetch_fsck_objects);
+ repo_config_get_bool(the_repository, "transfer.fsckobjects", &transfer_fsck_objects);
+ repo_config_get_bool(the_repository, "transfer.advertisesid", &advertise_sid);
if (!uri_protocols.nr) {
char *str;
- if (!git_config_get_string("fetch.uriprotocols", &str) && str) {
- string_list_split(&uri_protocols, str, ',', -1);
+ if (!repo_config_get_string(the_repository, "fetch.uriprotocols", &str) && str) {
+ string_list_split(&uri_protocols, str, ",", -1);
free(str);
}
}
- git_config(fetch_pack_config_cb, NULL);
+ repo_config(the_repository, fetch_pack_config_cb, NULL);
}
static void fetch_pack_setup(void)
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index 40174efa3d..c9085edc40 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -26,13 +26,15 @@ static struct string_list suppress_dest_patterns = STRING_LIST_INIT_DUP;
int fmt_merge_msg_config(const char *key, const char *value,
const struct config_context *ctx, void *cb)
{
+ int *merge_log_config = cb;
+
if (!strcmp(key, "merge.log") || !strcmp(key, "merge.summary")) {
int is_bool;
- merge_log_config = git_config_bool_or_int(key, value, ctx->kvi, &is_bool);
- if (!is_bool && merge_log_config < 0)
+ *merge_log_config = git_config_bool_or_int(key, value, ctx->kvi, &is_bool);
+ if (!is_bool && *merge_log_config < 0)
return error("%s: negative length %s", key, value);
- if (is_bool && merge_log_config)
- merge_log_config = DEFAULT_MERGE_LOG_LEN;
+ if (is_bool && *merge_log_config)
+ *merge_log_config = DEFAULT_MERGE_LOG_LEN;
} else if (!strcmp(key, "merge.branchdesc")) {
use_branch_desc = git_config_bool(key, value);
} else if (!strcmp(key, "merge.suppressdest")) {
diff --git a/fmt-merge-msg.h b/fmt-merge-msg.h
index 73ca3e4465..c066d83761 100644
--- a/fmt-merge-msg.h
+++ b/fmt-merge-msg.h
@@ -12,7 +12,6 @@ struct fmt_merge_msg_opts {
const char *into_name;
};
-extern int merge_log_config;
int fmt_merge_msg_config(const char *key, const char *value,
const struct config_context *ctx, void *cb);
int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
diff --git a/for-each-ref.h b/for-each-ref.h
new file mode 100644
index 0000000000..a5e0b6d17a
--- /dev/null
+++ b/for-each-ref.h
@@ -0,0 +1,26 @@
+#ifndef FOR_EACH_REF_H
+#define FOR_EACH_REF_H
+
+struct repository;
+
+/*
+ * Shared usage string for options common to git-for-each-ref(1)
+ * and git-refs-list(1). The command-specific part (e.g., "git refs list ")
+ * must be prepended by the caller.
+ */
+#define COMMON_USAGE_FOR_EACH_REF \
+ "[--count=<count>] [--shell|--perl|--python|--tcl]\n" \
+ " [(--sort=<key>)...] [--format=<format>]\n" \
+ " [--include-root-refs] [--points-at=<object>]\n" \
+ " [--merged[=<object>]] [--no-merged[=<object>]]\n" \
+ " [--contains[=<object>]] [--no-contains[=<object>]]\n" \
+ " [(--exclude=<pattern>)...] [--start-after=<marker>]\n" \
+ " [ --stdin | <pattern>... ]"
+
+/*
+ * The core logic for for-each-ref and its clones.
+ */
+int for_each_ref_core(int argc, const char **argv, const char *prefix,
+ struct repository *repo, const char *const *usage);
+
+#endif /* FOR_EACH_REF_H */
diff --git a/fsck.c b/fsck.c
index 23965e1880..171b424dd5 100644
--- a/fsck.c
+++ b/fsck.c
@@ -3,6 +3,7 @@
#include "git-compat-util.h"
#include "date.h"
#include "dir.h"
+#include "environment.h"
#include "hex.h"
#include "odb.h"
#include "path.h"
diff --git a/fsck.h b/fsck.h
index 0c5869ac34..dd7df3d5b3 100644
--- a/fsck.h
+++ b/fsck.h
@@ -287,7 +287,7 @@ const char *fsck_describe_object(struct fsck_options *options,
struct key_value_info;
/*
- * git_config() callback for use by fsck-y tools that want to support
+ * repo_config() callback for use by fsck-y tools that want to support
* fsck.<msg> fsck.skipList etc.
*/
int git_fsck_config(const char *var, const char *value,
diff --git a/fsmonitor.c b/fsmonitor.c
index 98b2b476f0..d07dc18967 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -43,7 +43,7 @@ static int fsmonitor_hook_version(void)
{
int hook_version;
- if (git_config_get_int("core.fsmonitorhookversion", &hook_version))
+ if (repo_config_get_int(the_repository, "core.fsmonitorhookversion", &hook_version))
return -1;
if (hook_version == HOOK_INTERFACE_VERSION1 ||
diff --git a/git-gui/.gitignore b/git-gui/.gitignore
index ff6e0be4b4..5130b4f018 100644
--- a/git-gui/.gitignore
+++ b/git-gui/.gitignore
@@ -1,8 +1,8 @@
.DS_Store
config.mak
-Git Gui.app*
git-gui.tcl
GIT-GUI-BUILD-OPTIONS
GIT-VERSION-FILE
git-gui
+git-gui--askpass
lib/tclIndex
diff --git a/git-gui/GIT-GUI-BUILD-OPTIONS.in b/git-gui/GIT-GUI-BUILD-OPTIONS.in
index 5fd885c2bf..3c112af578 100644
--- a/git-gui/GIT-GUI-BUILD-OPTIONS.in
+++ b/git-gui/GIT-GUI-BUILD-OPTIONS.in
@@ -4,4 +4,3 @@ GITGUI_RELATIVE=@GITGUI_RELATIVE@
SHELL_PATH=@SHELL_PATH@
TCLTK_PATH=@TCLTK_PATH@
TCL_PATH=@TCL_PATH@
-TKEXECUTABLE=@TKEXECUTABLE@
diff --git a/git-gui/Makefile b/git-gui/Makefile
index 8672dd2d6b..27bbe051de 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -12,7 +12,6 @@ GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN . $@
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
-uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
SCRIPT_SH = git-gui.sh
@@ -54,8 +53,6 @@ INSTALL_R0 = $(INSTALL) -m 644 # space is required here
INSTALL_R1 =
INSTALL_X0 = $(INSTALL) -m 755 # space is required here
INSTALL_X1 =
-INSTALL_A0 = find # space is required here
-INSTALL_A1 = | cpio -pud
INSTALL_L0 = rm -f # space is required here
INSTALL_L1 = && ln # space is required here
INSTALL_L2 =
@@ -80,8 +77,6 @@ ifndef V
INSTALL_R1 = && echo ' ' INSTALL 644 `basename $$src` && $(INSTALL) -m 644 $$src
INSTALL_X0 = src=
INSTALL_X1 = && echo ' ' INSTALL 755 `basename $$src` && $(INSTALL) -m 755 $$src
- INSTALL_A0 = src=
- INSTALL_A1 = && echo ' ' INSTALL ' ' `basename "$$src"` && find "$$src" | cpio -pud
INSTALL_L0 = dst=
INSTALL_L1 = && src=
@@ -102,18 +97,6 @@ else
TCL_PATH ?= $(dir $(TCLTK_PATH))$(notdir $(subst wish,tclsh,$(TCLTK_PATH)))
endif
-ifeq ($(uname_S),Darwin)
- TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app
- ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n)
- TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app
- ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n)
- TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app
- endif
- endif
- TKEXECUTABLE = $(TKFRAMEWORK)/Contents/MacOS/$(shell basename "$(TKFRAMEWORK)" .app)
- TKEXECUTABLE_SQ = $(subst ','\'',$(TKEXECUTABLE))
-endif
-
ifeq ($(findstring $(firstword -$(MAKEFLAGS)),s),s)
QUIET_GEN =
endif
@@ -131,16 +114,10 @@ libdir_SQ = $(subst ','\'',$(gg_libdir))
exedir = $(dir $(gitexecdir))share/git-gui/lib
GITGUI_RELATIVE :=
-GITGUI_MACOSXAPP :=
ifeq ($(exedir),$(gg_libdir))
GITGUI_RELATIVE := 1
endif
-ifeq ($(uname_S),Darwin)
- ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y)
- GITGUI_MACOSXAPP := YesPlease
- endif
-endif
ifneq (,$(findstring MINGW,$(uname_S)))
ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
NO_MSGFMT=1
@@ -149,20 +126,6 @@ endif
GITGUI_RELATIVE := 1
endif
-ifdef GITGUI_MACOSXAPP
-GITGUI_MAIN := git-gui.tcl
-
-git-gui: generate-macos-wrapper.sh GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS
- $(QUIET_GEN)$(SHELL_PATH) generate-macos-wrapper.sh "$@" ./GIT-GUI-BUILD-OPTIONS ./GIT-VERSION-FILE
-
-Git\ Gui.app: GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS \
- macosx/Info.plist \
- macosx/git-gui.icns \
- macosx/AppMain.tcl \
- $(TKEXECUTABLE)
- $(QUIET_GEN)$(SHELL_PATH) generate-macos-app.sh . "$@" ./GIT-GUI-BUILD-OPTIONS ./GIT-VERSION-FILE
-endif
-
ifdef GITGUI_WINDOWS_WRAPPER
GITGUI_MAIN := git-gui.tcl
@@ -170,7 +133,7 @@ git-gui: windows/git-gui.sh
cp $< $@
endif
-$(GITGUI_MAIN): git-gui.sh GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS
+$(GITGUI_MAIN): git-gui.sh GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS generate-git-gui.sh
$(QUIET_GEN)$(SHELL_PATH) generate-git-gui.sh "$<" "$@" ./GIT-GUI-BUILD-OPTIONS ./GIT-VERSION-FILE
XGETTEXT ?= xgettext
@@ -207,18 +170,17 @@ GIT-GUI-BUILD-OPTIONS: FORCE
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-e 's|@TCLTK_PATH@|$(TCLTK_PATH_SQ)|' \
-e 's|@TCL_PATH@|$(TCL_PATH_SQ)|' \
- -e 's|@TKEXECUTABLE@|$(TKEXECUTABLE_SQ)|' \
$@.in >$@+
@if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi
@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
-ifdef GITGUI_MACOSXAPP
-all:: git-gui Git\ Gui.app
-endif
+git-gui--askpass: git-gui--askpass.sh GIT-GUI-BUILD-OPTIONS generate-script.sh
+ $(QUIET_GEN)$(SHELL_PATH) generate-script.sh $@ $< ./GIT-GUI-BUILD-OPTIONS
+
ifdef GITGUI_WINDOWS_WRAPPER
all:: git-gui
endif
-all:: $(GITGUI_MAIN) lib/tclIndex $(ALL_MSGFILES)
+all:: $(GITGUI_MAIN) git-gui--askpass lib/tclIndex $(ALL_MSGFILES)
install: all
$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
@@ -230,10 +192,6 @@ ifdef GITGUI_WINDOWS_WRAPPER
endif
$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(INSTALL_D1)
$(QUIET)$(INSTALL_R0)lib/tclIndex $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)'
-ifdef GITGUI_MACOSXAPP
- $(QUIET)$(INSTALL_A0)'Git Gui.app' $(INSTALL_A1) '$(DESTDIR_SQ)$(libdir_SQ)'
- $(QUIET)$(INSTALL_X0)git-gui.tcl $(INSTALL_X1) '$(DESTDIR_SQ)$(libdir_SQ)'
-endif
$(QUIET)$(foreach p,$(ALL_LIBFILES) $(NONTCL_LIBFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' &&) true
$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(msgsdir_SQ)' $(INSTALL_D1)
$(QUIET)$(foreach p,$(ALL_MSGFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(msgsdir_SQ)' &&) true
@@ -248,10 +206,6 @@ ifdef GITGUI_WINDOWS_WRAPPER
endif
$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(libdir_SQ)'
$(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/tclIndex $(REMOVE_F1)
-ifdef GITGUI_MACOSXAPP
- $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)/Git Gui.app' $(REMOVE_F1)
- $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/git-gui.tcl $(REMOVE_F1)
-endif
$(QUIET)$(foreach p,$(ALL_LIBFILES) $(NONTCL_LIBFILES), $(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/$(notdir $p) $(REMOVE_F1) &&) true
$(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(msgsdir_SQ)'
$(QUIET)$(foreach p,$(ALL_MSGFILES), $(REMOVE_F0)'$(DESTDIR_SQ)$(msgsdir_SQ)'/$(notdir $p) $(REMOVE_F1) &&) true
@@ -265,11 +219,8 @@ dist-version: GIT-VERSION-FILE
@sed 's|^GITGUI_VERSION=||' <GIT-VERSION-FILE >$(TARDIR)/version
clean::
- $(RM_RF) $(GITGUI_MAIN) lib/tclIndex po/*.msg $(PO_TEMPLATE)
+ $(RM_RF) $(GITGUI_MAIN) git-gui--askpass lib/tclIndex po/*.msg $(PO_TEMPLATE)
$(RM_RF) GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS
-ifdef GITGUI_MACOSXAPP
- $(RM_RF) 'Git Gui.app'* git-gui
-endif
ifdef GITGUI_WINDOWS_WRAPPER
$(RM_RF) git-gui
endif
diff --git a/git-gui/generate-macos-app.sh b/git-gui/generate-macos-app.sh
deleted file mode 100755
index 71b9fa67a4..0000000000
--- a/git-gui/generate-macos-app.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-
-set -e
-
-SOURCE_DIR="$1"
-OUTPUT="$2"
-BUILD_OPTIONS="$3"
-VERSION_FILE="$4"
-
-. "$BUILD_OPTIONS"
-. "$VERSION_FILE"
-
-rm -rf "$OUTPUT" "$OUTPUT+"
-
-mkdir -p "$OUTPUT+/Contents/MacOS"
-mkdir -p "$OUTPUT+/Contents/Resources/Scripts"
-
-cp "$TKEXECUTABLE" "$OUTPUT+/Contents/MacOS"
-cp "$SOURCE_DIR/macosx/git-gui.icns" "$OUTPUT+/Contents/Resources"
-sed \
- -e "s/@@GITGUI_VERSION@@/$GITGUI_VERSION/g" \
- -e "s/@@GITGUI_TKEXECUTABLE@@/$(basename "$TKEXECUTABLE")/g" \
- "$SOURCE_DIR/macosx/Info.plist" \
- >"$OUTPUT+/Contents/Info.plist"
-sed \
- -e "s|@@gitexecdir@@|$GITGUI_GITEXECDIR|" \
- -e "s|@@GITGUI_LIBDIR@@|$GITGUI_LIBDIR|" \
- "$SOURCE_DIR/macosx/AppMain.tcl" \
- >"$OUTPUT+/Contents/Resources/Scripts/AppMain.tcl"
-mv "$OUTPUT+" "$OUTPUT"
diff --git a/git-gui/generate-macos-wrapper.sh b/git-gui/generate-macos-wrapper.sh
deleted file mode 100755
index 0304937f41..0000000000
--- a/git-gui/generate-macos-wrapper.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if test "$#" -ne 3
-then
- echo >&2 "usage: $0 <OUTPUT> <BUILD_OPTIONS> <VERSION_FILE>"
- exit 1
-fi
-
-OUTPUT="$1"
-BUILD_OPTIONS="$2"
-VERSION_FILE="$3"
-
-. "$BUILD_OPTIONS"
-
-rm -f "$OUTPUT" "$OUTPUT+"
-
-(
- echo "#!$SHELL_PATH"
- cat "$BUILD_OPTIONS" "$VERSION_FILE"
- cat <<-'EOF'
- if test "z$*" = zversion ||
- test "z$*" = z--version
- then
- echo "git-gui version $GITGUI_VERSION"
- else
- libdir="${GIT_GUI_LIB_DIR:-$GITGUI_LIBDIR}"
- exec "$libdir/Git Gui.app/Contents/MacOS/$(basename "$TKEXECUTABLE")" "$0" "$@"
- fi
- EOF
-) >"$OUTPUT+"
-
-chmod +x "$OUTPUT+"
-mv "$OUTPUT+" "$OUTPUT"
diff --git a/git-gui/generate-script.sh b/git-gui/generate-script.sh
new file mode 100755
index 0000000000..0dd2da92e3
--- /dev/null
+++ b/git-gui/generate-script.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+set -e
+
+if test $# -ne 3
+then
+ echo >&2 "USAGE: $0 <OUTPUT> <INPUT> <GIT-GUI-BUILD-OPTIONS>"
+ exit 1
+fi
+
+OUTPUT="$1"
+INPUT="$2"
+BUILD_OPTIONS="$3"
+
+. "$BUILD_OPTIONS"
+
+sed \
+ -e "1s|#!.*/sh|#!$SHELL_PATH|" \
+ -e "1,3s|^exec wish|exec '$TCLTK_PATH'|" \
+ "$INPUT" >"$OUTPUT"
+
+chmod a+x "$OUTPUT"
diff --git a/git-gui/git-gui--askpass b/git-gui/git-gui--askpass.sh
index 71a536d232..71a536d232 100755
--- a/git-gui/git-gui--askpass
+++ b/git-gui/git-gui--askpass.sh
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 8bb121db4f..a931d7f7c9 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -30,7 +30,7 @@ along with this program; if not, see <https://www.gnu.org/licenses/>.}]
##
## Tcl/Tk sanity check
-if {[catch {package require Tcl 8.6-8.8} err]} {
+if {[catch {package require Tcl 8.6-} err]} {
catch {wm withdraw .}
tk_messageBox \
-icon error \
@@ -74,6 +74,26 @@ proc is_Cygwin {} {
}
######################################################################
+## Enable Tcl8 profile in Tcl9, allowing consumption of data that has
+## bytes not conforming to the assumed encoding profile.
+
+if {[package vcompare $::tcl_version 9.0] >= 0} {
+ rename open _strict_open
+ proc open args {
+ set f [_strict_open {*}$args]
+ chan configure $f -profile tcl8
+ return $f
+ }
+ proc convertfrom args {
+ return [encoding convertfrom -profile tcl8 {*}$args]
+ }
+} else {
+ proc convertfrom args {
+ return [encoding convertfrom {*}$args]
+ }
+}
+
+######################################################################
##
## PATH lookup. Sanitize $PATH, assure exec/open use only that
@@ -83,12 +103,6 @@ if {[is_Windows]} {
set _path_sep {:}
}
-if {[is_Windows]} {
- set gitguidir [file dirname [info script]]
- regsub -all ";" $gitguidir "\\;" gitguidir
- set env(PATH) "$gitguidir;$env(PATH)"
-}
-
set _search_path {}
set _path_seen [dict create]
foreach p [split $env(PATH) $_path_sep] {
@@ -183,7 +197,9 @@ if {[is_Windows]} {
set command_line [string trim [string range $arg0 1 end]]
lset args 0 "| [sanitize_command_line $command_line 0]"
}
- uplevel 1 real_open $args
+ set fd [real_open {*}$args]
+ fconfigure $fd -eofchar {}
+ return $fd
}
} else {
@@ -575,8 +591,6 @@ proc _lappend_nice {cmd_var} {
set _nice [_which nice]
if {[catch {safe_exec [list $_nice git version]}]} {
set _nice {}
- } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} {
- set _nice {}
}
}
if {$_nice ne {}} {
@@ -590,7 +604,7 @@ proc git {args} {
proc git_redir {cmd redir} {
set fd [git_read $cmd $redir]
- fconfigure $fd -translation binary -encoding utf-8
+ fconfigure $fd -encoding utf-8
set result [string trimright [read $fd] "\n"]
close $fd
if {$::_trace} {
@@ -607,7 +621,6 @@ proc safe_open_command {cmd {redir {}}} {
} err]} {
error $err
}
- fconfigure $fd -eofchar {}
return $fd
}
@@ -1003,7 +1016,7 @@ proc _parse_config {arr_name args} {
[concat config \
$args \
--null --list]]
- fconfigure $fd_rc -translation binary -encoding utf-8
+ fconfigure $fd_rc -encoding utf-8
set buf [read $fd_rc]
close $fd_rc
}
@@ -1113,9 +1126,11 @@ citool {
## execution environment
# Suggest our implementation of askpass, if none is set
+set argv0dir [file dirname [file normalize $::argv0]]
if {![info exists env(SSH_ASKPASS)]} {
- set env(SSH_ASKPASS) [file join [git --exec-path] git-gui--askpass]
+ set env(SSH_ASKPASS) [file join $argv0dir git-gui--askpass]
}
+unset argv0dir
######################################################################
##
@@ -1405,15 +1420,15 @@ proc rescan_stage2 {fd after} {
set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]]
set fd_df [git_read [list diff-files -z]]
- fconfigure $fd_di -blocking 0 -translation binary -encoding binary
- fconfigure $fd_df -blocking 0 -translation binary -encoding binary
+ fconfigure $fd_di -blocking 0 -translation binary
+ fconfigure $fd_df -blocking 0 -translation binary
fileevent $fd_di readable [list read_diff_index $fd_di $after]
fileevent $fd_df readable [list read_diff_files $fd_df $after]
if {[is_config_true gui.displayuntracked]} {
set fd_lo [git_read [concat ls-files --others -z $ls_others]]
- fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
+ fconfigure $fd_lo -blocking 0 -translation binary
fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
incr rescan_active
}
@@ -1427,7 +1442,6 @@ proc load_message {file {encoding {}}} {
if {[catch {set fd [safe_open_file $f r]}]} {
return 0
}
- fconfigure $fd -eofchar {}
if {$encoding ne {}} {
fconfigure $fd -encoding $encoding
}
@@ -1484,7 +1498,7 @@ proc run_prepare_commit_msg_hook {} {
ui_status [mc "Calling prepare-commit-msg hook..."]
set pch_error {}
- fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fconfigure $fd_ph -blocking 0 -translation binary
fileevent $fd_ph readable \
[list prepare_commit_msg_hook_wait $fd_ph]
@@ -1530,7 +1544,7 @@ proc read_diff_index {fd after} {
set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
merge_state \
- [encoding convertfrom utf-8 $p] \
+ [convertfrom utf-8 $p] \
[lindex $i 4]? \
[list [lindex $i 0] [lindex $i 2]] \
[list]
@@ -1563,7 +1577,7 @@ proc read_diff_files {fd after} {
set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
merge_state \
- [encoding convertfrom utf-8 $p] \
+ [convertfrom utf-8 $p] \
?[lindex $i 4] \
[list] \
[list [lindex $i 0] [lindex $i 2]]
@@ -1586,7 +1600,7 @@ proc read_ls_others {fd after} {
set pck [split $buf_rlo "\0"]
set buf_rlo [lindex $pck end]
foreach p [lrange $pck 0 end-1] {
- set p [encoding convertfrom utf-8 $p]
+ set p [convertfrom utf-8 $p]
if {[string index $p end] eq {/}} {
set p [string range $p 0 end-1]
}
diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl
index 9d4d1ac872..4477b84eae 100644
--- a/git-gui/lib/blame.tcl
+++ b/git-gui/lib/blame.tcl
@@ -483,7 +483,6 @@ method _load {jump} {
} else {
set fd [safe_open_file $path r]
}
- fconfigure $fd -eofchar {}
} else {
if {$do_textconv ne 0} {
set fd [git_read [list cat-file --textconv "$commit:$path"]]
@@ -493,7 +492,6 @@ method _load {jump} {
}
fconfigure $fd \
-blocking 0 \
- -translation lf \
-encoding [get_path_encoding $path]
fileevent $fd readable [cb _read_file $fd $jump]
set current_fd $fd
@@ -620,7 +618,7 @@ method _exec_blame {cur_w cur_d options cur_s} {
lappend options -- $path
set fd [git_read_nice [concat blame $options]]
- fconfigure $fd -blocking 0 -translation lf -encoding utf-8
+ fconfigure $fd -blocking 0 -encoding utf-8
fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
set current_fd $fd
set blame_lines 0
@@ -986,7 +984,7 @@ method _showcommit {cur_w lno} {
set msg {}
catch {
set fd [git_read [list cat-file commit $cmit]]
- fconfigure $fd -encoding binary -translation lf
+ fconfigure $fd -encoding iso8859-1
# By default commits are assumed to be in utf-8
set enc utf-8
while {[gets $fd line] > 0} {
@@ -999,7 +997,7 @@ method _showcommit {cur_w lno} {
set enc [tcl_encoding $enc]
if {$enc ne {}} {
- set msg [encoding convertfrom $enc $msg]
+ set msg [convertfrom $enc $msg]
}
set msg [string trim $msg]
}
@@ -1143,7 +1141,6 @@ method _blameparent {} {
fconfigure $fd \
-blocking 0 \
- -encoding binary \
-translation binary
fileevent $fd readable [cb _read_diff_load_commit \
$fd $cparent $new_path $r_orig_line]
diff --git a/git-gui/lib/branch.tcl b/git-gui/lib/branch.tcl
index 39e0f2dc98..97c9ec1c00 100644
--- a/git-gui/lib/branch.tcl
+++ b/git-gui/lib/branch.tcl
@@ -8,7 +8,7 @@ proc load_all_heads {} {
set rh_len [expr {[string length $rh] + 1}]
set all_heads [list]
set fd [git_read [list for-each-ref --format=%(refname) $rh]]
- fconfigure $fd -translation binary -encoding utf-8
+ fconfigure $fd -encoding utf-8
while {[gets $fd line] > 0} {
if {!$some_heads_tracking || ![is_tracking_branch $line]} {
lappend all_heads [string range $line $rh_len end]
@@ -25,7 +25,7 @@ proc load_all_tags {} {
--sort=-taggerdate \
--format=%(refname) \
refs/tags]]
- fconfigure $fd -translation binary -encoding utf-8
+ fconfigure $fd -encoding utf-8
while {[gets $fd line] > 0} {
if {![regsub ^refs/tags/ $line {} name]} continue
lappend all_tags $name
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index f53eb952cf..fe72de025e 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -195,7 +195,7 @@ method _ls {tree_id {name {}}} {
$w conf -state disabled
set fd [git_read [list ls-tree -z $tree_id]]
- fconfigure $fd -blocking 0 -translation binary -encoding utf-8
+ fconfigure $fd -blocking 0 -encoding utf-8
fileevent $fd readable [cb _read $fd]
}
diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl
index 987486a4b6..449e89e2bc 100644
--- a/git-gui/lib/checkout_op.tcl
+++ b/git-gui/lib/checkout_op.tcl
@@ -462,7 +462,7 @@ If you wanted to be on a branch, create one now starting from 'This Detached Che
if {$fd_ph ne {}} {
global pch_error
set pch_error {}
- fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fconfigure $fd_ph -blocking 0 -translation binary
fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph]
} else {
_update_repo_state $this
diff --git a/git-gui/lib/choose_rev.tcl b/git-gui/lib/choose_rev.tcl
index 7a9e3c83bb..cd355cc92a 100644
--- a/git-gui/lib/choose_rev.tcl
+++ b/git-gui/lib/choose_rev.tcl
@@ -147,7 +147,7 @@ constructor _new {path unmerged_only title} {
refs/remotes \
refs/tags \
]]
- fconfigure $fr_fd -translation lf -encoding utf-8
+ fconfigure $fr_fd -encoding utf-8
while {[gets $fr_fd line] > 0} {
set line [eval $line]
if {[lindex $line 1 0] eq {tag}} {
@@ -570,7 +570,7 @@ method _reflog_last {name} {
set last {}
if {[catch {set last [file mtime [gitdir $name]]}]
&& ![catch {set g [safe_open_file [gitdir logs $name] r]}]} {
- fconfigure $g -translation binary
+ fconfigure $g -encoding iso8859-1
while {[gets $g line] >= 0} {
if {[regexp {> ([1-9][0-9]*) } $line line when]} {
set last $when
diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl
index 2fd57a51fb..89eb8c7b73 100644
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -28,7 +28,7 @@ You are currently in the middle of a merge that has not been fully completed. Y
set name ""
set email ""
set fd [git_read [list cat-file commit $curHEAD]]
- fconfigure $fd -encoding binary -translation lf
+ fconfigure $fd -encoding iso8859-1
# By default commits are assumed to be in utf-8
set enc utf-8
while {[gets $fd line] > 0} {
@@ -43,9 +43,9 @@ You are currently in the middle of a merge that has not been fully completed. Y
set enc [tcl_encoding $enc]
if {$enc ne {}} {
- set msg [encoding convertfrom $enc $msg]
- set name [encoding convertfrom $enc $name]
- set email [encoding convertfrom $enc $email]
+ set msg [convertfrom $enc $msg]
+ set name [convertfrom $enc $name]
+ set email [convertfrom $enc $email]
}
if {$name ne {} && $email ne {}} {
set commit_author [list name $name email $email date $time]
@@ -208,28 +208,6 @@ You must stage at least 1 file before you can commit.
# -- A message is required.
#
set msg [$ui_comm get 1.0 end]
- # Strip trailing whitespace
- regsub -all -line {[ \t\r]+$} $msg {} msg
- # Strip comment lines
- global comment_string
- set cmt_rx [strcat {(^|\n)} [regsub -all {\W} $comment_string {\\&}] {[^\n]*}]
- regsub -all $cmt_rx $msg {\1} msg
- # Strip leading and trailing empty lines (puts adds one \n)
- set msg [string trim $msg \n]
- # Compress consecutive empty lines
- regsub -all {\n{3,}} $msg "\n\n" msg
- if {$msg eq {}} {
- error_popup [mc "Please supply a commit message.
-
-A good commit message has the following format:
-
-- First line: Describe in one sentence what you did.
-- Second line: Blank
-- Remaining lines: Describe why this change is good.
-"]
- unlock_index
- return
- }
# -- Build the message file.
#
@@ -252,7 +230,7 @@ A good commit message has the following format:
ui_status [mc "Calling pre-commit hook..."]
set pch_error {}
- fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fconfigure $fd_ph -blocking 0 -translation binary
fileevent $fd_ph readable \
[list commit_prehook_wait $fd_ph $curHEAD $msg_p]
}
@@ -307,7 +285,7 @@ Do you really want to proceed with your Commit?"]
ui_status [mc "Calling commit-msg hook..."]
set pch_error {}
- fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fconfigure $fd_ph -blocking 0 -translation binary
fileevent $fd_ph readable \
[list commit_commitmsg_wait $fd_ph $curHEAD $msg_p]
}
@@ -332,7 +310,52 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
fconfigure $fd_ph -blocking 0
}
+proc wash_commit_message {msg} {
+ # Strip trailing whitespace
+ regsub -all -line {[ \t\r]+$} $msg {} msg
+ # Strip comment lines
+ global comment_string
+ set cmt_rx [strcat {(^|\n)} [regsub -all {\W} $comment_string {\\&}] {[^\n]*}]
+ regsub -all $cmt_rx $msg {\1} msg
+ # Strip leading and trailing empty lines (puts adds one \n)
+ set msg [string trim $msg \n]
+ # Compress consecutive empty lines
+ regsub -all {\n{3,}} $msg \n\n msg
+
+ return $msg
+}
+
proc commit_writetree {curHEAD msg_p} {
+ # -- Process the commit message after hooks have run.
+ #
+ set msg_fd [safe_open_file $msg_p r]
+ setup_commit_encoding $msg_fd 1
+ set msg [read $msg_fd]
+ close $msg_fd
+
+ # Process the message (strip whitespace, comments, etc.)
+ set msg [wash_commit_message $msg]
+
+ if {$msg eq {}} {
+ error_popup [mc "Please supply a commit message.
+
+A good commit message has the following format:
+
+- First line: Describe in one sentence what you did.
+- Second line: Blank
+- Remaining lines: Describe why this change is good.
+"]
+ unlock_index
+ return
+ }
+
+ # Write the processed message back to the file
+ set msg_wt [safe_open_file $msg_p w]
+ fconfigure $msg_wt -translation lf
+ setup_commit_encoding $msg_wt
+ puts $msg_wt $msg
+ close $msg_wt
+
ui_status [mc "Committing changes..."]
set fd_wt [git_read [list write-tree]]
fileevent $fd_wt readable \
@@ -361,7 +384,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {
#
if {$commit_type eq {normal}} {
set fd_ot [git_read [list cat-file commit $PARENT]]
- fconfigure $fd_ot -encoding binary -translation lf
+ fconfigure $fd_ot -encoding iso8859-1
set old_tree [gets $fd_ot]
close $fd_ot
@@ -460,7 +483,7 @@ A rescan will be automatically started now.
if {$fd_ph ne {}} {
global pch_error
set pch_error {}
- fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fconfigure $fd_ph -blocking 0 -translation binary
fileevent $fd_ph readable \
[list commit_postcommit_wait $fd_ph $cmt_id]
}
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index 1acd37bdb4..442737ba4f 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -191,7 +191,6 @@ proc show_other_diff {path w m cont_info} {
file {
set fd [safe_open_file $path r]
fconfigure $fd \
- -eofchar {} \
-encoding [get_path_encoding $path]
set content [read $fd $max_sz]
close $fd
@@ -325,6 +324,8 @@ proc start_show_diff {cont_info {add_opts {}}} {
# '++' lines which is not bijective. Thus, we need to maintain a state
# across lines.
set ::conflict_in_pre_image 0
+
+ # git-diff has eol==\n, \r if present is part of the text
fconfigure $fd \
-blocking 0 \
-encoding [get_path_encoding $path] \
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 377547034b..7aa09c7728 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -78,7 +78,6 @@ proc update_indexinfo {msg path_list after} {
-blocking 0 \
-buffering full \
-buffersize 512 \
- -encoding binary \
-translation binary
fileevent $fd writable [list \
write_update_indexinfo \
@@ -147,7 +146,6 @@ proc update_index {msg path_list after} {
-blocking 0 \
-buffering full \
-buffersize 512 \
- -encoding binary \
-translation binary
fileevent $fd writable [list \
write_update_index \
@@ -227,7 +225,6 @@ proc checkout_index {msg path_list after capture_error} {
-blocking 0 \
-buffering full \
-buffersize 512 \
- -encoding binary \
-translation binary
fileevent $fd writable [list \
write_checkout_index \
diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl
index 2c9bb3af40..44be4ed3ff 100644
--- a/git-gui/lib/mergetool.tcl
+++ b/git-gui/lib/mergetool.tcl
@@ -90,7 +90,7 @@ proc merge_load_stages {path cont} {
set merge_stages_fd [git_read [list ls-files -u -z -- $path]]
- fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary
+ fconfigure $merge_stages_fd -blocking 0 -translation binary
fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont]
}
@@ -370,7 +370,7 @@ proc merge_tool_start {cmdline target backup stages} {
ui_status [mc "Running merge tool..."]
- fconfigure $mtool_fd -blocking 0 -translation binary -encoding binary
+ fconfigure $mtool_fd -blocking 0 -translation binary
fileevent $mtool_fd readable [list read_mtool_output $mtool_fd]
}
diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl
index 349d31edf3..f0814efdd7 100644
--- a/git-gui/lib/remote_branch_delete.tcl
+++ b/git-gui/lib/remote_branch_delete.tcl
@@ -307,7 +307,6 @@ method _load {cache uri} {
set active_ls [git_read [list ls-remote $uri]]
fconfigure $active_ls \
-blocking 0 \
- -translation lf \
-encoding utf-8
fileevent $active_ls readable [cb _read $cache $active_ls]
} else {
diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl
index 1d01d9cbfa..431665059e 100644
--- a/git-gui/lib/shortcut.tcl
+++ b/git-gui/lib/shortcut.tcl
@@ -3,27 +3,41 @@
proc do_windows_shortcut {} {
global _gitworktree
- set fn [tk_getSaveFile \
- -parent . \
- -title [mc "%s (%s): Create Desktop Icon" [appname] [reponame]] \
- -initialfile "Git [reponame].lnk"]
- if {$fn != {}} {
- if {[file extension $fn] ne {.lnk}} {
- set fn ${fn}.lnk
- }
- # Use git-gui.exe if available (ie: git-for-windows)
- set cmdLine [list [_which git-gui]]
- if {$cmdLine eq {}} {
- set cmdLine [list [info nameofexecutable] \
- [file normalize $::argv0]]
- }
- if {[catch {
- win32_create_lnk $fn $cmdLine \
- [file normalize $_gitworktree]
- } err]} {
- error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"]
+
+ set desktop [safe_exec [list cygpath -mD]]
+ set link_file "Git [reponame].lnk"
+ set link_path [file normalize [file join $desktop $link_file]]
+
+ # on Windows, tk_getSaveFile dereferences .lnk files, so no simple
+ # filename chooser is available. Use the default or quit.
+ if {[file exists $link_path]} {
+ set answer [tk_messageBox \
+ -type yesno \
+ -title [mc "%s (%s): Create Desktop Icon" [appname] [reponame]] \
+ -default yes \
+ -message [mc "Replace existing shortcut: %s?" $link_file]]
+ if {$answer == no} {
+ return
}
}
+
+ # Use git-gui.exe if found, fall back to wish + launcher
+ set link_arguments {}
+ set link_target [safe_exec [list cygpath -m /cmd/git-gui.exe]]
+ if {![file executable $link_target]} {
+ set link_target [_which git-gui]
+ }
+ if {![file executable $link_target]} {
+ set link_target [file normalize [info nameofexecutable]]
+ set link_arguments [file normalize $::argv0]
+ }
+ set cmdLine [list $link_target $link_arguments]
+ if {[catch {
+ win32_create_lnk $link_path $cmdLine \
+ [file normalize $_gitworktree]
+ } err]} {
+ error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"]
+ }
}
proc do_cygwin_shortcut {} {
diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl
index 538d61c792..634656820d 100644
--- a/git-gui/lib/spellcheck.tcl
+++ b/git-gui/lib/spellcheck.tcl
@@ -33,7 +33,6 @@ constructor init {pipe_fd ui_text ui_menu} {
method _connect {pipe_fd} {
fconfigure $pipe_fd \
-encoding utf-8 \
- -eofchar {} \
-translation lf
if {[gets $pipe_fd s_version] <= 0} {
diff --git a/git-gui/lib/themed.tcl b/git-gui/lib/themed.tcl
index 8c4a0c2ee7..c18e201d85 100644
--- a/git-gui/lib/themed.tcl
+++ b/git-gui/lib/themed.tcl
@@ -21,10 +21,10 @@ namespace eval color {
set inactive_select_bg [convert_rgb_to_gray $select_bg]
set inactive_select_fg $select_fg
- set color::select_bg $select_bg
- set color::select_fg $select_fg
- set color::inactive_select_bg $inactive_select_bg
- set color::inactive_select_fg $inactive_select_fg
+ set ::color::select_bg $select_bg
+ set ::color::select_fg $select_fg
+ set ::color::inactive_select_bg $inactive_select_bg
+ set ::color::inactive_select_fg $inactive_select_fg
proc add_option {key val} {
option add $key $val widgetDefault
diff --git a/git-gui/macosx/AppMain.tcl b/git-gui/macosx/AppMain.tcl
deleted file mode 100644
index b6c6dc3500..0000000000
--- a/git-gui/macosx/AppMain.tcl
+++ /dev/null
@@ -1,29 +0,0 @@
-set gitexecdir {@@gitexecdir@@}
-if { [info exists ::env(GIT_GUI_LIB_DIR) ] } {
- set gitguilib $::env(GIT_GUI_LIB_DIR)
-} else {
- set gitguilib {@@GITGUI_LIBDIR@@}
-}
-
-set env(PATH) "$gitexecdir:$env(PATH)"
-
-if {[string first -psn [lindex $argv 0]] == 0} {
- lset argv 0 [file join $gitexecdir git-gui]
-}
-
-if {[file tail [lindex $argv 0]] eq {gitk}} {
- set argv0 [lindex $argv 0]
- set AppMain_source $argv0
-} else {
- set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]]
- set AppMain_source [file join $gitguilib git-gui.tcl]
- if {[info exists env(PWD)]} {
- cd $env(PWD)
- } elseif {[pwd] eq {/}} {
- cd $env(HOME)
- }
-}
-
-unset gitexecdir gitguilib
-set argv [lrange $argv 1 end]
-source $AppMain_source
diff --git a/git-gui/macosx/Info.plist b/git-gui/macosx/Info.plist
deleted file mode 100644
index 1ade121c4c..0000000000
--- a/git-gui/macosx/Info.plist
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>@@GITGUI_TKEXECUTABLE@@</string>
- <key>CFBundleGetInfoString</key>
- <string>Git Gui @@GITGUI_VERSION@@ © 2006-2007 Shawn Pearce, et. al.</string>
- <key>CFBundleIconFile</key>
- <string>git-gui.icns</string>
- <key>CFBundleIdentifier</key>
- <string>cz.or.repo.git-gui</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>Git Gui</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>@@GITGUI_VERSION@@</string>
- <key>CFBundleSignature</key>
- <string>GITg</string>
- <key>CFBundleVersion</key>
- <string>@@GITGUI_VERSION@@</string>
- <key>NSHighResolutionCapable</key>
- <true/>
-</dict>
-</plist>
diff --git a/git-gui/macosx/git-gui.icns b/git-gui/macosx/git-gui.icns
deleted file mode 100644
index 77d88a77a7..0000000000
--- a/git-gui/macosx/git-gui.icns
+++ /dev/null
Binary files differ
diff --git a/git-gui/meson.build b/git-gui/meson.build
index cdae85e4b9..320ba09ecf 100644
--- a/git-gui/meson.build
+++ b/git-gui/meson.build
@@ -19,17 +19,6 @@ build_options_config.set_quoted('GITGUI_LIBDIR', get_option('prefix') / get_opti
build_options_config.set_quoted('SHELL_PATH', fs.as_posix(shell.full_path()))
build_options_config.set_quoted('TCLTK_PATH', fs.as_posix(wish.full_path()))
build_options_config.set_quoted('TCL_PATH', fs.as_posix(tclsh.full_path()))
-if target_machine.system() == 'darwin'
- tkexecutables = [
- '/Library/Frameworks/Tk.framework/Resources/Wish.app/Contents/MacOS/Wish',
- '/System/Library/Frameworks/Tk.framework/Resources/Wish.app/Contents/MacOS/Wish',
- '/System/Library/Frameworks/Tk.framework/Resources/Wish Shell.app/Contents/MacOS/Wish Shell',
- ]
- tkexecutable = find_program(tkexecutables)
- build_options_config.set_quoted('TKEXECUTABLE', tkexecutable.full_path())
-else
- build_options_config.set('TKEXECUTABLE', '')
-endif
build_options = configure_file(
input: 'GIT-GUI-BUILD-OPTIONS.in',
@@ -49,14 +38,6 @@ version_file = custom_target(
build_always_stale: true,
)
-configure_file(
- input: 'git-gui--askpass',
- output: 'git-gui--askpass',
- copy: true,
- install: true,
- install_dir: get_option('libexecdir') / 'git-core',
-)
-
gitgui_main = 'git-gui'
gitgui_main_install_dir = get_option('libexecdir') / 'git-core'
@@ -70,55 +51,23 @@ if target_machine.system() == 'windows'
install: true,
install_dir: get_option('libexecdir') / 'git-core',
)
-elif target_machine.system() == 'darwin'
- gitgui_main = 'git-gui.tcl'
- gitgui_main_install_dir = get_option('datadir') / 'git-gui/lib'
-
- custom_target(
- output: 'git-gui',
- command: [
- shell,
- meson.current_source_dir() / 'generate-macos-wrapper.sh',
- '@OUTPUT@',
- meson.current_build_dir() / 'GIT-GUI-BUILD-OPTIONS',
- meson.current_build_dir() / 'GIT-VERSION-FILE',
- ],
- depends: [
- version_file,
- ],
- depend_files: [
- build_options,
- ],
- install: true,
- install_dir: get_option('libexecdir') / 'git-core',
- )
-
- custom_target(
- output: 'Git Gui.app',
- command: [
- shell,
- meson.current_source_dir() / 'generate-macos-app.sh',
- meson.current_source_dir(),
- meson.current_build_dir() / 'Git Gui.app',
- meson.current_build_dir() / 'GIT-GUI-BUILD-OPTIONS',
- meson.current_build_dir() / 'GIT-VERSION-FILE',
- ],
- depends: [
- version_file,
- ],
- depend_files: [
- build_options,
- 'macosx/AppMain.tcl',
- 'macosx/Info.plist',
- 'macosx/git-gui.icns',
- ],
- build_by_default: true,
- install: true,
- install_dir: get_option('datadir') / 'git-gui/lib',
- )
endif
custom_target(
+ output: 'git-gui--askpass',
+ input: 'git-gui--askpass.sh',
+ command: [
+ shell,
+ meson.current_source_dir() / 'generate-script.sh',
+ '@OUTPUT@',
+ '@INPUT@',
+ meson.current_build_dir() / 'GIT-GUI-BUILD-OPTIONS',
+ ],
+ install: true,
+ install_dir: get_option('libexecdir') / 'git-core',
+)
+
+custom_target(
input: 'git-gui.sh',
output: gitgui_main,
command: [
diff --git a/git-gui/po/bg.po b/git-gui/po/bg.po
index 70ab2b438a..21f5bd54e9 100644
--- a/git-gui/po/bg.po
+++ b/git-gui/po/bg.po
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git-gui master\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-04-20 09:27+0200\n"
-"PO-Revision-Date: 2025-05-29 13:37+0200\n"
+"POT-Creation-Date: 2025-07-22 17:37+0200\n"
+"PO-Revision-Date: 2025-07-28 11:56+0200\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
@@ -18,88 +18,58 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: git-gui.sh:861
#, tcl-format
msgid "Invalid font specified in %s:"
msgstr "Указан е неправилен шрифт в „%s“:"
-#: git-gui.sh:924
msgid "Main Font"
msgstr "Основен шрифт"
-#: git-gui.sh:925
msgid "Diff/Console Font"
msgstr "Шрифт за разликите/конзолата"
-#: git-gui.sh:940 git-gui.sh:954 git-gui.sh:967 git-gui.sh:1057 git-gui.sh:1076
-#: git-gui.sh:3217
msgid "git-gui: fatal error"
msgstr "git-gui: фатална грешка"
-#: git-gui.sh:941
msgid "Cannot find git in PATH."
msgstr "Командата git липсва в пътя (PATH)."
-#: git-gui.sh:968
msgid "Cannot parse Git version string:"
msgstr "Низът с версията на Git не може да се анализира:"
-#: git-gui.sh:993
-#, tcl-format
-msgid ""
-"Git version cannot be determined.\n"
-"\n"
-"%s claims it is version '%s'.\n"
-"\n"
-"%s requires at least Git 1.5.0 or later.\n"
-"\n"
-"Assume '%s' is version 1.5.0?\n"
-msgstr ""
-"Версията на Git не може да се определи.\n"
-"\n"
-"Версията на „%s“ изглежда, че е „%s“.\n"
-"\n"
-"„%s“ изисква Git, версия поне 1.5.0.\n"
-"\n"
-"Да се приеме ли, че „%s“ е версия „1.5.0“?\n"
+msgid "Insufficient git version, require: "
+msgstr "Прекалено ниска версия на git, необходима е поне: "
+
+msgid "git returned:"
+msgstr "git върна:"
-#: git-gui.sh:1287
msgid "Git directory not found:"
msgstr "Директорията на Git не е открита:"
-#: git-gui.sh:1317
msgid "Cannot move to top of working directory:"
msgstr "Не може да се премине към родителската директория."
-#: git-gui.sh:1325
msgid "Cannot use bare repository:"
msgstr "Голо хранилище не може да се използва:"
-#: git-gui.sh:1333
msgid "No working directory"
msgstr "Работната директория липсва"
-#: git-gui.sh:1507 lib/checkout_op.tcl:306
msgid "Refreshing file status..."
msgstr "Обновяване на състоянието на файла…"
-#: git-gui.sh:1551
msgid "Scanning for modified files ..."
msgstr "Проверка за променени файлове…"
-#: git-gui.sh:1635
msgid "Calling prepare-commit-msg hook..."
msgstr "Куката „prepare-commit-msg“ се изпълнява в момента…"
-#: git-gui.sh:1652
msgid "Commit declined by prepare-commit-msg hook."
msgstr "Подаването е отхвърлено от куката „prepare-commit-msg“."
-#: git-gui.sh:1810 lib/browser.tcl:252
msgid "Ready."
msgstr "Готово."
-#: git-gui.sh:1974
#, tcl-format
msgid ""
"Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files."
@@ -108,721 +78,539 @@ msgstr ""
"извеждане(gui.maxfilesdisplayed = %s), съответно не са показани всички %s "
"файла."
-#: git-gui.sh:2097
msgid "Unmodified"
msgstr "Непроменен"
-#: git-gui.sh:2099
msgid "Modified, not staged"
msgstr "Променен, но не е в индекса"
-#: git-gui.sh:2100 git-gui.sh:2112
msgid "Staged for commit"
msgstr "В индекса за подаване"
-#: git-gui.sh:2101 git-gui.sh:2113
msgid "Portions staged for commit"
msgstr "Части са в индекса за подаване"
-#: git-gui.sh:2102 git-gui.sh:2114
msgid "Staged for commit, missing"
msgstr "В индекса за подаване, но липсва"
-#: git-gui.sh:2104
msgid "File type changed, not staged"
msgstr "Видът на файла е сменен, но не е в индекса"
-#: git-gui.sh:2105 git-gui.sh:2106
msgid "File type changed, old type staged for commit"
msgstr "Видът на файла е сменен, но новият вид не е в индекса"
-#: git-gui.sh:2107
msgid "File type changed, staged"
msgstr "Видът на файла е сменен и е в индекса"
-#: git-gui.sh:2108
msgid "File type change staged, modification not staged"
msgstr "Видът на файла е сменен в индекса, но не и съдържанието"
-#: git-gui.sh:2109
msgid "File type change staged, file missing"
msgstr "Видът на файла е сменен в индекса, но файлът липсва"
-#: git-gui.sh:2111
msgid "Untracked, not staged"
msgstr "Неследен"
-#: git-gui.sh:2116
msgid "Missing"
msgstr "Липсващ"
-#: git-gui.sh:2117
msgid "Staged for removal"
msgstr "В индекса за изтриване"
-#: git-gui.sh:2118
msgid "Staged for removal, still present"
msgstr "В индекса за изтриване, но още го има"
-#: git-gui.sh:2120 git-gui.sh:2121 git-gui.sh:2122 git-gui.sh:2123
-#: git-gui.sh:2124 git-gui.sh:2125
msgid "Requires merge resolution"
msgstr "Изисква коригиране при сливане"
-#: git-gui.sh:2170
msgid "Couldn't find gitk in PATH"
msgstr "Командата „gitk“ липсва в пътищата, определени от променливата PATH."
-#: git-gui.sh:2217 git-gui.sh:2253
#, tcl-format
msgid "Starting %s... please wait..."
msgstr "Стартиране на „%s“…, изчакайте…"
-#: git-gui.sh:2232
msgid "Couldn't find git gui in PATH"
msgstr ""
"Командата „git gui“ липсва в пътищата, определени от променливата PATH."
-#: git-gui.sh:2735 lib/choose_repository.tcl:53
msgid "Repository"
msgstr "Хранилище"
-#: git-gui.sh:2736
msgid "Edit"
msgstr "Редактиране"
-#: git-gui.sh:2738 lib/choose_rev.tcl:567
msgid "Branch"
msgstr "Клон"
-#: git-gui.sh:2741 lib/choose_rev.tcl:554
msgid "Commit@@noun"
msgstr "Подаване"
-#: git-gui.sh:2744 lib/merge.tcl:127 lib/merge.tcl:174
msgid "Merge"
msgstr "Сливане"
-#: git-gui.sh:2745 lib/choose_rev.tcl:563
msgid "Remote"
msgstr "Отдалечено хранилище"
-#: git-gui.sh:2748
msgid "Tools"
msgstr "Команди"
-#: git-gui.sh:2757
msgid "Explore Working Copy"
msgstr "Разглеждане на работното копие"
-#: git-gui.sh:2772
msgid "Git Bash"
msgstr "Bash за Git"
-#: git-gui.sh:2781
msgid "Browse Current Branch's Files"
msgstr "Разглеждане на файловете в текущия клон"
-#: git-gui.sh:2785
msgid "Browse Branch Files..."
msgstr "Разглеждане на текущия клон…"
-#: git-gui.sh:2790
msgid "Visualize Current Branch's History"
msgstr "Визуализация на историята на текущия клон"
-#: git-gui.sh:2794
msgid "Visualize All Branch History"
msgstr "Визуализация на историята на всички клонове"
-#: git-gui.sh:2801
#, tcl-format
msgid "Browse %s's Files"
msgstr "Разглеждане на файловете в „%s“"
-#: git-gui.sh:2803
#, tcl-format
msgid "Visualize %s's History"
msgstr "Визуализация на историята на „%s“"
-#: git-gui.sh:2808 lib/database.tcl:40
msgid "Database Statistics"
msgstr "Статистика на базата от данни"
-#: git-gui.sh:2811 lib/database.tcl:33
msgid "Compress Database"
msgstr "Компресиране на базата от данни"
-#: git-gui.sh:2814
msgid "Verify Database"
msgstr "Проверка на базата от данни"
-#: git-gui.sh:2821 git-gui.sh:2825 git-gui.sh:2829
msgid "Create Desktop Icon"
msgstr "Добавяне на икона на работния плот"
-#: git-gui.sh:2837 lib/choose_repository.tcl:206 lib/choose_repository.tcl:214
msgid "Quit"
msgstr "Спиране на програмата"
-#: git-gui.sh:2845
msgid "Undo"
msgstr "Отмяна"
-#: git-gui.sh:2848
msgid "Redo"
msgstr "Повторение"
-#: git-gui.sh:2852 git-gui.sh:3477
msgid "Cut"
msgstr "Отрязване"
-#: git-gui.sh:2855 git-gui.sh:3480 git-gui.sh:3556 git-gui.sh:3651
-#: lib/console.tcl:69
msgid "Copy"
msgstr "Копиране"
-#: git-gui.sh:2858 git-gui.sh:3483
msgid "Paste"
msgstr "Поставяне"
-#: git-gui.sh:2861 git-gui.sh:3486 lib/branch_delete.tcl:28
-#: lib/remote_branch_delete.tcl:39
msgid "Delete"
msgstr "Изтриване"
-#: git-gui.sh:2865 git-gui.sh:3490 git-gui.sh:3655 lib/console.tcl:71
msgid "Select All"
msgstr "Избиране на всичко"
-#: git-gui.sh:2874
msgid "Create..."
msgstr "Създаване…"
-#: git-gui.sh:2880
msgid "Checkout..."
msgstr "Изтегляне…"
-#: git-gui.sh:2886
msgid "Rename..."
msgstr "Преименуване…"
-#: git-gui.sh:2891
msgid "Delete..."
msgstr "Изтриване…"
-#: git-gui.sh:2896
msgid "Reset..."
msgstr "Отмяна на промените…"
-#: git-gui.sh:2906
msgid "Done"
msgstr "Готово"
-#: git-gui.sh:2908
msgid "Commit@@verb"
msgstr "Подаване"
-#: git-gui.sh:2917 git-gui.sh:3416
msgid "Amend Last Commit"
msgstr "Поправяне на последното подаване"
-#: git-gui.sh:2927 git-gui.sh:3377 lib/remote_branch_delete.tcl:101
msgid "Rescan"
msgstr "Обновяване"
-#: git-gui.sh:2933
msgid "Stage To Commit"
msgstr "Към индекса за подаване"
-#: git-gui.sh:2939
msgid "Stage Changed Files To Commit"
msgstr "Всички променени файлове към индекса за подаване"
-#: git-gui.sh:2945
msgid "Unstage From Commit"
msgstr "Изваждане от индекса за подаване"
-#: git-gui.sh:2951 lib/index.tcl:521
msgid "Revert Changes"
msgstr "Връщане на оригинала"
-#: git-gui.sh:2959 git-gui.sh:3718 git-gui.sh:3749
msgid "Show Less Context"
msgstr "По-малко контекст"
-#: git-gui.sh:2963 git-gui.sh:3722 git-gui.sh:3753
msgid "Show More Context"
msgstr "Повече контекст"
-#: git-gui.sh:2970 git-gui.sh:3390 git-gui.sh:3501
msgid "Sign Off"
msgstr "Подписване"
-#: git-gui.sh:2986
msgid "Local Merge..."
msgstr "Локално сливане…"
-#: git-gui.sh:2991
msgid "Abort Merge..."
msgstr "Преустановяване на сливане…"
-#: git-gui.sh:3003 git-gui.sh:3031
msgid "Add..."
msgstr "Добавяне…"
-#: git-gui.sh:3007
msgid "Push..."
msgstr "Изтласкване…"
-#: git-gui.sh:3011
msgid "Delete Branch..."
msgstr "Изтриване на клон…"
-#: git-gui.sh:3021 git-gui.sh:3684
msgid "Options..."
msgstr "Опции…"
-#: git-gui.sh:3032
msgid "Remove..."
msgstr "Премахване…"
-#: git-gui.sh:3041 lib/choose_repository.tcl:67
msgid "Help"
msgstr "Помощ"
-#: git-gui.sh:3045 git-gui.sh:3049 lib/about.tcl:14
-#: lib/choose_repository.tcl:61 lib/choose_repository.tcl:70
#, tcl-format
msgid "About %s"
msgstr "Относно „%s“"
-#: git-gui.sh:3069
msgid "Online Documentation"
msgstr "Документация в Интернет"
-#: git-gui.sh:3072 lib/choose_repository.tcl:64 lib/choose_repository.tcl:73
msgid "Show SSH Key"
msgstr "Показване на ключа за SSH"
-#: git-gui.sh:3102 git-gui.sh:3234
msgid "usage:"
msgstr "употреба:"
-#: git-gui.sh:3106 git-gui.sh:3238
msgid "Usage"
msgstr "Употреба"
-#: git-gui.sh:3187 lib/blame.tcl:576
msgid "Error"
msgstr "Грешка"
-#: git-gui.sh:3218
#, tcl-format
msgid "fatal: cannot stat path %s: No such file or directory"
msgstr "ФАТАЛНА ГРЕШКА: пътят „%s“ липсва: такъв файл или директория няма"
-#: git-gui.sh:3251
msgid "Current Branch:"
msgstr "Текущ клон:"
-#: git-gui.sh:3276
msgid "Unstaged Changes"
msgstr "Промени извън индекса"
-#: git-gui.sh:3298
msgid "Staged Changes (Will Commit)"
msgstr "Промени в индекса (за подаване)"
-#: git-gui.sh:3383
msgid "Stage Changed"
msgstr "Индексът е променен"
-#: git-gui.sh:3402 lib/transport.tcl:137
msgid "Push"
msgstr "Изтласкване"
-#: git-gui.sh:3429
msgid "Initial Commit Message:"
msgstr "Първоначално съобщение при подаване:"
-#: git-gui.sh:3430
msgid "Amended Commit Message:"
msgstr "Поправено съобщение при подаване:"
-#: git-gui.sh:3431
msgid "Amended Initial Commit Message:"
msgstr "Поправено първоначално съобщение при подаване:"
-#: git-gui.sh:3432
msgid "Amended Merge Commit Message:"
msgstr "Поправено съобщение при подаване със сливане:"
-#: git-gui.sh:3433
msgid "Merge Commit Message:"
msgstr "Съобщение при подаване със сливане:"
-#: git-gui.sh:3434
msgid "Commit Message:"
msgstr "Съобщение при подаване:"
-#: git-gui.sh:3493 git-gui.sh:3659 lib/console.tcl:73
msgid "Copy All"
msgstr "Копиране на всичко"
-#: git-gui.sh:3517 lib/blame.tcl:106
msgid "File:"
msgstr "Файл:"
-#: git-gui.sh:3565 lib/choose_repository.tcl:1054
msgid "Open"
msgstr "Отваряне"
-#: git-gui.sh:3647
msgid "Refresh"
msgstr "Обновяване"
-#: git-gui.sh:3668
msgid "Decrease Font Size"
msgstr "По-дребен шрифт"
-#: git-gui.sh:3672
msgid "Increase Font Size"
msgstr "По-едър шрифт"
-#: git-gui.sh:3680 lib/blame.tcl:296
msgid "Encoding"
msgstr "Кодиране"
-#: git-gui.sh:3691
msgid "Apply/Reverse Hunk"
msgstr "Прилагане/връщане на парче"
-#: git-gui.sh:3696
msgid "Apply/Reverse Line"
msgstr "Прилагане/връщане на ред"
-#: git-gui.sh:3702 git-gui.sh:3812 git-gui.sh:3823
msgid "Revert Hunk"
msgstr "Връщане на парче"
-#: git-gui.sh:3707 git-gui.sh:3819 git-gui.sh:3830
msgid "Revert Line"
msgstr "Връщане на ред"
-#: git-gui.sh:3712 git-gui.sh:3809
msgid "Undo Last Revert"
msgstr "Отмяна на последното връщане"
-#: git-gui.sh:3731
msgid "Run Merge Tool"
msgstr "Изпълнение на програмата за сливане"
-#: git-gui.sh:3736
msgid "Use Remote Version"
msgstr "Версия от отдалеченото хранилище"
-#: git-gui.sh:3740
msgid "Use Local Version"
msgstr "Локална версия"
-#: git-gui.sh:3744
msgid "Revert To Base"
msgstr "Връщане към родителската версия"
-#: git-gui.sh:3762
msgid "Visualize These Changes In The Submodule"
msgstr "Визуализиране на промените в подмодула"
-#: git-gui.sh:3766
msgid "Visualize Current Branch History In The Submodule"
msgstr "Визуализация на историята на текущия клон в историята за подмодула"
-#: git-gui.sh:3770
msgid "Visualize All Branch History In The Submodule"
msgstr "Визуализация на историята на всички клони в историята за подмодула"
-#: git-gui.sh:3775
msgid "Start git gui In The Submodule"
msgstr "Стартиране на „git gui“ за подмодула"
-#: git-gui.sh:3811
msgid "Unstage Hunk From Commit"
msgstr "Изваждане на парчето от подаването"
-#: git-gui.sh:3815
msgid "Unstage Lines From Commit"
msgstr "Изваждане на редовете от подаването"
-#: git-gui.sh:3816 git-gui.sh:3827
msgid "Revert Lines"
msgstr "Връщане на редовете"
-#: git-gui.sh:3818
msgid "Unstage Line From Commit"
msgstr "Изваждане на реда от подаването"
-#: git-gui.sh:3822
msgid "Stage Hunk For Commit"
msgstr "Добавяне на парчето за подаване"
-#: git-gui.sh:3826
msgid "Stage Lines For Commit"
msgstr "Добавяне на редовете за подаване"
-#: git-gui.sh:3829
msgid "Stage Line For Commit"
msgstr "Добавяне на реда за подаване"
-#: git-gui.sh:3879
msgid "Initializing..."
msgstr "Инициализиране…"
-#: lib/about.tcl:26
msgid "git-gui - a graphical user interface for Git."
msgstr "git-gui — графичен интерфейс за Git."
-#: lib/blame.tcl:74
#, tcl-format
msgid "%s (%s): File Viewer"
msgstr "%s (%s): Преглед на файлове"
-#: lib/blame.tcl:80
msgid "Commit:"
msgstr "Подаване:"
-#: lib/blame.tcl:282
msgid "Copy Commit"
msgstr "Копиране на подаване"
-#: lib/blame.tcl:286
msgid "Find Text..."
msgstr "Търсене на текст…"
-#: lib/blame.tcl:290
msgid "Goto Line..."
msgstr "Към ред…"
-#: lib/blame.tcl:299
msgid "Do Full Copy Detection"
msgstr "Пълно търсене на копиране"
-#: lib/blame.tcl:303
msgid "Show History Context"
msgstr "Показване на контекста от историята"
-#: lib/blame.tcl:306
msgid "Blame Parent Commit"
msgstr "Анотиране на родителското подаване"
-#: lib/blame.tcl:469
#, tcl-format
msgid "Reading %s..."
msgstr "Чете се „%s“…"
-#: lib/blame.tcl:597
msgid "Loading copy/move tracking annotations..."
msgstr "Зареждане на анотациите за проследяване на копирането/преместването…"
-#: lib/blame.tcl:614
msgid "lines annotated"
msgstr "реда анотирани"
-#: lib/blame.tcl:816
msgid "Loading original location annotations..."
msgstr "Зареждане на анотациите за първоначалното местоположение…"
-#: lib/blame.tcl:819
msgid "Annotation complete."
msgstr "Анотирането завърши."
-#: lib/blame.tcl:850
msgid "Busy"
msgstr "Операцията не е завършила"
-#: lib/blame.tcl:851
msgid "Annotation process is already running."
msgstr "В момента тече процес на анотиране."
-#: lib/blame.tcl:890
msgid "Running thorough copy detection..."
msgstr "Изпълнява се цялостен процес на откриване на копиране…"
-#: lib/blame.tcl:958
msgid "Loading annotation..."
msgstr "Зареждане на анотации…"
-#: lib/blame.tcl:1011
msgid "Author:"
msgstr "Автор:"
-#: lib/blame.tcl:1015
msgid "Committer:"
msgstr "Подал:"
-#: lib/blame.tcl:1020
msgid "Original File:"
msgstr "Първоначален файл:"
-#: lib/blame.tcl:1068
msgid "Cannot find HEAD commit:"
msgstr "Подаването за връх „HEAD“ не може да се открие:"
-#: lib/blame.tcl:1123
msgid "Cannot find parent commit:"
msgstr "Родителското подаване не може да се открие"
-#: lib/blame.tcl:1138
msgid "Unable to display parent"
msgstr "Родителят не може да се покаже"
-#: lib/blame.tcl:1139 lib/diff.tcl:334
msgid "Error loading diff:"
msgstr "Грешка при зареждане на разлика:"
-#: lib/blame.tcl:1280
msgid "Originally By:"
msgstr "Първоначално от:"
-#: lib/blame.tcl:1286
msgid "In File:"
msgstr "Във файл:"
-#: lib/blame.tcl:1291
msgid "Copied Or Moved Here By:"
msgstr "Копирано или преместено тук от:"
-#: lib/branch_checkout.tcl:16
#, tcl-format
msgid "%s (%s): Checkout Branch"
msgstr "%s (%s): Клон за изтегляне"
-#: lib/branch_checkout.tcl:21
msgid "Checkout Branch"
msgstr "Клон за изтегляне"
-#: lib/branch_checkout.tcl:26
msgid "Checkout"
msgstr "Изтегляне"
-#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 lib/branch_delete.tcl:34
-#: lib/branch_rename.tcl:32 lib/browser.tcl:292 lib/checkout_op.tcl:580
-#: lib/choose_font.tcl:45 lib/merge.tcl:178 lib/option.tcl:127
-#: lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 lib/tools_dlg.tcl:41
-#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/transport.tcl:141
msgid "Cancel"
msgstr "Отказване"
-#: lib/branch_checkout.tcl:35 lib/browser.tcl:297 lib/tools_dlg.tcl:321
msgid "Revision"
msgstr "Версия"
-#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:310
msgid "Options"
msgstr "Опции"
-#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92
msgid "Fetch Tracking Branch"
msgstr "Изтегляне на промените от следения клон"
-#: lib/branch_checkout.tcl:47
msgid "Detach From Local Branch"
msgstr "Изтриване от локалния клон"
-#: lib/branch_create.tcl:23
#, tcl-format
msgid "%s (%s): Create Branch"
msgstr "%s (%s): Създаване на клон"
-#: lib/branch_create.tcl:28
msgid "Create New Branch"
msgstr "Създаване на нов клон"
-#: lib/branch_create.tcl:33 lib/choose_repository.tcl:386
msgid "Create"
msgstr "Създаване"
-#: lib/branch_create.tcl:42
msgid "Branch Name"
msgstr "Име на клона"
-#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51
msgid "Name:"
msgstr "Име:"
-#: lib/branch_create.tcl:57
msgid "Match Tracking Branch Name"
msgstr "Съвпадане по името на следения клон"
-#: lib/branch_create.tcl:66
msgid "Starting Revision"
msgstr "Начална версия"
-#: lib/branch_create.tcl:72
msgid "Update Existing Branch:"
msgstr "Обновяване на съществуващ клон:"
-#: lib/branch_create.tcl:75
msgid "No"
msgstr "Не"
-#: lib/branch_create.tcl:80
msgid "Fast Forward Only"
msgstr "Само тривиално превъртащо сливане"
-#: lib/branch_create.tcl:85 lib/checkout_op.tcl:572
msgid "Reset"
msgstr "Отначало"
-#: lib/branch_create.tcl:97
msgid "Checkout After Creation"
msgstr "Преминаване към клона след създаването му"
-#: lib/branch_create.tcl:132
msgid "Please select a tracking branch."
msgstr "Изберете клон за следени."
-#: lib/branch_create.tcl:141
#, tcl-format
msgid "Tracking branch %s is not a branch in the remote repository."
msgstr "Следящият клон — „%s“, не съществува в отдалеченото хранилище."
-#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92
msgid "Please supply a branch name."
msgstr "Дайте име на клона."
-#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112
#, tcl-format
msgid "'%s' is not an acceptable branch name."
msgstr "„%s“ не може да се използва за име на клон."
-#: lib/branch_delete.tcl:16
#, tcl-format
msgid "%s (%s): Delete Branch"
msgstr "%s (%s): Изтриване на клон"
-#: lib/branch_delete.tcl:21
msgid "Delete Local Branch"
msgstr "Изтриване на локален клон"
-#: lib/branch_delete.tcl:39
msgid "Local Branches"
msgstr "Локални клони"
-#: lib/branch_delete.tcl:51
msgid "Delete Only If Merged Into"
msgstr "Изтриване, само ако промените са слети и другаде"
-#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120
msgid "Always (Do not perform merge checks)"
msgstr "Винаги (без проверка за сливане)"
-#: lib/branch_delete.tcl:103
#, tcl-format
msgid "The following branches are not completely merged into %s:"
msgstr "Не всички промени в клоните са слети в „%s“:"
-#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218
msgid ""
"Recovering deleted branches is difficult.\n"
"\n"
@@ -832,12 +620,10 @@ msgstr ""
"\n"
"Сигурни ли сте, че искате да триете?"
-#: lib/branch_delete.tcl:131
#, tcl-format
msgid " - %s:"
msgstr " — „%s:“"
-#: lib/branch_delete.tcl:141
#, tcl-format
msgid ""
"Failed to delete branches:\n"
@@ -846,100 +632,76 @@ msgstr ""
"Неуспешно триене на клони:\n"
"%s"
-#: lib/branch_rename.tcl:15
#, tcl-format
msgid "%s (%s): Rename Branch"
msgstr "%s (%s): Преименуване на клон"
-#: lib/branch_rename.tcl:23
msgid "Rename Branch"
msgstr "Преименуване на клон"
-#: lib/branch_rename.tcl:28
msgid "Rename"
msgstr "Преименуване"
-#: lib/branch_rename.tcl:38
msgid "Branch:"
msgstr "Клон:"
-#: lib/branch_rename.tcl:46
msgid "New Name:"
msgstr "Ново име:"
-#: lib/branch_rename.tcl:81
msgid "Please select a branch to rename."
msgstr "Изберете клон за преименуване."
-#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202
#, tcl-format
msgid "Branch '%s' already exists."
msgstr "Клонът „%s“ вече съществува."
-#: lib/branch_rename.tcl:123
#, tcl-format
msgid "Failed to rename '%s'."
msgstr "Неуспешно преименуване на „%s“."
-#: lib/browser.tcl:17
msgid "Starting..."
msgstr "Стартиране…"
-#: lib/browser.tcl:27
#, tcl-format
msgid "%s (%s): File Browser"
msgstr "%s (%s): Файлов браузър"
-#: lib/browser.tcl:132 lib/browser.tcl:149
#, tcl-format
msgid "Loading %s..."
msgstr "Зареждане на „%s“…"
-#: lib/browser.tcl:193
msgid "[Up To Parent]"
msgstr "[Към родителя]"
-#: lib/browser.tcl:275
#, tcl-format
msgid "%s (%s): Browse Branch Files"
msgstr "%s (%s): Разглеждане на файловете в клона"
-#: lib/browser.tcl:282
msgid "Browse Branch Files"
msgstr "Разглеждане на файловете в клона"
-#: lib/browser.tcl:288 lib/choose_repository.tcl:401
-#: lib/choose_repository.tcl:488 lib/choose_repository.tcl:497
-#: lib/choose_repository.tcl:1069
msgid "Browse"
msgstr "Разглеждане"
-#: lib/checkout_op.tcl:85
#, tcl-format
msgid "Fetching %s from %s"
msgstr "Доставяне на „%s“ от „%s“"
-#: lib/checkout_op.tcl:133
#, tcl-format
msgid "fatal: Cannot resolve %s"
msgstr "фатална грешка: „%s“ не може да се открие"
-#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30
-#: lib/sshkey.tcl:58
msgid "Close"
msgstr "Затваряне"
-#: lib/checkout_op.tcl:175
#, tcl-format
msgid "Branch '%s' does not exist."
msgstr "Клонът „%s“ не съществува."
-#: lib/checkout_op.tcl:194
#, tcl-format
msgid "Failed to configure simplified git-pull for '%s'."
msgstr "Неуспешно настройване на опростен git-pull за „%s“."
-#: lib/checkout_op.tcl:229
#, tcl-format
msgid ""
"Branch '%s' already exists.\n"
@@ -952,21 +714,17 @@ msgstr ""
"Той не може да се слее тривиално до „%s“.\n"
"Необходимо е сливане."
-#: lib/checkout_op.tcl:243
#, tcl-format
msgid "Merge strategy '%s' not supported."
msgstr "Стратегия за сливане „%s“ не се поддържа."
-#: lib/checkout_op.tcl:262
#, tcl-format
msgid "Failed to update '%s'."
msgstr "Неуспешно обновяване на „%s“."
-#: lib/checkout_op.tcl:274
msgid "Staging area (index) is already locked."
msgstr "Индексът вече е заключен."
-#: lib/checkout_op.tcl:289
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
@@ -983,31 +741,25 @@ msgstr ""
"\n"
"Автоматично ще започне нова проверка.\n"
-#: lib/checkout_op.tcl:345
#, tcl-format
msgid "Updating working directory to '%s'..."
msgstr "Работната директория се привежда към „%s“…"
-#: lib/checkout_op.tcl:346
msgid "files checked out"
msgstr "файла са изтеглени"
-#: lib/checkout_op.tcl:377
#, tcl-format
msgid "Aborted checkout of '%s' (file level merging is required)."
msgstr ""
"Преустановяване на изтеглянето на „%s“ (необходимо е пофайлово сливане)."
-#: lib/checkout_op.tcl:378
msgid "File level merge required."
msgstr "Необходимо е пофайлово сливане."
-#: lib/checkout_op.tcl:382
#, tcl-format
msgid "Staying on branch '%s'."
msgstr "Оставане върху клона „%s“."
-#: lib/checkout_op.tcl:453
msgid ""
"You are no longer on a local branch.\n"
"\n"
@@ -1018,31 +770,25 @@ msgstr ""
"\n"
"Ако искате да сте на клон, създайте базиран на „Това несвързано изтегляне“."
-#: lib/checkout_op.tcl:504 lib/checkout_op.tcl:508
#, tcl-format
msgid "Checked out '%s'."
msgstr "„%s“ е изтеглен."
-#: lib/checkout_op.tcl:536
#, tcl-format
msgid "Resetting '%s' to '%s' will lose the following commits:"
msgstr ""
"Зануляването на „%s“ към „%s“ ще доведе до загубването на следните подавания:"
-#: lib/checkout_op.tcl:558
msgid "Recovering lost commits may not be easy."
msgstr "Възстановяването на загубените подавания може да е трудно."
-#: lib/checkout_op.tcl:563
#, tcl-format
msgid "Reset '%s'?"
msgstr "Зануляване на „%s“?"
-#: lib/checkout_op.tcl:568 lib/merge.tcl:170 lib/tools_dlg.tcl:336
msgid "Visualize"
msgstr "Визуализация"
-#: lib/checkout_op.tcl:636
#, tcl-format
msgid ""
"Failed to set current branch.\n"
@@ -1060,23 +806,18 @@ msgstr ""
"Това състояние е аварийно и не трябва да се случва. Програмата „%s“ ще "
"преустанови работа."
-#: lib/choose_font.tcl:41
msgid "Select"
msgstr "Избор"
-#: lib/choose_font.tcl:55
msgid "Font Family"
msgstr "Шрифт"
-#: lib/choose_font.tcl:76
msgid "Font Size"
msgstr "Размер"
-#: lib/choose_font.tcl:93
msgid "Font Example"
msgstr "Мостра"
-#: lib/choose_font.tcl:105
msgid ""
"This is example text.\n"
"If you like this text, it can be your font."
@@ -1084,289 +825,137 @@ msgstr ""
"Това е примерен текст.\n"
"Ако ви харесва как изглежда, изберете шрифта."
-#: lib/choose_repository.tcl:45
msgid "Git Gui"
msgstr "ГПИ на Git"
-#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:391
msgid "Create New Repository"
msgstr "Създаване на ново хранилище"
-#: lib/choose_repository.tcl:110
msgid "New..."
msgstr "Ново…"
-#: lib/choose_repository.tcl:117 lib/choose_repository.tcl:475
msgid "Clone Existing Repository"
msgstr "Клониране на съществуващо хранилище"
-#: lib/choose_repository.tcl:128
msgid "Clone..."
msgstr "Клониране…"
-#: lib/choose_repository.tcl:135 lib/choose_repository.tcl:1059
msgid "Open Existing Repository"
msgstr "Отваряне на съществуващо хранилище"
-#: lib/choose_repository.tcl:141
msgid "Open..."
msgstr "Отваряне…"
-#: lib/choose_repository.tcl:154
msgid "Recent Repositories"
msgstr "Скоро ползвани"
-#: lib/choose_repository.tcl:164
msgid "Open Recent Repository:"
msgstr "Отваряне на хранилище ползвано наскоро:"
-#: lib/choose_repository.tcl:328 lib/choose_repository.tcl:335
-#: lib/choose_repository.tcl:342
#, tcl-format
msgid "Failed to create repository %s:"
msgstr "Неуспешно създаване на хранилището „%s“:"
-#: lib/choose_repository.tcl:396
msgid "Directory:"
msgstr "Директория:"
-#: lib/choose_repository.tcl:426 lib/choose_repository.tcl:552
-#: lib/choose_repository.tcl:1093
msgid "Git Repository"
msgstr "Хранилище на Git"
-#: lib/choose_repository.tcl:451
#, tcl-format
msgid "Directory %s already exists."
msgstr "Вече съществува директория „%s“."
-#: lib/choose_repository.tcl:455
#, tcl-format
msgid "File %s already exists."
msgstr "Вече съществува файл „%s“."
-#: lib/choose_repository.tcl:470
msgid "Clone"
msgstr "Клониране"
-#: lib/choose_repository.tcl:483
msgid "Source Location:"
msgstr "Адрес на източника:"
-#: lib/choose_repository.tcl:492
msgid "Target Directory:"
msgstr "Целева директория:"
-#: lib/choose_repository.tcl:502
msgid "Clone Type:"
msgstr "Вид клониране:"
-#: lib/choose_repository.tcl:507
msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
msgstr "Стандартно (бързо, частично споделяне на файлове, твърди връзки)"
-#: lib/choose_repository.tcl:512
msgid "Full Copy (Slower, Redundant Backup)"
msgstr "Пълно (бавно, пълноценно резервно копие)"
-#: lib/choose_repository.tcl:517
msgid "Shared (Fastest, Not Recommended, No Backup)"
msgstr "Споделено (най-бързо, не се препоръчва, не прави резервно копие)"
-#: lib/choose_repository.tcl:524
msgid "Recursively clone submodules too"
msgstr "Рекурсивно клониране и на подмодулите"
-#: lib/choose_repository.tcl:558 lib/choose_repository.tcl:605
-#: lib/choose_repository.tcl:744 lib/choose_repository.tcl:818
-#: lib/choose_repository.tcl:1099 lib/choose_repository.tcl:1107
#, tcl-format
msgid "Not a Git repository: %s"
msgstr "Това не е хранилище на Git: %s"
-#: lib/choose_repository.tcl:594
+msgid "Hardlinks are unavailable. Falling back to copying."
+msgstr "Не се поддържат твърди връзки. Преминава се към копиране."
+
msgid "Standard only available for local repository."
msgstr "Само локални хранилища може да се клонират стандартно"
-#: lib/choose_repository.tcl:598
msgid "Shared only available for local repository."
msgstr "Само локални хранилища може да се клонират споделено"
-#: lib/choose_repository.tcl:613
#, tcl-format
msgid "Location %s already exists."
msgstr "Местоположението „%s“ вече съществува."
-#: lib/choose_repository.tcl:624
-msgid "Failed to configure origin"
-msgstr "Неуспешно настройване на хранилището-източник"
-
-#: lib/choose_repository.tcl:636
-msgid "Counting objects"
-msgstr "Преброяване на обекти"
-
-#: lib/choose_repository.tcl:637
-msgid "buckets"
-msgstr "клетки"
-
-#: lib/choose_repository.tcl:657
-#, tcl-format
-msgid "Unable to copy objects/info/alternates: %s"
-msgstr "Обектите/Информацията/Синонимите не може да се копират: %s"
-
-#: lib/choose_repository.tcl:694
-#, tcl-format
-msgid "Nothing to clone from %s."
-msgstr "Няма какво да се клонира от „%s“."
-
-#: lib/choose_repository.tcl:696 lib/choose_repository.tcl:916
-#: lib/choose_repository.tcl:928
-msgid "The 'master' branch has not been initialized."
-msgstr "Основният клон — „master“ не е инициализиран."
-
-#: lib/choose_repository.tcl:709
-msgid "Hardlinks are unavailable. Falling back to copying."
-msgstr "Не се поддържат твърди връзки. Преминава се към копиране."
-
-#: lib/choose_repository.tcl:723
#, tcl-format
msgid "Cloning from %s"
msgstr "Клониране на „%s“"
-#: lib/choose_repository.tcl:754
-msgid "Copying objects"
-msgstr "Копиране на обекти"
-
-#: lib/choose_repository.tcl:755
-msgid "KiB"
-msgstr "KiB"
-
-#: lib/choose_repository.tcl:779
-#, tcl-format
-msgid "Unable to copy object: %s"
-msgstr "Неуспешно копиране на обект: %s"
-
-#: lib/choose_repository.tcl:791
-msgid "Linking objects"
-msgstr "Създаване на връзки към обектите"
-
-#: lib/choose_repository.tcl:792
-msgid "objects"
-msgstr "обекти"
-
-#: lib/choose_repository.tcl:800
-#, tcl-format
-msgid "Unable to hardlink object: %s"
-msgstr "Неуспешно създаване на твърда връзка към обект: %s"
-
-#: lib/choose_repository.tcl:857
-msgid "Cannot fetch branches and objects. See console output for details."
-msgstr ""
-"Клоните и обектите не може да се изтеглят. За повече информация погледнете "
-"изхода на конзолата."
-
-#: lib/choose_repository.tcl:868
-msgid "Cannot fetch tags. See console output for details."
-msgstr ""
-"Етикетите не може да се изтеглят. За повече информация погледнете изхода на "
-"конзолата."
-
-#: lib/choose_repository.tcl:892
-msgid "Cannot determine HEAD. See console output for details."
-msgstr ""
-"Върхът „HEAD“ не може да се определи. За повече информация погледнете изхода "
-"на конзолата."
-
-#: lib/choose_repository.tcl:901
-#, tcl-format
-msgid "Unable to cleanup %s"
-msgstr "„%s“ не може да се изчисти"
-
-#: lib/choose_repository.tcl:907
msgid "Clone failed."
msgstr "Неуспешно клониране."
-#: lib/choose_repository.tcl:914
-msgid "No default branch obtained."
-msgstr "Не е получен клон по подразбиране."
-
-#: lib/choose_repository.tcl:925
-#, tcl-format
-msgid "Cannot resolve %s as a commit."
-msgstr "Няма подаване отговарящо на „%s“."
-
-#: lib/choose_repository.tcl:952
-msgid "Creating working directory"
-msgstr "Създаване на работната директория"
-
-#: lib/choose_repository.tcl:953 lib/index.tcl:77 lib/index.tcl:146
-#: lib/index.tcl:220 lib/index.tcl:589
-msgid "files"
-msgstr "файлове"
-
-#: lib/choose_repository.tcl:982
-msgid "Initial file checkout failed."
-msgstr "Неуспешно първоначално изтегляне."
-
-#: lib/choose_repository.tcl:1026
-msgid "Cloning submodules"
-msgstr "Клониране на подмодули"
-
-#: lib/choose_repository.tcl:1041
-msgid "Cannot clone submodules."
-msgstr "Подмодулите не може да се клонират."
-
-#: lib/choose_repository.tcl:1064
msgid "Repository:"
msgstr "Хранилище:"
-#: lib/choose_repository.tcl:1113
#, tcl-format
msgid "Failed to open repository %s:"
msgstr "Неуспешно отваряне на хранилището „%s“:"
-#: lib/choose_rev.tcl:52
msgid "This Detached Checkout"
msgstr "Това несвързано изтегляне"
-#: lib/choose_rev.tcl:60
msgid "Revision Expression:"
msgstr "Израз за версия:"
-#: lib/choose_rev.tcl:72
msgid "Local Branch"
msgstr "Локален клон"
-#: lib/choose_rev.tcl:77
msgid "Tracking Branch"
msgstr "Следящ клон"
-#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544
msgid "Tag"
msgstr "Етикет"
-#: lib/choose_rev.tcl:321
#, tcl-format
msgid "Invalid revision: %s"
msgstr "Неправилна версия: %s"
-#: lib/choose_rev.tcl:342
msgid "No revision selected."
msgstr "Не е избрана версия."
-#: lib/choose_rev.tcl:350
msgid "Revision expression is empty."
msgstr "Изразът за версия е празен."
-#: lib/choose_rev.tcl:537
msgid "Updated"
msgstr "Обновен"
-#: lib/choose_rev.tcl:565
msgid "URL"
msgstr "Адрес"
-#: lib/commit.tcl:9
msgid ""
"There is nothing to amend.\n"
"\n"
@@ -1378,7 +967,6 @@ msgstr ""
"Ще създадете първоначалното подаване. Преди него няма други подавания, които "
"да поправите.\n"
-#: lib/commit.tcl:18
msgid ""
"Cannot amend while merging.\n"
"\n"
@@ -1391,24 +979,19 @@ msgstr ""
"В момента все още не сте завършили операция по сливане. Не може да поправите "
"предишното подаване, освен ако първо не преустановите текущото сливане.\n"
-#: lib/commit.tcl:56
msgid "Error loading commit data for amend:"
msgstr "Грешка при зареждане на данните от подаване, които да се поправят:"
-#: lib/commit.tcl:83
msgid "Unable to obtain your identity:"
msgstr "Идентификацията ви не може да се определи:"
-#: lib/commit.tcl:88
msgid "Invalid GIT_COMMITTER_IDENT:"
msgstr "Неправилно поле „GIT_COMMITTER_IDENT“:"
-#: lib/commit.tcl:138
#, tcl-format
msgid "warning: Tcl does not support encoding '%s'."
msgstr "предупреждение: Tcl не поддържа кодирането „%s“."
-#: lib/commit.tcl:158
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
@@ -1425,7 +1008,6 @@ msgstr ""
"\n"
"Автоматично ще започне нова проверка.\n"
-#: lib/commit.tcl:182
#, tcl-format
msgid ""
"Unmerged files cannot be committed.\n"
@@ -1438,7 +1020,6 @@ msgstr ""
"Във файла „%s“ има конфликти при сливане. За да го подадете, трябва първо да "
"коригирате конфликтите и да добавите файла към индекса за подаване.\n"
-#: lib/commit.tcl:190
#, tcl-format
msgid ""
"Unknown file state %s detected.\n"
@@ -1449,7 +1030,6 @@ msgstr ""
"\n"
"Файлът „%s“ не може да се подаде чрез текущата програма.\n"
-#: lib/commit.tcl:198
msgid ""
"No changes to commit.\n"
"\n"
@@ -1459,7 +1039,6 @@ msgstr ""
"\n"
"Трябва да добавите поне един файл към индекса, за да подадете.\n"
-#: lib/commit.tcl:224
msgid ""
"Please supply a commit message.\n"
"\n"
@@ -1477,15 +1056,12 @@ msgstr ""
"● Втори ред: празен.\n"
"● Останалите редове: опишете защо се налага тази промяна.\n"
-#: lib/commit.tcl:255
msgid "Calling pre-commit hook..."
msgstr "Изпълняване на куката преди подаване…"
-#: lib/commit.tcl:270
msgid "Commit declined by pre-commit hook."
msgstr "Подаването е отхвърлено от куката преди подаване."
-#: lib/commit.tcl:289
msgid ""
"You are about to commit on a detached head. This is a potentially dangerous "
"thing to do because if you switch to another branch you will lose your "
@@ -1501,32 +1077,25 @@ msgstr ""
" \n"
"Сигурни ли сте, че искате да извършите текущото подаване?"
-#: lib/commit.tcl:310
msgid "Calling commit-msg hook..."
msgstr "Изпълняване на куката за съобщението при подаване…"
-#: lib/commit.tcl:325
msgid "Commit declined by commit-msg hook."
msgstr "Подаването е отхвърлено от куката за съобщението при подаване."
-#: lib/commit.tcl:338
msgid "Committing changes..."
msgstr "Подаване на промените…"
-#: lib/commit.tcl:355
msgid "write-tree failed:"
msgstr "неуспешно запазване на дървото (write-tree):"
-#: lib/commit.tcl:356 lib/commit.tcl:406 lib/commit.tcl:433
msgid "Commit failed."
msgstr "Неуспешно подаване."
-#: lib/commit.tcl:373
#, tcl-format
msgid "Commit %s appears to be corrupt"
msgstr "Подаването „%s“ изглежда повредено"
-#: lib/commit.tcl:378
msgid ""
"No changes to commit.\n"
"\n"
@@ -1541,83 +1110,63 @@ msgstr ""
"\n"
"Автоматично ще започне нова проверка.\n"
-#: lib/commit.tcl:385
msgid "No changes to commit."
msgstr "Няма промени за подаване."
-#: lib/commit.tcl:405
msgid "commit-tree failed:"
msgstr "неуспешно подаване на дървото (commit-tree):"
-#: lib/commit.tcl:432
msgid "update-ref failed:"
msgstr "неуспешно обновяване на указателите (update-ref):"
-#: lib/commit.tcl:526
#, tcl-format
msgid "Created commit %s: %s"
msgstr "Успешно подаване %s: %s"
-#: lib/console.tcl:59
msgid "Working... please wait..."
msgstr "В момента се извършва действие, изчакайте…"
-#: lib/console.tcl:186
msgid "Success"
msgstr "Успех"
-#: lib/console.tcl:200
msgid "Error: Command Failed"
msgstr "Грешка: неуспешно изпълнение на команда"
-#: lib/database.tcl:42
msgid "Number of loose objects"
msgstr "Брой непакетирани обекти"
-#: lib/database.tcl:43
msgid "Disk space used by loose objects"
msgstr "Дисково пространство заето от непакетирани обекти"
-#: lib/database.tcl:44
msgid "Number of packed objects"
msgstr "Брой пакетирани обекти"
-#: lib/database.tcl:45
msgid "Number of packs"
msgstr "Брой пакети"
-#: lib/database.tcl:46
msgid "Disk space used by packed objects"
msgstr "Дисково пространство заето от пакетирани обекти"
-#: lib/database.tcl:47
msgid "Packed objects waiting for pruning"
msgstr "Пакетирани обекти за окастряне"
-#: lib/database.tcl:48
msgid "Garbage files"
msgstr "Файлове за боклука"
-#: lib/database.tcl:57 lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220
-#: lib/option.tcl:282
#, tcl-format
msgid "%s:"
msgstr "%s:"
-#: lib/database.tcl:66
#, tcl-format
msgid "%s (%s): Database Statistics"
msgstr "%s (%s): Статистика на базата от данни"
-#: lib/database.tcl:72
msgid "Compressing the object database"
msgstr "Компресиране на базата с данни за обектите"
-#: lib/database.tcl:83
msgid "Verifying the object database with fsck-objects"
msgstr "Проверка на базата с данни за обектите с програмата „fsck-objects“"
-#: lib/database.tcl:107
#, tcl-format
msgid ""
"This repository currently has approximately %i loose objects.\n"
@@ -1634,12 +1183,10 @@ msgstr ""
"\n"
"Да се започне ли компресирането?"
-#: lib/date.tcl:25
#, tcl-format
msgid "Invalid date from Git: %s"
msgstr "Неправилни данни от Git: %s"
-#: lib/diff.tcl:74
msgid ""
"* No differences detected; stage the file to de-list it from Unstaged "
"Changes.\n"
@@ -1647,16 +1194,13 @@ msgstr ""
"● Няма разлики. Добавете файла към индекса, за да се извади от промените "
"извън индекса.\n"
-#: lib/diff.tcl:75
msgid "* Click to find other files that may have the same state.\n"
msgstr "● Натиснете, за да потърсите други файлове в това състояние.\n"
-#: lib/diff.tcl:106
#, tcl-format
msgid "Loading diff of %s..."
msgstr "Зареждане на разликите в „%s“…"
-#: lib/diff.tcl:132
msgid ""
"LOCAL: deleted\n"
"REMOTE:\n"
@@ -1664,7 +1208,6 @@ msgstr ""
"ЛОКАЛНО: изтрит\n"
"ОТДАЛЕЧЕНО:\n"
-#: lib/diff.tcl:137
msgid ""
"REMOTE: deleted\n"
"LOCAL:\n"
@@ -1672,32 +1215,25 @@ msgstr ""
"ОТДАЛЕЧЕНО: изтрит\n"
"ЛОКАЛНО:\n"
-#: lib/diff.tcl:144
msgid "LOCAL:\n"
msgstr "ЛОКАЛНО:\n"
-#: lib/diff.tcl:147
msgid "REMOTE:\n"
msgstr "ОТДАЛЕЧЕНО:\n"
-#: lib/diff.tcl:209 lib/diff.tcl:333
#, tcl-format
msgid "Unable to display %s"
msgstr "Файлът „%s“ не може да се покаже"
-#: lib/diff.tcl:210
msgid "Error loading file:"
msgstr "Грешка при зареждане на файл:"
-#: lib/diff.tcl:216
msgid "Git Repository (subproject)"
msgstr "Хранилище на Git (подмодул)"
-#: lib/diff.tcl:228
msgid "* Binary file (not showing content)."
msgstr "● Двоичен файл (съдържанието не се показва)."
-#: lib/diff.tcl:233
#, tcl-format
msgid ""
"* Untracked file is %d bytes.\n"
@@ -1706,7 +1242,6 @@ msgstr ""
"● Неследеният файл е %d байта.\n"
"● Показват се само първите %d байта.\n"
-#: lib/diff.tcl:239
#, tcl-format
msgid ""
"\n"
@@ -1717,80 +1252,62 @@ msgstr ""
"● Неследеният файл е отрязан дотук от програмата „%s“.\n"
"● Използвайте външен редактор, за да видите целия файл.\n"
-#: lib/diff.tcl:569
msgid "Failed to unstage selected hunk."
msgstr "Избраното парче не може да се извади от индекса."
-#: lib/diff.tcl:577
msgid "Failed to revert selected hunk."
msgstr "Избраното парче не може да се върне."
-#: lib/diff.tcl:580
msgid "Failed to stage selected hunk."
msgstr "Избраното парче не може да се добави към индекса."
-#: lib/diff.tcl:673
msgid "Failed to unstage selected line."
msgstr "Избраният ред не може да се извади от индекса."
-#: lib/diff.tcl:682
msgid "Failed to revert selected line."
msgstr "Избраният ред не може да се върне."
-#: lib/diff.tcl:686
msgid "Failed to stage selected line."
msgstr "Избраният ред не може да се добави към индекса."
-#: lib/diff.tcl:875
msgid "Failed to undo last revert."
msgstr "Неуспешна отмяна на последното връщане."
-#: lib/encoding.tcl:443
msgid "Default"
msgstr "Стандартното"
-#: lib/encoding.tcl:448
#, tcl-format
msgid "System (%s)"
msgstr "Системното (%s)"
-#: lib/encoding.tcl:459 lib/encoding.tcl:465
msgid "Other"
msgstr "Друго"
-#: lib/error.tcl:20
#, tcl-format
msgid "%s: error"
msgstr "%s: грешка"
-#: lib/error.tcl:36
#, tcl-format
msgid "%s: warning"
msgstr "%s: предупреждение"
-#: lib/error.tcl:80
#, tcl-format
msgid "%s hook failed:"
msgstr "%s: грешка от куката"
-#: lib/error.tcl:96
msgid "You must correct the above errors before committing."
msgstr "Преди да можете да подадете, коригирайте горните грешки."
-#: lib/error.tcl:116
#, tcl-format
msgid "%s (%s): error"
msgstr "%s (%s): грешка"
-#: lib/index.tcl:6
msgid "Unable to unlock the index."
msgstr "Индексът не може да се отключи."
-#: lib/index.tcl:30
msgid "Index Error"
msgstr "Грешка в индекса"
-#: lib/index.tcl:32
msgid ""
"Updating the Git index failed. A rescan will be automatically started to "
"resynchronize git-gui."
@@ -1798,119 +1315,96 @@ msgstr ""
"Неуспешно обновяване на индекса на Git. Автоматично ще започне нова проверка "
"за синхронизирането на git-gui."
-#: lib/index.tcl:43
msgid "Continue"
msgstr "Продължаване"
-#: lib/index.tcl:46
msgid "Unlock Index"
msgstr "Отключване на индекса"
-#: lib/index.tcl:326
+msgid "files"
+msgstr "файлове"
+
msgid "Unstaging selected files from commit"
msgstr "Изваждане на избраните файлове от подаването"
-#: lib/index.tcl:330
#, tcl-format
msgid "Unstaging %s from commit"
msgstr "Изваждане на „%s“ от подаването"
-#: lib/index.tcl:369
msgid "Ready to commit."
msgstr "Готовност за подаване."
-#: lib/index.tcl:378
msgid "Adding selected files"
msgstr "Добавяне на избраните файлове"
-#: lib/index.tcl:382
#, tcl-format
msgid "Adding %s"
msgstr "Добавяне на „%s“"
-#: lib/index.tcl:412
#, tcl-format
msgid "Stage %d untracked files?"
msgstr "Да се добавят ли %d неследени файла към индекса?"
-#: lib/index.tcl:420
msgid "Adding all changed files"
msgstr "Добавяне на всички променени файлове"
-#: lib/index.tcl:503
#, tcl-format
msgid "Revert changes in file %s?"
msgstr "Да се махнат ли промените във файла „%s“?"
-#: lib/index.tcl:508
#, tcl-format
msgid "Revert changes in these %i files?"
msgstr "Да се махнат ли промените в тези %i файла?"
-#: lib/index.tcl:517
msgid "Any unstaged changes will be permanently lost by the revert."
msgstr ""
"Всички промени, които не са били добавени в индекса, ще се загубят "
"безвъзвратно."
-#: lib/index.tcl:520 lib/index.tcl:564
msgid "Do Nothing"
msgstr "Нищо да не се прави"
-#: lib/index.tcl:546
#, tcl-format
msgid "Delete untracked file %s?"
msgstr "Да се изтрие ли неследеният файл „%s“?"
-#: lib/index.tcl:551
#, tcl-format
msgid "Delete these %i untracked files?"
msgstr "Да се изтрият ли тези %d неследени файла?"
-#: lib/index.tcl:561
msgid "Files will be permanently deleted."
msgstr "Файловете ще се изтрият окончателно."
-#: lib/index.tcl:565
msgid "Delete Files"
msgstr "Изтриване на файлове"
-#: lib/index.tcl:588
msgid "Deleting"
msgstr "Изтриване"
-#: lib/index.tcl:667
msgid "Encountered errors deleting files:\n"
msgstr "Грешки при изтриване на файловете:\n"
-#: lib/index.tcl:676
#, tcl-format
msgid "None of the %d selected files could be deleted."
msgstr "Никой от избраните %d файла не бе изтрит."
-#: lib/index.tcl:681
#, tcl-format
msgid "%d of the %d selected files could not be deleted."
msgstr "%d от избраните %d файла не бяха изтрити."
-#: lib/index.tcl:728
msgid "Reverting selected files"
msgstr "Махане на промените в избраните файлове"
-#: lib/index.tcl:732
#, tcl-format
msgid "Reverting %s"
msgstr "Махане на промените в „%s“"
-#: lib/line.tcl:17
msgid "Goto Line:"
msgstr "Към ред:"
-#: lib/line.tcl:23
msgid "Go"
msgstr "Към"
-#: lib/merge.tcl:13
msgid ""
"Cannot merge while amending.\n"
"\n"
@@ -1921,7 +1415,6 @@ msgstr ""
"Трябва да завършите поправянето на текущото подаване, преди да започнете "
"сливане.\n"
-#: lib/merge.tcl:27
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
@@ -1938,7 +1431,6 @@ msgstr ""
"Автоматично ще започне нова проверка.\n"
"\n"
-#: lib/merge.tcl:45
#, tcl-format
msgid ""
"You are in the middle of a conflicted merge.\n"
@@ -1956,7 +1448,6 @@ msgstr ""
"завършите текущото сливане чрез подаване. Чак тогава може да започнете ново "
"сливане.\n"
-#: lib/merge.tcl:55
#, tcl-format
msgid ""
"You are in the middle of a change.\n"
@@ -1973,39 +1464,31 @@ msgstr ""
"Трябва да завършите текущото подаване, преди да започнете сливане. Така ще "
"можете лесно да преустановите сливането, ако възникне нужда.\n"
-#: lib/merge.tcl:108
#, tcl-format
msgid "%s of %s"
msgstr "%s от общо %s"
-#: lib/merge.tcl:126
#, tcl-format
msgid "Merging %s and %s..."
msgstr "Сливане на „%s“ и „%s“…"
-#: lib/merge.tcl:137
msgid "Merge completed successfully."
msgstr "Сливането завърши успешно."
-#: lib/merge.tcl:139
msgid "Merge failed. Conflict resolution is required."
msgstr "Неуспешно сливане — има конфликти за коригиране."
-#: lib/merge.tcl:156
#, tcl-format
msgid "%s (%s): Merge"
msgstr "%s (%s): Сливане"
-#: lib/merge.tcl:164
#, tcl-format
msgid "Merge Into %s"
msgstr "Сливане в „%s“"
-#: lib/merge.tcl:183
msgid "Revision To Merge"
msgstr "Версия за сливане"
-#: lib/merge.tcl:218
msgid ""
"Cannot abort while amending.\n"
"\n"
@@ -2015,7 +1498,6 @@ msgstr ""
"\n"
"Трябва да завършите поправката на това подаване.\n"
-#: lib/merge.tcl:228
msgid ""
"Abort merge?\n"
"\n"
@@ -2029,7 +1511,6 @@ msgstr ""
"\n"
"Наистина ли да се преустанови сливането?"
-#: lib/merge.tcl:234
msgid ""
"Reset changes?\n"
"\n"
@@ -2043,35 +1524,27 @@ msgstr ""
"\n"
"Наистина ли да се занулят промените?"
-#: lib/merge.tcl:246
msgid "Aborting"
msgstr "Преустановяване"
-#: lib/merge.tcl:247
msgid "files reset"
msgstr "файла със занулени промени"
-#: lib/merge.tcl:277
msgid "Abort failed."
msgstr "Неуспешно преустановяване."
-#: lib/merge.tcl:279
msgid "Abort completed. Ready."
msgstr "Успешно преустановяване. Готовност за следващо действие."
-#: lib/mergetool.tcl:8
msgid "Force resolution to the base version?"
msgstr "Да се използва базовата версия"
-#: lib/mergetool.tcl:9
msgid "Force resolution to this branch?"
msgstr "Да се използва версията от този клон"
-#: lib/mergetool.tcl:10
msgid "Force resolution to the other branch?"
msgstr "Да се използва версията от другия клон"
-#: lib/mergetool.tcl:14
#, tcl-format
msgid ""
"Note that the diff shows only conflicting changes.\n"
@@ -2086,34 +1559,28 @@ msgstr ""
"\n"
"Тази операция може да се отмени само чрез започване на сливането наново."
-#: lib/mergetool.tcl:45
#, tcl-format
msgid "File %s seems to have unresolved conflicts, still stage?"
msgstr ""
"Изглежда, че все още има некоригирани конфликти във файла „%s“. Да се добави "
"ли файлът към индекса?"
-#: lib/mergetool.tcl:60
#, tcl-format
msgid "Adding resolution for %s"
msgstr "Добавяне на корекция на конфликтите в „%s“"
-#: lib/mergetool.tcl:141
msgid "Cannot resolve deletion or link conflicts using a tool"
msgstr ""
"Конфликтите при символни връзки или изтриване не може да се коригират с "
"външна програма."
-#: lib/mergetool.tcl:146
msgid "Conflict file does not exist"
msgstr "Файлът, в който е конфликтът, не съществува"
-#: lib/mergetool.tcl:246
#, tcl-format
msgid "Not a GUI merge tool: '%s'"
msgstr "Това не е графична програма за сливане: „%s“"
-#: lib/mergetool.tcl:278
#, tcl-format
msgid ""
"Unable to process square brackets in \"mergetool.%s.cmd\" configuration "
@@ -2125,7 +1592,6 @@ msgstr ""
"\n"
"Махнете ги."
-#: lib/mergetool.tcl:289
#, tcl-format
msgid ""
"Unsupported merge tool '%s'.\n"
@@ -2138,11 +1604,9 @@ msgstr ""
"За да я използвате, настройте „mergetool.%s.cmd“ както както е обяснено в "
"страницата на ръководството за „git-config“."
-#: lib/mergetool.tcl:327
msgid "Merge tool is already running, terminate it?"
msgstr "Програмата за сливане вече е стартирана. Да се изключи ли?"
-#: lib/mergetool.tcl:347
#, tcl-format
msgid ""
"Error retrieving versions:\n"
@@ -2151,7 +1615,6 @@ msgstr ""
"Грешка при изтеглянето на версии:\n"
"%s"
-#: lib/mergetool.tcl:367
#, tcl-format
msgid ""
"Could not start the merge tool:\n"
@@ -2162,277 +1625,211 @@ msgstr ""
"\n"
"%s"
-#: lib/mergetool.tcl:371
msgid "Running merge tool..."
msgstr "Стартиране на програмата за сливане…"
-#: lib/mergetool.tcl:399 lib/mergetool.tcl:407
msgid "Merge tool failed."
msgstr "Грешка в програмата за сливане."
-#: lib/option.tcl:11
#, tcl-format
msgid "Invalid global encoding '%s'"
msgstr "Неправилно глобално кодиране „%s“"
-#: lib/option.tcl:19
#, tcl-format
msgid "Invalid repo encoding '%s'"
msgstr "Неправилно кодиране „%s“ на хранилището"
-#: lib/option.tcl:119
msgid "Restore Defaults"
msgstr "Стандартни настройки"
-#: lib/option.tcl:123
msgid "Save"
msgstr "Запазване"
-#: lib/option.tcl:133
#, tcl-format
msgid "%s Repository"
msgstr "Хранилище „%s“"
-#: lib/option.tcl:134
msgid "Global (All Repositories)"
msgstr "Глобално (за всички хранилища)"
-#: lib/option.tcl:140
msgid "User Name"
msgstr "Потребителско име"
-#: lib/option.tcl:141
msgid "Email Address"
msgstr "Адрес на е-поща"
-#: lib/option.tcl:143
msgid "Summarize Merge Commits"
msgstr "Обобщаване на подаванията при сливане"
-#: lib/option.tcl:144
msgid "Merge Verbosity"
msgstr "Подробности при сливанията"
-#: lib/option.tcl:145
msgid "Show Diffstat After Merge"
msgstr "Извеждане на статистика след сливанията"
-#: lib/option.tcl:146
msgid "Use Merge Tool"
msgstr "Използване на програма за сливане"
-#: lib/option.tcl:148
msgid "Trust File Modification Timestamps"
msgstr "Доверие във времето на промяна на файловете"
-#: lib/option.tcl:149
msgid "Prune Tracking Branches During Fetch"
msgstr "Окастряне на следящите клонове при доставяне"
-#: lib/option.tcl:150
msgid "Match Tracking Branches"
msgstr "Напасване на следящите клонове"
-#: lib/option.tcl:151
msgid "Use Textconv For Diffs and Blames"
msgstr "Използване на „textconv“ за разликите и анотирането"
-#: lib/option.tcl:152
msgid "Blame Copy Only On Changed Files"
msgstr "Анотиране на копието само по променените файлове"
-#: lib/option.tcl:153
msgid "Maximum Length of Recent Repositories List"
msgstr "Максимален брой на списъка „Скоро ползвани“ хранилища"
-#: lib/option.tcl:154
msgid "Minimum Letters To Blame Copy On"
msgstr "Минимален брой знаци за анотиране на копието"
-#: lib/option.tcl:155
msgid "Blame History Context Radius (days)"
msgstr "Исторически обхват за анотиране в дни"
-#: lib/option.tcl:156
msgid "Number of Diff Context Lines"
msgstr "Брой редове за контекста на разликите"
-#: lib/option.tcl:157
msgid "Additional Diff Parameters"
msgstr "Аргументи към командата за разликите"
-#: lib/option.tcl:158
msgid "Commit Message Text Width"
msgstr "Широчина на текста на съобщението при подаване"
-#: lib/option.tcl:159
msgid "New Branch Name Template"
msgstr "Шаблон за името на новите клони"
-#: lib/option.tcl:160
msgid "Default File Contents Encoding"
msgstr "Кодиране на файловете"
-#: lib/option.tcl:161
msgid "Warn before committing to a detached head"
msgstr "Предупреждаване при подаване към несвързан указател"
-#: lib/option.tcl:162
msgid "Staging of untracked files"
msgstr "Добавяне на неследените файлове към индекса"
-#: lib/option.tcl:163
msgid "Show untracked files"
msgstr "Показване на неследените файлове"
-#: lib/option.tcl:164
msgid "Tab spacing"
msgstr "Ширина на табулацията"
-#: lib/option.tcl:210
msgid "Change"
msgstr "Смяна"
-#: lib/option.tcl:254
msgid "Spelling Dictionary:"
msgstr "Правописен речник:"
-#: lib/option.tcl:284
msgid "Change Font"
msgstr "Смяна на шрифта"
-#: lib/option.tcl:288
#, tcl-format
msgid "Choose %s"
msgstr "Избор на „%s“"
-#: lib/option.tcl:294
msgid "pt."
msgstr "тчк."
-#: lib/option.tcl:308
msgid "Preferences"
msgstr "Настройки"
-#: lib/option.tcl:345
msgid "Failed to completely save options:"
msgstr "Неуспешно запазване на настройките:"
-#: lib/remote_add.tcl:20
#, tcl-format
msgid "%s (%s): Add Remote"
msgstr "%s (%s): Добавяне на отдалечено хранилище"
-#: lib/remote_add.tcl:25
msgid "Add New Remote"
msgstr "Добавяне на отдалечено хранилище"
-#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37
msgid "Add"
msgstr "Добавяне"
-#: lib/remote_add.tcl:39
msgid "Remote Details"
msgstr "Данни за отдалеченото хранилище"
-#: lib/remote_add.tcl:50
msgid "Location:"
msgstr "Местоположение:"
-#: lib/remote_add.tcl:60
msgid "Further Action"
msgstr "Следващо действие"
-#: lib/remote_add.tcl:63
msgid "Fetch Immediately"
msgstr "Незабавно доставяне"
-#: lib/remote_add.tcl:69
msgid "Initialize Remote Repository and Push"
msgstr "Инициализиране на отдалеченото хранилище и изтласкване на промените"
-#: lib/remote_add.tcl:75
msgid "Do Nothing Else Now"
msgstr "Да не се прави нищо"
-#: lib/remote_add.tcl:100
msgid "Please supply a remote name."
msgstr "Задайте име за отдалеченото хранилище."
-#: lib/remote_add.tcl:113
#, tcl-format
msgid "'%s' is not an acceptable remote name."
msgstr "Отдалечено хранилище не може да се казва „%s“."
-#: lib/remote_add.tcl:124
#, tcl-format
msgid "Failed to add remote '%s' of location '%s'."
msgstr "Неуспешно добавяне на отдалеченото хранилище „%s“ от адрес „%s“."
-#: lib/remote_add.tcl:132 lib/transport.tcl:6
#, tcl-format
msgid "fetch %s"
msgstr "доставяне на „%s“"
-#: lib/remote_add.tcl:133
#, tcl-format
msgid "Fetching the %s"
msgstr "Доставяне на „%s“"
-#: lib/remote_add.tcl:156
#, tcl-format
msgid "Do not know how to initialize repository at location '%s'."
msgstr "Хранилището с местоположение „%s“ не може да се инициализира."
-#: lib/remote_add.tcl:162 lib/transport.tcl:54 lib/transport.tcl:92
-#: lib/transport.tcl:110
#, tcl-format
msgid "push %s"
msgstr "изтласкване на „%s“"
-#: lib/remote_add.tcl:163
#, tcl-format
msgid "Setting up the %s (at %s)"
msgstr "Добавяне на хранилище „%s“ (с адрес „%s“)"
-#: lib/remote_branch_delete.tcl:29
#, tcl-format
msgid "%s (%s): Delete Branch Remotely"
msgstr "%s (%s): Изтриване на отдалечения клон"
-#: lib/remote_branch_delete.tcl:34
msgid "Delete Branch Remotely"
msgstr "Изтриване на отдалечения клон"
-#: lib/remote_branch_delete.tcl:48
msgid "From Repository"
msgstr "От хранилище"
-#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:165
msgid "Remote:"
msgstr "Отдалечено хранилище:"
-#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:187
msgid "Arbitrary Location:"
msgstr "Произволно местоположение:"
-#: lib/remote_branch_delete.tcl:88
msgid "Branches"
msgstr "Клони"
-#: lib/remote_branch_delete.tcl:110
msgid "Delete Only If"
msgstr "Изтриване, само ако"
-#: lib/remote_branch_delete.tcl:112
msgid "Merged Into:"
msgstr "Слят в:"
-#: lib/remote_branch_delete.tcl:153
msgid "A branch is required for 'Merged Into'."
msgstr "За данните „Слят в“ е необходимо да зададете клон."
-#: lib/remote_branch_delete.tcl:185
#, tcl-format
msgid ""
"The following branches are not completely merged into %s:\n"
@@ -2443,7 +1840,6 @@ msgstr ""
"\n"
" ● %s"
-#: lib/remote_branch_delete.tcl:190
#, tcl-format
msgid ""
"One or more of the merge tests failed because you have not fetched the "
@@ -2452,140 +1848,107 @@ msgstr ""
"Поне една от пробите за сливане е неуспешна, защото не сте доставили всички "
"необходими подавания. Пробвайте първо да доставите подаванията от „%s“."
-#: lib/remote_branch_delete.tcl:208
msgid "Please select one or more branches to delete."
msgstr "Изберете поне един клон за изтриване."
-#: lib/remote_branch_delete.tcl:227
#, tcl-format
msgid "Deleting branches from %s"
msgstr "Изтриване на клони от „%s“"
-#: lib/remote_branch_delete.tcl:300
msgid "No repository selected."
msgstr "Не е избрано хранилище."
-#: lib/remote_branch_delete.tcl:305
#, tcl-format
msgid "Scanning %s..."
msgstr "Претърсване на „%s“…"
-#: lib/remote.tcl:200
msgid "Push to"
msgstr "Изтласкване към"
-#: lib/remote.tcl:218
msgid "Remove Remote"
msgstr "Премахване на отдалечено хранилище"
-#: lib/remote.tcl:223
msgid "Prune from"
msgstr "Окастряне от"
-#: lib/remote.tcl:228
msgid "Fetch from"
msgstr "Доставяне от"
-#: lib/remote.tcl:249 lib/remote.tcl:253 lib/remote.tcl:258 lib/remote.tcl:264
msgid "All"
msgstr "Всички"
-#: lib/search.tcl:48
msgid "Find:"
msgstr "Търсене:"
-#: lib/search.tcl:50
msgid "Next"
msgstr "Следваща поява"
-#: lib/search.tcl:51
msgid "Prev"
msgstr "Предишна поява"
-#: lib/search.tcl:52
msgid "RegExp"
msgstr "РегИзр"
-#: lib/search.tcl:54
msgid "Case"
msgstr "Главни/Малки"
-#: lib/shortcut.tcl:8 lib/shortcut.tcl:40 lib/shortcut.tcl:72
#, tcl-format
msgid "%s (%s): Create Desktop Icon"
msgstr "%s (%s): Добавяне на икона на работния плот"
-#: lib/shortcut.tcl:24 lib/shortcut.tcl:62
msgid "Cannot write shortcut:"
msgstr "Клавишната комбинация не може да се запази:"
-#: lib/shortcut.tcl:137
msgid "Cannot write icon:"
msgstr "Иконата не може да се запази:"
-#: lib/spellcheck.tcl:57
msgid "Unsupported spell checker"
msgstr "Тази програма за проверка на правописа не се поддържа"
-#: lib/spellcheck.tcl:65
msgid "Spell checking is unavailable"
msgstr "Липсва програма за проверка на правописа"
-#: lib/spellcheck.tcl:68
msgid "Invalid spell checking configuration"
msgstr "Неправилни настройки на проверката на правописа"
-#: lib/spellcheck.tcl:70
#, tcl-format
msgid "Reverting dictionary to %s."
msgstr "Ползване на речник за език „%s“."
-#: lib/spellcheck.tcl:73
msgid "Spell checker silently failed on startup"
msgstr "Програмата за правопис даже не стартира успешно."
-#: lib/spellcheck.tcl:80
msgid "Unrecognized spell checker"
msgstr "Непозната програма за проверка на правописа"
-#: lib/spellcheck.tcl:186
msgid "No Suggestions"
msgstr "Няма предложения"
-#: lib/spellcheck.tcl:388
msgid "Unexpected EOF from spell checker"
msgstr "Неочакван край на файл от програмата за проверка на правописа"
-#: lib/spellcheck.tcl:392
msgid "Spell Checker Failed"
msgstr "Грешка в програмата за проверка на правописа"
-#: lib/sshkey.tcl:34
msgid "No keys found."
msgstr "Не са открити ключове."
-#: lib/sshkey.tcl:37
#, tcl-format
msgid "Found a public key in: %s"
msgstr "Открит е публичен ключ в „%s“"
-#: lib/sshkey.tcl:43
msgid "Generate Key"
msgstr "Генериране на ключ"
-#: lib/sshkey.tcl:61
msgid "Copy To Clipboard"
msgstr "Копиране към системния буфер"
-#: lib/sshkey.tcl:75
msgid "Your OpenSSH Public Key"
msgstr "Публичният ви ключ за OpenSSH"
-#: lib/sshkey.tcl:83
msgid "Generating..."
msgstr "Генериране…"
-#: lib/sshkey.tcl:89
#, tcl-format
msgid ""
"Could not start ssh-keygen:\n"
@@ -2596,81 +1959,63 @@ msgstr ""
"\n"
"%s"
-#: lib/sshkey.tcl:116
msgid "Generation failed."
msgstr "Неуспешно генериране."
-#: lib/sshkey.tcl:123
msgid "Generation succeeded, but no keys found."
msgstr "Генерирането завърши успешно, а не са намерени ключове."
-#: lib/sshkey.tcl:126
#, tcl-format
msgid "Your key is in: %s"
msgstr "Ключът ви е в „%s“"
-#: lib/status_bar.tcl:263
#, tcl-format
msgid "%s ... %*i of %*i %s (%3i%%)"
msgstr "%s… %*i от общо %*i %s (%3i%%)"
-#: lib/tools_dlg.tcl:22
#, tcl-format
msgid "%s (%s): Add Tool"
msgstr "%s (%s): Добавяне на команда"
-#: lib/tools_dlg.tcl:28
msgid "Add New Tool Command"
msgstr "Добавяне на команда"
-#: lib/tools_dlg.tcl:34
msgid "Add globally"
msgstr "Глобално добавяне"
-#: lib/tools_dlg.tcl:46
msgid "Tool Details"
msgstr "Подробности за командата"
-#: lib/tools_dlg.tcl:49
msgid "Use '/' separators to create a submenu tree:"
msgstr "За създаване на подменюта използвайте знака „/“ за разделител:"
-#: lib/tools_dlg.tcl:60
msgid "Command:"
msgstr "Команда:"
-#: lib/tools_dlg.tcl:71
msgid "Show a dialog before running"
msgstr "Преди изпълнение да се извежда диалогов прозорец"
-#: lib/tools_dlg.tcl:77
msgid "Ask the user to select a revision (sets $REVISION)"
msgstr "Потребителят да укаже версия (задаване на променливата $REVISION)"
-#: lib/tools_dlg.tcl:82
msgid "Ask the user for additional arguments (sets $ARGS)"
msgstr ""
"Потребителят да укаже допълнителни аргументи (задаване на променливата $ARGS)"
-#: lib/tools_dlg.tcl:89
msgid "Don't show the command output window"
msgstr "Без показване на прозорец с изхода от командата"
-#: lib/tools_dlg.tcl:94
msgid "Run only if a diff is selected ($FILENAME not empty)"
msgstr ""
"Стартиране само след избор на разлика (променливата $FILENAME не е празна)"
-#: lib/tools_dlg.tcl:118
msgid "Please supply a name for the tool."
msgstr "Задайте име за командата."
-#: lib/tools_dlg.tcl:126
#, tcl-format
msgid "Tool '%s' already exists."
msgstr "Командата „%s“ вече съществува."
-#: lib/tools_dlg.tcl:148
#, tcl-format
msgid ""
"Could not add tool:\n"
@@ -2679,154 +2024,121 @@ msgstr ""
"Командата не може да се добави:\n"
"%s"
-#: lib/tools_dlg.tcl:187
#, tcl-format
msgid "%s (%s): Remove Tool"
msgstr "%s (%s): Премахване на команда"
-#: lib/tools_dlg.tcl:193
msgid "Remove Tool Commands"
msgstr "Премахване на команди"
-#: lib/tools_dlg.tcl:198
msgid "Remove"
msgstr "Премахване"
-#: lib/tools_dlg.tcl:231
msgid "(Blue denotes repository-local tools)"
msgstr "(командите към локалното хранилище са обозначени в синьо)"
-#: lib/tools_dlg.tcl:283
#, tcl-format
msgid "%s (%s):"
msgstr "%s (%s):"
-#: lib/tools_dlg.tcl:292
#, tcl-format
msgid "Run Command: %s"
msgstr "Изпълнение на командата „%s“"
-#: lib/tools_dlg.tcl:306
msgid "Arguments"
msgstr "Аргументи"
-#: lib/tools_dlg.tcl:341
msgid "OK"
msgstr "Добре"
-#: lib/tools.tcl:76
#, tcl-format
msgid "Running %s requires a selected file."
msgstr "За изпълнението на „%s“ трябва да изберете файл."
-#: lib/tools.tcl:92
#, tcl-format
msgid "Are you sure you want to run %1$s on file \"%2$s\"?"
msgstr "Сигурни ли сте, че искате да изпълните „%1$s“ върху файла „%2$s“?"
-#: lib/tools.tcl:96
#, tcl-format
msgid "Are you sure you want to run %s?"
msgstr "Сигурни ли сте, че искате да изпълните „%s“?"
-#: lib/tools.tcl:118
#, tcl-format
msgid "Tool: %s"
msgstr "Команда: %s"
-#: lib/tools.tcl:119
#, tcl-format
msgid "Running: %s"
msgstr "Изпълнение: %s"
-#: lib/tools.tcl:158
#, tcl-format
msgid "Tool completed successfully: %s"
msgstr "Командата завърши успешно: %s"
-#: lib/tools.tcl:160
#, tcl-format
msgid "Tool failed: %s"
msgstr "Командата върна грешка: %s"
-#: lib/transport.tcl:7
#, tcl-format
msgid "Fetching new changes from %s"
msgstr "Доставяне на промените от „%s“"
-#: lib/transport.tcl:18
#, tcl-format
msgid "remote prune %s"
msgstr "окастряне на следящите клони към „%s“"
-#: lib/transport.tcl:19
#, tcl-format
msgid "Pruning tracking branches deleted from %s"
msgstr "Окастряне на следящите клони на изтритите клони от „%s“"
-#: lib/transport.tcl:25
msgid "fetch all remotes"
msgstr "доставяне от всички отдалечени"
-#: lib/transport.tcl:26
msgid "Fetching new changes from all remotes"
msgstr "Доставяне на промените от всички отдалечени хранилища"
-#: lib/transport.tcl:40
msgid "remote prune all remotes"
msgstr "окастряне на следящите изтрити"
-#: lib/transport.tcl:41
msgid "Pruning tracking branches deleted from all remotes"
msgstr ""
"Окастряне на следящите клони на изтритите клони от всички отдалечени "
"хранилища"
-#: lib/transport.tcl:55
#, tcl-format
msgid "Pushing changes to %s"
msgstr "Изтласкване на промените към „%s“"
-#: lib/transport.tcl:93
#, tcl-format
msgid "Mirroring to %s"
msgstr "Изтласкване на всичко към „%s“"
-#: lib/transport.tcl:111
#, tcl-format
msgid "Pushing %s %s to %s"
msgstr "Изтласкване на %s „%s“ към „%s“"
-#: lib/transport.tcl:132
msgid "Push Branches"
msgstr "Клони за изтласкване"
-#: lib/transport.tcl:147
msgid "Source Branches"
msgstr "Клони-източници"
-#: lib/transport.tcl:162
msgid "Destination Repository"
msgstr "Целево хранилище"
-#: lib/transport.tcl:205
msgid "Transfer Options"
msgstr "Настройки при пренасянето"
-#: lib/transport.tcl:207
msgid "Force overwrite existing branch (may discard changes)"
msgstr ""
"Изрично презаписване на съществуващ клон (някои промени може да се загубят)"
-#: lib/transport.tcl:211
msgid "Use thin pack (for slow network connections)"
msgstr "Максимална компресия (за бавни мрежови връзки)"
-#: lib/transport.tcl:215
msgid "Include tags"
msgstr "Включване на етикетите"
-#: lib/transport.tcl:229
#, tcl-format
msgid "%s (%s): Push"
msgstr "%s (%s): Изтласкване"
diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh
index b1845c5055..38debe376c 100755
--- a/git-gui/windows/git-gui.sh
+++ b/git-gui/windows/git-gui.sh
@@ -13,13 +13,5 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } {
incr argc -2
}
-set basedir [file dirname \
- [file dirname \
- [file dirname [info script]]]]
-set bindir [file join $basedir bin]
-set bindir "$bindir;[file join $basedir mingw bin]"
-regsub -all ";" $bindir "\\;" bindir
-set env(PATH) "$bindir;$env(PATH)"
-unset bindir
-
-source [file join [file dirname [info script]] git-gui.tcl]
+set thisdir [file normalize [file dirname [info script]]]
+source [file join $thisdir git-gui.tcl]
diff --git a/git.c b/git.c
index 07a5fe39fb..958796d0b4 100644
--- a/git.c
+++ b/git.c
@@ -371,7 +371,7 @@ static int handle_alias(struct strvec *args)
alias_command = args->v[0];
alias_string = alias_lookup(alias_command);
if (alias_string) {
- if (args->nr > 1 && !strcmp(args->v[1], "-h"))
+ if (args->nr == 2 && !strcmp(args->v[1], "-h"))
fprintf_ln(stderr, _("'%s' is aliased to '%s'"),
alias_command, alias_string);
if (alias_string[0] == '!') {
@@ -445,7 +445,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct
const char *prefix;
int run_setup = (p->option & (RUN_SETUP | RUN_SETUP_GENTLY));
- help = argc == 2 && !strcmp(argv[1], "-h");
+ help = argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help-all"));
if (help && (run_setup & RUN_SETUP))
/* demote to GENTLY to allow 'git cmd -h' outside repo */
run_setup = RUN_SETUP_GENTLY;
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 427a8a96c9..3b6acfc592 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -7,7 +7,7 @@ exec wish "$0" -- "$@"
# and distributed under the terms of the GNU General Public Licence,
# either version 2, or (at your option) any later version.
-if {[catch {package require Tcl 8.6-8.8} err]} {
+if {[catch {package require Tcl 8.6-} err]} {
catch {wm withdraw .}
tk_messageBox \
-icon error \
@@ -34,6 +34,26 @@ The version of git found is $git_version."
}
######################################################################
+## Enable Tcl8 profile in Tcl9, allowing consumption of data that has
+## bytes not conforming to the assumed encoding profile.
+
+if {[package vcompare $::tcl_version 9.0] >= 0} {
+ rename open _strict_open
+ proc open args {
+ set f [_strict_open {*}$args]
+ chan configure $f -profile tcl8
+ return $f
+ }
+ proc convertfrom args {
+ return [encoding convertfrom -profile tcl8 {*}$args]
+ }
+} else {
+ proc convertfrom args {
+ return [encoding convertfrom {*}$args]
+ }
+}
+
+######################################################################
##
## Enabling platform-specific code paths
@@ -2033,8 +2053,10 @@ proc readrefs {} {
set tagids($name) $id
lappend idtags($id) $name
} else {
- set otherrefids($name) $id
- lappend idotherrefs($id) $name
+ if [is_other_ref_visible $name] {
+ set otherrefids($name) $id
+ lappend idotherrefs($id) $name
+ }
}
}
catch {close $refd}
@@ -2288,6 +2310,16 @@ proc bind_mousewheel {} {
bind $cflist <MouseWheel> {$cflist yview scroll [scrollval %D 2] units}
bind $cflist <Shift-MouseWheel> break
bind $canv <Shift-MouseWheel> {$canv xview scroll [scrollval %D] units}
+
+ if {[package vcompare $::tcl_version 8.7] >= 0} {
+ bindall <Alt-MouseWheel> {allcanvs yview scroll [scrollval 5*%D] units}
+ bindall <Alt-Shift-MouseWheel> break
+ bind $ctext <Alt-MouseWheel> {$ctext yview scroll [scrollval 5*%D 2] units}
+ bind $ctext <Alt-Shift-MouseWheel> {$ctext xview scroll [scrollval 5*%D 2] units}
+ bind $cflist <Alt-MouseWheel> {$cflist yview scroll [scrollval 5*%D 2] units}
+ bind $cflist <Alt-Shift-MouseWheel> break
+ bind $canv <Alt-Shift-MouseWheel> {$canv xview scroll [scrollval 5*%D] units}
+ }
}
proc bind_mousewheel_buttons {} {
@@ -2747,7 +2779,7 @@ proc makewindow {} {
bindall <1> {selcanvline %W %x %y}
#Mouse / touchpad scrolling
- if {[tk windowingsystem] == "win32"} {
+ if {[tk windowingsystem] == "win32" || [package vcompare $::tcl_version 8.7] >= 0} {
set scroll_D0 120
bind_mousewheel
} elseif {[tk windowingsystem] == "x11"} {
@@ -7794,7 +7826,7 @@ proc gettree {id} {
set treepending $id
set treefilelist($id) {}
set treeidlist($id) {}
- fconfigure $gtf -blocking 0 -encoding binary
+ fconfigure $gtf -blocking 0 -translation binary
filerun $gtf [list gettreeline $gtf $id]
}
} else {
@@ -7821,7 +7853,7 @@ proc gettreeline {gtf id} {
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
- set fname [encoding convertfrom utf-8 $fname]
+ set fname [convertfrom utf-8 $fname]
lappend treefilelist($id) $fname
}
if {![eof $gtf]} {
@@ -8055,7 +8087,7 @@ proc gettreediffs {ids} {
set treepending $ids
set treediff {}
- fconfigure $gdtf -blocking 0 -encoding binary
+ fconfigure $gdtf -blocking 0 -translation binary
filerun $gdtf [list gettreediffline $gdtf $ids]
}
@@ -8081,7 +8113,7 @@ proc gettreediffline {gdtf ids} {
if {[string index $file 0] eq "\""} {
set file [lindex $file 0]
}
- set file [encoding convertfrom utf-8 $file]
+ set file [convertfrom utf-8 $file]
if {$file ne [lindex $treediff end]} {
lappend treediff $file
lappend sublist $file
@@ -8166,7 +8198,7 @@ proc getblobdiffs {ids} {
error_popup [mc "Error getting diffs: %s" $err]
return
}
- fconfigure $bdf -blocking 0 -encoding binary -eofchar {}
+ fconfigure $bdf -blocking 0 -translation binary
set blobdifffd($ids) $bdf
initblobdiffvars
filerun $bdf [list getblobdiffline $bdf $diffids]
@@ -8217,7 +8249,7 @@ proc makediffhdr {fname ids} {
global ctext curdiffstart treediffs diffencoding
global ctext_file_names jump_to_here targetline diffline
- set fname [encoding convertfrom utf-8 $fname]
+ set fname [convertfrom utf-8 $fname]
set diffencoding [get_path_encoding $fname]
set i [lsearch -exact $treediffs($ids) $fname]
if {$i >= 0} {
@@ -8279,7 +8311,7 @@ proc parseblobdiffline {ids line} {
if {![string compare -length 5 "diff " $line]} {
if {![regexp {^diff (--cc|--git) } $line m type]} {
- set line [encoding convertfrom utf-8 $line]
+ set line [convertfrom utf-8 $line]
$ctext insert end "$line\n" hunksep
continue
}
@@ -8328,7 +8360,7 @@ proc parseblobdiffline {ids line} {
makediffhdr $fname $ids
} elseif {![string compare -length 16 "* Unmerged path " $line]} {
- set fname [encoding convertfrom utf-8 [string range $line 16 end]]
+ set fname [convertfrom utf-8 [string range $line 16 end]]
$ctext insert end "\n"
set curdiffstart [$ctext index "end - 1c"]
lappend ctext_file_names $fname
@@ -8341,7 +8373,7 @@ proc parseblobdiffline {ids line} {
} elseif {![string compare -length 2 "@@" $line]} {
regexp {^@@+} $line ats
- set line [encoding convertfrom $diffencoding $line]
+ set line [convertfrom $diffencoding $line]
$ctext insert end "$line\n" hunksep
if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
set diffline $nl
@@ -8370,10 +8402,10 @@ proc parseblobdiffline {ids line} {
$ctext insert end "$line\n" filesep
}
} elseif {$currdiffsubmod != "" && ![string compare -length 3 " >" $line]} {
- set line [encoding convertfrom $diffencoding $line]
+ set line [convertfrom $diffencoding $line]
$ctext insert end "$line\n" dresult
} elseif {$currdiffsubmod != "" && ![string compare -length 3 " <" $line]} {
- set line [encoding convertfrom $diffencoding $line]
+ set line [convertfrom $diffencoding $line]
$ctext insert end "$line\n" d0
} elseif {$diffinhdr} {
if {![string compare -length 12 "rename from " $line]} {
@@ -8381,7 +8413,7 @@ proc parseblobdiffline {ids line} {
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
- set fname [encoding convertfrom utf-8 $fname]
+ set fname [convertfrom utf-8 $fname]
set i [lsearch -exact $treediffs($ids) $fname]
if {$i >= 0} {
setinlist difffilestart $i $curdiffstart
@@ -8400,12 +8432,12 @@ proc parseblobdiffline {ids line} {
set diffinhdr 0
return
}
- set line [encoding convertfrom utf-8 $line]
+ set line [convertfrom utf-8 $line]
$ctext insert end "$line\n" filesep
} else {
set line [string map {\x1A ^Z} \
- [encoding convertfrom $diffencoding $line]]
+ [convertfrom $diffencoding $line]]
# parse the prefix - one ' ', '-' or '+' for each parent
set prefix [string range $line 0 [expr {$diffnparents - 1}]]
set tag [expr {$diffnparents > 1? "m": "d"}]
@@ -10238,7 +10270,7 @@ proc refill_reflist {} {
if {![string match "remotes/*" $n] && [string match $reflistfilter $n]} {
if {[commitinview $headids($n) $curview]} {
lappend localrefs [list $n H]
- if {[info exists upstreamofref($n)]} {
+ if {[info exists upstreamofref($n)] && [commitinview $headids($upstreamofref($n)) $curview]} {
lappend trackedremoterefs [list $upstreamofref($n) R]
}
} else {
@@ -10246,7 +10278,7 @@ proc refill_reflist {} {
}
}
}
- set trackedremoterefs [lsort -index 0 $trackedremoterefs]
+ set trackedremoterefs [lsort -index 0 -unique $trackedremoterefs]
set localrefs [lsort -index 0 $localrefs]
foreach n [array names headids] {
@@ -11649,6 +11681,13 @@ proc prefspage_general {notebook} {
-variable hideremotes
grid x $page.hideremotes -sticky w
+ ttk::entry $page.refstohide -textvariable refstohide
+ ttk::frame $page.refstohidef
+ ttk::label $page.refstohidef.l -text [mc "Refs to hide (space-separated globs)" ]
+ pack $page.refstohidef.l -side left
+ pack configure $page.refstohidef.l -padx 10
+ grid x $page.refstohidef $page.refstohide -sticky ew
+
ttk::checkbutton $page.autocopy -text [mc "Copy commit ID to clipboard"] \
-variable autocopy
grid x $page.autocopy -sticky w
@@ -11720,57 +11759,63 @@ proc prefspage_colors {notebook} {
grid $page.cdisp - -sticky w -pady 10
label $page.ui -padx 40 -relief sunk -background $uicolor
ttk::button $page.uibut -text [mc "Interface"] \
- -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+ -command [list choosecolor uicolor {} $page [mc "interface"]]
grid x $page.uibut $page.ui -sticky w
label $page.bg -padx 40 -relief sunk -background $bgcolor
ttk::button $page.bgbut -text [mc "Background"] \
- -command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+ -command [list choosecolor bgcolor {} $page [mc "background"]]
grid x $page.bgbut $page.bg -sticky w
label $page.fg -padx 40 -relief sunk -background $fgcolor
ttk::button $page.fgbut -text [mc "Foreground"] \
- -command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+ -command [list choosecolor fgcolor {} $page [mc "foreground"]]
grid x $page.fgbut $page.fg -sticky w
label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
ttk::button $page.diffoldbut -text [mc "Diff: old lines"] \
- -command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
- [list $ctext tag conf d0 -foreground]]
+ -command [list choosecolor diffcolors 0 $page [mc "diff old lines"]]
grid x $page.diffoldbut $page.diffold -sticky w
label $page.diffoldbg -padx 40 -relief sunk -background [lindex $diffbgcolors 0]
ttk::button $page.diffoldbgbut -text [mc "Diff: old lines bg"] \
- -command [list choosecolor diffbgcolors 0 $page.diffoldbg \
- [mc "diff old lines bg"] \
- [list $ctext tag conf d0 -background]]
+ -command [list choosecolor diffbgcolors 0 $page [mc "diff old lines bg"]]
grid x $page.diffoldbgbut $page.diffoldbg -sticky w
label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
ttk::button $page.diffnewbut -text [mc "Diff: new lines"] \
- -command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
- [list $ctext tag conf dresult -foreground]]
+ -command [list choosecolor diffcolors 1 $page [mc "diff new lines"]]
grid x $page.diffnewbut $page.diffnew -sticky w
label $page.diffnewbg -padx 40 -relief sunk -background [lindex $diffbgcolors 1]
ttk::button $page.diffnewbgbut -text [mc "Diff: new lines bg"] \
- -command [list choosecolor diffbgcolors 1 $page.diffnewbg \
- [mc "diff new lines bg"] \
- [list $ctext tag conf dresult -background]]
+ -command [list choosecolor diffbgcolors 1 $page [mc "diff new lines bg"]]
grid x $page.diffnewbgbut $page.diffnewbg -sticky w
label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
ttk::button $page.hunksepbut -text [mc "Diff: hunk header"] \
- -command [list choosecolor diffcolors 2 $page.hunksep \
- [mc "diff hunk header"] \
- [list $ctext tag conf hunksep -foreground]]
+ -command [list choosecolor diffcolors 2 $page [mc "diff hunk header"]]
grid x $page.hunksepbut $page.hunksep -sticky w
label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
ttk::button $page.markbgbut -text [mc "Marked line bg"] \
- -command [list choosecolor markbgcolor {} $page.markbgsep \
- [mc "marked line background"] \
- [list $ctext tag conf omark -background]]
+ -command [list choosecolor markbgcolor {} $page [mc "marked line background"]]
grid x $page.markbgbut $page.markbgsep -sticky w
label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
ttk::button $page.selbgbut -text [mc "Select bg"] \
- -command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+ -command [list choosecolor selectbgcolor {} $page [mc "background"]]
grid x $page.selbgbut $page.selbgsep -sticky w
return $page
}
+proc prefspage_set_colorswatches {page} {
+ global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+ global diffbgcolors
+
+ $page.ui configure -background $uicolor
+ $page.bg configure -background $bgcolor
+ $page.fg configure -background $fgcolor
+ $page.diffold configure -background [lindex $diffcolors 0]
+ $page.diffoldbg configure -background [lindex $diffbgcolors 0]
+ $page.diffnew configure -background [lindex $diffcolors 1]
+ $page.diffnewbg configure -background [lindex $diffbgcolors 1]
+ $page.hunksep configure -background [lindex $diffcolors 2]
+ $page.markbgsep configure -background $markbgcolor
+ $page.selbgsep configure -background $selectbgcolor
+}
+
proc prefspage_fonts {notebook} {
set page [create_prefs_page $notebook.fonts]
ttk::label $page.cfont -text [mc "Fonts: press to choose"] -font mainfontbold
@@ -11838,15 +11883,15 @@ proc choose_extdiff {} {
}
}
-proc choosecolor {v vi w x cmd} {
+proc choosecolor {v vi prefspage x} {
global $v
set c [tk_chooseColor -initialcolor [lindex [set $v] $vi] \
-title [mc "Gitk: choose color for %s" $x]]
if {$c eq {}} return
- $w conf -background $c
lset $v $vi $c
- eval $cmd $c
+ set_gui_colors
+ prefspage_set_colorswatches $prefspage
}
proc setselbg {c} {
@@ -11899,6 +11944,22 @@ proc setfg {c} {
$canv itemconf markid -outline $c
}
+proc set_gui_colors {} {
+ global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+ global diffbgcolors
+
+ setui $uicolor
+ setbg $bgcolor
+ setfg $fgcolor
+ $ctext tag conf d0 -foreground [lindex $diffcolors 0]
+ $ctext tag conf d0 -background [lindex $diffbgcolors 0]
+ $ctext tag conf dresult -foreground [lindex $diffcolors 1]
+ $ctext tag conf dresult -background [lindex $diffbgcolors 1]
+ $ctext tag conf hunksep -foreground [lindex $diffcolors 2]
+ $ctext tag conf omark -background $markbgcolor
+ setselbg $selectbgcolor
+}
+
proc prefscan {} {
global oldprefs prefstop
global {*}$::config_variables
@@ -11909,6 +11970,7 @@ proc prefscan {} {
catch {destroy $prefstop}
unset prefstop
fontcan
+ set_gui_colors
}
proc prefsok {} {
@@ -11960,7 +12022,7 @@ proc prefsok {} {
$limitdiffs != $oldprefs(limitdiffs)} {
reselectline
}
- if {$hideremotes != $oldprefs(hideremotes)} {
+ if {$hideremotes != $oldprefs(hideremotes) || $refstohide != $oldprefs(refstohide)} {
rereadrefs
}
if {$wrapcomment != $oldprefs(wrapcomment)} {
@@ -12316,7 +12378,7 @@ proc cache_gitattr {attr pathlist} {
foreach row [split $rlist "\n"] {
if {[regexp "(.*): $attr: (.*)" $row m path value]} {
if {[string index $path 0] eq "\""} {
- set path [encoding convertfrom utf-8 [lindex $path 0]]
+ set path [convertfrom utf-8 [lindex $path 0]]
}
set path_attr_cache($attr,$path) $value
}
@@ -12337,6 +12399,23 @@ proc get_path_encoding {path} {
return $tcl_enc
}
+proc is_other_ref_visible {ref} {
+ global refstohide
+
+ if {$refstohide eq {}} {
+ return 1
+ }
+
+ foreach pat [split $refstohide " "] {
+ if {$pat eq {}} continue
+ if {[string match $pat $ref]} {
+ return 0
+ }
+ }
+
+ return 1
+}
+
## For msgcat loading, first locate the installation location.
if { [info exists ::env(GITK_MSGSDIR)] } {
## Msgsdir was manually set in the environment.
@@ -12444,6 +12523,7 @@ set wrapcomment "none"
set wrapdefault "none"
set showneartags 1
set hideremotes 0
+set refstohide ""
set sortrefsbytype 1
set maxrefs 20
set visiblerefs {"master"}
@@ -12531,14 +12611,14 @@ catch {
set config_file_tmp [file join $env(XDG_CONFIG_HOME) git gitk-tmp]
} else {
# default XDG_CONFIG_HOME
- set config_file "~/.config/git/gitk"
- set config_file_tmp "~/.config/git/gitk-tmp"
+ set config_file "$env(HOME)/.config/git/gitk"
+ set config_file_tmp "$env(HOME)/.config/git/gitk-tmp"
}
if {![file exists $config_file]} {
# for backward compatibility use the old config file if it exists
- if {[file exists "~/.gitk"]} {
- set config_file "~/.gitk"
- set config_file_tmp "~/.gitk-tmp"
+ if {[file exists "$env(HOME)/.gitk"]} {
+ set config_file "$env(HOME)/.gitk"
+ set config_file_tmp "$env(HOME)/.gitk-tmp"
} elseif {![file exists [file dirname $config_file]]} {
file mkdir [file dirname $config_file]
}
@@ -12587,6 +12667,7 @@ set config_variables {
mergecolors
perfile_attrs
reflinecolor
+ refstohide
remotebgcolor
selectbgcolor
showlocalchanges
@@ -12624,8 +12705,6 @@ eval font create textfontbold [fontflags textfont 1]
parsefont uifont $uifont
eval font create uifont [fontflags uifont]
-setui $uicolor
-
setoptions
# check that we can find a .git directory somewhere...
@@ -12814,6 +12893,8 @@ if {[tk windowingsystem] eq "win32"} {
focus -force .
}
+set_gui_colors
+
getcommits {}
# Local variables:
diff --git a/gitk-git/po/bg.po b/gitk-git/po/bg.po
index 773a049831..d1e7d92425 100644
--- a/gitk-git/po/bg.po
+++ b/gitk-git/po/bg.po
@@ -1,15 +1,15 @@
# Bulgarian translation of gitk po-file.
-# Copyright (C) 2014, 2015, 2019, 2020, 2024 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015, 2019, 2020, 2024, 2025 Alexander Shopov <ash@kambanaria.org>.
# This file is distributed under the same license as the git package.
-# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2019, 2020, 2024.
+# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2019, 2020, 2024, 2025.
#
#
msgid ""
msgstr ""
"Project-Id-Version: gitk master\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-12-24 11:01+0100\n"
-"PO-Revision-Date: 2024-12-24 11:05+0100\n"
+"POT-Creation-Date: 2025-07-22 18:34+0200\n"
+"PO-Revision-Date: 2025-07-28 13:38+0200\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
@@ -18,32 +18,25 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: gitk:139
msgid "Couldn't get list of unmerged files:"
msgstr "Списъкът с неслети файлове не може да се получи:"
-#: gitk:211 gitk:2430
msgid "Color words"
msgstr "Оцветяване на думите"
-#: gitk:216 gitk:2430 gitk:8335 gitk:8368
msgid "Markup words"
msgstr "Отбелязване на думите"
-#: gitk:323
msgid "Error parsing revisions:"
msgstr "Грешка при анализ на версиите:"
-#: gitk:389
msgid "Error executing --argscmd command:"
msgstr "Грешка при изпълнение на командата с „--argscmd“."
-#: gitk:402
msgid "No files selected: --merge specified but no files are unmerged."
msgstr ""
"Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове."
-#: gitk:405
msgid ""
"No files selected: --merge specified but no unmerged files are within file "
"limit."
@@ -51,326 +44,246 @@ msgstr ""
"Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове "
"в ограниченията."
-#: gitk:430 gitk:585
msgid "Error executing git log:"
msgstr "Грешка при изпълнение на „git log“:"
-#: gitk:448 gitk:601
msgid "Reading"
msgstr "Прочитане"
-#: gitk:508 gitk:4596
msgid "Reading commits..."
msgstr "Прочитане на подаванията…"
-#: gitk:511 gitk:1660 gitk:4599
msgid "No commits selected"
msgstr "Не са избрани подавания"
-#: gitk:1468 gitk:4116 gitk:12738
msgid "Command line"
msgstr "Команден ред"
-#: gitk:1534
msgid "Can't parse git log output:"
msgstr "Изходът от „git log“ не може да се анализира:"
-#: gitk:1763
msgid "No commit information available"
msgstr "Липсва информация за подавания"
-#: gitk:1930 gitk:1959 gitk:4386 gitk:9875 gitk:11485 gitk:11805
msgid "OK"
msgstr "Добре"
-#: gitk:1961 gitk:4388 gitk:9311 gitk:9390 gitk:9520 gitk:9606 gitk:9877
-#: gitk:11486 gitk:11806
msgid "Cancel"
msgstr "Отказ"
-#: gitk:2114
msgid "&Update"
msgstr "&Обновяване"
-#: gitk:2115
msgid "&Reload"
msgstr "&Презареждане"
-#: gitk:2116
msgid "Reread re&ferences"
msgstr "Прочитане &наново"
-#: gitk:2117
msgid "&List references"
msgstr "&Изброяване на указателите"
-#: gitk:2119
msgid "Start git &gui"
msgstr "&Стартиране на „git gui“"
-#: gitk:2121
msgid "&Quit"
msgstr "&Спиране на програмата"
-#: gitk:2113
msgid "&File"
msgstr "&Файл"
-#: gitk:2125
msgid "&Preferences"
msgstr "&Настройки"
-#: gitk:2124
msgid "&Edit"
msgstr "&Редактиране"
-#: gitk:2129
msgid "&New view..."
msgstr "&Нов изглед…"
-#: gitk:2130
msgid "&Edit view..."
msgstr "&Редактиране на изгледа…"
-#: gitk:2131
msgid "&Delete view"
msgstr "&Изтриване на изгледа"
-#: gitk:2133
msgid "&All files"
msgstr "&Всички файлове"
-#: gitk:2128
msgid "&View"
msgstr "&Изглед"
-#: gitk:2138 gitk:2148
msgid "&About gitk"
msgstr "&Относно gitk"
-#: gitk:2139 gitk:2153
msgid "&Key bindings"
msgstr "&Клавишни комбинации"
-#: gitk:2137 gitk:2152
msgid "&Help"
msgstr "Помо&щ"
-#: gitk:2230 gitk:8767
msgid "Commit ID:"
msgstr "Подаване:"
-#: gitk:2274
msgid "Row"
msgstr "Ред"
-#: gitk:2312
msgid "Find"
msgstr "Търсене"
-#: gitk:2340
msgid "commit"
msgstr "подаване"
-#: gitk:2344 gitk:2346 gitk:4758 gitk:4781 gitk:4805 gitk:6826 gitk:6898
-#: gitk:6983
msgid "containing:"
msgstr "съдържащо:"
-#: gitk:2347 gitk:3597 gitk:3602 gitk:4834
msgid "touching paths:"
msgstr "в пътищата:"
-#: gitk:2348 gitk:4848
msgid "adding/removing string:"
msgstr "добавящо/премахващо низ"
-#: gitk:2349 gitk:4850
msgid "changing lines matching:"
msgstr "променящо редове напасващи:"
-#: gitk:2358 gitk:2360 gitk:4837
msgid "Exact"
msgstr "Точно"
-#: gitk:2360 gitk:4925 gitk:6794
msgid "IgnCase"
msgstr "Без регистър"
-#: gitk:2360 gitk:4807 gitk:4923 gitk:6790
msgid "Regexp"
msgstr "Рег. израз"
-#: gitk:2362 gitk:2363 gitk:4945 gitk:4975 gitk:4982 gitk:6919 gitk:6987
msgid "All fields"
msgstr "Всички полета"
-#: gitk:2363 gitk:4942 gitk:4975 gitk:6857
msgid "Headline"
msgstr "Първи ред"
-#: gitk:2364 gitk:4942 gitk:6857 gitk:6987 gitk:7499
msgid "Comments"
msgstr "Коментари"
-#: gitk:2364 gitk:4942 gitk:4947 gitk:4982 gitk:6857 gitk:7434 gitk:8945
-#: gitk:8960
msgid "Author"
msgstr "Автор"
-#: gitk:2364 gitk:4942 gitk:6857 gitk:7436
msgid "Committer"
msgstr "Подаващ"
-#: gitk:2398
msgid "Search"
msgstr "Търсене"
-#: gitk:2406
msgid "Diff"
msgstr "Разлики"
-#: gitk:2408
msgid "Old version"
msgstr "Стара версия"
-#: gitk:2410
msgid "New version"
msgstr "Нова версия"
-#: gitk:2413
msgid "Lines of context"
msgstr "Контекст в редове"
-#: gitk:2423
msgid "Ignore space change"
msgstr "Празните знаци без значение"
-#: gitk:2427 gitk:2429 gitk:8069 gitk:8321
msgid "Line diff"
msgstr "Поредови разлики"
-#: gitk:2502
msgid "Patch"
msgstr "Кръпка"
-#: gitk:2504
msgid "Tree"
msgstr "Дърво"
-#: gitk:2674 gitk:2695
+msgid "Unknown windowing system, cannot bind mouse"
+msgstr "Непозната графична система, не може да се установи връзка с мишка"
+
msgid "Diff this -> selected"
msgstr "Разлики между това и избраното"
-#: gitk:2675 gitk:2696
msgid "Diff selected -> this"
msgstr "Разлики между избраното и това"
-#: gitk:2676 gitk:2697
msgid "Make patch"
msgstr "Създаване на кръпка"
-#: gitk:2677 gitk:9369
msgid "Create tag"
msgstr "Създаване на етикет"
-#: gitk:2678
msgid "Copy commit reference"
msgstr "Копиране на указателя на подаване"
-#: gitk:2679 gitk:9500
msgid "Write commit to file"
msgstr "Запазване на подаването във файл"
-#: gitk:2680
msgid "Create new branch"
msgstr "Създаване на нов клон"
-#: gitk:2681
msgid "Cherry-pick this commit"
msgstr "Отбиране на това подаване"
-#: gitk:2682
msgid "Reset HEAD branch to here"
msgstr "Привеждане на върха на клона към текущото подаване"
-#: gitk:2683
msgid "Mark this commit"
msgstr "Отбелязване на това подаване"
-#: gitk:2684
msgid "Return to mark"
msgstr "Връщане към отбелязаното подаване"
-#: gitk:2685
msgid "Find descendant of this and mark"
msgstr "Откриване и отбелязване на наследниците"
-#: gitk:2686
msgid "Compare with marked commit"
msgstr "Сравнение с отбелязаното подаване"
-#: gitk:2687 gitk:2698
msgid "Diff this -> marked commit"
msgstr "Разлики между това и отбелязаното"
-#: gitk:2688 gitk:2699
msgid "Diff marked commit -> this"
msgstr "Разлики между отбелязаното и това"
-#: gitk:2689
msgid "Revert this commit"
msgstr "Отмяна на това подаване"
-#: gitk:2705
msgid "Check out this branch"
msgstr "Изтегляне на този клон"
-#: gitk:2706
msgid "Rename this branch"
msgstr "Преименуване на този клон"
-#: gitk:2707
msgid "Remove this branch"
msgstr "Изтриване на този клон"
-#: gitk:2708
msgid "Copy branch name"
msgstr "Копиране на името на клона"
-#: gitk:2715
msgid "Highlight this too"
msgstr "Отбелязване и на това"
-#: gitk:2716
msgid "Highlight this only"
msgstr "Отбелязване само на това"
-#: gitk:2717
msgid "External diff"
msgstr "Външна програма за разлики"
-#: gitk:2718
msgid "Blame parent commit"
msgstr "Анотиране на родителското подаване"
-#: gitk:2719
msgid "Copy path"
msgstr "Копиране на пътя"
-#: gitk:2726
msgid "Show origin of this line"
msgstr "Показване на произхода на този ред"
-#: gitk:2727
msgid "Run git gui blame on this line"
msgstr "Изпълнение на „git gui blame“ върху този ред"
-#: gitk:3081
msgid "About gitk"
msgstr "Относно gitk"
-#: gitk:3083
msgid ""
"\n"
"Gitk - a commit viewer for git\n"
@@ -386,324 +299,250 @@ msgstr ""
"\n"
"Използвайте и разпространявайте при условията на ОПЛ на ГНУ"
-#: gitk:3091 gitk:3158 gitk:10090
msgid "Close"
msgstr "Затваряне"
-#: gitk:3112
msgid "Gitk key bindings"
msgstr "Клавишни комбинации"
-#: gitk:3115
msgid "Gitk key bindings:"
msgstr "Клавишни комбинации:"
-#: gitk:3117
#, tcl-format
msgid "<%s-Q>\t\tQuit"
msgstr "<%s-Q>\t\tСпиране на програмата"
-#: gitk:3118
#, tcl-format
msgid "<%s-W>\t\tClose window"
msgstr "<%s-W>\t\tЗатваряне на прозореца"
-#: gitk:3119
msgid "<Home>\t\tMove to first commit"
msgstr "<Home>\t\tКъм първото подаване"
-#: gitk:3120
msgid "<End>\t\tMove to last commit"
msgstr "<End>\t\tКъм последното подаване"
-#: gitk:3121
msgid "<Up>, p, k\tMove up one commit"
msgstr "<Up>, p, k\tЕдно подаване нагоре"
-#: gitk:3122
msgid "<Down>, n, j\tMove down one commit"
msgstr "<Down>, n, j\tЕдно подаване надолу"
-#: gitk:3123
msgid "<Left>, z, h\tGo back in history list"
msgstr "<Left>, z, h\tНазад в историята"
-#: gitk:3124
msgid "<Right>, x, l\tGo forward in history list"
msgstr "<Right>, x, l\tНапред в историята"
-#: gitk:3125
#, tcl-format
msgid "<%s-n>\tGo to n-th parent of current commit in history list"
msgstr "<%s-n>\tКъм n-тия родител на текущото подаване в историята"
-#: gitk:3126
msgid "<PageUp>\tMove up one page in commit list"
msgstr "<PageUp>\tСтраница нагоре в списъка с подаванията"
-#: gitk:3127
msgid "<PageDown>\tMove down one page in commit list"
msgstr "<PageDown>\tСтраница надолу в списъка с подаванията"
-#: gitk:3128
#, tcl-format
msgid "<%s-Home>\tScroll to top of commit list"
msgstr "<%s-Home>\tКъм началото на списъка с подаванията"
-#: gitk:3129
#, tcl-format
msgid "<%s-End>\tScroll to bottom of commit list"
msgstr "<%s-End>\tКъм края на списъка с подаванията"
-#: gitk:3130
#, tcl-format
msgid "<%s-Up>\tScroll commit list up one line"
msgstr "<%s-Up>\tРед нагоре в списъка с подавания"
-#: gitk:3131
#, tcl-format
msgid "<%s-Down>\tScroll commit list down one line"
msgstr "<%s-Down>\tРед надолу в списъка с подавания"
-#: gitk:3132
#, tcl-format
msgid "<%s-PageUp>\tScroll commit list up one page"
msgstr "<%s-PageUp>\tСтраница нагоре в списъка с подавания"
-#: gitk:3133
#, tcl-format
msgid "<%s-PageDown>\tScroll commit list down one page"
msgstr "<%s-PageDown>\tСтраница надолу в списъка с подавания"
-#: gitk:3134
msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
msgstr "<Shift-Up>\tТърсене назад (визуално нагоре, исторически — последващи)"
-#: gitk:3135
msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
msgstr ""
"<Shift-Down>\tТърсене напред (визуално надолу, исторически — предхождащи)"
-#: gitk:3136
msgid "<Delete>, b\tScroll diff view up one page"
msgstr "<Delete>, b\tСтраница нагоре в изгледа за разлики"
-#: gitk:3137
msgid "<Backspace>\tScroll diff view up one page"
msgstr "<Backspace>\tСтраница надолу в изгледа за разлики"
-#: gitk:3138
msgid "<Space>\t\tScroll diff view down one page"
msgstr "<Space>\t\tСтраница надолу в изгледа за разлики"
-#: gitk:3139
msgid "u\t\tScroll diff view up 18 lines"
msgstr "u\t\t18 реда нагоре в изгледа за разлики"
-#: gitk:3140
msgid "d\t\tScroll diff view down 18 lines"
msgstr "d\t\t18 реда надолу в изгледа за разлики"
-#: gitk:3141
#, tcl-format
msgid "<%s-F>\t\tFind"
msgstr "<%s-F>\t\tТърсене"
-#: gitk:3142
#, tcl-format
msgid "<%s-G>\t\tMove to next find hit"
msgstr "<%s-G>\t\tКъм следващата поява"
-#: gitk:3143
msgid "<Return>\tMove to next find hit"
msgstr "<Return>\tКъм следващата поява"
-#: gitk:3144
msgid "g\t\tGo to commit"
msgstr "g\t\tКъм последното подаване"
-#: gitk:3145
msgid "/\t\tFocus the search box"
msgstr "/\t\tФокус върху полето за търсене"
-#: gitk:3146
msgid "?\t\tMove to previous find hit"
msgstr "?\t\tКъм предишната поява"
-#: gitk:3147
msgid "f\t\tScroll diff view to next file"
msgstr "f\t\tСледващ файл в изгледа за разлики"
-#: gitk:3148
#, tcl-format
msgid "<%s-S>\t\tSearch for next hit in diff view"
msgstr "<%s-S>\t\tТърсене на следващата поява в изгледа за разлики"
-#: gitk:3149
#, tcl-format
msgid "<%s-R>\t\tSearch for previous hit in diff view"
msgstr "<%s-R>\t\tТърсене на предишната поява в изгледа за разлики"
-#: gitk:3150
#, tcl-format
msgid "<%s-KP+>\tIncrease font size"
msgstr "<%s-KP+>\tПо-голям размер на шрифта"
-#: gitk:3151
#, tcl-format
msgid "<%s-plus>\tIncrease font size"
msgstr "<%s-plus>\tПо-голям размер на шрифта"
-#: gitk:3152
#, tcl-format
msgid "<%s-KP->\tDecrease font size"
msgstr "<%s-KP->\tПо-малък размер на шрифта"
-#: gitk:3153
#, tcl-format
msgid "<%s-minus>\tDecrease font size"
msgstr "<%s-minus>\tПо-малък размер на шрифта"
-#: gitk:3154
msgid "<F5>\t\tUpdate"
msgstr "<F5>\t\tОбновяване"
-#: gitk:3621 gitk:3630
#, tcl-format
msgid "Error creating temporary directory %s:"
msgstr "Грешка при създаването на временната директория „%s“:"
-#: gitk:3643
#, tcl-format
msgid "Error getting \"%s\" from %s:"
msgstr "Грешка при получаването на „%s“ от %s:"
-#: gitk:3706
msgid "command failed:"
msgstr "неуспешно изпълнение на команда:"
-#: gitk:3855
msgid "No such commit"
msgstr "Такова подаване няма"
-#: gitk:3869
msgid "git gui blame: command failed:"
msgstr "„git gui blame“: неуспешно изпълнение на команда:"
-#: gitk:3900
#, tcl-format
msgid "Couldn't read merge head: %s"
msgstr "Върхът за сливане не може да се прочете: %s"
-#: gitk:3908
#, tcl-format
msgid "Error reading index: %s"
msgstr "Грешка при прочитане на индекса: %s"
-#: gitk:3933
#, tcl-format
msgid "Couldn't start git blame: %s"
msgstr "Командата „git blame“ не може да се стартира: %s"
-#: gitk:3936 gitk:6825
msgid "Searching"
msgstr "Търсене"
-#: gitk:3968
#, tcl-format
msgid "Error running git blame: %s"
msgstr "Грешка при изпълнението на „git blame“: %s"
-#: gitk:3996
#, tcl-format
msgid "That line comes from commit %s, which is not in this view"
msgstr "Този ред идва от подаването %s, което не е в изгледа"
-#: gitk:4010
msgid "External diff viewer failed:"
msgstr "Неуспешно изпълнение на външната програма за разлики:"
-#: gitk:4114
msgid "All files"
msgstr "Всички файлове"
-#: gitk:4138
msgid "View"
msgstr "Изглед"
-#: gitk:4141
msgid "Gitk view definition"
msgstr "Дефиниция на изглед в Gitk"
-#: gitk:4145
msgid "Remember this view"
msgstr "Запазване на този изглед"
-#: gitk:4146
msgid "References (space separated list):"
msgstr "Указатели (списък с разделител интервал):"
-#: gitk:4147
msgid "Branches & tags:"
msgstr "Клони и етикети:"
-#: gitk:4148
msgid "All refs"
msgstr "Всички указатели"
-#: gitk:4149
msgid "All (local) branches"
msgstr "Всички (локални) клони"
-#: gitk:4150
msgid "All tags"
msgstr "Всички етикети"
-#: gitk:4151
msgid "All remote-tracking branches"
msgstr "Всички следящи клони"
-#: gitk:4152
msgid "Commit Info (regular expressions):"
msgstr "Информация за подаване (рег. изр.):"
-#: gitk:4153
msgid "Author:"
msgstr "Автор:"
-#: gitk:4154
msgid "Committer:"
msgstr "Подал:"
-#: gitk:4155
msgid "Commit Message:"
msgstr "Съобщение при подаване:"
-#: gitk:4156
msgid "Matches all Commit Info criteria"
msgstr "Съвпадение по всички характеристики на подаването"
-#: gitk:4157
msgid "Matches no Commit Info criteria"
msgstr "Не съвпада по никоя от характеристиките на подаването"
-#: gitk:4158
msgid "Changes to Files:"
msgstr "Промени по файловете:"
-#: gitk:4159
msgid "Fixed String"
msgstr "Дословен низ"
-#: gitk:4160
msgid "Regular Expression"
msgstr "Регулярен израз"
-#: gitk:4161
msgid "Search string:"
msgstr "Низ за търсене:"
-#: gitk:4162
msgid ""
"Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
"15:27:38\"):"
@@ -711,208 +550,159 @@ msgstr ""
"Дата на подаване („2 weeks ago“ (преди 2 седмици), „2009-03-17 15:27:38“, "
"„March 17, 2009 15:27:38“):"
-#: gitk:4163
msgid "Since:"
msgstr "От:"
-#: gitk:4164
msgid "Until:"
msgstr "До:"
-#: gitk:4165
msgid "Limit and/or skip a number of revisions (positive integer):"
msgstr ""
"Ограничаване и/или прескачане на определен брой версии (неотрицателно цяло "
"число):"
-#: gitk:4166
msgid "Number to show:"
msgstr "Брой показани:"
-#: gitk:4167
msgid "Number to skip:"
msgstr "Брой прескочени:"
-#: gitk:4168
msgid "Miscellaneous options:"
msgstr "Разни:"
-#: gitk:4169
msgid "Strictly sort by date"
msgstr "Подреждане по дата"
-#: gitk:4170
msgid "Mark branch sides"
msgstr "Отбелязване на страните по клона"
-#: gitk:4171
msgid "Limit to first parent"
msgstr "Само първия родител"
-#: gitk:4172
msgid "Simple history"
msgstr "Опростена история"
-#: gitk:4173
msgid "Additional arguments to git log:"
msgstr "Допълнителни аргументи към „git log“:"
-#: gitk:4174
msgid "Enter files and directories to include, one per line:"
msgstr "Въведете файловете и директориите за включване, по елемент на ред"
-#: gitk:4175
msgid "Command to generate more commits to include:"
msgstr ""
"Команда за генерирането на допълнителни подавания, които да се включат:"
-#: gitk:4299
msgid "Gitk: edit view"
msgstr "Gitk: редактиране на изглед"
-#: gitk:4307
msgid "-- criteria for selecting revisions"
msgstr "— критерии за избор на версии"
-#: gitk:4312
msgid "View Name"
msgstr "Име на изглед"
-#: gitk:4387
msgid "Apply (F5)"
msgstr "Прилагане (F5)"
-#: gitk:4425
msgid "Error in commit selection arguments:"
msgstr "Грешка в аргументите за избор на подавания:"
-#: gitk:4480 gitk:4533 gitk:4995 gitk:5009 gitk:6279 gitk:12679 gitk:12680
msgid "None"
msgstr "Няма"
-#: gitk:5092 gitk:5097
msgid "Descendant"
msgstr "Наследник"
-#: gitk:5093
msgid "Not descendant"
msgstr "Не е наследник"
-#: gitk:5100 gitk:5105
msgid "Ancestor"
msgstr "Предшественик"
-#: gitk:5101
msgid "Not ancestor"
msgstr "Не е предшественик"
-#: gitk:5395
msgid "Local changes checked in to index but not committed"
msgstr "Локални промени добавени към индекса, но неподадени"
-#: gitk:5431
msgid "Local uncommitted changes, not checked in to index"
msgstr "Локални промени извън индекса"
-#: gitk:7179
msgid "Error starting web browser:"
msgstr "Грешка при стартирането на уеб браузър:"
-#: gitk:7240
msgid "and many more"
msgstr "и още много"
-#: gitk:7243
msgid "many"
msgstr "много"
-#: gitk:7438
msgid "Tags:"
msgstr "Етикети:"
-#: gitk:7455 gitk:7461 gitk:8940
msgid "Parent"
msgstr "Родител"
-#: gitk:7466
msgid "Child"
msgstr "Дете"
-#: gitk:7475
msgid "Branch"
msgstr "Клон"
-#: gitk:7478
msgid "Follows"
msgstr "Следва"
-#: gitk:7481
msgid "Precedes"
msgstr "Предшества"
-#: gitk:8076
#, tcl-format
msgid "Error getting diffs: %s"
msgstr "Грешка при получаването на разликите: %s"
-#: gitk:8765
msgid "Goto:"
msgstr "Към ред:"
-#: gitk:8786
#, tcl-format
msgid "Short commit ID %s is ambiguous"
msgstr "Съкратената контролна сума %s не е еднозначна"
-#: gitk:8793
#, tcl-format
msgid "Revision %s is not known"
msgstr "Непозната версия %s"
-#: gitk:8803
#, tcl-format
msgid "Commit ID %s is not known"
msgstr "Непозната контролна сума %s"
-#: gitk:8805
#, tcl-format
msgid "Revision %s is not in the current view"
msgstr "Версия %s не е в текущия изглед"
-#: gitk:8947 gitk:8962
msgid "Date"
msgstr "Дата"
-#: gitk:8950
msgid "Children"
msgstr "Деца"
-#: gitk:9013
#, tcl-format
msgid "Reset %s branch to here"
msgstr "Зануляване на клона „%s“ към текущото подаване"
-#: gitk:9015
msgid "Detached head: can't reset"
msgstr "Несвързан връх: невъзможно зануляване"
-#: gitk:9120 gitk:9126
msgid "Skipping merge commit "
msgstr "Пропускане на подаването на сливането"
-#: gitk:9135 gitk:9140
msgid "Error getting patch ID for "
msgstr "Грешка при получаването на идентификатора на "
-#: gitk:9136 gitk:9141
msgid " - stopping\n"
msgstr " — спиране\n"
-#: gitk:9146 gitk:9149 gitk:9157 gitk:9171 gitk:9180
msgid "Commit "
msgstr "Подаване"
-#: gitk:9150
msgid ""
" is the same patch as\n"
" "
@@ -920,7 +710,6 @@ msgstr ""
" е същата кръпка като\n"
" "
-#: gitk:9158
msgid ""
" differs from\n"
" "
@@ -928,7 +717,6 @@ msgstr ""
" се различава от\n"
" "
-#: gitk:9160
msgid ""
"Diff of commits:\n"
"\n"
@@ -936,147 +724,113 @@ msgstr ""
"Разлика между подаванията:\n"
"\n"
-#: gitk:9172 gitk:9181
#, tcl-format
msgid " has %s children - stopping\n"
msgstr " има %s деца — спиране\n"
-#: gitk:9200
#, tcl-format
msgid "Error writing commit to file: %s"
msgstr "Грешка при запазването на подаването във файл: %s"
-#: gitk:9206
#, tcl-format
msgid "Error diffing commits: %s"
msgstr "Грешка при изчисляването на разликите между подаванията: %s"
-#: gitk:9252
msgid "Top"
msgstr "Най-горе"
-#: gitk:9253
msgid "From"
msgstr "От"
-#: gitk:9258
msgid "To"
msgstr "До"
-#: gitk:9282
msgid "Generate patch"
msgstr "Генериране на кръпка"
-#: gitk:9284
msgid "From:"
msgstr "От:"
-#: gitk:9293
msgid "To:"
msgstr "До:"
-#: gitk:9302
msgid "Reverse"
msgstr "Обръщане"
-#: gitk:9304 gitk:9514
msgid "Output file:"
msgstr "Запазване във файла:"
-#: gitk:9310
msgid "Generate"
msgstr "Генериране"
-#: gitk:9348
msgid "Error creating patch:"
msgstr "Грешка при създаването на кръпка:"
-#: gitk:9371 gitk:9502 gitk:9590
msgid "ID:"
msgstr "Идентификатор:"
-#: gitk:9380
msgid "Tag name:"
msgstr "Име на етикет:"
-#: gitk:9383
msgid "Tag message is optional"
msgstr "Съобщението за етикет е незадължително"
-#: gitk:9385
msgid "Tag message:"
msgstr "Съобщение за етикет:"
-#: gitk:9389 gitk:9560
msgid "Create"
msgstr "Създаване"
-#: gitk:9407
msgid "No tag name specified"
msgstr "Липсва име на етикет"
-#: gitk:9411
#, tcl-format
msgid "Tag \"%s\" already exists"
msgstr "Етикетът „%s“ вече съществува"
-#: gitk:9421
msgid "Error creating tag:"
msgstr "Грешка при създаването на етикет:"
-#: gitk:9511
msgid "Command:"
msgstr "Команда:"
-#: gitk:9519
msgid "Write"
msgstr "Запазване"
-#: gitk:9537
msgid "Error writing commit:"
msgstr "Грешка при запазването на подаването:"
-#: gitk:9559
msgid "Create branch"
msgstr "Създаване на клон"
-#: gitk:9575
#, tcl-format
msgid "Rename branch %s"
msgstr "Преименуване на клона „%s“"
-#: gitk:9576
msgid "Rename"
msgstr "Преименуване"
-#: gitk:9600
msgid "Name:"
msgstr "Име:"
-#: gitk:9624
msgid "Please specify a name for the new branch"
msgstr "Укажете име за новия клон"
-#: gitk:9629
#, tcl-format
msgid "Branch '%s' already exists. Overwrite?"
msgstr "Клонът „%s“ вече съществува. Да се презапише ли?"
-#: gitk:9673
msgid "Please specify a new name for the branch"
msgstr "Укажете ново име за клона"
-#: gitk:9736
#, tcl-format
msgid "Commit %s is already included in branch %s -- really re-apply it?"
msgstr ""
"Подаването „%s“ вече е включено в клона „%s“ — да се приложи ли отново?"
-#: gitk:9741
msgid "Cherry-picking"
msgstr "Отбиране"
-#: gitk:9750
#, tcl-format
msgid ""
"Cherry-pick failed because of local changes to file '%s'.\n"
@@ -1085,7 +839,6 @@ msgstr ""
"Неуспешно отбиране, защото във файла „%s“ има локални промени.\n"
"Подайте, занулете или ги скатайте и пробвайте отново."
-#: gitk:9756
msgid ""
"Cherry-pick failed because of merge conflict.\n"
"Do you wish to run git citool to resolve it?"
@@ -1093,20 +846,16 @@ msgstr ""
"Неуспешно отбиране поради конфликти при сливане.\n"
"Искате ли да ги коригирате чрез „git citool“?"
-#: gitk:9772 gitk:9830
msgid "No changes committed"
msgstr "Не са подадени промени"
-#: gitk:9799
#, tcl-format
msgid "Commit %s is not included in branch %s -- really revert it?"
msgstr "Подаването „%s“ не е включено в клона „%s“. Да се отменени ли?"
-#: gitk:9804
msgid "Reverting"
msgstr "Отмяна"
-#: gitk:9812
#, tcl-format
msgid ""
"Revert failed because of local changes to the following files:%s Please "
@@ -1115,7 +864,6 @@ msgstr ""
"Неуспешна отмяна, защото във файла „%s“ има локални промени.\n"
"Подайте, занулете или ги скатайте и пробвайте отново."
-#: gitk:9816
msgid ""
"Revert failed because of merge conflict.\n"
" Do you wish to run git citool to resolve it?"
@@ -1123,28 +871,22 @@ msgstr ""
"Неуспешно отмяна поради конфликти при сливане.\n"
"Искате ли да ги коригирате чрез „git citool“?"
-#: gitk:9859
msgid "Confirm reset"
msgstr "Потвърждаване на зануляването"
-#: gitk:9861
#, tcl-format
msgid "Reset branch %s to %s?"
msgstr "Да се занули ли клонът „%s“ към „%s“?"
-#: gitk:9863
msgid "Reset type:"
msgstr "Вид зануляване:"
-#: gitk:9866
msgid "Soft: Leave working tree and index untouched"
msgstr "Слабо: работното дърво и индекса остават същите"
-#: gitk:9869
msgid "Mixed: Leave working tree untouched, reset index"
msgstr "Смесено: работното дърво остава същото, индексът се занулява"
-#: gitk:9872
msgid ""
"Hard: Reset working tree and index\n"
"(discard ALL local changes)"
@@ -1152,24 +894,19 @@ msgstr ""
"Силно: зануляване и на работното дърво, и на индекса\n"
"(ВСИЧКИ локални промени ще се загубят безвъзвратно)"
-#: gitk:9889
msgid "Resetting"
msgstr "Зануляване"
-#: gitk:9962
#, tcl-format
msgid "A local branch named %s exists already"
msgstr "Вече съществува локален клон „%s“."
-#: gitk:9970
msgid "Checking out"
msgstr "Изтегляне"
-#: gitk:10029
msgid "Cannot delete the currently checked-out branch"
msgstr "Текущо изтегленият клон не може да се изтрие"
-#: gitk:10035
#, tcl-format
msgid ""
"The commits on branch %s aren't on any other branch.\n"
@@ -1178,16 +915,16 @@ msgstr ""
"Подаванията на клона „%s“ не са на никой друг клон.\n"
"Наистина ли искате да изтриете клона „%s“?"
-#: gitk:10066
#, tcl-format
msgid "Tags and heads: %s"
msgstr "Етикети и върхове: %s"
-#: gitk:10083
msgid "Filter"
msgstr "Филтриране"
-#: gitk:10390
+msgid "Sort refs by type"
+msgstr "Подредба на указателите по вид"
+
msgid ""
"Error reading commit topology information; branch and preceding/following "
"tag information will be incomplete."
@@ -1195,253 +932,167 @@ msgstr ""
"Грешка при прочитането на топологията на подаванията. Информацията за клона "
"и предшестващите/следващите етикети ще е непълна."
-#: gitk:11367
msgid "Tag"
msgstr "Етикет"
-#: gitk:11371
msgid "Id"
msgstr "Идентификатор"
-#: gitk:11454
-msgid "Gitk font chooser"
-msgstr "Избор на шрифт за Gitk"
-
-#: gitk:11471
-msgid "B"
-msgstr "Ч"
-
-#: gitk:11474
-msgid "I"
-msgstr "К"
-
-#: gitk:11593
msgid "Commit list display options"
msgstr "Настройки на списъка с подавания"
-#: gitk:11596
msgid "Maximum graph width (lines)"
msgstr "Максимална широчина на графа (в редове)"
-#: gitk:11600
#, no-tcl-format
msgid "Maximum graph width (% of pane)"
msgstr "Максимална широчина на графа (% от панела)"
-#: gitk:11603
msgid "Show local changes"
msgstr "Показване на локалните промени"
-#: gitk:11606
msgid "Hide remote refs"
msgstr "Скриване на отдалечените указатели"
-#: gitk:11610
msgid "Copy commit ID to clipboard"
msgstr "Копиране на контролната сума към буфера за обмен"
-#: gitk:11614
msgid "Copy commit ID to X11 selection"
msgstr "Копиране на контролната сума в селекцията на X11"
-#: gitk:11619
msgid "Length of commit ID to copy"
msgstr "Дължина на контролната сума, която се копира"
-#: gitk:11622
+msgid "Wheel scrolling multiplier"
+msgstr "Множител за колелцето на мишката"
+
msgid "Diff display options"
msgstr "Настройки на показването на разликите"
-#: gitk:11624
msgid "Tab spacing"
msgstr "Широчина на табулатора"
-#: gitk:11628
msgid "Wrap comment text"
msgstr "Пренасяне на думите в коментарите"
-#: gitk:11633
msgid "Wrap other text"
msgstr "Пренасяне на другия текст"
-#: gitk:11638
msgid "Display nearby tags/heads"
msgstr "Извеждане на близките етикети и върхове"
-#: gitk:11641
msgid "Maximum # tags/heads to show"
msgstr "Максимален брой етикети/върхове за показване"
-#: gitk:11644
msgid "Limit diffs to listed paths"
msgstr "Разлика само в избраните пътища"
-#: gitk:11647
msgid "Support per-file encodings"
msgstr "Поддръжка на различни кодирания за всеки файл"
-#: gitk:11653 gitk:11820
msgid "External diff tool"
msgstr "Външен инструмент за разлики"
-#: gitk:11654
msgid "Choose..."
msgstr "Избор…"
-#: gitk:11661
msgid "Web browser"
msgstr "Уеб браузър"
-#: gitk:11666
-msgid "General options"
-msgstr "Общи настройки"
-
-#: gitk:11669
-msgid "Use themed widgets"
-msgstr "Използване на тема за графичните обекти"
-
-#: gitk:11671
-msgid "(change requires restart)"
-msgstr "(промяната изисква рестартиране на Gitk)"
-
-#: gitk:11673
-msgid "(currently unavailable)"
-msgstr "(в момента недостъпно)"
-
-#: gitk:11685
msgid "Colors: press to choose"
msgstr "Цветове: избира се с натискане"
-#: gitk:11688
msgid "Interface"
msgstr "Интерфейс"
-#: gitk:11689
msgid "interface"
msgstr "интерфейс"
-#: gitk:11692
msgid "Background"
msgstr "Фон"
-#: gitk:11693 gitk:11735
msgid "background"
msgstr "фон"
-#: gitk:11696
msgid "Foreground"
msgstr "Знаци"
-#: gitk:11697
msgid "foreground"
msgstr "знаци"
-#: gitk:11700
msgid "Diff: old lines"
msgstr "Разлика: стари редове"
-#: gitk:11701
msgid "diff old lines"
msgstr "разлика, стари редове"
-#: gitk:11705
msgid "Diff: old lines bg"
msgstr "Разлика: фон на стари редове"
-#: gitk:11707
msgid "diff old lines bg"
msgstr "разлика, фон на стари редове"
-#: gitk:11711
msgid "Diff: new lines"
msgstr "Разлика: нови редове"
-#: gitk:11712
msgid "diff new lines"
msgstr "разлика, нови редове"
-#: gitk:11716
msgid "Diff: new lines bg"
msgstr "Разлика: фон на нови редове"
-#: gitk:11718
msgid "diff new lines bg"
msgstr "разлика, фон на нови редове"
-#: gitk:11722
msgid "Diff: hunk header"
msgstr "Разлика: начало на парче"
-#: gitk:11724
msgid "diff hunk header"
msgstr "разлика, начало на парче"
-#: gitk:11728
msgid "Marked line bg"
msgstr "Фон на отбелязан ред"
-#: gitk:11730
msgid "marked line background"
msgstr "фон на отбелязан ред"
-#: gitk:11734
msgid "Select bg"
msgstr "Избор на фон"
-#: gitk:11743
msgid "Fonts: press to choose"
msgstr "Шрифтове: избира се с натискане"
-#: gitk:11745
msgid "Main font"
msgstr "Основен шрифт"
-#: gitk:11746
msgid "Diff display font"
msgstr "Шрифт за разликите"
-#: gitk:11747
msgid "User interface font"
msgstr "Шрифт на интерфейса"
-#: gitk:11769
msgid "Gitk preferences"
msgstr "Настройки на Gitk"
-#: gitk:11778
msgid "General"
msgstr "Общи"
-#: gitk:11779
msgid "Colors"
msgstr "Цветове"
-#: gitk:11780
msgid "Fonts"
msgstr "Шрифтове"
-#: gitk:11830
#, tcl-format
msgid "Gitk: choose color for %s"
msgstr "Gitk: избор на цвят на „%s“"
-#: gitk:12350
-msgid ""
-"Sorry, gitk cannot run with this version of Tcl/Tk.\n"
-" Gitk requires at least Tcl/Tk 8.4."
-msgstr ""
-"Тази версия на Tcl/Tk не се поддържа от Gitk.\n"
-" Необходима ви е поне Tcl/Tk 8.4."
-
-#: gitk:12571
msgid "Cannot find a git repository here."
msgstr "Тук липсва хранилище на Git."
-#: gitk:12618
#, tcl-format
msgid "Ambiguous argument '%s': both revision and filename"
msgstr "Нееднозначен аргумент „%s“: има и такава версия, и такъв файл"
-#: gitk:12630
msgid "Bad arguments to gitk:"
msgstr "Неправилни аргументи на gitk:"
diff --git a/gpg-interface.c b/gpg-interface.c
index d26c7135b0..06e7fb5060 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -25,7 +25,7 @@ static void gpg_interface_lazy_init(void)
if (done)
return;
done = 1;
- git_config(git_gpg_config, NULL);
+ repo_config(the_repository, git_gpg_config, NULL);
}
static char *configured_signing_key;
diff --git a/help.c b/help.c
index 652efebf00..bb20498cfd 100644
--- a/help.c
+++ b/help.c
@@ -332,7 +332,7 @@ static int get_colopts(const char *var, const char *value,
void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds)
{
unsigned int colopts = 0;
- git_config(get_colopts, &colopts);
+ repo_config(the_repository, get_colopts, &colopts);
if (main_cmds->cnt) {
const char *exec_path = git_exec_path();
@@ -417,7 +417,7 @@ void list_cmds_by_config(struct string_list *list)
{
const char *cmd_list;
- if (git_config_get_string_tmp("completion.commands", &cmd_list))
+ if (repo_config_get_string_tmp(the_repository, "completion.commands", &cmd_list))
return;
string_list_sort(list);
@@ -502,7 +502,7 @@ static void list_all_cmds_help_aliases(int longest)
struct cmdname_help *aliases;
int i;
- git_config(get_alias, &alias_list);
+ repo_config(the_repository, get_alias, &alias_list);
string_list_sort(&alias_list);
for (i = 0; i < alias_list.nr; i++) {
diff --git a/http-backend.c b/http-backend.c
index ad8c403749..d5dfe762bb 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -246,13 +246,13 @@ static void http_config(void)
int i, value = 0;
struct strbuf var = STRBUF_INIT;
- git_config_get_bool("http.getanyfile", &getanyfile);
- git_config_get_ulong("http.maxrequestbuffer", &max_request_buffer);
+ repo_config_get_bool(the_repository, "http.getanyfile", &getanyfile);
+ repo_config_get_ulong(the_repository, "http.maxrequestbuffer", &max_request_buffer);
for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
struct rpc_service *svc = &rpc_service[i];
strbuf_addf(&var, "http.%s", svc->config_name);
- if (!git_config_get_bool(var.buf, &value))
+ if (!repo_config_get_bool(the_repository, var.buf, &value))
svc->enabled = value;
strbuf_reset(&var);
}
diff --git a/http-fetch.c b/http-fetch.c
index 02ab80533f..1922e23fcd 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -2,6 +2,7 @@
#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "http.h"
@@ -150,7 +151,7 @@ int cmd_main(int argc, const char **argv)
trace2_cmd_name("http-fetch");
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
if (packfile) {
if (!index_pack_args.nr)
diff --git a/http.c b/http.c
index 9b62f627dc..98853d6483 100644
--- a/http.c
+++ b/http.c
@@ -3,6 +3,7 @@
#include "git-compat-util.h"
#include "git-curl-compat.h"
+#include "environment.h"
#include "hex.h"
#include "http.h"
#include "config.h"
@@ -1315,7 +1316,7 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
http_is_verbose = 0;
normalized_url = url_normalize(url, &config.url);
- git_config(urlmatch_config_entry, &config);
+ repo_config(the_repository, urlmatch_config_entry, &config);
free(normalized_url);
string_list_clear(&config.vars, 1);
@@ -2331,7 +2332,7 @@ int http_get_file(const char *url, const char *filename,
ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
fclose(result);
- if (ret == HTTP_OK && finalize_object_file(tmpfile.buf, filename))
+ if (ret == HTTP_OK && finalize_object_file(the_repository, tmpfile.buf, filename))
ret = HTTP_ERROR;
cleanup:
strbuf_release(&tmpfile);
@@ -2815,7 +2816,7 @@ int finish_http_object_request(struct http_object_request *freq)
return -1;
}
odb_loose_path(the_repository->objects->sources, &filename, &freq->oid);
- freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
+ freq->rename = finalize_object_file(the_repository, freq->tmpfile.buf, filename.buf);
strbuf_release(&filename);
return freq->rename;
diff --git a/ident.c b/ident.c
index 281e830573..0b7aacecd7 100644
--- a/ident.c
+++ b/ident.c
@@ -272,7 +272,7 @@ static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src)
* can still be NULL if the input line only has the name/email part
* (e.g. reading from a reflog entry).
*/
-int split_ident_line(struct ident_split *split, const char *line, int len)
+int split_ident_line(struct ident_split *split, const char *line, size_t len)
{
const char *cp;
size_t span;
diff --git a/ident.h b/ident.h
index 6a79febba1..3c03403879 100644
--- a/ident.h
+++ b/ident.h
@@ -35,7 +35,7 @@ void reset_ident_date(void);
* Signals an success with 0, but time part of the result may be NULL
* if the input lacks timestamp and zone
*/
-int split_ident_line(struct ident_split *, const char *, int);
+int split_ident_line(struct ident_split *, const char *, size_t);
/*
* Given a commit or tag object buffer and the commit or tag headers, replaces
diff --git a/imap-send.c b/imap-send.c
index f5a656ac71..254ec83ab7 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -28,6 +28,7 @@
#include "advice.h"
#include "config.h"
#include "credential.h"
+#include "environment.h"
#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
@@ -1776,7 +1777,7 @@ int cmd_main(int argc, const char **argv)
int ret;
setup_git_directory_gently(&nongit_ok);
- git_config(git_imap_config, &server);
+ repo_config(the_repository, git_imap_config, &server);
argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 948376d42d..7420bf81fe 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -350,7 +350,7 @@ void partial_clone_register(
/* Add promisor config for the remote */
cfg_name = xstrfmt("remote.%s.promisor", remote);
- git_config_set(cfg_name, "true");
+ repo_config_set(the_repository, cfg_name, "true");
free(cfg_name);
}
@@ -360,8 +360,8 @@ void partial_clone_register(
*/
filter_name = xstrfmt("remote.%s.partialclonefilter", remote);
/* NEEDSWORK: 'expand' result leaking??? */
- git_config_set(filter_name,
- expand_list_objects_filter_spec(filter_options));
+ repo_config_set(the_repository, filter_name,
+ expand_list_objects_filter_spec(filter_options));
free(filter_name);
/* Make sure the config info are reset */
diff --git a/loose.c b/loose.c
index 519f5db793..e8ea6e7e24 100644
--- a/loose.c
+++ b/loose.c
@@ -166,7 +166,8 @@ errout:
return -1;
}
-static int write_one_object(struct repository *repo, const struct object_id *oid,
+static int write_one_object(struct odb_source *source,
+ const struct object_id *oid,
const struct object_id *compat_oid)
{
struct lock_file lock;
@@ -174,7 +175,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
struct stat st;
struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
- repo_common_path_replace(repo, &path, "objects/loose-object-idx");
+ strbuf_addf(&path, "%s/loose-object-idx", source->path);
hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
@@ -190,7 +191,7 @@ static int write_one_object(struct repository *repo, const struct object_id *oid
goto errout;
if (close(fd))
goto errout;
- adjust_shared_perm(repo, path.buf);
+ adjust_shared_perm(source->odb->repo, path.buf);
rollback_lock_file(&lock);
strbuf_release(&buf);
strbuf_release(&path);
@@ -204,17 +205,18 @@ errout:
return -1;
}
-int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
+int repo_add_loose_object_map(struct odb_source *source,
+ const struct object_id *oid,
const struct object_id *compat_oid)
{
int inserted = 0;
- if (!should_use_loose_object_map(repo))
+ if (!should_use_loose_object_map(source->odb->repo))
return 0;
- inserted = insert_loose_map(repo->objects->sources, oid, compat_oid);
+ inserted = insert_loose_map(source, oid, compat_oid);
if (inserted)
- return write_one_object(repo, oid, compat_oid);
+ return write_one_object(source, oid, compat_oid);
return 0;
}
diff --git a/loose.h b/loose.h
index 28512306e5..6af1702973 100644
--- a/loose.h
+++ b/loose.h
@@ -4,6 +4,7 @@
#include "khash.h"
struct repository;
+struct odb_source;
struct loose_object_map {
kh_oid_map_t *to_compat;
@@ -16,7 +17,8 @@ int repo_loose_object_map_oid(struct repository *repo,
const struct object_id *src,
const struct git_hash_algo *dest_algo,
struct object_id *dest);
-int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
+int repo_add_loose_object_map(struct odb_source *source,
+ const struct object_id *oid,
const struct object_id *compat_oid);
int repo_read_loose_object_map(struct repository *repo);
int repo_write_loose_object_map(struct repository *repo);
diff --git a/ls-refs.c b/ls-refs.c
index e28c841375..c47acde07f 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -159,7 +159,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
strbuf_init(&data.buf, 0);
strvec_init(&data.hidden_refs);
- git_config(ls_refs_config, &data);
+ repo_config(the_repository, ls_refs_config, &data);
while (packet_reader_read(request) == PACKET_READ_NORMAL) {
const char *arg = request->line;
diff --git a/mailinfo.c b/mailinfo.c
index b4e815b2d8..99ac596e09 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -2,6 +2,7 @@
#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex-ll.h"
#include "utf8.h"
diff --git a/match-trees.c b/match-trees.c
index 5a8a5c39b0..4216933d06 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -246,7 +246,7 @@ static int splice_tree(struct repository *r,
rewrite_with = oid2;
}
hashcpy(rewrite_here, rewrite_with->hash, r->hash_algo);
- status = write_object_file(buf, sz, OBJ_TREE, result);
+ status = odb_write_object(r->objects, buf, sz, OBJ_TREE, result);
free(buf);
return status;
}
diff --git a/merge-ll.c b/merge-ll.c
index b2dc26da4f..fafe2c9197 100644
--- a/merge-ll.c
+++ b/merge-ll.c
@@ -357,7 +357,7 @@ static void initialize_ll_merge(void)
if (ll_user_merge_tail)
return;
ll_user_merge_tail = &ll_user_merge;
- git_config(read_merge_config, NULL);
+ repo_config(the_repository, read_merge_config, NULL);
}
static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr)
diff --git a/merge-ort.c b/merge-ort.c
index 473ff61e36..29858074f9 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -316,9 +316,14 @@ struct merge_options_internal {
* (e.g. "drivers/firmware/raspberrypi.c").
* * store all relevant paths in the repo, both directories and
* files (e.g. drivers, drivers/firmware would also be included)
- * * these keys serve to intern all the path strings, which allows
- * us to do pointer comparison on directory names instead of
- * strcmp; we just have to be careful to use the interned strings.
+ * * these keys serve to intern *all* path strings, which allows us
+ * to do pointer comparisons on file & directory names instead of
+ * using strcmp; however, for this pointer-comparison optimization
+ * to work, any code path that independently computes a path needs
+ * to check for it existing in this strmap, and if so, point to
+ * the path in this strmap instead of their computed copy. See
+ * the "reuse known pointer" comment in
+ * apply_directory_rename_modifications() for an example.
*
* The values of paths:
* * either a pointer to a merged_info, or a conflict_info struct
@@ -2163,7 +2168,7 @@ static int handle_content_merge(struct merge_options *opt,
/*
* FIXME: If opt->priv->call_depth && !clean, then we really
* should not make result->mode match either a->mode or
- * b->mode; that causes t6036 "check conflicting mode for
+ * b->mode; that causes t6416 "check conflicting mode for
* regular file" to fail. It would be best to use some other
* mode, but we'll confuse all kinds of stuff if we use one
* where S_ISREG(result->mode) isn't true, and if we use
@@ -2216,8 +2221,8 @@ static int handle_content_merge(struct merge_options *opt,
}
if (!ret && record_object &&
- write_object_file(result_buf.ptr, result_buf.size,
- OBJ_BLOB, &result->oid)) {
+ odb_write_object(the_repository->objects, result_buf.ptr, result_buf.size,
+ OBJ_BLOB, &result->oid)) {
path_msg(opt, ERROR_OBJECT_WRITE_FAILED, 0,
pathnames[0], pathnames[1], pathnames[2], NULL,
_("error: unable to add %s to database"), path);
@@ -2313,14 +2318,20 @@ static char *apply_dir_rename(struct strmap_entry *rename_info,
return strbuf_detach(&new_path, NULL);
}
-static int path_in_way(struct strmap *paths, const char *path, unsigned side_mask)
+static int path_in_way(struct strmap *paths,
+ const char *path,
+ unsigned side_mask,
+ struct diff_filepair *p)
{
struct merged_info *mi = strmap_get(paths, path);
struct conflict_info *ci;
if (!mi)
return 0;
INITIALIZE_CI(ci, mi);
- return mi->clean || (side_mask & (ci->filemask | ci->dirmask));
+ return mi->clean || (side_mask & (ci->filemask | ci->dirmask))
+ /* See testcases 12[npq] of t6423 for this next condition */
+ || ((ci->filemask & 0x01) &&
+ strcmp(p->one->path, path));
}
/*
@@ -2332,6 +2343,7 @@ static int path_in_way(struct strmap *paths, const char *path, unsigned side_mas
static char *handle_path_level_conflicts(struct merge_options *opt,
const char *path,
unsigned side_index,
+ struct diff_filepair *p,
struct strmap_entry *rename_info,
struct strmap *collisions)
{
@@ -2366,7 +2378,7 @@ static char *handle_path_level_conflicts(struct merge_options *opt,
*/
if (c_info->reported_already) {
clean = 0;
- } else if (path_in_way(&opt->priv->paths, new_path, 1 << side_index)) {
+ } else if (path_in_way(&opt->priv->paths, new_path, 1 << side_index, p)) {
c_info->reported_already = 1;
strbuf_add_separated_string_list(&collision_paths, ", ",
&c_info->source_files);
@@ -2520,7 +2532,7 @@ static void compute_collisions(struct strmap *collisions,
* happening, and fall back to no-directory-rename detection
* behavior for those paths.
*
- * See testcases 9e and all of section 5 from t6043 for examples.
+ * See testcases 9e and all of section 5 from t6423 for examples.
*/
for (i = 0; i < pairs->nr; ++i) {
struct strmap_entry *rename_info;
@@ -2573,6 +2585,7 @@ static void free_collisions(struct strmap *collisions)
static char *check_for_directory_rename(struct merge_options *opt,
const char *path,
unsigned side_index,
+ struct diff_filepair *p,
struct strmap *dir_renames,
struct strmap *dir_rename_exclusions,
struct strmap *collisions,
@@ -2580,7 +2593,6 @@ static char *check_for_directory_rename(struct merge_options *opt,
{
char *new_path;
struct strmap_entry *rename_info;
- struct strmap_entry *otherinfo;
const char *new_dir;
int other_side = 3 - side_index;
@@ -2615,14 +2627,13 @@ static char *check_for_directory_rename(struct merge_options *opt,
* to not let Side1 do the rename to dumbdir, since we know that is
* the source of one of our directory renames.
*
- * That's why otherinfo and dir_rename_exclusions is here.
+ * That's why dir_rename_exclusions is here.
*
* As it turns out, this also prevents N-way transient rename
- * confusion; See testcases 9c and 9d of t6043.
+ * confusion; See testcases 9c and 9d of t6423.
*/
new_dir = rename_info->value; /* old_dir = rename_info->key; */
- otherinfo = strmap_get_entry(dir_rename_exclusions, new_dir);
- if (otherinfo) {
+ if (strmap_contains(dir_rename_exclusions, new_dir)) {
path_msg(opt, INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME, 1,
rename_info->key, path, new_dir, NULL,
_("WARNING: Avoiding applying %s -> %s rename "
@@ -2631,7 +2642,7 @@ static char *check_for_directory_rename(struct merge_options *opt,
return NULL;
}
- new_path = handle_path_level_conflicts(opt, path, side_index,
+ new_path = handle_path_level_conflicts(opt, path, side_index, p,
rename_info,
&collisions[side_index]);
*clean_merge &= (new_path != NULL);
@@ -2876,6 +2887,20 @@ static int process_renames(struct merge_options *opt,
}
/*
+ * Directory renames can result in rename-to-self; the code
+ * below assumes we have A->B with different A & B, and tries
+ * to move all entries to path B. If A & B are the same path,
+ * the logic can get confused, so skip further processing when
+ * A & B are already the same path.
+ *
+ * As a reminder, we can avoid strcmp here because all paths
+ * are interned in opt->priv->paths; see the comment above
+ * "paths" in struct merge_options_internal.
+ */
+ if (oldpath == newpath)
+ continue;
+
+ /*
* If pair->one->path isn't in opt->priv->paths, that means
* that either directory rename detection removed that
* path, or a parent directory of oldpath was resolved and
@@ -3419,7 +3444,7 @@ static int collect_renames(struct merge_options *opt,
}
new_path = check_for_directory_rename(opt, p->two->path,
- side_index,
+ side_index, p,
dir_renames_for_side,
rename_exclusions,
collisions,
@@ -3772,7 +3797,8 @@ static int write_tree(struct object_id *result_oid,
}
/* Write this object file out, and record in result_oid */
- if (write_object_file(buf.buf, buf.len, OBJ_TREE, result_oid))
+ if (odb_write_object(the_repository->objects, buf.buf,
+ buf.len, OBJ_TREE, result_oid))
ret = -1;
strbuf_release(&buf);
return ret;
@@ -5353,20 +5379,20 @@ static void merge_recursive_config(struct merge_options *opt, int ui)
{
char *value = NULL;
int renormalize = 0;
- git_config_get_int("merge.verbosity", &opt->verbosity);
- git_config_get_int("diff.renamelimit", &opt->rename_limit);
- git_config_get_int("merge.renamelimit", &opt->rename_limit);
- git_config_get_bool("merge.renormalize", &renormalize);
+ repo_config_get_int(the_repository, "merge.verbosity", &opt->verbosity);
+ repo_config_get_int(the_repository, "diff.renamelimit", &opt->rename_limit);
+ repo_config_get_int(the_repository, "merge.renamelimit", &opt->rename_limit);
+ repo_config_get_bool(the_repository, "merge.renormalize", &renormalize);
opt->renormalize = renormalize;
- if (!git_config_get_string("diff.renames", &value)) {
+ if (!repo_config_get_string(the_repository, "diff.renames", &value)) {
opt->detect_renames = git_config_rename("diff.renames", value);
free(value);
}
- if (!git_config_get_string("merge.renames", &value)) {
+ if (!repo_config_get_string(the_repository, "merge.renames", &value)) {
opt->detect_renames = git_config_rename("merge.renames", value);
free(value);
}
- if (!git_config_get_string("merge.directoryrenames", &value)) {
+ if (!repo_config_get_string(the_repository, "merge.directoryrenames", &value)) {
int boolval = git_parse_maybe_bool(value);
if (0 <= boolval) {
opt->detect_directory_renames = boolval ?
@@ -5379,7 +5405,7 @@ static void merge_recursive_config(struct merge_options *opt, int ui)
free(value);
}
if (ui) {
- if (!git_config_get_string("diff.algorithm", &value)) {
+ if (!repo_config_get_string(the_repository, "diff.algorithm", &value)) {
long diff_algorithm = parse_algorithm_value(value);
if (diff_algorithm < 0)
die(_("unknown value for config '%s': %s"), "diff.algorithm", value);
@@ -5387,7 +5413,7 @@ static void merge_recursive_config(struct merge_options *opt, int ui)
free(value);
}
}
- git_config(git_xmerge_config, NULL);
+ repo_config(the_repository, git_xmerge_config, NULL);
}
static void init_merge_options(struct merge_options *opt,
diff --git a/meson.build b/meson.build
index c043a79dca..5dd299b496 100644
--- a/meson.build
+++ b/meson.build
@@ -694,9 +694,14 @@ third_party_excludes = [
headers_to_check = []
if git.found() and fs.exists(meson.project_source_root() / '.git')
- foreach header : run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_excludes, check: true).stdout().split()
- headers_to_check += header
- endforeach
+ ls_headers = run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_excludes, check: false)
+ if ls_headers.returncode() == 0
+ foreach header : ls_headers.stdout().split()
+ headers_to_check += header
+ endforeach
+ else
+ warning('could not list headers, disabling static analysis targets')
+ endif
endif
if not get_option('breaking_changes')
diff --git a/midx-write.c b/midx-write.c
index f2cfb85476..a0aceab5e0 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -667,7 +667,7 @@ static void write_midx_reverse_index(struct write_midx_context *ctx,
tmp_file = write_rev_file_order(ctx->repo, NULL, ctx->pack_order,
ctx->entries_nr, midx_hash, WRITE_REV);
- if (finalize_object_file(tmp_file, buf.buf))
+ if (finalize_object_file(ctx->repo, tmp_file, buf.buf))
die(_("cannot store reverse index file"));
strbuf_release(&buf);
@@ -916,26 +916,8 @@ cleanup:
static struct multi_pack_index *lookup_multi_pack_index(struct repository *r,
const char *object_dir)
{
- struct multi_pack_index *result = NULL;
- struct multi_pack_index *cur;
- char *obj_dir_real = real_pathdup(object_dir, 1);
- struct strbuf cur_path_real = STRBUF_INIT;
-
- /* Ensure the given object_dir is local, or a known alternate. */
- odb_find_source(r->objects, obj_dir_real);
-
- for (cur = get_multi_pack_index(r); cur; cur = cur->next) {
- strbuf_realpath(&cur_path_real, cur->object_dir, 1);
- if (!strcmp(obj_dir_real, cur_path_real.buf)) {
- result = cur;
- goto cleanup;
- }
- }
-
-cleanup:
- free(obj_dir_real);
- strbuf_release(&cur_path_real);
- return result;
+ struct odb_source *source = odb_find_source(r->objects, object_dir);
+ return get_multi_pack_index(source);
}
static int fill_packs_from_midx(struct write_midx_context *ctx,
diff --git a/midx.c b/midx.c
index 3c5bc82173..7d407682e6 100644
--- a/midx.c
+++ b/midx.c
@@ -401,7 +401,6 @@ void close_midx(struct multi_pack_index *m)
if (!m)
return;
- close_midx(m->next);
close_midx(m->base_midx);
munmap((unsigned char *)m->data, m->data_len);
@@ -724,32 +723,20 @@ int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id)
return 0;
}
-int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local)
+int prepare_multi_pack_index_one(struct odb_source *source, int local)
{
- struct multi_pack_index *m;
- struct multi_pack_index *m_search;
+ struct repository *r = source->odb->repo;
prepare_repo_settings(r);
if (!r->settings.core_multi_pack_index)
return 0;
- for (m_search = r->objects->multi_pack_index; m_search; m_search = m_search->next)
- if (!strcmp(object_dir, m_search->object_dir))
- return 1;
-
- m = load_multi_pack_index(r, object_dir, local);
-
- if (m) {
- struct multi_pack_index *mp = r->objects->multi_pack_index;
- if (mp) {
- m->next = mp->next;
- mp->next = m;
- } else
- r->objects->multi_pack_index = m;
+ if (source->midx)
return 1;
- }
- return 0;
+ source->midx = load_multi_pack_index(r, source->path, local);
+
+ return !!source->midx;
}
int midx_checksum_valid(struct multi_pack_index *m)
@@ -834,9 +821,14 @@ void clear_midx_file(struct repository *r)
get_midx_filename(r->hash_algo, &midx, r->objects->sources->path);
- if (r->objects && r->objects->multi_pack_index) {
- close_midx(r->objects->multi_pack_index);
- r->objects->multi_pack_index = NULL;
+ if (r->objects) {
+ struct odb_source *source;
+
+ for (source = r->objects->sources; source; source = source->next) {
+ if (source->midx)
+ close_midx(source->midx);
+ source->midx = NULL;
+ }
}
if (remove_path(midx.buf))
diff --git a/midx.h b/midx.h
index 9d1374cbd5..076382de8a 100644
--- a/midx.h
+++ b/midx.h
@@ -8,6 +8,7 @@ struct pack_entry;
struct repository;
struct bitmapped_pack;
struct git_hash_algo;
+struct odb_source;
#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
#define MIDX_VERSION 1
@@ -34,8 +35,6 @@ struct git_hash_algo;
"GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL"
struct multi_pack_index {
- struct multi_pack_index *next;
-
const unsigned char *data;
size_t data_len;
@@ -123,7 +122,7 @@ int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pa
int midx_contains_pack(struct multi_pack_index *m,
const char *idx_or_pack_name);
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);
+int prepare_multi_pack_index_one(struct odb_source *source, int local);
/*
* Variant of write_midx_file which writes a MIDX containing only the packs
diff --git a/notes-cache.c b/notes-cache.c
index dd56feed6e..bf5bb1f6c1 100644
--- a/notes-cache.c
+++ b/notes-cache.c
@@ -98,7 +98,8 @@ int notes_cache_put(struct notes_cache *c, struct object_id *key_oid,
{
struct object_id value_oid;
- if (write_object_file(data, size, OBJ_BLOB, &value_oid) < 0)
+ if (odb_write_object(the_repository->objects, data,
+ size, OBJ_BLOB, &value_oid) < 0)
return -1;
return add_note(&c->tree, key_oid, &value_oid, NULL);
}
diff --git a/notes-utils.c b/notes-utils.c
index ac66b82dd3..6a50c6d564 100644
--- a/notes-utils.c
+++ b/notes-utils.c
@@ -162,7 +162,7 @@ struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)
c->refs_from_env = 1;
string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env);
}
- git_config(notes_rewrite_config, c);
+ repo_config(the_repository, notes_rewrite_config, c);
if (!c->enabled || !c->refs->nr) {
string_list_clear(c->refs, 0);
free(c->refs);
diff --git a/notes.c b/notes.c
index 97b995f3f2..9a2e9181fe 100644
--- a/notes.c
+++ b/notes.c
@@ -682,7 +682,8 @@ static int tree_write_stack_finish_subtree(struct tree_write_stack *tws)
ret = tree_write_stack_finish_subtree(n);
if (ret)
return ret;
- ret = write_object_file(n->buf.buf, n->buf.len, OBJ_TREE, &s);
+ ret = odb_write_object(the_repository->objects, n->buf.buf,
+ n->buf.len, OBJ_TREE, &s);
if (ret)
return ret;
strbuf_release(&n->buf);
@@ -847,7 +848,8 @@ int combine_notes_concatenate(struct object_id *cur_oid,
free(new_msg);
/* create a new blob object from buf */
- ret = write_object_file(buf, buf_len, OBJ_BLOB, cur_oid);
+ ret = odb_write_object(the_repository->objects, buf,
+ buf_len, OBJ_BLOB, cur_oid);
free(buf);
return ret;
}
@@ -892,7 +894,7 @@ static int string_list_add_note_lines(struct string_list *list,
* later, along with any empty strings that came from empty
* lines within the file.
*/
- string_list_split(list, data, '\n', -1);
+ string_list_split(list, data, "\n", -1);
free(data);
return 0;
}
@@ -927,7 +929,8 @@ int combine_notes_cat_sort_uniq(struct object_id *cur_oid,
string_list_join_lines_helper, &buf))
goto out;
- ret = write_object_file(buf.buf, buf.len, OBJ_BLOB, cur_oid);
+ ret = odb_write_object(the_repository->objects, buf.buf,
+ buf.len, OBJ_BLOB, cur_oid);
out:
strbuf_release(&buf);
@@ -970,8 +973,8 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
char *globs_copy = xstrdup(globs);
int i;
- string_list_split_in_place(&split, globs_copy, ":", -1);
- string_list_remove_empty_items(&split, 0);
+ string_list_split_in_place_f(&split, globs_copy, ":", -1,
+ STRING_LIST_SPLIT_NONEMPTY);
for (i = 0; i < split.nr; i++)
string_list_add_refs_by_glob(list, split.items[i].string);
@@ -1123,7 +1126,7 @@ void load_display_notes(struct display_notes_opt *opt)
load_config_refs = 1;
}
- git_config(notes_display_config, &load_config_refs);
+ repo_config(the_repository, notes_display_config, &load_config_refs);
if (opt) {
struct string_list_item *item;
@@ -1215,7 +1218,8 @@ int write_notes_tree(struct notes_tree *t, struct object_id *result)
ret = for_each_note(t, flags, write_each_note, &cb_data) ||
write_each_non_note_until(NULL, &cb_data) ||
tree_write_stack_finish_subtree(&root) ||
- write_object_file(root.buf.buf, root.buf.len, OBJ_TREE, result);
+ odb_write_object(the_repository->objects, root.buf.buf,
+ root.buf.len, OBJ_TREE, result);
strbuf_release(&root.buf);
return ret;
}
diff --git a/object-file.c b/object-file.c
index 3d674d1093..2bc36ab3ee 100644
--- a/object-file.c
+++ b/object-file.c
@@ -8,7 +8,6 @@
*/
#define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
#include "bulk-checkin.h"
@@ -26,6 +25,7 @@
#include "pack.h"
#include "packfile.h"
#include "path.h"
+#include "read-cache-ll.h"
#include "setup.h"
#include "streaming.h"
@@ -42,10 +42,11 @@ static int get_conv_flags(unsigned flags)
return 0;
}
-static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
+static void fill_loose_path(struct strbuf *buf,
+ const struct object_id *oid,
+ const struct git_hash_algo *algop)
{
- int i;
- for (i = 0; i < the_hash_algo->rawsz; i++) {
+ for (size_t i = 0; i < algop->rawsz; i++) {
static char hex[] = "0123456789abcdef";
unsigned int val = oid->hash[i];
strbuf_addch(buf, hex[val >> 4]);
@@ -62,7 +63,7 @@ const char *odb_loose_path(struct odb_source *source,
strbuf_reset(buf);
strbuf_addstr(buf, source->path);
strbuf_addch(buf, '/');
- fill_loose_path(buf, oid);
+ fill_loose_path(buf, oid, source->odb->repo->hash_algo);
return buf->buf;
}
@@ -88,46 +89,19 @@ int check_and_freshen_file(const char *fn, int freshen)
return 1;
}
-static int check_and_freshen_odb(struct odb_source *source,
- const struct object_id *oid,
- int freshen)
+static int check_and_freshen_source(struct odb_source *source,
+ const struct object_id *oid,
+ int freshen)
{
static struct strbuf path = STRBUF_INIT;
odb_loose_path(source, &path, oid);
return check_and_freshen_file(path.buf, freshen);
}
-static int check_and_freshen_local(const struct object_id *oid, int freshen)
+int has_loose_object(struct odb_source *source,
+ const struct object_id *oid)
{
- return check_and_freshen_odb(the_repository->objects->sources, oid, freshen);
-}
-
-static int check_and_freshen_nonlocal(const struct object_id *oid, int freshen)
-{
- struct odb_source *source;
-
- odb_prepare_alternates(the_repository->objects);
- for (source = the_repository->objects->sources->next; source; source = source->next) {
- if (check_and_freshen_odb(source, oid, freshen))
- return 1;
- }
- return 0;
-}
-
-static int check_and_freshen(const struct object_id *oid, int freshen)
-{
- return check_and_freshen_local(oid, freshen) ||
- check_and_freshen_nonlocal(oid, freshen);
-}
-
-int has_loose_object_nonlocal(const struct object_id *oid)
-{
- return check_and_freshen_nonlocal(oid, 0);
-}
-
-int has_loose_object(const struct object_id *oid)
-{
- return check_and_freshen(oid, 0);
+ return check_and_freshen_source(source, oid, 0);
}
int format_object_header(char *str, size_t size, enum object_type type,
@@ -327,9 +301,8 @@ static void *unpack_loose_rest(git_zstream *stream,
void *buffer, unsigned long size,
const struct object_id *oid)
{
- int bytes = strlen(buffer) + 1;
+ size_t bytes = strlen(buffer) + 1, n;
unsigned char *buf = xmallocz(size);
- unsigned long n;
int status = Z_OK;
n = stream->total_out - bytes;
@@ -448,7 +421,7 @@ int loose_object_info(struct repository *r,
enum object_type type_scratch;
if (oi->delta_base_oid)
- oidclr(oi->delta_base_oid, the_repository->hash_algo);
+ oidclr(oi->delta_base_oid, r->hash_algo);
/*
* If we don't care about type or size, then we don't
@@ -596,7 +569,7 @@ static int check_collision(const char *source, const char *dest)
goto out;
}
- if (sz_a < sizeof(buf_source))
+ if ((size_t) sz_a < sizeof(buf_source))
break;
}
@@ -611,12 +584,14 @@ out:
/*
* Move the just written object into its final resting place.
*/
-int finalize_object_file(const char *tmpfile, const char *filename)
+int finalize_object_file(struct repository *repo,
+ const char *tmpfile, const char *filename)
{
- return finalize_object_file_flags(tmpfile, filename, 0);
+ return finalize_object_file_flags(repo, tmpfile, filename, 0);
}
-int finalize_object_file_flags(const char *tmpfile, const char *filename,
+int finalize_object_file_flags(struct repository *repo,
+ const char *tmpfile, const char *filename,
enum finalize_object_file_flags flags)
{
unsigned retries = 0;
@@ -676,7 +651,7 @@ retry:
}
out:
- if (adjust_shared_perm(the_repository, filename))
+ if (adjust_shared_perm(repo, filename))
return error(_("unable to set permission to '%s'"), filename);
return 0;
}
@@ -692,9 +667,10 @@ void hash_object_file(const struct git_hash_algo *algo, const void *buf,
}
/* Finalize a file on disk, and close it. */
-static void close_loose_object(int fd, const char *filename)
+static void close_loose_object(struct odb_source *source,
+ int fd, const char *filename)
{
- if (the_repository->objects->sources->will_destroy)
+ if (source->will_destroy)
goto out;
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
@@ -726,7 +702,8 @@ static inline int directory_size(const char *filename)
* We want to avoid cross-directory filename renames, because those
* can have problems on various filesystems (FAT, NFS, Coda).
*/
-static int create_tmpfile(struct strbuf *tmp, const char *filename)
+static int create_tmpfile(struct repository *repo,
+ struct strbuf *tmp, const char *filename)
{
int fd, dirlen = directory_size(filename);
@@ -745,7 +722,7 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
strbuf_add(tmp, filename, dirlen - 1);
if (mkdir(tmp->buf, 0777) && errno != EEXIST)
return -1;
- if (adjust_shared_perm(the_repository, tmp->buf))
+ if (adjust_shared_perm(repo, tmp->buf))
return -1;
/* Try again */
@@ -766,26 +743,26 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
* Returns a "fd", which should later be provided to
* end_loose_object_common().
*/
-static int start_loose_object_common(struct strbuf *tmp_file,
+static int start_loose_object_common(struct odb_source *source,
+ struct strbuf *tmp_file,
const char *filename, unsigned flags,
git_zstream *stream,
unsigned char *buf, size_t buflen,
struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
char *hdr, int hdrlen)
{
- struct repository *repo = the_repository;
- const struct git_hash_algo *algo = repo->hash_algo;
- const struct git_hash_algo *compat = repo->compat_hash_algo;
+ const struct git_hash_algo *algo = source->odb->repo->hash_algo;
+ const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
int fd;
- fd = create_tmpfile(tmp_file, filename);
+ fd = create_tmpfile(source->odb->repo, tmp_file, filename);
if (fd < 0) {
- if (flags & WRITE_OBJECT_FILE_SILENT)
+ if (flags & WRITE_OBJECT_SILENT)
return -1;
else if (errno == EACCES)
return error(_("insufficient permission for adding "
"an object to repository database %s"),
- repo_get_object_directory(the_repository));
+ source->path);
else
return error_errno(
_("unable to create temporary file"));
@@ -815,14 +792,14 @@ static int start_loose_object_common(struct strbuf *tmp_file,
* Common steps for the inner git_deflate() loop for writing loose
* objects. Returns what git_deflate() returns.
*/
-static int write_loose_object_common(struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
+static int write_loose_object_common(struct odb_source *source,
+ struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
git_zstream *stream, const int flush,
unsigned char *in0, const int fd,
unsigned char *compressed,
const size_t compressed_len)
{
- struct repository *repo = the_repository;
- const struct git_hash_algo *compat = repo->compat_hash_algo;
+ const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
int ret;
ret = git_deflate(stream, flush ? Z_FINISH : 0);
@@ -843,12 +820,12 @@ static int write_loose_object_common(struct git_hash_ctx *c, struct git_hash_ctx
* - End the compression of zlib stream.
* - Get the calculated oid to "oid".
*/
-static int end_loose_object_common(struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
+static int end_loose_object_common(struct odb_source *source,
+ struct git_hash_ctx *c, struct git_hash_ctx *compat_c,
git_zstream *stream, struct object_id *oid,
struct object_id *compat_oid)
{
- struct repository *repo = the_repository;
- const struct git_hash_algo *compat = repo->compat_hash_algo;
+ const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
int ret;
ret = git_deflate_end_gently(stream);
@@ -861,7 +838,8 @@ static int end_loose_object_common(struct git_hash_ctx *c, struct git_hash_ctx *
return Z_OK;
}
-static int write_loose_object(const struct object_id *oid, char *hdr,
+static int write_loose_object(struct odb_source *source,
+ const struct object_id *oid, char *hdr,
int hdrlen, const void *buf, unsigned long len,
time_t mtime, unsigned flags)
{
@@ -876,9 +854,9 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
prepare_loose_object_bulk_checkin();
- odb_loose_path(the_repository->objects->sources, &filename, oid);
+ odb_loose_path(source, &filename, oid);
- fd = start_loose_object_common(&tmp_file, filename.buf, flags,
+ fd = start_loose_object_common(source, &tmp_file, filename.buf, flags,
&stream, compressed, sizeof(compressed),
&c, NULL, hdr, hdrlen);
if (fd < 0)
@@ -890,14 +868,14 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
do {
unsigned char *in0 = stream.next_in;
- ret = write_loose_object_common(&c, NULL, &stream, 1, in0, fd,
+ ret = write_loose_object_common(source, &c, NULL, &stream, 1, in0, fd,
compressed, sizeof(compressed));
} while (ret == Z_OK);
if (ret != Z_STREAM_END)
die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
ret);
- ret = end_loose_object_common(&c, NULL, &stream, &parano_oid, NULL);
+ ret = end_loose_object_common(source, &c, NULL, &stream, &parano_oid, NULL);
if (ret != Z_OK)
die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
ret);
@@ -905,30 +883,36 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
die(_("confused by unstable object source data for %s"),
oid_to_hex(oid));
- close_loose_object(fd, tmp_file.buf);
+ close_loose_object(source, fd, tmp_file.buf);
if (mtime) {
struct utimbuf utb;
utb.actime = mtime;
utb.modtime = mtime;
if (utime(tmp_file.buf, &utb) < 0 &&
- !(flags & WRITE_OBJECT_FILE_SILENT))
+ !(flags & WRITE_OBJECT_SILENT))
warning_errno(_("failed utime() on %s"), tmp_file.buf);
}
- return finalize_object_file_flags(tmp_file.buf, filename.buf,
+ return finalize_object_file_flags(source->odb->repo, tmp_file.buf, filename.buf,
FOF_SKIP_COLLISION_CHECK);
}
-static int freshen_loose_object(const struct object_id *oid)
+static int freshen_loose_object(struct object_database *odb,
+ const struct object_id *oid)
{
- return check_and_freshen(oid, 1);
+ odb_prepare_alternates(odb);
+ for (struct odb_source *source = odb->sources; source; source = source->next)
+ if (check_and_freshen_source(source, oid, 1))
+ return 1;
+ return 0;
}
-static int freshen_packed_object(const struct object_id *oid)
+static int freshen_packed_object(struct object_database *odb,
+ const struct object_id *oid)
{
struct pack_entry e;
- if (!find_pack_entry(the_repository, oid, &e))
+ if (!find_pack_entry(odb->repo, oid, &e))
return 0;
if (e.p->is_cruft)
return 0;
@@ -940,10 +924,11 @@ static int freshen_packed_object(const struct object_id *oid)
return 1;
}
-int stream_loose_object(struct input_stream *in_stream, size_t len,
+int stream_loose_object(struct odb_source *source,
+ struct input_stream *in_stream, size_t len,
struct object_id *oid)
{
- const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+ const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
struct object_id compat_oid;
int fd, ret, err = 0, flush = 0;
unsigned char compressed[4096];
@@ -959,7 +944,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
prepare_loose_object_bulk_checkin();
/* Since oid is not determined, save tmp file to odb path. */
- strbuf_addf(&filename, "%s/", repo_get_object_directory(the_repository));
+ strbuf_addf(&filename, "%s/", source->path);
hdrlen = format_object_header(hdr, sizeof(hdr), OBJ_BLOB, len);
/*
@@ -970,7 +955,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
* - Setup zlib stream for compression.
* - Start to feed header to zlib stream.
*/
- fd = start_loose_object_common(&tmp_file, filename.buf, 0,
+ fd = start_loose_object_common(source, &tmp_file, filename.buf, 0,
&stream, compressed, sizeof(compressed),
&c, &compat_c, hdr, hdrlen);
if (fd < 0) {
@@ -990,7 +975,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
if (in_stream->is_finished)
flush = 1;
}
- ret = write_loose_object_common(&c, &compat_c, &stream, flush, in0, fd,
+ ret = write_loose_object_common(source, &c, &compat_c, &stream, flush, in0, fd,
compressed, sizeof(compressed));
/*
* Unlike write_loose_object(), we do not have the entire
@@ -1013,17 +998,18 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
*/
if (ret != Z_STREAM_END)
die(_("unable to stream deflate new object (%d)"), ret);
- ret = end_loose_object_common(&c, &compat_c, &stream, oid, &compat_oid);
+ ret = end_loose_object_common(source, &c, &compat_c, &stream, oid, &compat_oid);
if (ret != Z_OK)
die(_("deflateEnd on stream object failed (%d)"), ret);
- close_loose_object(fd, tmp_file.buf);
+ close_loose_object(source, fd, tmp_file.buf);
- if (freshen_packed_object(oid) || freshen_loose_object(oid)) {
+ if (freshen_packed_object(source->odb, oid) ||
+ freshen_loose_object(source->odb, oid)) {
unlink_or_warn(tmp_file.buf);
goto cleanup;
}
- odb_loose_path(the_repository->objects->sources, &filename, oid);
+ odb_loose_path(source, &filename, oid);
/* We finally know the object path, and create the missing dir. */
dirlen = directory_size(filename.buf);
@@ -1031,7 +1017,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
struct strbuf dir = STRBUF_INIT;
strbuf_add(&dir, filename.buf, dirlen);
- if (safe_create_dir_in_gitdir(the_repository, dir.buf) &&
+ if (safe_create_dir_in_gitdir(source->odb->repo, dir.buf) &&
errno != EEXIST) {
err = error_errno(_("unable to create directory %s"), dir.buf);
strbuf_release(&dir);
@@ -1040,23 +1026,23 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
strbuf_release(&dir);
}
- err = finalize_object_file_flags(tmp_file.buf, filename.buf,
+ err = finalize_object_file_flags(source->odb->repo, tmp_file.buf, filename.buf,
FOF_SKIP_COLLISION_CHECK);
if (!err && compat)
- err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
+ err = repo_add_loose_object_map(source, oid, &compat_oid);
cleanup:
strbuf_release(&tmp_file);
strbuf_release(&filename);
return err;
}
-int write_object_file_flags(const void *buf, unsigned long len,
- enum object_type type, struct object_id *oid,
- struct object_id *compat_oid_in, unsigned flags)
+int write_object_file(struct odb_source *source,
+ const void *buf, unsigned long len,
+ enum object_type type, struct object_id *oid,
+ struct object_id *compat_oid_in, unsigned flags)
{
- struct repository *repo = the_repository;
- const struct git_hash_algo *algo = repo->hash_algo;
- const struct git_hash_algo *compat = repo->compat_hash_algo;
+ const struct git_hash_algo *algo = source->odb->repo->hash_algo;
+ const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
struct object_id compat_oid;
char hdr[MAX_HEADER_LEN];
int hdrlen = sizeof(hdr);
@@ -1069,7 +1055,7 @@ int write_object_file_flags(const void *buf, unsigned long len,
hash_object_file(compat, buf, len, type, &compat_oid);
else {
struct strbuf converted = STRBUF_INIT;
- convert_object_file(the_repository, &converted, algo, compat,
+ convert_object_file(source->odb->repo, &converted, algo, compat,
buf, len, type, 0);
hash_object_file(compat, converted.buf, converted.len,
type, &compat_oid);
@@ -1081,19 +1067,20 @@ int write_object_file_flags(const void *buf, unsigned long len,
* it out into .git/objects/??/?{38} file.
*/
write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
- if (freshen_packed_object(oid) || freshen_loose_object(oid))
+ if (freshen_packed_object(source->odb, oid) ||
+ freshen_loose_object(source->odb, oid))
return 0;
- if (write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags))
+ if (write_loose_object(source, oid, hdr, hdrlen, buf, len, 0, flags))
return -1;
if (compat)
- return repo_add_loose_object_map(repo, oid, &compat_oid);
+ return repo_add_loose_object_map(source, oid, &compat_oid);
return 0;
}
-int force_object_loose(const struct object_id *oid, time_t mtime)
+int force_object_loose(struct odb_source *source,
+ const struct object_id *oid, time_t mtime)
{
- struct repository *repo = the_repository;
- const struct git_hash_algo *compat = repo->compat_hash_algo;
+ const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
void *buf;
unsigned long len;
struct object_info oi = OBJECT_INFO_INIT;
@@ -1103,22 +1090,24 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
int hdrlen;
int ret;
- if (has_loose_object(oid))
- return 0;
+ for (struct odb_source *s = source->odb->sources; s; s = s->next)
+ if (has_loose_object(s, oid))
+ return 0;
+
oi.typep = &type;
oi.sizep = &len;
oi.contentp = &buf;
- if (odb_read_object_info_extended(the_repository->objects, oid, &oi, 0))
+ if (odb_read_object_info_extended(source->odb, oid, &oi, 0))
return error(_("cannot read object for %s"), oid_to_hex(oid));
if (compat) {
- if (repo_oid_to_algop(repo, oid, compat, &compat_oid))
+ if (repo_oid_to_algop(source->odb->repo, oid, compat, &compat_oid))
return error(_("cannot map object %s to %s"),
oid_to_hex(oid), compat->name);
}
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
- ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
+ ret = write_loose_object(source, oid, hdr, hdrlen, buf, len, mtime, 0);
if (!ret && compat)
- ret = repo_add_loose_object_map(the_repository, oid, &compat_oid);
+ ret = repo_add_loose_object_map(source, oid, &compat_oid);
free(buf);
return ret;
@@ -1168,15 +1157,15 @@ static int index_mem(struct index_state *istate,
opts.strict = 1;
opts.error_func = hash_format_check_report;
- if (fsck_buffer(null_oid(the_hash_algo), type, buf, size, &opts))
+ if (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts))
die(_("refusing to create malformed object"));
fsck_finish(&opts);
}
if (write_object)
- ret = write_object_file(buf, size, type, oid);
+ ret = odb_write_object(istate->repo->objects, buf, size, type, oid);
else
- hash_object_file(the_hash_algo, buf, size, type, oid);
+ hash_object_file(istate->repo->hash_algo, buf, size, type, oid);
strbuf_release(&nbuf);
return ret;
@@ -1199,10 +1188,10 @@ static int index_stream_convert_blob(struct index_state *istate,
get_conv_flags(flags));
if (write_object)
- ret = write_object_file(sbuf.buf, sbuf.len, OBJ_BLOB,
- oid);
+ ret = odb_write_object(istate->repo->objects, sbuf.buf, sbuf.len, OBJ_BLOB,
+ oid);
else
- hash_object_file(the_hash_algo, sbuf.buf, sbuf.len, OBJ_BLOB,
+ hash_object_file(istate->repo->hash_algo, sbuf.buf, sbuf.len, OBJ_BLOB,
oid);
strbuf_release(&sbuf);
return ret;
@@ -1240,7 +1229,7 @@ static int index_core(struct index_state *istate,
if (read_result < 0)
ret = error_errno(_("read error while indexing %s"),
path ? path : "<unknown>");
- else if (read_result != size)
+ else if ((size_t) read_result != size)
ret = error(_("short read while indexing %s"),
path ? path : "<unknown>");
else
@@ -1268,7 +1257,7 @@ int index_fd(struct index_state *istate, struct object_id *oid,
ret = index_stream_convert_blob(istate, oid, fd, path, flags);
else if (!S_ISREG(st->st_mode))
ret = index_pipe(istate, oid, fd, type, path, flags);
- else if (st->st_size <= repo_settings_get_big_file_threshold(the_repository) ||
+ else if ((st->st_size >= 0 && (size_t) st->st_size <= repo_settings_get_big_file_threshold(istate->repo)) ||
type != OBJ_BLOB ||
(path && would_convert_to_git(istate, path)))
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
@@ -1300,14 +1289,14 @@ int index_path(struct index_state *istate, struct object_id *oid,
if (strbuf_readlink(&sb, path, st->st_size))
return error_errno("readlink(\"%s\")", path);
if (!(flags & INDEX_WRITE_OBJECT))
- hash_object_file(the_hash_algo, sb.buf, sb.len,
+ hash_object_file(istate->repo->hash_algo, sb.buf, sb.len,
OBJ_BLOB, oid);
- else if (write_object_file(sb.buf, sb.len, OBJ_BLOB, oid))
+ else if (odb_write_object(istate->repo->objects, sb.buf, sb.len, OBJ_BLOB, oid))
rc = error(_("%s: failed to insert into database"), path);
strbuf_release(&sb);
break;
case S_IFDIR:
- return repo_resolve_gitlink_ref(the_repository, path, "HEAD", oid);
+ return repo_resolve_gitlink_ref(istate->repo, path, "HEAD", oid);
default:
return error(_("%s: unsupported file type"), path);
}
@@ -1329,12 +1318,13 @@ int read_pack_header(int fd, struct pack_header *header)
return 0;
}
-int for_each_file_in_obj_subdir(unsigned int subdir_nr,
- struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data)
+static int for_each_file_in_obj_subdir(unsigned int subdir_nr,
+ struct strbuf *path,
+ const struct git_hash_algo *algop,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data)
{
size_t origlen, baselen;
DIR *dir;
@@ -1367,12 +1357,12 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
namelen = strlen(de->d_name);
strbuf_setlen(path, baselen);
strbuf_add(path, de->d_name, namelen);
- if (namelen == the_hash_algo->hexsz - 2 &&
+ if (namelen == algop->hexsz - 2 &&
!hex_to_bytes(oid.hash + 1, de->d_name,
- the_hash_algo->rawsz - 1)) {
- oid_set_algo(&oid, the_hash_algo);
- memset(oid.hash + the_hash_algo->rawsz, 0,
- GIT_MAX_RAWSZ - the_hash_algo->rawsz);
+ algop->rawsz - 1)) {
+ oid_set_algo(&oid, algop);
+ memset(oid.hash + algop->rawsz, 0,
+ GIT_MAX_RAWSZ - algop->rawsz);
if (obj_cb) {
r = obj_cb(&oid, path->buf, data);
if (r)
@@ -1398,26 +1388,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
return r;
}
-int for_each_loose_file_in_objdir_buf(struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data)
-{
- int r = 0;
- int i;
-
- for (i = 0; i < 256; i++) {
- r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
- subdir_cb, data);
- if (r)
- break;
- }
-
- return r;
-}
-
-int for_each_loose_file_in_objdir(const char *path,
+int for_each_loose_file_in_source(struct odb_source *source,
each_loose_object_fn obj_cb,
each_loose_cruft_fn cruft_cb,
each_loose_subdir_fn subdir_cb,
@@ -1426,22 +1397,27 @@ int for_each_loose_file_in_objdir(const char *path,
struct strbuf buf = STRBUF_INIT;
int r;
- strbuf_addstr(&buf, path);
- r = for_each_loose_file_in_objdir_buf(&buf, obj_cb, cruft_cb,
- subdir_cb, data);
- strbuf_release(&buf);
+ strbuf_addstr(&buf, source->path);
+ for (int i = 0; i < 256; i++) {
+ r = for_each_file_in_obj_subdir(i, &buf, source->odb->repo->hash_algo,
+ obj_cb, cruft_cb, subdir_cb, data);
+ if (r)
+ break;
+ }
+ strbuf_release(&buf);
return r;
}
-int for_each_loose_object(each_loose_object_fn cb, void *data,
+int for_each_loose_object(struct object_database *odb,
+ each_loose_object_fn cb, void *data,
enum for_each_object_flags flags)
{
struct odb_source *source;
- odb_prepare_alternates(the_repository->objects);
- for (source = the_repository->objects->sources; source; source = source->next) {
- int r = for_each_loose_file_in_objdir(source->path, cb, NULL,
+ odb_prepare_alternates(odb);
+ for (source = odb->sources; source; source = source->next) {
+ int r = for_each_loose_file_in_source(source, cb, NULL,
NULL, data);
if (r)
return r;
@@ -1472,7 +1448,7 @@ struct oidtree *odb_loose_cache(struct odb_source *source,
uint32_t *bitmap;
if (subdir_nr < 0 ||
- subdir_nr >= bitsizeof(source->loose_objects_subdir_seen))
+ (size_t) subdir_nr >= bitsizeof(source->loose_objects_subdir_seen))
BUG("subdir_nr out of range");
bitmap = &source->loose_objects_subdir_seen[word_index];
@@ -1484,6 +1460,7 @@ struct oidtree *odb_loose_cache(struct odb_source *source,
}
strbuf_addstr(&buf, source->path);
for_each_file_in_obj_subdir(subdir_nr, &buf,
+ source->odb->repo->hash_algo,
append_loose_object,
NULL, NULL,
source->loose_objects_cache);
@@ -1504,7 +1481,8 @@ static int check_stream_oid(git_zstream *stream,
const char *hdr,
unsigned long size,
const char *path,
- const struct object_id *expected_oid)
+ const struct object_id *expected_oid,
+ const struct git_hash_algo *algop)
{
struct git_hash_ctx c;
struct object_id real_oid;
@@ -1512,7 +1490,7 @@ static int check_stream_oid(git_zstream *stream,
unsigned long total_read;
int status = Z_OK;
- the_hash_algo->init_fn(&c);
+ algop->init_fn(&c);
git_hash_update(&c, hdr, stream->total_out);
/*
@@ -1557,7 +1535,8 @@ static int check_stream_oid(git_zstream *stream,
return 0;
}
-int read_loose_object(const char *path,
+int read_loose_object(struct repository *repo,
+ const char *path,
const struct object_id *expected_oid,
struct object_id *real_oid,
void **contents,
@@ -1596,8 +1575,9 @@ int read_loose_object(const char *path,
}
if (*oi->typep == OBJ_BLOB &&
- *size > repo_settings_get_big_file_threshold(the_repository)) {
- if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)
+ *size > repo_settings_get_big_file_threshold(repo)) {
+ if (check_stream_oid(&stream, hdr, *size, path, expected_oid,
+ repo->hash_algo) < 0)
goto out_inflate;
} else {
*contents = unpack_loose_rest(&stream, hdr, *size, expected_oid);
@@ -1605,7 +1585,7 @@ int read_loose_object(const char *path,
error(_("unable to unpack contents of %s"), path);
goto out_inflate;
}
- hash_object_file(the_repository->hash_algo,
+ hash_object_file(repo->hash_algo,
*contents, *size,
*oi->typep, real_oid);
if (!oideq(expected_oid, real_oid))
diff --git a/object-file.h b/object-file.h
index 67b4ffc480..15d97630d3 100644
--- a/object-file.h
+++ b/object-file.h
@@ -45,13 +45,12 @@ const char *odb_loose_path(struct odb_source *source,
const struct object_id *oid);
/*
- * Return true iff an alternate object database has a loose object
+ * Return true iff an object database source has a loose object
* with the specified name. This function does not respect replace
* references.
*/
-int has_loose_object_nonlocal(const struct object_id *);
-
-int has_loose_object(const struct object_id *);
+int has_loose_object(struct odb_source *source,
+ const struct object_id *oid);
void *map_loose_object(struct repository *r, const struct object_id *oid,
unsigned long *size);
@@ -87,22 +86,11 @@ typedef int each_loose_cruft_fn(const char *basename,
typedef int each_loose_subdir_fn(unsigned int nr,
const char *path,
void *data);
-int for_each_file_in_obj_subdir(unsigned int subdir_nr,
- struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data);
-int for_each_loose_file_in_objdir(const char *path,
+int for_each_loose_file_in_source(struct odb_source *source,
each_loose_object_fn obj_cb,
each_loose_cruft_fn cruft_cb,
each_loose_subdir_fn subdir_cb,
void *data);
-int for_each_loose_file_in_objdir_buf(struct strbuf *path,
- each_loose_object_fn obj_cb,
- each_loose_cruft_fn cruft_cb,
- each_loose_subdir_fn subdir_cb,
- void *data);
/*
* Iterate over all accessible loose objects without respect to
@@ -111,7 +99,8 @@ int for_each_loose_file_in_objdir_buf(struct strbuf *path,
*
* Any flags specific to packs are ignored.
*/
-int for_each_loose_object(each_loose_object_fn, void *,
+int for_each_loose_object(struct object_database *odb,
+ each_loose_object_fn, void *,
enum for_each_object_flags flags);
@@ -157,29 +146,10 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
struct object_info;
int parse_loose_header(const char *hdr, struct object_info *oi);
-enum {
- /*
- * By default, `write_object_file()` does not actually write
- * anything into the object store, but only computes the object ID.
- * This flag changes that so that the object will be written as a loose
- * object and persisted.
- */
- WRITE_OBJECT_FILE_PERSIST = (1 << 0),
-
- /*
- * Do not print an error in case something gose wrong.
- */
- WRITE_OBJECT_FILE_SILENT = (1 << 1),
-};
-
-int write_object_file_flags(const void *buf, unsigned long len,
- enum object_type type, struct object_id *oid,
- struct object_id *compat_oid_in, unsigned flags);
-static inline int write_object_file(const void *buf, unsigned long len,
- enum object_type type, struct object_id *oid)
-{
- return write_object_file_flags(buf, len, type, oid, NULL, 0);
-}
+int write_object_file(struct odb_source *source,
+ const void *buf, unsigned long len,
+ enum object_type type, struct object_id *oid,
+ struct object_id *compat_oid_in, unsigned flags);
struct input_stream {
const void *(*read)(struct input_stream *, unsigned long *len);
@@ -187,10 +157,12 @@ struct input_stream {
int is_finished;
};
-int stream_loose_object(struct input_stream *in_stream, size_t len,
+int stream_loose_object(struct odb_source *source,
+ struct input_stream *in_stream, size_t len,
struct object_id *oid);
-int force_object_loose(const struct object_id *oid, time_t mtime);
+int force_object_loose(struct odb_source *source,
+ const struct object_id *oid, time_t mtime);
/**
* With in-core object data in "buf", rehash it to make sure the
@@ -218,8 +190,10 @@ enum finalize_object_file_flags {
FOF_SKIP_COLLISION_CHECK = 1,
};
-int finalize_object_file(const char *tmpfile, const char *filename);
-int finalize_object_file_flags(const char *tmpfile, const char *filename,
+int finalize_object_file(struct repository *repo,
+ const char *tmpfile, const char *filename);
+int finalize_object_file_flags(struct repository *repo,
+ const char *tmpfile, const char *filename,
enum finalize_object_file_flags flags);
void hash_object_file(const struct git_hash_algo *algo, const void *buf,
@@ -237,7 +211,8 @@ int check_and_freshen_file(const char *fn, int freshen);
*
* Returns 0 on success, negative on error (details may be written to stderr).
*/
-int read_loose_object(const char *path,
+int read_loose_object(struct repository *repo,
+ const char *path,
const struct object_id *expected_oid,
struct object_id *real_oid,
void **contents,
diff --git a/object-name.c b/object-name.c
index 41930609e3..732056ff5e 100644
--- a/object-name.c
+++ b/object-name.c
@@ -199,16 +199,20 @@ static void unique_in_pack(struct packed_git *p,
static void find_short_packed_object(struct disambiguate_state *ds)
{
- struct multi_pack_index *m;
+ struct odb_source *source;
struct packed_git *p;
/* Skip, unless oids from the storage hash algorithm are wanted */
if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
return;
- for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous;
- m = m->next)
- unique_in_midx(m, ds);
+ odb_prepare_alternates(ds->repo->objects);
+ for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
+ if (m)
+ unique_in_midx(m, ds);
+ }
+
for (p = get_packed_git(ds->repo); p && !ds->ambiguous;
p = p->next)
unique_in_pack(p, ds);
@@ -793,11 +797,15 @@ static void find_abbrev_len_for_pack(struct packed_git *p,
static void find_abbrev_len_packed(struct min_abbrev_data *mad)
{
- struct multi_pack_index *m;
struct packed_git *p;
- for (m = get_multi_pack_index(mad->repo); m; m = m->next)
- find_abbrev_len_for_midx(m, mad);
+ odb_prepare_alternates(mad->repo->objects);
+ for (struct odb_source *source = mad->repo->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
+ if (m)
+ find_abbrev_len_for_midx(m, mad);
+ }
+
for (p = get_packed_git(mad->repo); p; p = p->next)
find_abbrev_len_for_pack(p, mad);
}
@@ -1517,7 +1525,8 @@ struct grab_nth_branch_switch_cbdata {
struct strbuf *sb;
};
-static int grab_nth_branch_switch(struct object_id *ooid UNUSED,
+static int grab_nth_branch_switch(const char *refname UNUSED,
+ struct object_id *ooid UNUSED,
struct object_id *noid UNUSED,
const char *email UNUSED,
timestamp_t timestamp UNUSED,
diff --git a/odb.c b/odb.c
index 1f48a0448e..2a92a018c4 100644
--- a/odb.c
+++ b/odb.c
@@ -980,6 +980,16 @@ void odb_assert_oid_type(struct object_database *odb,
type_name(expect));
}
+int odb_write_object_ext(struct object_database *odb,
+ const void *buf, unsigned long len,
+ enum object_type type,
+ struct object_id *oid,
+ struct object_id *compat_oid,
+ unsigned flags)
+{
+ return write_object_file(odb->sources, buf, len, type, oid, compat_oid, flags);
+}
+
struct object_database *odb_new(struct repository *repo)
{
struct object_database *o = xmalloc(sizeof(*o));
diff --git a/odb.h b/odb.h
index e922f25680..3dfc66d75a 100644
--- a/odb.h
+++ b/odb.h
@@ -13,6 +13,7 @@ struct oidmap;
struct oidtree;
struct strbuf;
struct repository;
+struct multi_pack_index;
/*
* Compute the exact path an alternate is at and returns it. In case of
@@ -56,6 +57,13 @@ struct odb_source {
struct loose_object_map *loose_map;
/*
+ * private data
+ *
+ * should only be accessed directly by packfile.c and midx.c
+ */
+ struct multi_pack_index *midx;
+
+ /*
* This is a temporary object store created by the tmp_objdir
* facility. Disable ref updates since the objects in the store
* might be discarded on rollback.
@@ -75,7 +83,6 @@ struct odb_source {
};
struct packed_git;
-struct multi_pack_index;
struct cached_object_entry;
/*
@@ -119,13 +126,6 @@ struct object_database {
/*
* private data
*
- * should only be accessed directly by packfile.c and midx.c
- */
- struct multi_pack_index *multi_pack_index;
-
- /*
- * private data
- *
* should only be accessed directly by packfile.c
*/
@@ -437,6 +437,44 @@ enum for_each_object_flags {
FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
};
+enum {
+ /*
+ * By default, `odb_write_object()` does not actually write anything
+ * into the object store, but only computes the object ID. This flag
+ * changes that so that the object will be written as a loose object
+ * and persisted.
+ */
+ WRITE_OBJECT_PERSIST = (1 << 0),
+
+ /*
+ * Do not print an error in case something goes wrong.
+ */
+ WRITE_OBJECT_SILENT = (1 << 1),
+};
+
+/*
+ * Write an object into the object database. The object is being written into
+ * the local alternate of the repository. If provided, the converted object ID
+ * as well as the compatibility object ID are written to the respective
+ * pointers.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int odb_write_object_ext(struct object_database *odb,
+ const void *buf, unsigned long len,
+ enum object_type type,
+ struct object_id *oid,
+ struct object_id *compat_oid,
+ unsigned flags);
+
+static inline int odb_write_object(struct object_database *odb,
+ const void *buf, unsigned long len,
+ enum object_type type,
+ struct object_id *oid)
+{
+ return odb_write_object_ext(odb, buf, len, type, oid, NULL, 0);
+}
+
/* Compatibility wrappers, to be removed once Git 2.51 has been released. */
#include "repository.h"
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 15cf51166e..d14421ee20 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -683,13 +683,15 @@ static int open_pack_bitmap(struct repository *r,
static int open_midx_bitmap(struct repository *r,
struct bitmap_index *bitmap_git)
{
+ struct odb_source *source;
int ret = -1;
- struct multi_pack_index *midx;
assert(!bitmap_git->map);
- for (midx = get_multi_pack_index(r); midx; midx = midx->next) {
- if (!open_midx_bitmap_1(bitmap_git, midx))
+ odb_prepare_alternates(r->objects);
+ for (source = r->objects->sources; source; source = source->next) {
+ struct multi_pack_index *midx = get_multi_pack_index(source);
+ if (midx && !open_midx_bitmap_1(bitmap_git, midx))
ret = 0;
}
return ret;
@@ -3345,11 +3347,18 @@ static int verify_bitmap_file(const struct git_hash_algo *algop,
int verify_bitmap_files(struct repository *r)
{
+ struct odb_source *source;
int res = 0;
- for (struct multi_pack_index *m = get_multi_pack_index(r);
- m; m = m->next) {
- char *midx_bitmap_name = midx_bitmap_filename(m);
+ odb_prepare_alternates(r->objects);
+ for (source = r->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
+ char *midx_bitmap_name;
+
+ if (!m)
+ continue;
+
+ midx_bitmap_name = midx_bitmap_filename(m);
res |= verify_bitmap_file(r->hash_algo, midx_bitmap_name);
free(midx_bitmap_name);
}
diff --git a/pack-write.c b/pack-write.c
index eccdc798e3..83eaf88541 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -538,22 +538,24 @@ struct hashfile *create_tmp_packfile(struct repository *repo,
return hashfd(repo->hash_algo, fd, *pack_tmp_name);
}
-static void rename_tmp_packfile(struct strbuf *name_prefix, const char *source,
+static void rename_tmp_packfile(struct repository *repo,
+ struct strbuf *name_prefix, const char *source,
const char *ext)
{
size_t name_prefix_len = name_prefix->len;
strbuf_addstr(name_prefix, ext);
- if (finalize_object_file(source, name_prefix->buf))
+ if (finalize_object_file(repo, source, name_prefix->buf))
die("unable to rename temporary file to '%s'",
name_prefix->buf);
strbuf_setlen(name_prefix, name_prefix_len);
}
-void rename_tmp_packfile_idx(struct strbuf *name_buffer,
+void rename_tmp_packfile_idx(struct repository *repo,
+ struct strbuf *name_buffer,
char **idx_tmp_name)
{
- rename_tmp_packfile(name_buffer, *idx_tmp_name, "idx");
+ rename_tmp_packfile(repo, name_buffer, *idx_tmp_name, "idx");
}
void stage_tmp_packfiles(struct repository *repo,
@@ -586,11 +588,11 @@ void stage_tmp_packfiles(struct repository *repo,
hash);
}
- rename_tmp_packfile(name_buffer, pack_tmp_name, "pack");
+ rename_tmp_packfile(repo, name_buffer, pack_tmp_name, "pack");
if (rev_tmp_name)
- rename_tmp_packfile(name_buffer, rev_tmp_name, "rev");
+ rename_tmp_packfile(repo, name_buffer, rev_tmp_name, "rev");
if (mtimes_tmp_name)
- rename_tmp_packfile(name_buffer, mtimes_tmp_name, "mtimes");
+ rename_tmp_packfile(repo, name_buffer, mtimes_tmp_name, "mtimes");
free(rev_tmp_name);
free(mtimes_tmp_name);
diff --git a/pack.h b/pack.h
index 5d4393eaff..ec76472e49 100644
--- a/pack.h
+++ b/pack.h
@@ -145,7 +145,8 @@ void stage_tmp_packfiles(struct repository *repo,
struct pack_idx_option *pack_idx_opts,
unsigned char hash[],
char **idx_tmp_name);
-void rename_tmp_packfile_idx(struct strbuf *basename,
+void rename_tmp_packfile_idx(struct repository *repo,
+ struct strbuf *basename,
char **idx_tmp_name);
#endif
diff --git a/packfile.c b/packfile.c
index af9ccfdba6..5d73932f50 100644
--- a/packfile.c
+++ b/packfile.c
@@ -361,6 +361,7 @@ void close_pack(struct packed_git *p)
void close_object_store(struct object_database *o)
{
+ struct odb_source *source;
struct packed_git *p;
for (p = o->packed_git; p; p = p->next)
@@ -369,9 +370,10 @@ void close_object_store(struct object_database *o)
else
close_pack(p);
- if (o->multi_pack_index) {
- close_midx(o->multi_pack_index);
- o->multi_pack_index = NULL;
+ for (source = o->sources; source; source = source->next) {
+ if (source->midx)
+ close_midx(source->midx);
+ source->midx = NULL;
}
close_commit_graph(o);
@@ -933,22 +935,17 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
report_garbage(PACKDIR_FILE_GARBAGE, full_name);
}
-static void prepare_packed_git_one(struct repository *r, char *objdir, int local)
+static void prepare_packed_git_one(struct odb_source *source, int local)
{
- struct prepare_pack_data data;
struct string_list garbage = STRING_LIST_INIT_DUP;
+ struct prepare_pack_data data = {
+ .m = source->midx,
+ .r = source->odb->repo,
+ .garbage = &garbage,
+ .local = local,
+ };
- data.m = r->objects->multi_pack_index;
-
- /* look for the multi-pack-index for this object directory */
- while (data.m && strcmp(data.m->object_dir, objdir))
- data.m = data.m->next;
-
- data.r = r;
- data.garbage = &garbage;
- data.local = local;
-
- for_each_file_in_pack_dir(objdir, prepare_pack, &data);
+ for_each_file_in_pack_dir(source->path, prepare_pack, &data);
report_pack_garbage(data.garbage);
string_list_clear(data.garbage, 0);
@@ -965,14 +962,18 @@ static void prepare_packed_git(struct repository *r);
unsigned long repo_approximate_object_count(struct repository *r)
{
if (!r->objects->approximate_object_count_valid) {
- unsigned long count;
- struct multi_pack_index *m;
+ struct odb_source *source;
+ unsigned long count = 0;
struct packed_git *p;
prepare_packed_git(r);
- count = 0;
- for (m = get_multi_pack_index(r); m; m = m->next)
- count += m->num_objects;
+
+ for (source = r->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
+ if (m)
+ count += m->num_objects;
+ }
+
for (p = r->objects->packed_git; p; p = p->next) {
if (open_pack_index(p))
continue;
@@ -1037,8 +1038,8 @@ static void prepare_packed_git(struct repository *r)
odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
int local = (source == r->objects->sources);
- prepare_multi_pack_index_one(r, source->path, local);
- prepare_packed_git_one(r, source->path, local);
+ prepare_multi_pack_index_one(source, local);
+ prepare_packed_git_one(source, local);
}
rearrange_packed_git(r);
@@ -1076,31 +1077,21 @@ struct packed_git *get_packed_git(struct repository *r)
return r->objects->packed_git;
}
-struct multi_pack_index *get_multi_pack_index(struct repository *r)
+struct multi_pack_index *get_multi_pack_index(struct odb_source *source)
{
- prepare_packed_git(r);
- return r->objects->multi_pack_index;
-}
-
-struct multi_pack_index *get_local_multi_pack_index(struct repository *r)
-{
- struct multi_pack_index *m = get_multi_pack_index(r);
-
- /* no need to iterate; we always put the local one first (if any) */
- if (m && m->local)
- return m;
-
- return NULL;
+ prepare_packed_git(source->odb->repo);
+ return source->midx;
}
struct packed_git *get_all_packs(struct repository *r)
{
- struct multi_pack_index *m;
-
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 + m->num_packs_in_base; i++)
+
+ for (struct odb_source *source = r->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = source->midx;
+ if (!m)
+ continue;
+ for (uint32_t i = 0; i < m->num_packs + m->num_packs_in_base; i++)
prepare_midx_pack(r, m, i);
}
@@ -2083,16 +2074,15 @@ static int fill_pack_entry(const struct object_id *oid,
int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e)
{
struct list_head *pos;
- struct multi_pack_index *m;
prepare_packed_git(r);
- if (!r->objects->packed_git && !r->objects->multi_pack_index)
- return 0;
- for (m = r->objects->multi_pack_index; m; m = m->next) {
- if (fill_midx_entry(r, oid, e, m))
+ for (struct odb_source *source = r->objects->sources; source; source = source->next)
+ if (source->midx && fill_midx_entry(r, oid, e, source->midx))
return 1;
- }
+
+ if (!r->objects->packed_git)
+ return 0;
list_for_each(pos, &r->objects->packed_git_mru) {
struct packed_git *p = list_entry(pos, struct packed_git, mru);
diff --git a/packfile.h b/packfile.h
index 53c3b7d3b4..f16753f2a9 100644
--- a/packfile.h
+++ b/packfile.h
@@ -147,8 +147,7 @@ void install_packed_git(struct repository *r, struct packed_git *pack);
struct packed_git *get_packed_git(struct repository *r);
struct list_head *get_packed_git_mru(struct repository *r);
-struct multi_pack_index *get_multi_pack_index(struct repository *r);
-struct multi_pack_index *get_local_multi_pack_index(struct repository *r);
+struct multi_pack_index *get_multi_pack_index(struct odb_source *source);
struct packed_git *get_all_packs(struct repository *r);
/*
diff --git a/parallel-checkout.c b/parallel-checkout.c
index 57c2dcaa8f..fba6aa65a6 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -57,12 +57,12 @@ void get_parallel_checkout_configs(int *num_workers, int *threshold)
return;
}
- if (git_config_get_int("checkout.workers", num_workers))
+ if (repo_config_get_int(the_repository, "checkout.workers", num_workers))
*num_workers = DEFAULT_NUM_WORKERS;
else if (*num_workers < 1)
*num_workers = online_cpus();
- if (git_config_get_int("checkout.thresholdForParallelism", threshold))
+ if (repo_config_get_int(the_repository, "checkout.thresholdForParallelism", threshold))
*threshold = DEFAULT_THRESHOLD_FOR_PARALLELISM;
}
diff --git a/parse-options.c b/parse-options.c
index 5224203ffe..992ec9631f 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -953,10 +953,16 @@ static void free_preprocessed_options(struct option *options)
free(options);
}
+#define USAGE_NORMAL 0
+#define USAGE_FULL 1
+#define USAGE_TO_STDOUT 0
+#define USAGE_TO_STDERR 1
+
static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *,
const char * const *,
const struct option *,
- int, int);
+ int full_usage,
+ int usage_to_stderr);
enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
const struct option *options,
@@ -1088,7 +1094,8 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
}
if (internal_help && !strcmp(arg + 2, "help-all"))
- return usage_with_options_internal(ctx, usagestr, options, 1, 0);
+ return usage_with_options_internal(ctx, usagestr, options,
+ USAGE_FULL, USAGE_TO_STDOUT);
if (internal_help && !strcmp(arg + 2, "help"))
goto show_usage;
switch (parse_long_opt(ctx, arg + 2, options)) {
@@ -1129,7 +1136,8 @@ unknown:
return PARSE_OPT_DONE;
show_usage:
- return usage_with_options_internal(ctx, usagestr, options, 0, 0);
+ return usage_with_options_internal(ctx, usagestr, options,
+ USAGE_NORMAL, USAGE_TO_STDOUT);
}
int parse_options_end(struct parse_opt_ctx_t *ctx)
@@ -1338,7 +1346,7 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
if (!saw_empty_line && !*str)
saw_empty_line = 1;
- string_list_split(&list, str, '\n', -1);
+ string_list_split(&list, str, "\n", -1);
for (j = 0; j < list.nr; j++) {
const char *line = list.items[j].string;
@@ -1444,7 +1452,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
void NORETURN usage_with_options(const char * const *usagestr,
const struct option *opts)
{
- usage_with_options_internal(NULL, usagestr, opts, 0, 1);
+ usage_with_options_internal(NULL, usagestr, opts,
+ USAGE_NORMAL, USAGE_TO_STDERR);
exit(129);
}
@@ -1452,9 +1461,16 @@ void show_usage_with_options_if_asked(int ac, const char **av,
const char * const *usagestr,
const struct option *opts)
{
- if (ac == 2 && !strcmp(av[1], "-h")) {
- usage_with_options_internal(NULL, usagestr, opts, 0, 0);
- exit(129);
+ if (ac == 2) {
+ if (!strcmp(av[1], "-h")) {
+ usage_with_options_internal(NULL, usagestr, opts,
+ USAGE_NORMAL, USAGE_TO_STDOUT);
+ exit(129);
+ } else if (!strcmp(av[1], "--help-all")) {
+ usage_with_options_internal(NULL, usagestr, opts,
+ USAGE_FULL, USAGE_TO_STDOUT);
+ exit(129);
+ }
}
}
diff --git a/parse-options.h b/parse-options.h
index 312045604d..706de9729f 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -623,6 +623,8 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
#define OPT_PATHSPEC_FROM_FILE(v) OPT_FILENAME(0, "pathspec-from-file", v, N_("read pathspec from file"))
#define OPT_PATHSPEC_FILE_NUL(v) OPT_BOOL(0, "pathspec-file-nul", v, N_("with --pathspec-from-file, pathspec elements are separated with NUL character"))
#define OPT_AUTOSTASH(v) OPT_BOOL(0, "autostash", v, N_("automatically stash/stash pop before and after"))
+#define OPT_DIFF_UNIFIED(v) OPT_INTEGER_F('U', "unified", v, N_("generate diffs with <n> lines context"), PARSE_OPT_NONEG)
+#define OPT_DIFF_INTERHUNK_CONTEXT(v) OPT_INTEGER_F(0, "inter-hunk-context", v, N_("show context between diff hunks up to the specified number of lines"), PARSE_OPT_NONEG)
#define OPT_IPVERSION(v) \
OPT_SET_INT_F('4', "ipv4", (v), N_("use IPv4 addresses only"), \
diff --git a/pathspec.c b/pathspec.c
index a3ddd701c7..5993c4afa0 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -201,8 +201,7 @@ static void parse_pathspec_attr_match(struct pathspec_item *item, const char *va
if (!value || !*value)
die(_("attr spec must not be empty"));
- string_list_split(&list, value, ' ', -1);
- string_list_remove_empty_items(&list, 0);
+ string_list_split_f(&list, value, " ", -1, STRING_LIST_SPLIT_NONEMPTY);
item->attr_check = attr_check_alloc();
CALLOC_ARRAY(item->attr_match, list.nr);
diff --git a/pretty.c b/pretty.c
index 0bc8ad8a9a..cee96b9d94 100644
--- a/pretty.c
+++ b/pretty.c
@@ -141,7 +141,7 @@ static void setup_commit_formats(void)
COPY_ARRAY(commit_formats, builtin_formats,
ARRAY_SIZE(builtin_formats));
- git_config(git_pretty_formats_config, NULL);
+ repo_config(the_repository, git_pretty_formats_config, NULL);
}
static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
diff --git a/promisor-remote.c b/promisor-remote.c
index be6f82d12f..08b0da8962 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -46,7 +46,7 @@ static int fetch_objects(struct repository *repo,
"fetch", remote_name, "--no-tags",
"--no-write-fetch-head", "--recurse-submodules=no",
"--filter=blob:none", "--stdin", NULL);
- if (!git_config_get_bool("promisor.quiet", &quiet) && quiet)
+ if (!repo_config_get_bool(the_repository, "promisor.quiet", &quiet) && quiet)
strvec_push(&child.args, "--quiet");
if (start_command(&child))
die(_("promisor-remote: unable to fork off fetch subprocess"));
@@ -327,7 +327,7 @@ static void promisor_info_vecs(struct repository *repo,
char *url_key = xstrfmt("remote.%s.url", r->name);
/* Only add remotes with a non empty URL */
- if (!git_config_get_string_tmp(url_key, &url) && *url) {
+ if (!repo_config_get_string_tmp(the_repository, url_key, &url) && *url) {
strvec_push(names, r->name);
strvec_push(urls, url);
}
@@ -343,7 +343,7 @@ char *promisor_remote_info(struct repository *repo)
struct strvec names = STRVEC_INIT;
struct strvec urls = STRVEC_INIT;
- git_config_get_bool("promisor.advertise", &advertise_promisors);
+ repo_config_get_bool(the_repository, "promisor.advertise", &advertise_promisors);
if (!advertise_promisors)
return NULL;
@@ -433,7 +433,7 @@ static void filter_promisor_remote(struct repository *repo,
struct strvec names = STRVEC_INIT;
struct strvec urls = STRVEC_INIT;
- if (!git_config_get_string_tmp("promisor.acceptfromserver", &accept_str)) {
+ if (!repo_config_get_string_tmp(the_repository, "promisor.acceptfromserver", &accept_str)) {
if (!*accept_str || !strcasecmp("None", accept_str))
accept = ACCEPT_NONE;
else if (!strcasecmp("KnownUrl", accept_str))
diff --git a/prompt.c b/prompt.c
index f21c5bf1c7..706fba2a50 100644
--- a/prompt.c
+++ b/prompt.c
@@ -77,12 +77,6 @@ char *git_prompt(const char *prompt, int flags)
int git_read_line_interactively(struct strbuf *line)
{
- int ret;
-
fflush(stdout);
- ret = strbuf_getline_lf(line, stdin);
- if (ret != EOF)
- strbuf_trim_trailing_newline(line);
-
- return ret;
+ return strbuf_getline(line, stdin);
}
diff --git a/protocol.c b/protocol.c
index bae7226ff4..a3e26a8dd3 100644
--- a/protocol.c
+++ b/protocol.c
@@ -24,7 +24,7 @@ enum protocol_version get_protocol_version_config(void)
const char *git_test_k = "GIT_TEST_PROTOCOL_VERSION";
const char *git_test_v;
- if (!git_config_get_string_tmp("protocol.version", &value)) {
+ if (!repo_config_get_string_tmp(the_repository, "protocol.version", &value)) {
enum protocol_version version = parse_protocol_version(value);
if (version == protocol_unknown_version)
@@ -61,7 +61,7 @@ enum protocol_version determine_protocol_version_server(void)
if (git_protocol) {
struct string_list list = STRING_LIST_INIT_DUP;
const struct string_list_item *item;
- string_list_split(&list, git_protocol, ':', -1);
+ string_list_split(&list, git_protocol, ":", -1);
for_each_string_list_item(item, &list) {
const char *value;
diff --git a/prune-packed.c b/prune-packed.c
index 92fb4fbb0e..d49dc11957 100644
--- a/prune-packed.c
+++ b/prune-packed.c
@@ -40,7 +40,7 @@ void prune_packed_objects(int opts)
progress = start_delayed_progress(the_repository,
_("Removing duplicate objects"), 256);
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ for_each_loose_file_in_source(the_repository->objects->sources,
prune_object, NULL, prune_subdir, &opts);
/* Ensure we show 100% before finishing progress */
diff --git a/reachable.c b/reachable.c
index e984b68a0c..22266db523 100644
--- a/reachable.c
+++ b/reachable.c
@@ -170,7 +170,7 @@ static void load_gc_recent_objects(struct recent_data *data)
data->extra_recent_oids_loaded = 1;
- if (git_config_get_string_multi("gc.recentobjectshook", &programs))
+ if (repo_config_get_string_multi(the_repository, "gc.recentobjectshook", &programs))
return;
for (i = 0; i < programs->nr; i++) {
@@ -319,7 +319,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
oidset_init(&data.extra_recent_oids, 0);
data.extra_recent_oids_loaded = 0;
- r = for_each_loose_object(add_recent_loose, &data,
+ r = for_each_loose_object(the_repository->objects, add_recent_loose, &data,
FOR_EACH_OBJECT_LOCAL_ONLY);
if (r)
goto done;
diff --git a/read-cache.c b/read-cache.c
index 5cf41b81f1..06ad74db22 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -690,7 +690,7 @@ static struct cache_entry *create_alias_ce(struct index_state *istate,
void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
{
struct object_id oid;
- if (write_object_file("", 0, OBJ_BLOB, &oid))
+ if (odb_write_object(the_repository->objects, "", 0, OBJ_BLOB, &oid))
die(_("cannot create an empty blob in the object database"));
oidcpy(&ce->oid, &oid);
}
@@ -2755,7 +2755,7 @@ static int record_eoie(void)
{
int val;
- if (!git_config_get_bool("index.recordendofindexentries", &val))
+ if (!repo_config_get_bool(the_repository, "index.recordendofindexentries", &val))
return val;
/*
@@ -2770,7 +2770,7 @@ static int record_ieot(void)
{
int val;
- if (!git_config_get_bool("index.recordoffsettable", &val))
+ if (!repo_config_get_bool(the_repository, "index.recordoffsettable", &val))
return val;
/*
diff --git a/rebase-interactive.c b/rebase-interactive.c
index cbeb864147..809f76a87b 100644
--- a/rebase-interactive.c
+++ b/rebase-interactive.c
@@ -30,7 +30,7 @@ static enum missing_commit_check_level get_missing_commit_check_level(void)
{
const char *value;
- if (git_config_get_value("rebase.missingcommitscheck", &value) ||
+ if (repo_config_get_value(the_repository, "rebase.missingcommitscheck", &value) ||
!strcasecmp("ignore", value))
return MISSING_COMMIT_CHECK_IGNORE;
if (!strcasecmp("warn", value))
diff --git a/ref-filter.c b/ref-filter.c
index f9f2c512a8..520d2539c9 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -435,7 +435,7 @@ static int remote_ref_atom_parser(struct ref_format *format UNUSED,
}
atom->u.remote_ref.nobracket = 0;
- string_list_split(&params, arg, ',', -1);
+ string_list_split(&params, arg, ",", -1);
for (i = 0; i < params.nr; i++) {
const char *s = params.items[i].string;
@@ -831,7 +831,7 @@ static int align_atom_parser(struct ref_format *format UNUSED,
align->position = ALIGN_LEFT;
- string_list_split(&params, arg, ',', -1);
+ string_list_split(&params, arg, ",", -1);
for (i = 0; i < params.nr; i++) {
const char *s = params.items[i].string;
int position;
@@ -2684,6 +2684,41 @@ static int filter_exclude_match(struct ref_filter *filter, const char *refname)
}
/*
+ * We need to seek to the reference right after a given marker but excluding any
+ * matching references. So we seek to the lexicographically next reference.
+ */
+static int start_ref_iterator_after(struct ref_iterator *iter, const char *marker)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret;
+
+ strbuf_addstr(&sb, marker);
+ strbuf_addch(&sb, 1);
+
+ ret = ref_iterator_seek(iter, sb.buf, 0);
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int for_each_fullref_with_seek(struct ref_filter *filter, each_ref_fn cb,
+ void *cb_data, unsigned int flags)
+{
+ struct ref_iterator *iter;
+ int ret = 0;
+
+ iter = refs_ref_iterator_begin(get_main_ref_store(the_repository), "",
+ NULL, 0, flags);
+ if (filter->start_after)
+ ret = start_ref_iterator_after(iter, filter->start_after);
+
+ if (ret)
+ return ret;
+
+ return do_for_each_ref_iterator(iter, cb, cb_data);
+}
+
+/*
* This is the same as for_each_fullref_in(), but it tries to iterate
* only over the patterns we'll care about. Note that it _doesn't_ do a full
* pattern match, so the callback still has to match each ref individually.
@@ -2694,8 +2729,8 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
{
if (filter->kind & FILTER_REFS_ROOT_REFS) {
/* In this case, we want to print all refs including root refs. */
- return refs_for_each_include_root_refs(get_main_ref_store(the_repository),
- cb, cb_data);
+ return for_each_fullref_with_seek(filter, cb, cb_data,
+ DO_FOR_EACH_INCLUDE_ROOT_REFS);
}
if (!filter->match_as_path) {
@@ -2704,8 +2739,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
* prefixes like "refs/heads/" etc. are stripped off,
* so we have to look at everything:
*/
- return refs_for_each_fullref_in(get_main_ref_store(the_repository),
- "", NULL, cb, cb_data);
+ return for_each_fullref_with_seek(filter, cb, cb_data, 0);
}
if (filter->ignore_case) {
@@ -2714,14 +2748,12 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
* so just return everything and let the caller
* sort it out.
*/
- return refs_for_each_fullref_in(get_main_ref_store(the_repository),
- "", NULL, cb, cb_data);
+ return for_each_fullref_with_seek(filter, cb, cb_data, 0);
}
if (!filter->name_patterns[0]) {
/* no patterns; we have to look at everything */
- return refs_for_each_fullref_in(get_main_ref_store(the_repository),
- "", filter->exclude.v, cb, cb_data);
+ return for_each_fullref_with_seek(filter, cb, cb_data, 0);
}
return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
@@ -3189,6 +3221,7 @@ void filter_is_base(struct repository *r,
static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref_fn fn, void *cb_data)
{
+ const char *prefix = NULL;
int ret = 0;
filter->kind = type & FILTER_REFS_KIND_MASK;
@@ -3199,38 +3232,48 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref
/* Simple per-ref filtering */
if (!filter->kind)
die("filter_refs: invalid type");
- else {
- /*
- * For common cases where we need only branches or remotes or tags,
- * we only iterate through those refs. If a mix of refs is needed,
- * we iterate over all refs and filter out required refs with the help
- * of filter_ref_kind().
- */
- if (filter->kind == FILTER_REFS_BRANCHES)
- ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
- "refs/heads/", NULL,
- fn, cb_data);
- else if (filter->kind == FILTER_REFS_REMOTES)
- ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
- "refs/remotes/", NULL,
- fn, cb_data);
- else if (filter->kind == FILTER_REFS_TAGS)
- ret = refs_for_each_fullref_in(get_main_ref_store(the_repository),
- "refs/tags/", NULL, fn,
- cb_data);
- else if (filter->kind & FILTER_REFS_REGULAR)
- ret = for_each_fullref_in_pattern(filter, fn, cb_data);
- /*
- * When printing all ref types, HEAD is already included,
- * so we don't want to print HEAD again.
- */
- if (!ret && !(filter->kind & FILTER_REFS_ROOT_REFS) &&
- (filter->kind & FILTER_REFS_DETACHED_HEAD))
- refs_head_ref(get_main_ref_store(the_repository), fn,
- cb_data);
+ /*
+ * For common cases where we need only branches or remotes or tags,
+ * we only iterate through those refs. If a mix of refs is needed,
+ * we iterate over all refs and filter out required refs with the help
+ * of filter_ref_kind().
+ */
+ if (filter->kind == FILTER_REFS_BRANCHES)
+ prefix = "refs/heads/";
+ else if (filter->kind == FILTER_REFS_REMOTES)
+ prefix = "refs/remotes/";
+ else if (filter->kind == FILTER_REFS_TAGS)
+ prefix = "refs/tags/";
+
+ if (prefix) {
+ struct ref_iterator *iter;
+
+ iter = refs_ref_iterator_begin(get_main_ref_store(the_repository),
+ "", NULL, 0, 0);
+
+ if (filter->start_after)
+ ret = start_ref_iterator_after(iter, filter->start_after);
+ else
+ ret = ref_iterator_seek(iter, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX);
+
+ if (!ret)
+ ret = do_for_each_ref_iterator(iter, fn, cb_data);
+ } else if (filter->kind & FILTER_REFS_REGULAR) {
+ ret = for_each_fullref_in_pattern(filter, fn, cb_data);
}
+ /*
+ * When printing all ref types, HEAD is already included,
+ * so we don't want to print HEAD again.
+ */
+ if (!ret && !(filter->kind & FILTER_REFS_ROOT_REFS) &&
+ (filter->kind & FILTER_REFS_DETACHED_HEAD))
+ refs_head_ref(get_main_ref_store(the_repository), fn,
+ cb_data);
+
+
clear_contains_cache(&filter->internal.contains_cache);
clear_contains_cache(&filter->internal.no_contains_cache);
diff --git a/ref-filter.h b/ref-filter.h
index c98c4fbd4c..f22ca94b49 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -64,6 +64,7 @@ struct ref_array {
struct ref_filter {
const char **name_patterns;
+ const char *start_after;
struct strvec exclude;
struct oid_array points_at;
struct commit_list *with_commit;
diff --git a/reflog-walk.c b/reflog-walk.c
index c7070b13b0..4f1ce04749 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -22,9 +22,10 @@ struct complete_reflogs {
int nr, alloc;
};
-static int read_one_reflog(struct object_id *ooid, struct object_id *noid,
- const char *email, timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
+static int read_one_reflog(const char *refname UNUSED,
+ struct object_id *ooid, struct object_id *noid,
+ const char *email, timestamp_t timestamp, int tz,
+ const char *message, void *cb_data)
{
struct complete_reflogs *array = cb_data;
struct reflog_info *item;
diff --git a/reflog.c b/reflog.c
index 9a68524df8..65ef259b4f 100644
--- a/reflog.c
+++ b/reflog.c
@@ -3,6 +3,7 @@
#include "git-compat-util.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "odb.h"
@@ -506,7 +507,8 @@ void reflog_expiry_cleanup(void *cb_data)
free_commit_list(cb->mark_list);
}
-int count_reflog_ent(struct object_id *ooid UNUSED,
+int count_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid UNUSED,
struct object_id *noid UNUSED,
const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED,
diff --git a/reflog.h b/reflog.h
index 74b3f3c4f0..b996712c00 100644
--- a/reflog.h
+++ b/reflog.h
@@ -65,7 +65,8 @@ void reflog_expiry_prepare(const char *refname, const struct object_id *oid,
int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data);
-int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
+int count_reflog_ent(const char *refname,
+ struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data);
int should_expire_reflog_ent_verbose(struct object_id *ooid,
diff --git a/refs.c b/refs.c
index 73913b6627..4ff55cf24f 100644
--- a/refs.c
+++ b/refs.c
@@ -945,7 +945,7 @@ long get_files_ref_lock_timeout_ms(void)
static int timeout_ms = 100;
if (!configured) {
- git_config_get_int("core.filesreflocktimeout", &timeout_ms);
+ repo_config_get_int(the_repository, "core.filesreflocktimeout", &timeout_ms);
configured = 1;
}
@@ -1022,7 +1022,6 @@ int is_branch(const char *refname)
}
struct read_ref_at_cb {
- const char *refname;
timestamp_t at_time;
int cnt;
int reccnt;
@@ -1052,7 +1051,8 @@ static void set_read_ref_cutoffs(struct read_ref_at_cb *cb,
*cb->cutoff_cnt = cb->reccnt;
}
-static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
+static int read_ref_at_ent(const char *refname,
+ struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp, int tz,
const char *message, void *cb_data)
@@ -1072,14 +1072,13 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
oidcpy(cb->oid, noid);
if (!oideq(&cb->ooid, noid))
warning(_("log for ref %s has gap after %s"),
- cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
+ refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
}
else if (cb->date == cb->at_time)
oidcpy(cb->oid, noid);
else if (!oideq(noid, cb->oid))
warning(_("log for ref %s unexpectedly ended on %s"),
- cb->refname, show_date(cb->date, cb->tz,
- DATE_MODE(RFC2822)));
+ refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
cb->reccnt++;
oidcpy(&cb->ooid, ooid);
oidcpy(&cb->noid, noid);
@@ -1094,7 +1093,8 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
return 0;
}
-static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
+static int read_ref_at_ent_oldest(const char *refname UNUSED,
+ struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp, int tz,
const char *message, void *cb_data)
@@ -1117,7 +1117,6 @@ int read_ref_at(struct ref_store *refs, const char *refname,
struct read_ref_at_cb cb;
memset(&cb, 0, sizeof(cb));
- cb.refname = refname;
cb.at_time = at_time;
cb.cnt = cnt;
cb.msg = msg;
@@ -1362,27 +1361,22 @@ int ref_transaction_update(struct ref_transaction *transaction,
return 0;
}
-/*
- * Similar to`ref_transaction_update`, but this function is only for adding
- * a reflog update. Supports providing custom committer information. The index
- * field can be utiltized to order updates as desired. When not used, the
- * updates default to being ordered by refname.
- */
-static int ref_transaction_update_reflog(struct ref_transaction *transaction,
- const char *refname,
- const struct object_id *new_oid,
- const struct object_id *old_oid,
- const char *committer_info,
- unsigned int flags,
- const char *msg,
- uint64_t index,
- struct strbuf *err)
+int ref_transaction_update_reflog(struct ref_transaction *transaction,
+ const char *refname,
+ const struct object_id *new_oid,
+ const struct object_id *old_oid,
+ const char *committer_info,
+ const char *msg,
+ uint64_t index,
+ struct strbuf *err)
{
struct ref_update *update;
+ unsigned int flags;
assert(err);
- flags |= REF_LOG_ONLY | REF_FORCE_CREATE_REFLOG | REF_NO_DEREF;
+ flags = REF_HAVE_OLD | REF_HAVE_NEW | REF_LOG_ONLY | REF_FORCE_CREATE_REFLOG | REF_NO_DEREF |
+ REF_LOG_USE_PROVIDED_OIDS;
if (!transaction_refname_valid(refname, new_oid, flags, err))
return -1;
@@ -1390,11 +1384,6 @@ static int ref_transaction_update_reflog(struct ref_transaction *transaction,
update = ref_transaction_add_update(transaction, refname, flags,
new_oid, old_oid, NULL, NULL,
committer_info, msg);
- /*
- * While we do set the old_oid value, we unset the flag to skip
- * old_oid verification which only makes sense for refs.
- */
- update->flags &= ~REF_HAVE_OLD;
update->index = index;
/*
@@ -1850,7 +1839,13 @@ int refs_for_each_namespaced_ref(struct ref_store *refs,
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
- return do_for_each_ref(refs, "", NULL, fn, 0,
+ return refs_for_each_rawref_in(refs, "", fn, cb_data);
+}
+
+int refs_for_each_rawref_in(struct ref_store *refs, const char *prefix,
+ each_ref_fn fn, void *cb_data)
+{
+ return do_for_each_ref(refs, prefix, NULL, fn, 0,
DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
}
@@ -2657,12 +2652,12 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs
if (!initial_transaction) {
int ok;
- if (!iter) {
+ if (!iter)
iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
DO_FOR_EACH_INCLUDE_BROKEN);
- } else if (ref_iterator_seek(iter, dirname.buf) < 0) {
+ else if (ref_iterator_seek(iter, dirname.buf,
+ REF_ITERATOR_SEEK_SET_PREFIX) < 0)
goto cleanup;
- }
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
if (skip &&
@@ -2951,7 +2946,8 @@ struct migration_data {
struct ref_store *old_refs;
struct ref_transaction *transaction;
struct strbuf *errbuf;
- struct strbuf sb;
+ struct strbuf sb, name, mail;
+ uint64_t index;
};
static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
@@ -2984,50 +2980,41 @@ done:
return ret;
}
-struct reflog_migration_data {
- uint64_t index;
- const char *refname;
- struct ref_store *old_refs;
- struct ref_transaction *transaction;
- struct strbuf *errbuf;
- struct strbuf *sb;
-};
-
-static int migrate_one_reflog_entry(struct object_id *old_oid,
+static int migrate_one_reflog_entry(const char *refname,
+ struct object_id *old_oid,
struct object_id *new_oid,
const char *committer,
timestamp_t timestamp, int tz,
const char *msg, void *cb_data)
{
- struct reflog_migration_data *data = cb_data;
+ struct migration_data *data = cb_data;
+ struct ident_split ident;
const char *date;
int ret;
+ if (split_ident_line(&ident, committer, strlen(committer)) < 0)
+ return -1;
+
+ strbuf_reset(&data->name);
+ strbuf_add(&data->name, ident.name_begin, ident.name_end - ident.name_begin);
+ strbuf_reset(&data->mail);
+ strbuf_add(&data->mail, ident.mail_begin, ident.mail_end - ident.mail_begin);
+
date = show_date(timestamp, tz, DATE_MODE(NORMAL));
- strbuf_reset(data->sb);
- /* committer contains name and email */
- strbuf_addstr(data->sb, fmt_ident("", committer, WANT_BLANK_IDENT, date, 0));
-
- ret = ref_transaction_update_reflog(data->transaction, data->refname,
- new_oid, old_oid, data->sb->buf,
- REF_HAVE_NEW | REF_HAVE_OLD, msg,
- data->index++, data->errbuf);
+ strbuf_reset(&data->sb);
+ strbuf_addstr(&data->sb, fmt_ident(data->name.buf, data->mail.buf, WANT_BLANK_IDENT, date, 0));
+
+ ret = ref_transaction_update_reflog(data->transaction, refname,
+ new_oid, old_oid, data->sb.buf,
+ msg, data->index++, data->errbuf);
return ret;
}
static int migrate_one_reflog(const char *refname, void *cb_data)
{
struct migration_data *migration_data = cb_data;
- struct reflog_migration_data data = {
- .refname = refname,
- .old_refs = migration_data->old_refs,
- .transaction = migration_data->transaction,
- .errbuf = migration_data->errbuf,
- .sb = &migration_data->sb,
- };
-
return refs_for_each_reflog_ent(migration_data->old_refs, refname,
- migrate_one_reflog_entry, &data);
+ migrate_one_reflog_entry, migration_data);
}
static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf)
@@ -3122,6 +3109,8 @@ int repo_migrate_ref_storage_format(struct repository *repo,
struct strbuf new_gitdir = STRBUF_INIT;
struct migration_data data = {
.sb = STRBUF_INIT,
+ .name = STRBUF_INIT,
+ .mail = STRBUF_INIT,
};
int did_migrate_refs = 0;
int ret;
@@ -3297,11 +3286,16 @@ done:
ref_transaction_free(transaction);
strbuf_release(&new_gitdir);
strbuf_release(&data.sb);
+ strbuf_release(&data.name);
+ strbuf_release(&data.mail);
return ret;
}
int ref_update_expects_existing_old_ref(struct ref_update *update)
{
+ if (update->flags & REF_LOG_ONLY)
+ return 0;
+
return (update->flags & REF_HAVE_OLD) &&
(!is_null_oid(&update->old_oid) || update->old_target);
}
diff --git a/refs.h b/refs.h
index efa182c6a1..f29e486e33 100644
--- a/refs.h
+++ b/refs.h
@@ -428,6 +428,8 @@ int refs_for_each_namespaced_ref(struct ref_store *refs,
/* can be used to learn about broken ref and symref */
int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
+int refs_for_each_rawref_in(struct ref_store *refs, const char *prefix,
+ each_ref_fn fn, void *cb_data);
/*
* Iterates over all refs including root refs, i.e. pseudorefs and HEAD.
@@ -558,10 +560,13 @@ int refs_delete_reflog(struct ref_store *refs, const char *refname);
* The cb_data is a caller-supplied pointer given to the iterator
* functions.
*/
-typedef int each_reflog_ent_fn(
- struct object_id *old_oid, struct object_id *new_oid,
- const char *committer, timestamp_t timestamp,
- int tz, const char *msg, void *cb_data);
+typedef int each_reflog_ent_fn(const char *refname,
+ struct object_id *old_oid,
+ struct object_id *new_oid,
+ const char *committer,
+ timestamp_t timestamp,
+ int tz, const char *msg,
+ void *cb_data);
/* Iterate over reflog entries in the log for `refname`. */
@@ -760,12 +765,19 @@ struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs,
#define REF_SKIP_CREATE_REFLOG (1 << 12)
/*
+ * When writing a REF_LOG_ONLY record, use the old and new object IDs provided
+ * in the update instead of resolving the old object ID. The caller must also
+ * set both REF_HAVE_OLD and REF_HAVE_NEW.
+ */
+#define REF_LOG_USE_PROVIDED_OIDS (1 << 13)
+
+/*
* Bitmask of all of the flags that are allowed to be passed in to
* ref_transaction_update() and friends:
*/
#define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \
(REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \
- REF_SKIP_REFNAME_VERIFICATION | REF_SKIP_CREATE_REFLOG)
+ REF_SKIP_REFNAME_VERIFICATION | REF_SKIP_CREATE_REFLOG | REF_LOG_USE_PROVIDED_OIDS)
/*
* Add a reference update to transaction. `new_oid` is the value that
@@ -795,6 +807,21 @@ int ref_transaction_update(struct ref_transaction *transaction,
struct strbuf *err);
/*
+ * Similar to `ref_transaction_update`, but this function is only for adding
+ * a reflog update. Supports providing custom committer information. The index
+ * field can be utiltized to order updates as desired. When set to zero, the
+ * updates default to being ordered by refname.
+ */
+int ref_transaction_update_reflog(struct ref_transaction *transaction,
+ const char *refname,
+ const struct object_id *new_oid,
+ const struct object_id *old_oid,
+ const char *committer_info,
+ const char *msg,
+ uint64_t index,
+ struct strbuf *err);
+
+/*
* Add a reference creation to transaction. new_oid is the value that
* the reference should have after the update; it must not be
* null_oid. It is verified that the reference does not exist
@@ -1194,4 +1221,159 @@ int repo_migrate_ref_storage_format(struct repository *repo,
unsigned int flags,
struct strbuf *err);
+/*
+ * Reference iterators
+ *
+ * A reference iterator encapsulates the state of an in-progress
+ * iteration over references. Create an instance of `struct
+ * ref_iterator` via one of the functions in this module.
+ *
+ * A freshly-created ref_iterator doesn't yet point at a reference. To
+ * advance the iterator, call ref_iterator_advance(). If successful,
+ * this sets the iterator's refname, oid, and flags fields to describe
+ * the next reference and returns ITER_OK. The data pointed at by
+ * refname and oid belong to the iterator; if you want to retain them
+ * after calling ref_iterator_advance() again or calling
+ * ref_iterator_free(), you must make a copy. When the iteration has
+ * been exhausted, ref_iterator_advance() releases any resources
+ * associated with the iteration, frees the ref_iterator object, and
+ * returns ITER_DONE. If you want to abort the iteration early, call
+ * ref_iterator_free(), which also frees the ref_iterator object and
+ * any associated resources. If there was an internal error advancing
+ * to the next entry, ref_iterator_advance() aborts the iteration,
+ * frees the ref_iterator, and returns ITER_ERROR.
+ *
+ * The reference currently being looked at can be peeled by calling
+ * ref_iterator_peel(). This function is often faster than peel_ref(),
+ * so it should be preferred when iterating over references.
+ *
+ * Putting it all together, a typical iteration looks like this:
+ *
+ * int ok;
+ * struct ref_iterator *iter = ...;
+ *
+ * while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
+ * if (want_to_stop_iteration()) {
+ * ok = ITER_DONE;
+ * break;
+ * }
+ *
+ * // Access information about the current reference:
+ * if (!(iter->flags & REF_ISSYMREF))
+ * printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid));
+ *
+ * // If you need to peel the reference:
+ * ref_iterator_peel(iter, &oid);
+ * }
+ *
+ * if (ok != ITER_DONE)
+ * handle_error();
+ * ref_iterator_free(iter);
+ */
+struct ref_iterator;
+
+/*
+ * These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(),
+ * which feeds it).
+ */
+enum do_for_each_ref_flags {
+ /*
+ * Include broken references in a do_for_each_ref*() iteration, which
+ * would normally be omitted. This includes both refs that point to
+ * missing objects (a true repository corruption), ones with illegal
+ * names (which we prefer not to expose to callers), as well as
+ * dangling symbolic refs (i.e., those that point to a non-existent
+ * ref; this is not a corruption, but as they have no valid oid, we
+ * omit them from normal iteration results).
+ */
+ DO_FOR_EACH_INCLUDE_BROKEN = (1 << 0),
+
+ /*
+ * Only include per-worktree refs in a do_for_each_ref*() iteration.
+ * Normally this will be used with a files ref_store, since that's
+ * where all reference backends will presumably store their
+ * per-worktree refs.
+ */
+ DO_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1),
+
+ /*
+ * Omit dangling symrefs from output; this only has an effect with
+ * INCLUDE_BROKEN, since they are otherwise not included at all.
+ */
+ DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
+
+ /*
+ * Include root refs i.e. HEAD and pseudorefs along with the regular
+ * refs.
+ */
+ DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
+};
+
+/*
+ * Return an iterator that goes over each reference in `refs` for
+ * which the refname begins with prefix. If trim is non-zero, then
+ * trim that many characters off the beginning of each refname.
+ * The output is ordered by refname.
+ */
+struct ref_iterator *refs_ref_iterator_begin(
+ struct ref_store *refs,
+ const char *prefix, const char **exclude_patterns,
+ int trim, enum do_for_each_ref_flags flags);
+
+/*
+ * Advance the iterator to the first or next item and return ITER_OK.
+ * If the iteration is exhausted, free the resources associated with
+ * the ref_iterator and return ITER_DONE. On errors, free the iterator
+ * resources and return ITER_ERROR. It is a bug to use ref_iterator or
+ * call this function again after it has returned ITER_DONE or
+ * ITER_ERROR.
+ */
+int ref_iterator_advance(struct ref_iterator *ref_iterator);
+
+enum ref_iterator_seek_flag {
+ /*
+ * When the REF_ITERATOR_SEEK_SET_PREFIX flag is set, the iterator's prefix is
+ * updated to match the provided string, affecting all subsequent iterations. If
+ * not, the iterator seeks to the specified reference and clears any previously
+ * set prefix.
+ */
+ REF_ITERATOR_SEEK_SET_PREFIX = (1 << 0),
+};
+
+/*
+ * Seek the iterator to the first reference matching the given seek string.
+ * The seek string is matched as a literal string, without regard for path
+ * separators. If seek is NULL or the empty string, seek the iterator to the
+ * first reference again.
+ *
+ * This function is expected to behave as if a new ref iterator has been
+ * created, but allows reuse of existing iterators for optimization.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
+ unsigned int flags);
+
+/*
+ * If possible, peel the reference currently being viewed by the
+ * iterator. Return 0 on success.
+ */
+int ref_iterator_peel(struct ref_iterator *ref_iterator,
+ struct object_id *peeled);
+
+/* Free the reference iterator and any associated resources. */
+void ref_iterator_free(struct ref_iterator *ref_iterator);
+
+/*
+ * The common backend for the for_each_*ref* functions. Call fn for
+ * each reference in iter. If the iterator itself ever returns
+ * ITER_ERROR, return -1. If fn ever returns a non-zero value, stop
+ * the iteration and return that value. Otherwise, return 0. In any
+ * case, free the iterator when done. This function is basically an
+ * adapter between the callback style of reference iteration and the
+ * iterator style.
+ */
+int do_for_each_ref_iterator(struct ref_iterator *iter,
+ each_ref_fn fn, void *cb_data);
+
#endif /* REFS_H */
diff --git a/refs/debug.c b/refs/debug.c
index 485e3079d7..1cb955961e 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -170,12 +170,13 @@ static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
static int debug_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct debug_ref_iterator *diter =
(struct debug_ref_iterator *)ref_iterator;
- int res = diter->iter->vtable->seek(diter->iter, prefix);
- trace_printf_key(&trace_refs, "iterator_seek: %s: %d\n", prefix ? prefix : "", res);
+ int res = diter->iter->vtable->seek(diter->iter, refname, flags);
+ trace_printf_key(&trace_refs, "iterator_seek: %s flags: %d: %d\n",
+ refname ? refname : "", flags, res);
return res;
}
@@ -276,7 +277,8 @@ struct debug_reflog {
void *cb_data;
};
-static int debug_print_reflog_ent(struct object_id *old_oid,
+static int debug_print_reflog_ent(const char *refname,
+ struct object_id *old_oid,
struct object_id *new_oid,
const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data)
@@ -291,7 +293,7 @@ static int debug_print_reflog_ent(struct object_id *old_oid,
if (new_oid)
oid_to_hex_r(n, new_oid);
- ret = dbg->fn(old_oid, new_oid, committer, timestamp, tz, msg,
+ ret = dbg->fn(refname, old_oid, new_oid, committer, timestamp, tz, msg,
dbg->cb_data);
trace_printf_key(&trace_refs,
"reflog_ent %s (ret %d): %s -> %s, %s %ld \"%.*s\"\n",
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 89ae4517a9..dfc8e9bc50 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -68,6 +68,12 @@
*/
#define REF_DELETED_RMDIR (1 << 9)
+/*
+ * Used to indicate that the reflog-only update has been created via
+ * `split_head_update()`.
+ */
+#define REF_LOG_VIA_SPLIT (1 << 14)
+
struct ref_lock {
char *ref_name;
struct lock_file lk;
@@ -929,11 +935,11 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
static int files_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct files_ref_iterator *iter =
(struct files_ref_iterator *)ref_iterator;
- return ref_iterator_seek(iter->iter0, prefix);
+ return ref_iterator_seek(iter->iter0, refname, flags);
}
static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
@@ -2109,7 +2115,9 @@ static int files_delete_reflog(struct ref_store *ref_store,
return ret;
}
-static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
+static int show_one_reflog_ent(struct files_ref_store *refs,
+ const char *refname,
+ struct strbuf *sb,
each_reflog_ent_fn fn, void *cb_data)
{
struct object_id ooid, noid;
@@ -2136,7 +2144,7 @@ static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb,
message += 6;
else
message += 7;
- return fn(&ooid, &noid, p, timestamp, tz, message, cb_data);
+ return fn(refname, &ooid, &noid, p, timestamp, tz, message, cb_data);
}
static char *find_beginning_of_line(char *bob, char *scan)
@@ -2220,7 +2228,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
- ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, refname, &sb, fn, cb_data);
strbuf_reset(&sb);
if (ret)
break;
@@ -2232,7 +2240,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store,
* Process it, and we can end the loop.
*/
strbuf_splice(&sb, 0, 0, buf, endp - buf);
- ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, refname, &sb, fn, cb_data);
strbuf_reset(&sb);
break;
}
@@ -2282,7 +2290,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store,
return -1;
while (!ret && !strbuf_getwholeline(&sb, logfp, '\n'))
- ret = show_one_reflog_ent(refs, &sb, fn, cb_data);
+ ret = show_one_reflog_ent(refs, refname, &sb, fn, cb_data);
fclose(logfp);
strbuf_release(&sb);
return ret;
@@ -2316,7 +2324,8 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
}
static int files_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
- const char *prefix UNUSED)
+ const char *refname UNUSED,
+ unsigned int flags UNUSED)
{
BUG("ref_iterator_seek() called for reflog_iterator");
}
@@ -2420,9 +2429,10 @@ static enum ref_transaction_error split_head_update(struct ref_update *update,
new_update = ref_transaction_add_update(
transaction, "HEAD",
- update->flags | REF_LOG_ONLY | REF_NO_DEREF,
+ update->flags | REF_LOG_ONLY | REF_NO_DEREF | REF_LOG_VIA_SPLIT,
&update->new_oid, &update->old_oid,
NULL, NULL, update->committer_info, update->msg);
+ new_update->parent_update = update;
/*
* Add "HEAD". This insertion is O(N) in the transaction
@@ -2493,7 +2503,6 @@ static enum ref_transaction_error split_symref_update(struct ref_update *update,
* done when new_update is processed.
*/
update->flags |= REF_LOG_ONLY | REF_NO_DEREF;
- update->flags &= ~REF_HAVE_OLD;
return 0;
}
@@ -2508,8 +2517,9 @@ static enum ref_transaction_error check_old_oid(struct ref_update *update,
struct object_id *oid,
struct strbuf *err)
{
- if (!(update->flags & REF_HAVE_OLD) ||
- oideq(oid, &update->old_oid))
+ if (update->flags & REF_LOG_ONLY ||
+ !(update->flags & REF_HAVE_OLD) ||
+ oideq(oid, &update->old_oid))
return 0;
if (is_null_oid(&update->old_oid)) {
@@ -2600,7 +2610,36 @@ static enum ref_transaction_error lock_ref_for_update(struct files_ref_store *re
update->backend_data = lock;
- if (update->type & REF_ISSYMREF) {
+ if (update->flags & REF_LOG_VIA_SPLIT) {
+ struct ref_lock *parent_lock;
+
+ if (!update->parent_update)
+ BUG("split update without a parent");
+
+ parent_lock = update->parent_update->backend_data;
+
+ /*
+ * Check that "HEAD" didn't racily change since we have looked
+ * it up. If it did we must refuse to write the reflog entry.
+ *
+ * Note that this does not catch all races: if "HEAD" was
+ * racily changed to point to one of the refs part of the
+ * transaction then we would miss writing the split reflog
+ * entry for "HEAD".
+ */
+ if (!(update->type & REF_ISSYMREF) ||
+ strcmp(update->parent_update->refname, referent.buf)) {
+ strbuf_addstr(err, "HEAD has been racily updated");
+ ret = REF_TRANSACTION_ERROR_GENERIC;
+ goto out;
+ }
+
+ if (update->flags & REF_HAVE_OLD) {
+ oidcpy(&lock->old_oid, &update->old_oid);
+ } else {
+ oidcpy(&lock->old_oid, &parent_lock->old_oid);
+ }
+ } else if (update->type & REF_ISSYMREF) {
if (update->flags & REF_NO_DEREF) {
/*
* We won't be reading the referent as part of
@@ -2976,6 +3015,20 @@ static int parse_and_write_reflog(struct files_ref_store *refs,
struct ref_lock *lock,
struct strbuf *err)
{
+ struct object_id *old_oid = &lock->old_oid;
+
+ if (update->flags & REF_LOG_USE_PROVIDED_OIDS) {
+ if (!(update->flags & REF_HAVE_OLD) ||
+ !(update->flags & REF_HAVE_NEW) ||
+ !(update->flags & REF_LOG_ONLY)) {
+ strbuf_addf(err, _("trying to write reflog for '%s'"
+ "with incomplete values"), update->refname);
+ return REF_TRANSACTION_ERROR_GENERIC;
+ }
+
+ old_oid = &update->old_oid;
+ }
+
if (update->new_target) {
/*
* We want to get the resolved OID for the target, to ensure
@@ -2993,7 +3046,7 @@ static int parse_and_write_reflog(struct files_ref_store *refs,
}
}
- if (files_log_ref_write(refs, lock->ref_name, &lock->old_oid,
+ if (files_log_ref_write(refs, lock->ref_name, old_oid,
&update->new_oid, update->committer_info,
update->msg, update->flags, err)) {
char *old_msg = strbuf_detach(err, NULL);
@@ -3061,7 +3114,8 @@ static int files_transaction_finish_initial(struct files_ref_store *refs,
for (i = 0; i < transaction->nr; i++) {
struct ref_update *update = transaction->updates[i];
- if ((update->flags & REF_HAVE_OLD) &&
+ if (!(update->flags & REF_LOG_ONLY) &&
+ (update->flags & REF_HAVE_OLD) &&
!is_null_oid(&update->old_oid))
BUG("initial ref transaction with old_sha1 set");
@@ -3308,7 +3362,8 @@ struct expire_reflog_cb {
dry_run:1;
};
-static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
+static int expire_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid, struct object_id *noid,
const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data)
{
diff --git a/refs/iterator.c b/refs/iterator.c
index 766d96e795..17ef841d8a 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -15,10 +15,10 @@ int ref_iterator_advance(struct ref_iterator *ref_iterator)
return ref_iterator->vtable->advance(ref_iterator);
}
-int ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname,
+ unsigned int flags)
{
- return ref_iterator->vtable->seek(ref_iterator, prefix);
+ return ref_iterator->vtable->seek(ref_iterator, refname, flags);
}
int ref_iterator_peel(struct ref_iterator *ref_iterator,
@@ -57,7 +57,8 @@ static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator UNUSED)
}
static int empty_ref_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
- const char *prefix UNUSED)
+ const char *refname UNUSED,
+ unsigned int flags UNUSED)
{
return 0;
}
@@ -224,7 +225,7 @@ error:
}
static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct merge_ref_iterator *iter =
(struct merge_ref_iterator *)ref_iterator;
@@ -234,11 +235,11 @@ static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator,
iter->iter0 = iter->iter0_owned;
iter->iter1 = iter->iter1_owned;
- ret = ref_iterator_seek(iter->iter0, prefix);
+ ret = ref_iterator_seek(iter->iter0, refname, flags);
if (ret < 0)
return ret;
- ret = ref_iterator_seek(iter->iter1, prefix);
+ ret = ref_iterator_seek(iter->iter1, refname, flags);
if (ret < 0)
return ret;
@@ -407,13 +408,16 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
static int prefix_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct prefix_ref_iterator *iter =
(struct prefix_ref_iterator *)ref_iterator;
- free(iter->prefix);
- iter->prefix = xstrdup_or_null(prefix);
- return ref_iterator_seek(iter->iter0, prefix);
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
+ free(iter->prefix);
+ iter->prefix = xstrdup_or_null(refname);
+ }
+ return ref_iterator_seek(iter->iter0, refname, flags);
}
static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 7fd73a0e6d..a8c22a0a7f 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1004,19 +1004,23 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct packed_ref_iterator *iter =
(struct packed_ref_iterator *)ref_iterator;
const char *start;
- if (prefix && *prefix)
- start = find_reference_location(iter->snapshot, prefix, 0);
+ if (refname && *refname)
+ start = find_reference_location(iter->snapshot, refname, 0);
else
start = iter->snapshot->start;
- free(iter->prefix);
- iter->prefix = xstrdup_or_null(prefix);
+ /* Unset any previously set prefix */
+ FREE_AND_NULL(iter->prefix);
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX)
+ iter->prefix = xstrdup_or_null(refname);
+
iter->pos = start;
iter->eof = iter->snapshot->eof;
@@ -1194,7 +1198,8 @@ static struct ref_iterator *packed_ref_iterator_begin(
iter->repo = ref_store->repo;
iter->flags = flags;
- if (packed_ref_iterator_seek(&iter->base, prefix) < 0) {
+ if (packed_ref_iterator_seek(&iter->base, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX) < 0) {
ref_iterator_free(&iter->base);
return NULL;
}
@@ -1228,7 +1233,7 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
static int timeout_value = 1000;
if (!timeout_configured) {
- git_config_get_int("core.packedrefstimeout", &timeout_value);
+ repo_config_get_int(the_repository, "core.packedrefstimeout", &timeout_value);
timeout_configured = 1;
}
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index c1f1bab1d5..c180e0aad7 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -194,20 +194,6 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir,
return dir;
}
-struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname)
-{
- int entry_index;
- struct ref_entry *entry;
- dir = find_containing_dir(dir, refname);
- if (!dir)
- return NULL;
- entry_index = search_ref_dir(dir, refname, strlen(refname));
- if (entry_index == -1)
- return NULL;
- entry = dir->entries[entry_index];
- return (entry->flag & REF_DIR) ? NULL : entry;
-}
-
/*
* Emit a warning and return true iff ref1 and ref2 have the same name
* and the same oid. Die if they have the same name but different
@@ -448,11 +434,9 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
}
-static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+static int cache_ref_iterator_set_prefix(struct cache_ref_iterator *iter,
+ const char *prefix)
{
- struct cache_ref_iterator *iter =
- (struct cache_ref_iterator *)ref_iterator;
struct cache_ref_iterator_level *level;
struct ref_dir *dir;
@@ -483,6 +467,84 @@ static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
return 0;
}
+static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator,
+ const char *refname, unsigned int flags)
+{
+ struct cache_ref_iterator *iter =
+ (struct cache_ref_iterator *)ref_iterator;
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
+ return cache_ref_iterator_set_prefix(iter, refname);
+ } else if (refname && *refname) {
+ struct cache_ref_iterator_level *level;
+ const char *slash = refname;
+ struct ref_dir *dir;
+
+ dir = get_ref_dir(iter->cache->root);
+
+ if (iter->prime_dir)
+ prime_ref_dir(dir, refname);
+
+ iter->levels_nr = 1;
+ level = &iter->levels[0];
+ level->index = -1;
+ level->dir = dir;
+
+ /* Unset any previously set prefix */
+ FREE_AND_NULL(iter->prefix);
+
+ /*
+ * Breakdown the provided seek path and assign the correct
+ * indexing to each level as needed.
+ */
+ do {
+ int idx;
+ size_t len;
+ int cmp = 0;
+
+ sort_ref_dir(dir);
+
+ slash = strchr(slash, '/');
+ len = slash ? (size_t)(slash - refname) : strlen(refname);
+
+ for (idx = 0; idx < dir->nr; idx++) {
+ cmp = strncmp(refname, dir->entries[idx]->name, len);
+ if (cmp <= 0)
+ break;
+ }
+ /* don't overflow the index */
+ idx = idx >= dir->nr ? dir->nr - 1 : idx;
+
+ if (slash)
+ slash = slash + 1;
+
+ level->index = idx;
+ if (dir->entries[idx]->flag & REF_DIR) {
+ /* push down a level */
+ dir = get_ref_dir(dir->entries[idx]);
+
+ ALLOC_GROW(iter->levels, iter->levels_nr + 1,
+ iter->levels_alloc);
+ level = &iter->levels[iter->levels_nr++];
+ level->dir = dir;
+ level->index = -1;
+ level->prefix_state = PREFIX_CONTAINS_DIR;
+ } else {
+ /* reduce the index so the leaf node is iterated over */
+ if (cmp <= 0 && !slash)
+ level->index = idx - 1;
+ /*
+ * while the seek path may not be exhausted, our
+ * match is exhausted at a leaf node.
+ */
+ break;
+ }
+ } while (slash);
+ }
+
+ return 0;
+}
+
static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
struct object_id *peeled)
{
@@ -523,7 +585,8 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache,
iter->cache = cache;
iter->prime_dir = prime_dir;
- if (cache_ref_iterator_seek(&iter->base, prefix) < 0) {
+ if (cache_ref_iterator_seek(&iter->base, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX) < 0) {
ref_iterator_free(&iter->base);
return NULL;
}
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 5f04e518c3..f635d2d824 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -202,13 +202,6 @@ void free_ref_cache(struct ref_cache *cache);
void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry);
/*
- * Find the value entry with the given name in dir, sorting ref_dirs
- * and recursing into subdirectories as necessary. If the name is not
- * found or it corresponds to a directory entry, return NULL.
- */
-struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname);
-
-/*
* Start iterating over references in `cache`. If `prefix` is
* specified, only include references whose names start with that
* prefix. If `prime_dir` is true, then fill any incomplete
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index f868870851..54c2079c12 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -244,90 +244,8 @@ const char *find_descendant_ref(const char *dirname,
#define SYMREF_MAXDEPTH 5
/*
- * These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(),
- * which feeds it).
- */
-enum do_for_each_ref_flags {
- /*
- * Include broken references in a do_for_each_ref*() iteration, which
- * would normally be omitted. This includes both refs that point to
- * missing objects (a true repository corruption), ones with illegal
- * names (which we prefer not to expose to callers), as well as
- * dangling symbolic refs (i.e., those that point to a non-existent
- * ref; this is not a corruption, but as they have no valid oid, we
- * omit them from normal iteration results).
- */
- DO_FOR_EACH_INCLUDE_BROKEN = (1 << 0),
-
- /*
- * Only include per-worktree refs in a do_for_each_ref*() iteration.
- * Normally this will be used with a files ref_store, since that's
- * where all reference backends will presumably store their
- * per-worktree refs.
- */
- DO_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1),
-
- /*
- * Omit dangling symrefs from output; this only has an effect with
- * INCLUDE_BROKEN, since they are otherwise not included at all.
- */
- DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2),
-
- /*
- * Include root refs i.e. HEAD and pseudorefs along with the regular
- * refs.
- */
- DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3),
-};
-
-/*
- * Reference iterators
- *
- * A reference iterator encapsulates the state of an in-progress
- * iteration over references. Create an instance of `struct
- * ref_iterator` via one of the functions in this module.
- *
- * A freshly-created ref_iterator doesn't yet point at a reference. To
- * advance the iterator, call ref_iterator_advance(). If successful,
- * this sets the iterator's refname, oid, and flags fields to describe
- * the next reference and returns ITER_OK. The data pointed at by
- * refname and oid belong to the iterator; if you want to retain them
- * after calling ref_iterator_advance() again or calling
- * ref_iterator_free(), you must make a copy. When the iteration has
- * been exhausted, ref_iterator_advance() releases any resources
- * associated with the iteration, frees the ref_iterator object, and
- * returns ITER_DONE. If you want to abort the iteration early, call
- * ref_iterator_free(), which also frees the ref_iterator object and
- * any associated resources. If there was an internal error advancing
- * to the next entry, ref_iterator_advance() aborts the iteration,
- * frees the ref_iterator, and returns ITER_ERROR.
- *
- * The reference currently being looked at can be peeled by calling
- * ref_iterator_peel(). This function is often faster than peel_ref(),
- * so it should be preferred when iterating over references.
- *
- * Putting it all together, a typical iteration looks like this:
- *
- * int ok;
- * struct ref_iterator *iter = ...;
- *
- * while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- * if (want_to_stop_iteration()) {
- * ok = ITER_DONE;
- * break;
- * }
- *
- * // Access information about the current reference:
- * if (!(iter->flags & REF_ISSYMREF))
- * printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid));
- *
- * // If you need to peel the reference:
- * ref_iterator_peel(iter, &oid);
- * }
- *
- * if (ok != ITER_DONE)
- * handle_error();
- * ref_iterator_free(iter);
+ * Data structure for holding a reference iterator. See refs.h for
+ * more details and usage instructions.
*/
struct ref_iterator {
struct ref_iterator_vtable *vtable;
@@ -338,42 +256,6 @@ struct ref_iterator {
};
/*
- * Advance the iterator to the first or next item and return ITER_OK.
- * If the iteration is exhausted, free the resources associated with
- * the ref_iterator and return ITER_DONE. On errors, free the iterator
- * resources and return ITER_ERROR. It is a bug to use ref_iterator or
- * call this function again after it has returned ITER_DONE or
- * ITER_ERROR.
- */
-int ref_iterator_advance(struct ref_iterator *ref_iterator);
-
-/*
- * Seek the iterator to the first reference with the given prefix.
- * The prefix is matched as a literal string, without regard for path
- * separators. If prefix is NULL or the empty string, seek the iterator to the
- * first reference again.
- *
- * This function is expected to behave as if a new ref iterator with the same
- * prefix had been created, but allows reuse of iterators and thus may allow
- * the backend to optimize. Parameters other than the prefix that have been
- * passed when creating the iterator will remain unchanged.
- *
- * Returns 0 on success, a negative error code otherwise.
- */
-int ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix);
-
-/*
- * If possible, peel the reference currently being viewed by the
- * iterator. Return 0 on success.
- */
-int ref_iterator_peel(struct ref_iterator *ref_iterator,
- struct object_id *peeled);
-
-/* Free the reference iterator and any associated resources. */
-void ref_iterator_free(struct ref_iterator *ref_iterator);
-
-/*
* An iterator over nothing (its first ref_iterator_advance() call
* returns ITER_DONE).
*/
@@ -385,17 +267,6 @@ struct ref_iterator *empty_ref_iterator_begin(void);
int is_empty_ref_iterator(struct ref_iterator *ref_iterator);
/*
- * Return an iterator that goes over each reference in `refs` for
- * which the refname begins with prefix. If trim is non-zero, then
- * trim that many characters off the beginning of each refname.
- * The output is ordered by refname.
- */
-struct ref_iterator *refs_ref_iterator_begin(
- struct ref_store *refs,
- const char *prefix, const char **exclude_patterns,
- int trim, enum do_for_each_ref_flags flags);
-
-/*
* A callback function used to instruct merge_ref_iterator how to
* interleave the entries from iter0 and iter1. The function should
* return one of the constants defined in enum iterator_selection. It
@@ -482,11 +353,12 @@ void base_ref_iterator_init(struct ref_iterator *iter,
typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator);
/*
- * Seek the iterator to the first reference matching the given prefix. Should
- * behave the same as if a new iterator was created with the same prefix.
+ * Seek the iterator to the first matching reference. If the
+ * REF_ITERATOR_SEEK_SET_PREFIX flag is set, it would behave the same as if a
+ * new iterator was created with the provided refname as prefix.
*/
typedef int ref_iterator_seek_fn(struct ref_iterator *ref_iterator,
- const char *prefix);
+ const char *refname, unsigned int flags);
/*
* Peels the current ref, returning 0 for success or -1 for failure.
@@ -520,18 +392,6 @@ struct ref_iterator_vtable {
*/
extern struct ref_iterator *current_ref_iter;
-/*
- * The common backend for the for_each_*ref* functions. Call fn for
- * each reference in iter. If the iterator itself ever returns
- * ITER_ERROR, return -1. If fn ever returns a non-zero value, stop
- * the iteration and return that value. Otherwise, return 0. In any
- * case, free the iterator when done. This function is basically an
- * adapter between the callback style of reference iteration and the
- * iterator style.
- */
-int do_for_each_ref_iterator(struct ref_iterator *iter,
- each_ref_fn fn, void *cb_data);
-
struct ref_store;
/* refs backends */
@@ -802,7 +662,8 @@ enum ref_transaction_error ref_update_check_old_target(const char *referent,
/*
* Check if the ref must exist, this means that the old_oid or
- * old_target is non NULL.
+ * old_target is non NULL. Log-only updates never require the old state to
+ * match.
*/
int ref_update_expects_existing_old_ref(struct ref_update *update);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 4c3817f4ec..570463da41 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -386,7 +386,7 @@ static struct ref_store *reftable_be_init(struct repository *repo,
refs->write_options.lock_timeout_ms = 100;
refs->write_options.fsync = reftable_be_fsync;
- git_config(reftable_be_config, &refs->write_options);
+ repo_config(the_repository, reftable_be_config, &refs->write_options);
/*
* It is somewhat unfortunate that we have to mirror the default block
@@ -719,15 +719,20 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
static int reftable_ref_iterator_seek(struct ref_iterator *ref_iterator,
- const char *prefix)
+ const char *refname, unsigned int flags)
{
struct reftable_ref_iterator *iter =
(struct reftable_ref_iterator *)ref_iterator;
- free(iter->prefix);
- iter->prefix = xstrdup_or_null(prefix);
- iter->prefix_len = prefix ? strlen(prefix) : 0;
- iter->err = reftable_iterator_seek_ref(&iter->iter, prefix);
+ /* Unset any previously set prefix */
+ FREE_AND_NULL(iter->prefix);
+ iter->prefix_len = 0;
+
+ if (flags & REF_ITERATOR_SEEK_SET_PREFIX) {
+ iter->prefix = xstrdup_or_null(refname);
+ iter->prefix_len = refname ? strlen(refname) : 0;
+ }
+ iter->err = reftable_iterator_seek_ref(&iter->iter, refname);
return iter->err;
}
@@ -839,7 +844,8 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
if (ret)
goto done;
- ret = reftable_ref_iterator_seek(&iter->base, prefix);
+ ret = reftable_ref_iterator_seek(&iter->base, prefix,
+ REF_ITERATOR_SEEK_SET_PREFIX);
if (ret)
goto done;
@@ -1096,6 +1102,20 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
if (ret)
return REF_TRANSACTION_ERROR_GENERIC;
+ if (u->flags & REF_LOG_USE_PROVIDED_OIDS) {
+ if (!(u->flags & REF_HAVE_OLD) ||
+ !(u->flags & REF_HAVE_NEW) ||
+ !(u->flags & REF_LOG_ONLY)) {
+ strbuf_addf(err, _("trying to write reflog for '%s'"
+ "with incomplete values"), u->refname);
+ return REF_TRANSACTION_ERROR_GENERIC;
+ }
+
+ if (queue_transaction_update(refs, tx_data, u, &u->old_oid, err))
+ return REF_TRANSACTION_ERROR_GENERIC;
+ return 0;
+ }
+
/* Verify that the new object ID is valid. */
if ((u->flags & REF_HAVE_NEW) && !is_null_oid(&u->new_oid) &&
!(u->flags & REF_SKIP_OID_VERIFICATION) &&
@@ -1180,8 +1200,6 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
if (ret > 0) {
/* The reference does not exist, but we expected it to. */
strbuf_addf(err, _("cannot lock ref '%s': "
-
-
"unable to resolve reference '%s'"),
ref_update_original_update_refname(u), u->refname);
return REF_TRANSACTION_ERROR_NONEXISTENT_REF;
@@ -1235,13 +1253,8 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
new_update->parent_update = u;
- /*
- * Change the symbolic ref update to log only. Also, it
- * doesn't need to check its old OID value, as that will be
- * done when new_update is processed.
- */
+ /* Change the symbolic ref update to log only. */
u->flags |= REF_LOG_ONLY | REF_NO_DEREF;
- u->flags &= ~REF_HAVE_OLD;
}
}
@@ -1265,7 +1278,8 @@ static enum ref_transaction_error prepare_single_update(struct reftable_ref_stor
ret = ref_update_check_old_target(referent->buf, u, err);
if (ret)
return ret;
- } else if ((u->flags & REF_HAVE_OLD) && !oideq(&current_oid, &u->old_oid)) {
+ } else if ((u->flags & (REF_LOG_ONLY | REF_HAVE_OLD)) == REF_HAVE_OLD &&
+ !oideq(&current_oid, &u->old_oid)) {
if (is_null_oid(&u->old_oid)) {
strbuf_addf(err, _("cannot lock ref '%s': "
"reference already exists"),
@@ -2042,7 +2056,8 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator)
}
static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED,
- const char *prefix UNUSED)
+ const char *refname UNUSED,
+ unsigned int flags UNUSED)
{
BUG("reftable reflog iterator cannot be seeked");
return -1;
@@ -2140,7 +2155,7 @@ static int yield_log_record(struct reftable_ref_store *refs,
full_committer = fmt_ident(log->value.update.name, log->value.update.email,
WANT_COMMITTER_IDENT, NULL, IDENT_NO_DATE);
- return fn(&old_oid, &new_oid, full_committer,
+ return fn(log->refname, &old_oid, &new_oid, full_committer,
log->value.update.time, log->value.update.tz_offset,
log->value.update.message, cb_data);
}
diff --git a/remote.c b/remote.c
index e965f022f1..81d8fc017e 100644
--- a/remote.c
+++ b/remote.c
@@ -734,7 +734,7 @@ static void validate_remote_url(struct remote *remote)
struct strbuf redacted = STRBUF_INIT;
int warn_not_die;
- if (git_config_get_string_tmp("transfer.credentialsinurl", &value))
+ if (repo_config_get_string_tmp(the_repository, "transfer.credentialsinurl", &value))
return;
if (!strcmp("warn", value))
@@ -1171,7 +1171,6 @@ static void show_push_unqualified_ref_name_error(const char *dst_value,
const char *matched_src_name)
{
struct object_id oid;
- enum object_type type;
/*
* TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
@@ -1196,30 +1195,37 @@ static void show_push_unqualified_ref_name_error(const char *dst_value,
BUG("'%s' is not a valid object, "
"match_explicit_lhs() should catch this!",
matched_src_name);
- type = odb_read_object_info(the_repository->objects, &oid, NULL);
- if (type == OBJ_COMMIT) {
+
+ switch (odb_read_object_info(the_repository->objects, &oid, NULL)) {
+ case OBJ_COMMIT:
advise(_("The <src> part of the refspec is a commit object.\n"
"Did you mean to create a new branch by pushing to\n"
"'%s:refs/heads/%s'?"),
matched_src_name, dst_value);
- } else if (type == OBJ_TAG) {
+ break;
+ case OBJ_TAG:
advise(_("The <src> part of the refspec is a tag object.\n"
"Did you mean to create a new tag by pushing to\n"
"'%s:refs/tags/%s'?"),
matched_src_name, dst_value);
- } else if (type == OBJ_TREE) {
+ break;
+ case OBJ_TREE:
advise(_("The <src> part of the refspec is a tree object.\n"
"Did you mean to tag a new tree by pushing to\n"
"'%s:refs/tags/%s'?"),
matched_src_name, dst_value);
- } else if (type == OBJ_BLOB) {
+ break;
+ case OBJ_BLOB:
advise(_("The <src> part of the refspec is a blob object.\n"
"Did you mean to tag a new blob by pushing to\n"
"'%s:refs/tags/%s'?"),
matched_src_name, dst_value);
- } else {
- BUG("'%s' should be commit/tag/tree/blob, is '%d'",
- matched_src_name, type);
+ break;
+ default:
+ advise(_("The <src> part of the refspec ('%s') "
+ "is an object ID that doesn't exist.\n"),
+ matched_src_name);
+ break;
}
}
@@ -2578,7 +2584,8 @@ struct check_and_collect_until_cb_data {
};
/* Get the timestamp of the latest entry. */
-static int peek_reflog(struct object_id *o_oid UNUSED,
+static int peek_reflog(const char *refname UNUSED,
+ struct object_id *o_oid UNUSED,
struct object_id *n_oid UNUSED,
const char *ident UNUSED,
timestamp_t timestamp, int tz UNUSED,
@@ -2589,7 +2596,8 @@ static int peek_reflog(struct object_id *o_oid UNUSED,
return 1;
}
-static int check_and_collect_until(struct object_id *o_oid UNUSED,
+static int check_and_collect_until(const char *refname UNUSED,
+ struct object_id *o_oid UNUSED,
struct object_id *n_oid,
const char *ident UNUSED,
timestamp_t timestamp, int tz UNUSED,
diff --git a/rerere.c b/rerere.c
index 8bb97c9822..6ec55964e2 100644
--- a/rerere.c
+++ b/rerere.c
@@ -5,6 +5,7 @@
#include "abspath.h"
#include "config.h"
#include "copy.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
@@ -877,9 +878,9 @@ static int do_plain_rerere(struct repository *r,
static void git_rerere_config(void)
{
- git_config_get_bool("rerere.enabled", &rerere_enabled);
- git_config_get_bool("rerere.autoupdate", &rerere_autoupdate);
- git_config(git_default_config, NULL);
+ repo_config_get_bool(the_repository, "rerere.enabled", &rerere_enabled);
+ repo_config_get_bool(the_repository, "rerere.autoupdate", &rerere_autoupdate);
+ repo_config(the_repository, git_default_config, NULL);
}
static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
@@ -1247,7 +1248,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
&cutoff_resolve, now);
repo_config_get_expiry_in_days(the_repository, "gc.rerereunresolved",
&cutoff_noresolve, now);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
dir = opendir(repo_git_path_replace(the_repository, &buf, "rr-cache"));
if (!dir)
die_errno(_("unable to open rr-cache directory"));
diff --git a/revision.c b/revision.c
index c2e17205a8..6ba8f67054 100644
--- a/revision.c
+++ b/revision.c
@@ -671,12 +671,17 @@ static void trace2_bloom_filter_statistics_atexit(void)
static int forbid_bloom_filters(struct pathspec *spec)
{
- if (spec->has_wildcard)
- return 1;
- if (spec->magic & ~PATHSPEC_LITERAL)
+ unsigned int allowed_magic =
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ATTR;
+
+ if (spec->magic & ~allowed_magic)
return 1;
for (size_t nr = 0; nr < spec->nr; nr++)
- if (spec->items[nr].magic & ~PATHSPEC_LITERAL)
+ if (spec->items[nr].magic & ~allowed_magic)
return 1;
return 0;
@@ -691,23 +696,34 @@ static int convert_pathspec_to_bloom_keyvec(struct bloom_keyvec **out,
char *path_alloc = NULL;
const char *path;
size_t len;
- int res = 0;
+ int res = -1;
+ len = pi->nowildcard_len;
+ if (len != pi->len) {
+ /*
+ * for path like "dir/file*", nowildcard part would be
+ * "dir/file", but only "dir" should be used for the
+ * bloom filter.
+ */
+ while (len > 0 && pi->match[len - 1] != '/')
+ len--;
+ }
/* remove single trailing slash from path, if needed */
- if (pi->len > 0 && pi->match[pi->len - 1] == '/') {
- path_alloc = xmemdupz(pi->match, pi->len - 1);
+ if (len > 0 && pi->match[len - 1] == '/')
+ len--;
+
+ if (!len)
+ goto cleanup;
+
+ if (len != pi->len) {
+ path_alloc = xmemdupz(pi->match, len);
path = path_alloc;
} else
path = pi->match;
- len = strlen(path);
- if (!len) {
- res = -1;
- goto cleanup;
- }
-
*out = bloom_keyvec_new(path, len, settings);
+ res = 0;
cleanup:
free(path_alloc);
return res;
@@ -1620,7 +1636,7 @@ void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section)
cb.exclusions = exclusions;
cb.section = section;
- git_config(hide_refs_config, &cb);
+ repo_config(the_repository, hide_refs_config, &cb);
}
struct all_refs_cb {
@@ -1689,7 +1705,8 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
}
}
-static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+static int handle_one_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp UNUSED,
int tz UNUSED,
diff --git a/run-command.c b/run-command.c
index 8833b23367..ed9575bd6a 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1817,7 +1817,7 @@ int prepare_auto_maintenance(int quiet, struct child_process *maint)
{
int enabled, auto_detach;
- if (!git_config_get_bool("maintenance.auto", &enabled) &&
+ if (!repo_config_get_bool(the_repository, "maintenance.auto", &enabled) &&
!enabled)
return 0;
@@ -1826,8 +1826,8 @@ int prepare_auto_maintenance(int quiet, struct child_process *maint)
* honoring `gc.autoDetach`. This is somewhat weird, but required to
* retain behaviour from when we used to run git-gc(1) here.
*/
- if (git_config_get_bool("maintenance.autodetach", &auto_detach) &&
- git_config_get_bool("gc.autodetach", &auto_detach))
+ if (repo_config_get_bool(the_repository, "maintenance.autodetach", &auto_detach) &&
+ repo_config_get_bool(the_repository, "gc.autodetach", &auto_detach))
auto_detach = 1;
maint->git_cmd = 1;
diff --git a/scalar.c b/scalar.c
index 0dc79fa9fb..4a373c133d 100644
--- a/scalar.c
+++ b/scalar.c
@@ -101,9 +101,9 @@ static int set_scalar_config(const struct scalar_config *config, int reconfigure
int res;
if ((reconfigure && config->overwrite_on_reconfigure) ||
- git_config_get_string(config->key, &value)) {
+ repo_config_get_string(the_repository, config->key, &value)) {
trace2_data_string("scalar", the_repository, config->key, "created");
- res = git_config_set_gently(config->key, config->value);
+ res = repo_config_set_gently(the_repository, config->key, config->value);
} else {
trace2_data_string("scalar", the_repository, config->key, "exists");
res = 0;
@@ -193,12 +193,12 @@ static int set_recommended_config(int reconfigure)
* The `log.excludeDecoration` setting is special because it allows
* for multiple values.
*/
- if (git_config_get_string("log.excludeDecoration", &value)) {
+ if (repo_config_get_string(the_repository, "log.excludeDecoration", &value)) {
trace2_data_string("scalar", the_repository,
"log.excludeDecoration", "created");
- if (git_config_set_multivar_gently("log.excludeDecoration",
- "refs/prefetch/*",
- CONFIG_REGEX_NONE, 0))
+ if (repo_config_set_multivar_gently(the_repository, "log.excludeDecoration",
+ "refs/prefetch/*",
+ CONFIG_REGEX_NONE, 0))
return error(_("could not configure "
"log.excludeDecoration"));
} else {
@@ -322,7 +322,7 @@ static int set_config(const char *fmt, ...)
value = strchr(buf.buf, '=');
if (value)
*(value++) = '\0';
- res = git_config_set_gently(buf.buf, value);
+ res = repo_config_set_gently(the_repository, buf.buf, value);
strbuf_release(&buf);
return res;
@@ -713,7 +713,7 @@ static int cmd_reconfigure(int argc, const char **argv)
maintenance_str);
}
- git_config(get_scalar_repos, &scalar_repos);
+ repo_config(the_repository, get_scalar_repos, &scalar_repos);
for (size_t i = 0; i < scalar_repos.nr; i++) {
int succeeded = 0;
@@ -763,7 +763,7 @@ static int cmd_reconfigure(int argc, const char **argv)
break;
}
- git_config_clear();
+ repo_config_clear(the_repository);
if (repo_init(&r, gitdir.buf, commondir.buf))
goto loop_end;
diff --git a/sequencer.c b/sequencer.c
index 67e4310edc..9ae40a91b2 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -327,7 +327,7 @@ static int git_sequencer_config(const char *k, const char *v,
void sequencer_init_config(struct replay_opts *opts)
{
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
- git_config(git_sequencer_config, opts);
+ repo_config(the_repository, git_sequencer_config, opts);
}
static inline int is_rebase_i(const struct replay_opts *opts)
@@ -2721,6 +2721,7 @@ static int check_merge_commit_insn(enum todo_command command)
return error(_("cannot squash merge commit into another commit"));
case TODO_MERGE:
+ case TODO_DROP:
return 0;
default:
@@ -3650,57 +3651,57 @@ static int save_opts(struct replay_opts *opts)
int res = 0;
if (opts->no_commit)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.no-commit", NULL, "true");
if (opts->edit >= 0)
- res |= git_config_set_in_file_gently(opts_file, "options.edit", NULL,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.edit", NULL,
opts->edit ? "true" : "false");
if (opts->allow_empty)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.allow-empty", NULL, "true");
if (opts->allow_empty_message)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.allow-empty-message", NULL, "true");
if (opts->drop_redundant_commits)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.drop-redundant-commits", NULL, "true");
if (opts->keep_redundant_commits)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.keep-redundant-commits", NULL, "true");
if (opts->signoff)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.signoff", NULL, "true");
if (opts->record_origin)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.record-origin", NULL, "true");
if (opts->allow_ff)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.allow-ff", NULL, "true");
if (opts->mainline) {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%d", opts->mainline);
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.mainline", NULL, buf.buf);
strbuf_release(&buf);
}
if (opts->strategy)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.strategy", NULL, opts->strategy);
if (opts->gpg_sign)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.gpg-sign", NULL, opts->gpg_sign);
for (size_t i = 0; i < opts->xopts.nr; i++)
- res |= git_config_set_multivar_in_file_gently(opts_file,
+ res |= repo_config_set_multivar_in_file_gently(the_repository, opts_file,
"options.strategy-option",
opts->xopts.v[i], "^$", NULL, 0);
if (opts->allow_rerere_auto)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.allow-rerere-auto", NULL,
opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
"true" : "false");
if (opts->explicit_cleanup)
- res |= git_config_set_in_file_gently(opts_file,
+ res |= repo_config_set_in_file_gently(the_repository, opts_file,
"options.default-msg-cleanup", NULL,
describe_cleanup_mode(opts->default_msg_cleanup));
return res;
@@ -5834,7 +5835,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
*cmd_reset = abbr ? "t" : "reset",
*cmd_merge = abbr ? "m" : "merge";
- git_config_get_int("rebase.maxlabellength", &state.max_label_length);
+ repo_config_get_int(the_repository, "rebase.maxlabellength", &state.max_label_length);
oidmap_init(&commit2todo, 0);
oidmap_init(&state.commit2label, 0);
@@ -6089,7 +6090,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
revs.topo_order = 1;
revs.pretty_given = 1;
- git_config_get_string("rebase.instructionFormat", &format);
+ repo_config_get_string(the_repository, "rebase.instructionFormat", &format);
if (!format || !*format) {
free(format);
format = xstrdup("# %s");
diff --git a/setup.c b/setup.c
index 6f52dab64c..7086741e6c 100644
--- a/setup.c
+++ b/setup.c
@@ -815,7 +815,7 @@ int upgrade_repository_format(int target_version)
}
strbuf_addf(&repo_version, "%d", target_version);
- git_config_set("core.repositoryformatversion", repo_version.buf);
+ repo_config_set(the_repository, "core.repositoryformatversion", repo_version.buf);
ret = 1;
@@ -1460,8 +1460,9 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
if (env_ceiling_dirs) {
int empty_entry_found = 0;
+ static const char path_sep[] = { PATH_SEP, '\0' };
- string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
+ string_list_split(&ceiling_dirs, env_ceiling_dirs, path_sep, -1);
filter_string_list(&ceiling_dirs, 0,
canonicalize_ceiling_entry, &empty_entry_found);
ceil_offset = longest_ancestor_length(dir->buf, &ceiling_dirs);
@@ -1741,7 +1742,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
* configuration (including the per-repo config file that we
* ignored previously).
*/
- git_config_clear();
+ repo_config_clear(the_repository);
/*
* Let's assume that we are in a git repository.
@@ -1877,7 +1878,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
* the core.precomposeunicode configuration, this
* has to happen after the above block that finds
* out where the repository is, i.e. a preparation
- * for calling git_config_get_bool().
+ * for calling repo_config_get_bool().
*/
if (prefix) {
prefix = precompose_string_if_needed(prefix);
@@ -2233,16 +2234,16 @@ void initialize_repository_version(int hash_algo,
target_version = GIT_REPO_VERSION_READ;
if (hash_algo != GIT_HASH_SHA1_LEGACY && hash_algo != GIT_HASH_UNKNOWN)
- git_config_set("extensions.objectformat",
- hash_algos[hash_algo].name);
+ repo_config_set(the_repository, "extensions.objectformat",
+ hash_algos[hash_algo].name);
else if (reinit)
- git_config_set_gently("extensions.objectformat", NULL);
+ repo_config_set_gently(the_repository, "extensions.objectformat", NULL);
if (ref_storage_format != REF_STORAGE_FORMAT_FILES)
- git_config_set("extensions.refstorage",
- ref_storage_format_to_name(ref_storage_format));
+ repo_config_set(the_repository, "extensions.refstorage",
+ ref_storage_format_to_name(ref_storage_format));
else if (reinit)
- git_config_set_gently("extensions.refstorage", NULL);
+ repo_config_set_gently(the_repository, "extensions.refstorage", NULL);
if (reinit) {
struct strbuf config = STRBUF_INIT;
@@ -2259,7 +2260,7 @@ void initialize_repository_version(int hash_algo,
}
strbuf_addf(&repo_version, "%d", target_version);
- git_config_set("core.repositoryformatversion", repo_version.buf);
+ repo_config_set(the_repository, "core.repositoryformatversion", repo_version.buf);
strbuf_release(&repo_version);
}
@@ -2337,9 +2338,9 @@ static int create_default_files(const char *template_path,
* disk).
*/
copy_templates(template_path);
- git_config_clear();
+ repo_config_clear(the_repository);
repo_settings_reset_shared_repository(the_repository);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
reinit = is_reinit();
@@ -2375,17 +2376,17 @@ static int create_default_files(const char *template_path,
if (filemode && !reinit && (st1.st_mode & S_IXUSR))
filemode = 0;
}
- git_config_set("core.filemode", filemode ? "true" : "false");
+ repo_config_set(the_repository, "core.filemode", filemode ? "true" : "false");
if (is_bare_repository())
- git_config_set("core.bare", "true");
+ repo_config_set(the_repository, "core.bare", "true");
else {
- git_config_set("core.bare", "false");
+ repo_config_set(the_repository, "core.bare", "false");
/* allow template config file to override the default */
if (repo_settings_get_log_all_ref_updates(the_repository) == LOG_REFS_UNSET)
- git_config_set("core.logallrefupdates", "true");
+ repo_config_set(the_repository, "core.logallrefupdates", "true");
if (needs_work_tree_config(original_git_dir, work_tree))
- git_config_set("core.worktree", work_tree);
+ repo_config_set(the_repository, "core.worktree", work_tree);
}
if (!reinit) {
@@ -2398,12 +2399,12 @@ static int create_default_files(const char *template_path,
S_ISLNK(st1.st_mode))
unlink(path.buf); /* good */
else
- git_config_set("core.symlinks", "false");
+ repo_config_set(the_repository, "core.symlinks", "false");
/* Check if the filesystem is case-insensitive */
repo_git_path_replace(the_repository, &path, "CoNfIg");
if (!access(path.buf, F_OK))
- git_config_set("core.ignorecase", "true");
+ repo_config_set(the_repository, "core.ignorecase", "true");
probe_utf8_pathname_composition();
}
@@ -2610,7 +2611,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
* have set up the repository format such that we can evaluate
* includeIf conditions correctly in the case of re-initialization.
*/
- git_config(platform_core_config, NULL);
+ repo_config(the_repository, platform_core_config, NULL);
safe_create_dir(the_repository, git_dir, 0);
@@ -2639,8 +2640,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
else
BUG("invalid value for shared_repository");
- git_config_set("core.sharedrepository", buf);
- git_config_set("receive.denyNonFastforwards", "true");
+ repo_config_set(the_repository, "core.sharedrepository", buf);
+ repo_config_set(the_repository, "receive.denyNonFastforwards", "true");
}
if (!(flags & INIT_DB_QUIET)) {
diff --git a/sideband.c b/sideband.c
index 251e9615ed..8f15b98a65 100644
--- a/sideband.c
+++ b/sideband.c
@@ -39,9 +39,9 @@ static int use_sideband_colors(void)
if (use_sideband_colors_cached >= 0)
return use_sideband_colors_cached;
- if (!git_config_get_string_tmp(key, &value))
+ if (!repo_config_get_string_tmp(the_repository, key, &value))
use_sideband_colors_cached = git_config_colorbool(key, value);
- else if (!git_config_get_string_tmp("color.ui", &value))
+ else if (!repo_config_get_string_tmp(the_repository, "color.ui", &value))
use_sideband_colors_cached = git_config_colorbool("color.ui", value);
else
use_sideband_colors_cached = GIT_COLOR_AUTO;
@@ -49,7 +49,7 @@ static int use_sideband_colors(void)
for (i = 0; i < ARRAY_SIZE(keywords); i++) {
strbuf_reset(&sb);
strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);
- if (git_config_get_string_tmp(sb.buf, &value))
+ if (repo_config_get_string_tmp(the_repository, sb.buf, &value))
continue;
color_parse(value, keywords[i].color);
}
diff --git a/string-list.c b/string-list.c
index 53faaa8420..343cf1ca90 100644
--- a/string-list.c
+++ b/string-list.c
@@ -276,55 +276,99 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
list->nr--;
}
-int string_list_split(struct string_list *list, const char *string,
- int delim, int maxsplit)
+/*
+ * append a substring [p..end] to list; return number of things it
+ * appended to the list.
+ */
+static int append_one(struct string_list *list,
+ const char *p, const char *end,
+ int in_place, unsigned flags)
+{
+ if (!end)
+ end = p + strlen(p);
+
+ if ((flags & STRING_LIST_SPLIT_TRIM)) {
+ /* rtrim */
+ for (; p < end; end--)
+ if (!isspace(end[-1]))
+ break;
+ }
+
+ if ((flags & STRING_LIST_SPLIT_NONEMPTY) && (end <= p))
+ return 0;
+
+ if (in_place) {
+ *((char *)end) = '\0';
+ string_list_append(list, p);
+ } else {
+ string_list_append_nodup(list, xmemdupz(p, end - p));
+ }
+ return 1;
+}
+
+/*
+ * Unfortunately this cannot become a public interface, as _in_place()
+ * wants to have "const char *string" while the other variant wants to
+ * have "char *string" for type safety.
+ *
+ * This accepts "const char *string" to allow both wrappers to use it;
+ * it internally casts away the constness when in_place is true by
+ * taking advantage of strpbrk() that takes a "const char *" arg and
+ * returns "char *" pointer into that const string. Yucky but works ;-).
+ */
+static int split_string(struct string_list *list, const char *string, const char *delim,
+ int maxsplit, int in_place, unsigned flags)
{
int count = 0;
- const char *p = string, *end;
+ const char *p = string;
+
+ if (in_place && list->strdup_strings)
+ BUG("string_list_split_in_place() called with strdup_strings");
+ else if (!in_place && !list->strdup_strings)
+ BUG("string_list_split() called without strdup_strings");
- if (!list->strdup_strings)
- die("internal error in string_list_split(): "
- "list->strdup_strings must be set");
for (;;) {
- count++;
- if (maxsplit >= 0 && count > maxsplit) {
- string_list_append(list, p);
- return count;
+ char *end;
+
+ if (flags & STRING_LIST_SPLIT_TRIM) {
+ /* ltrim */
+ while (*p && isspace(*p))
+ p++;
}
- end = strchr(p, delim);
- if (end) {
- string_list_append_nodup(list, xmemdupz(p, end - p));
- p = end + 1;
- } else {
- string_list_append(list, p);
+
+ if (0 <= maxsplit && maxsplit <= count)
+ end = NULL;
+ else
+ end = strpbrk(p, delim);
+
+ count += append_one(list, p, end, in_place, flags);
+
+ if (!end)
return count;
- }
+ p = end + 1;
}
}
+int string_list_split(struct string_list *list, const char *string,
+ const char *delim, int maxsplit)
+{
+ return split_string(list, string, delim, maxsplit, 0, 0);
+}
+
int string_list_split_in_place(struct string_list *list, char *string,
const char *delim, int maxsplit)
{
- int count = 0;
- char *p = string, *end;
+ return split_string(list, string, delim, maxsplit, 1, 0);
+}
- if (list->strdup_strings)
- die("internal error in string_list_split_in_place(): "
- "list->strdup_strings must not be set");
- for (;;) {
- count++;
- if (maxsplit >= 0 && count > maxsplit) {
- string_list_append(list, p);
- return count;
- }
- end = strpbrk(p, delim);
- if (end) {
- *end = '\0';
- string_list_append(list, p);
- p = end + 1;
- } else {
- string_list_append(list, p);
- return count;
- }
- }
+int string_list_split_f(struct string_list *list, const char *string,
+ const char *delim, int maxsplit, unsigned flags)
+{
+ return split_string(list, string, delim, maxsplit, 0, flags);
+}
+
+int string_list_split_in_place_f(struct string_list *list, char *string,
+ const char *delim, int maxsplit, unsigned flags)
+{
+ return split_string(list, string, delim, maxsplit, 1, flags);
}
diff --git a/string-list.h b/string-list.h
index 122b318641..2b438c7733 100644
--- a/string-list.h
+++ b/string-list.h
@@ -254,7 +254,7 @@ struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util);
/**
- * Split string into substrings on character `delim` and append the
+ * Split string into substrings on characters in `delim` and append the
* substrings to `list`. The input string is not modified.
* list->strdup_strings must be set, as new memory needs to be
* allocated to hold the substrings. If maxsplit is non-negative,
@@ -262,15 +262,15 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
* appended to list.
*
* Examples:
- * string_list_split(l, "foo:bar:baz", ':', -1) -> ["foo", "bar", "baz"]
- * string_list_split(l, "foo:bar:baz", ':', 0) -> ["foo:bar:baz"]
- * string_list_split(l, "foo:bar:baz", ':', 1) -> ["foo", "bar:baz"]
- * string_list_split(l, "foo:bar:", ':', -1) -> ["foo", "bar", ""]
- * string_list_split(l, "", ':', -1) -> [""]
- * string_list_split(l, ":", ':', -1) -> ["", ""]
+ * string_list_split(l, "foo:bar:baz", ":", -1) -> ["foo", "bar", "baz"]
+ * string_list_split(l, "foo:bar:baz", ":", 0) -> ["foo:bar:baz"]
+ * string_list_split(l, "foo:bar:baz", ":", 1) -> ["foo", "bar:baz"]
+ * string_list_split(l, "foo:bar:", ":", -1) -> ["foo", "bar", ""]
+ * string_list_split(l, "", ":", -1) -> [""]
+ * string_list_split(l, ":", ":", -1) -> ["", ""]
*/
int string_list_split(struct string_list *list, const char *string,
- int delim, int maxsplit);
+ const char *delim, int maxsplit);
/*
* Like string_list_split(), except that string is split in-place: the
@@ -281,4 +281,21 @@ int string_list_split(struct string_list *list, const char *string,
*/
int string_list_split_in_place(struct string_list *list, char *string,
const char *delim, int maxsplit);
+
+/* Flag bits for split_f and split_in_place_f functions */
+enum {
+ /*
+ * trim whitespaces around resulting string piece before adding
+ * it to the list
+ */
+ STRING_LIST_SPLIT_TRIM = (1 << 0),
+ /* omit adding empty string piece to the resulting list */
+ STRING_LIST_SPLIT_NONEMPTY = (1 << 1),
+};
+
+int string_list_split_f(struct string_list *, const char *string,
+ const char *delim, int maxsplit, unsigned flags);
+
+int string_list_split_in_place_f(struct string_list *, char *string,
+ const char *delim, int maxsplit, unsigned flags);
#endif /* STRING_LIST_H */
diff --git a/sub-process.c b/sub-process.c
index 1daf5a9752..83bf0a0e82 100644
--- a/sub-process.c
+++ b/sub-process.c
@@ -30,23 +30,20 @@ struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const ch
int subprocess_read_status(int fd, struct strbuf *status)
{
- struct strbuf **pair;
- char *line;
int len;
for (;;) {
+ char *line;
+ const char *value;
+
len = packet_read_line_gently(fd, NULL, &line);
if ((len < 0) || !line)
break;
- pair = strbuf_split_str(line, '=', 2);
- if (pair[0] && pair[0]->len && pair[1]) {
+ if (skip_prefix(line, "status=", &value)) {
/* the last "status=<foo>" line wins */
- if (!strcmp(pair[0]->buf, "status=")) {
- strbuf_reset(status);
- strbuf_addbuf(status, pair[1]);
- }
+ strbuf_reset(status);
+ strbuf_addstr(status, value);
}
- strbuf_list_free(pair);
}
return (len < 0) ? len : 0;
diff --git a/submodule-config.c b/submodule-config.c
index 70324da383..1f19fe2077 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -983,7 +983,7 @@ int config_set_in_gitmodules_file_gently(const char *key, const char *value)
{
int ret;
- ret = git_config_set_in_file_gently(GITMODULES_FILE, key, NULL, value);
+ ret = repo_config_set_in_file_gently(the_repository, GITMODULES_FILE, key, NULL, value);
if (ret < 0)
/* Maybe the user already did that, don't error out here */
warning(_("Could not update .gitmodules entry %s"), key);
diff --git a/submodule.c b/submodule.c
index f8373a9ea7..fff3c75570 100644
--- a/submodule.c
+++ b/submodule.c
@@ -2058,7 +2058,7 @@ void submodule_unset_core_worktree(const struct submodule *sub)
submodule_name_to_gitdir(&config_path, the_repository, sub->name);
strbuf_addstr(&config_path, "/config");
- if (git_config_set_in_file_gently(config_path.buf, "core.worktree", NULL, NULL))
+ if (repo_config_set_in_file_gently(the_repository, config_path.buf, "core.worktree", NULL, NULL))
warning(_("Could not unset core.worktree setting in submodule '%s'"),
sub->path);
diff --git a/t/for-each-ref-tests.sh b/t/for-each-ref-tests.sh
new file mode 100644
index 0000000000..e3ad19298a
--- /dev/null
+++ b/t/for-each-ref-tests.sh
@@ -0,0 +1,2141 @@
+git_for_each_ref=${git_for_each_ref:-git for-each-ref}
+GNUPGHOME_NOT_USED=$GNUPGHOME
+. "$TEST_DIRECTORY"/lib-gpg.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+# Mon Jul 3 23:18:43 2006 +0000
+datestamp=1151968723
+setdate_and_increment () {
+ GIT_COMMITTER_DATE="$datestamp +0200"
+ datestamp=$(expr "$datestamp" + 1)
+ GIT_AUTHOR_DATE="$datestamp +0200"
+ datestamp=$(expr "$datestamp" + 1)
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+}
+
+test_object_file_size () {
+ oid=$(git rev-parse "$1")
+ path=".git/objects/$(test_oid_to_path $oid)"
+ test_file_size "$path"
+}
+
+test_expect_success setup '
+ # setup .mailmap
+ cat >.mailmap <<-EOF &&
+ A Thor <athor@example.com> A U Thor <author@example.com>
+ C Mitter <cmitter@example.com> C O Mitter <committer@example.com>
+ EOF
+
+ setdate_and_increment &&
+ echo "Using $datestamp" > one &&
+ git add one &&
+ git commit -m "Initial" &&
+ git branch -M main &&
+ setdate_and_increment &&
+ git tag -a -m "Tagging at $datestamp" testtag &&
+ git update-ref refs/remotes/origin/main main &&
+ git remote add origin nowhere &&
+ git config branch.main.remote origin &&
+ git config branch.main.merge refs/heads/main &&
+ git remote add myfork elsewhere &&
+ git config remote.pushdefault myfork &&
+ git config push.default current
+'
+
+test_atom () {
+ case "$1" in
+ head) ref=refs/heads/main ;;
+ tag) ref=refs/tags/testtag ;;
+ sym) ref=refs/heads/sym ;;
+ *) ref=$1 ;;
+ esac
+ format=$2
+ test_do=test_expect_${4:-success}
+
+ printf '%s\n' "$3" >expected
+ $test_do $PREREQ "basic atom: $ref $format" '
+ ${git_for_each_ref} --format="%($format)" "$ref" >actual &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected actual.clean
+ '
+
+ # Automatically test "contents:size" atom after testing "contents"
+ if test "$format" = "contents"
+ then
+ # for commit leg, $3 is changed there
+ expect=$(printf '%s' "$3" | wc -c)
+ $test_do $PREREQ "basic atom: $ref contents:size" '
+ type=$(git cat-file -t "$ref") &&
+ case $type in
+ tag)
+ # We cannot use $3 as it expects sanitize_pgp to run
+ git cat-file tag $ref >out &&
+ expect=$(tail -n +6 out | wc -c) &&
+ rm -f out ;;
+ tree | blob)
+ expect="" ;;
+ commit)
+ : "use the calculated expect" ;;
+ *)
+ BUG "unknown object type" ;;
+ esac &&
+ # Leave $expect unquoted to lose possible leading whitespaces
+ echo $expect >expected &&
+ ${git_for_each_ref} --format="%(contents:size)" "$ref" >actual &&
+ test_cmp expected actual
+ '
+ fi
+}
+
+hexlen=$(test_oid hexsz)
+
+test_atom head refname refs/heads/main
+test_atom head refname: refs/heads/main
+test_atom head refname:short main
+test_atom head refname:lstrip=1 heads/main
+test_atom head refname:lstrip=2 main
+test_atom head refname:lstrip=-1 main
+test_atom head refname:lstrip=-2 heads/main
+test_atom head refname:rstrip=1 refs/heads
+test_atom head refname:rstrip=2 refs
+test_atom head refname:rstrip=-1 refs
+test_atom head refname:rstrip=-2 refs/heads
+test_atom head refname:strip=1 heads/main
+test_atom head refname:strip=2 main
+test_atom head refname:strip=-1 main
+test_atom head refname:strip=-2 heads/main
+test_atom head upstream refs/remotes/origin/main
+test_atom head upstream:short origin/main
+test_atom head upstream:lstrip=2 origin/main
+test_atom head upstream:lstrip=-2 origin/main
+test_atom head upstream:rstrip=2 refs/remotes
+test_atom head upstream:rstrip=-2 refs/remotes
+test_atom head upstream:strip=2 origin/main
+test_atom head upstream:strip=-2 origin/main
+test_atom head push refs/remotes/myfork/main
+test_atom head push:short myfork/main
+test_atom head push:lstrip=1 remotes/myfork/main
+test_atom head push:lstrip=-1 main
+test_atom head push:rstrip=1 refs/remotes/myfork
+test_atom head push:rstrip=-1 refs
+test_atom head push:strip=1 remotes/myfork/main
+test_atom head push:strip=-1 main
+test_atom head objecttype commit
+test_atom head objectsize $((131 + hexlen))
+test_atom head objectsize:disk $(test_object_file_size refs/heads/main)
+test_atom head deltabase $ZERO_OID
+test_atom head objectname $(git rev-parse refs/heads/main)
+test_atom head objectname:short $(git rev-parse --short refs/heads/main)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/main)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/main)
+test_atom head tree $(git rev-parse refs/heads/main^{tree})
+test_atom head tree:short $(git rev-parse --short refs/heads/main^{tree})
+test_atom head tree:short=1 $(git rev-parse --short=1 refs/heads/main^{tree})
+test_atom head tree:short=10 $(git rev-parse --short=10 refs/heads/main^{tree})
+test_atom head parent ''
+test_atom head parent:short ''
+test_atom head parent:short=1 ''
+test_atom head parent:short=10 ''
+test_atom head numparent 0
+test_atom head object ''
+test_atom head type ''
+test_atom head raw "$(git cat-file commit refs/heads/main)
+"
+test_atom head '*objectname' ''
+test_atom head '*objecttype' ''
+test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
+test_atom head authorname 'A U Thor'
+test_atom head authorname:mailmap 'A Thor'
+test_atom head authoremail '<author@example.com>'
+test_atom head authoremail:trim 'author@example.com'
+test_atom head authoremail:localpart 'author'
+test_atom head authoremail:trim,localpart 'author'
+test_atom head authoremail:mailmap '<athor@example.com>'
+test_atom head authoremail:mailmap,trim 'athor@example.com'
+test_atom head authoremail:trim,mailmap 'athor@example.com'
+test_atom head authoremail:mailmap,localpart 'athor'
+test_atom head authoremail:localpart,mailmap 'athor'
+test_atom head authoremail:mailmap,trim,localpart,mailmap,trim 'athor'
+test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'
+test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'
+test_atom head committername 'C O Mitter'
+test_atom head committername:mailmap 'C Mitter'
+test_atom head committeremail '<committer@example.com>'
+test_atom head committeremail:trim 'committer@example.com'
+test_atom head committeremail:localpart 'committer'
+test_atom head committeremail:localpart,trim 'committer'
+test_atom head committeremail:mailmap '<cmitter@example.com>'
+test_atom head committeremail:mailmap,trim 'cmitter@example.com'
+test_atom head committeremail:trim,mailmap 'cmitter@example.com'
+test_atom head committeremail:mailmap,localpart 'cmitter'
+test_atom head committeremail:localpart,mailmap 'cmitter'
+test_atom head committeremail:trim,mailmap,trim,trim,localpart 'cmitter'
+test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'
+test_atom head tag ''
+test_atom head tagger ''
+test_atom head taggername ''
+test_atom head taggeremail ''
+test_atom head taggeremail:trim ''
+test_atom head taggeremail:localpart ''
+test_atom head taggerdate ''
+test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200'
+test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200'
+test_atom head subject 'Initial'
+test_atom head subject:sanitize 'Initial'
+test_atom head contents:subject 'Initial'
+test_atom head body ''
+test_atom head contents:body ''
+test_atom head contents:signature ''
+test_atom head contents 'Initial
+'
+test_atom head HEAD '*'
+
+test_atom tag refname refs/tags/testtag
+test_atom tag refname:short testtag
+test_atom tag upstream ''
+test_atom tag push ''
+test_atom tag objecttype tag
+test_atom tag objectsize $((114 + hexlen))
+test_atom tag objectsize:disk $(test_object_file_size refs/tags/testtag)
+test_atom tag '*objectsize:disk' $(test_object_file_size refs/heads/main)
+test_atom tag deltabase $ZERO_OID
+test_atom tag '*deltabase' $ZERO_OID
+test_atom tag objectname $(git rev-parse refs/tags/testtag)
+test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/main)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/main)
+test_atom tag tree ''
+test_atom tag tree:short ''
+test_atom tag tree:short=1 ''
+test_atom tag tree:short=10 ''
+test_atom tag parent ''
+test_atom tag parent:short ''
+test_atom tag parent:short=1 ''
+test_atom tag parent:short=10 ''
+test_atom tag numparent ''
+test_atom tag object $(git rev-parse refs/tags/testtag^0)
+test_atom tag type 'commit'
+test_atom tag '*objectname' $(git rev-parse refs/tags/testtag^{})
+test_atom tag '*objecttype' 'commit'
+test_atom tag author ''
+test_atom tag authorname ''
+test_atom tag authorname:mailmap ''
+test_atom tag authoremail ''
+test_atom tag authoremail:trim ''
+test_atom tag authoremail:localpart ''
+test_atom tag authoremail:trim,localpart ''
+test_atom tag authoremail:mailmap ''
+test_atom tag authoremail:mailmap,trim ''
+test_atom tag authoremail:trim,mailmap ''
+test_atom tag authoremail:mailmap,localpart ''
+test_atom tag authoremail:localpart,mailmap ''
+test_atom tag authoremail:mailmap,trim,localpart,mailmap,trim ''
+test_atom tag authordate ''
+test_atom tag committer ''
+test_atom tag committername ''
+test_atom tag committername:mailmap ''
+test_atom tag committeremail ''
+test_atom tag committeremail:trim ''
+test_atom tag committeremail:localpart ''
+test_atom tag committeremail:localpart,trim ''
+test_atom tag committeremail:mailmap ''
+test_atom tag committeremail:mailmap,trim ''
+test_atom tag committeremail:trim,mailmap ''
+test_atom tag committeremail:mailmap,localpart ''
+test_atom tag committeremail:localpart,mailmap ''
+test_atom tag committeremail:trim,mailmap,trim,trim,localpart ''
+test_atom tag committerdate ''
+test_atom tag tag 'testtag'
+test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'
+test_atom tag taggername 'C O Mitter'
+test_atom tag taggername:mailmap 'C Mitter'
+test_atom tag taggeremail '<committer@example.com>'
+test_atom tag taggeremail:trim 'committer@example.com'
+test_atom tag taggeremail:localpart 'committer'
+test_atom tag taggeremail:trim,localpart 'committer'
+test_atom tag taggeremail:mailmap '<cmitter@example.com>'
+test_atom tag taggeremail:mailmap,trim 'cmitter@example.com'
+test_atom tag taggeremail:trim,mailmap 'cmitter@example.com'
+test_atom tag taggeremail:mailmap,localpart 'cmitter'
+test_atom tag taggeremail:localpart,mailmap 'cmitter'
+test_atom tag taggeremail:trim,mailmap,trim,localpart,localpart 'cmitter'
+test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'
+test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'
+test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'
+test_atom tag subject 'Tagging at 1151968727'
+test_atom tag subject:sanitize 'Tagging-at-1151968727'
+test_atom tag contents:subject 'Tagging at 1151968727'
+test_atom tag body ''
+test_atom tag contents:body ''
+test_atom tag contents:signature ''
+test_atom tag contents 'Tagging at 1151968727
+'
+test_atom tag HEAD ' '
+
+test_expect_success 'basic atom: refs/tags/testtag *raw' '
+ git cat-file commit refs/tags/testtag^{} >expected &&
+ ${git_for_each_ref} --format="%(*raw)" refs/tags/testtag >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
+test_expect_success 'Check invalid atoms names are errors' '
+ test_must_fail ${git_for_each_ref} --format="%(INVALID)" refs/heads
+'
+
+test_expect_success 'Check format specifiers are ignored in naming date atoms' '
+ ${git_for_each_ref} --format="%(authordate)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:default) %(authordate)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate) %(authordate:default)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:default) %(authordate:default)" refs/heads
+'
+
+test_expect_success 'Check valid format specifiers for date fields' '
+ ${git_for_each_ref} --format="%(authordate:default)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:relative)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:short)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:local)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:iso8601)" refs/heads &&
+ ${git_for_each_ref} --format="%(authordate:rfc2822)" refs/heads
+'
+
+test_expect_success 'Check invalid format specifiers are errors' '
+ test_must_fail ${git_for_each_ref} --format="%(authordate:INVALID)" refs/heads
+'
+
+test_expect_success 'arguments to %(objectname:short=) must be positive integers' '
+ test_must_fail ${git_for_each_ref} --format="%(objectname:short=0)" &&
+ test_must_fail ${git_for_each_ref} --format="%(objectname:short=-1)" &&
+ test_must_fail ${git_for_each_ref} --format="%(objectname:short=foo)"
+'
+
+test_bad_atom () {
+ case "$1" in
+ head) ref=refs/heads/main ;;
+ tag) ref=refs/tags/testtag ;;
+ sym) ref=refs/heads/sym ;;
+ *) ref=$1 ;;
+ esac
+ format=$2
+ test_do=test_expect_${4:-success}
+
+ printf '%s\n' "$3" >expect
+ $test_do $PREREQ "err basic atom: $ref $format" '
+ test_must_fail ${git_for_each_ref} \
+ --format="%($format)" "$ref" 2>error &&
+ test_cmp expect error
+ '
+}
+
+test_bad_atom head 'authoremail:foo' \
+ 'fatal: unrecognized %(authoremail) argument: foo'
+
+test_bad_atom head 'authoremail:mailmap,trim,bar' \
+ 'fatal: unrecognized %(authoremail) argument: bar'
+
+test_bad_atom head 'authoremail:trim,' \
+ 'fatal: unrecognized %(authoremail) argument: '
+
+test_bad_atom head 'authoremail:mailmaptrim' \
+ 'fatal: unrecognized %(authoremail) argument: trim'
+
+test_bad_atom head 'committeremail: ' \
+ 'fatal: unrecognized %(committeremail) argument: '
+
+test_bad_atom head 'committeremail: trim,foo' \
+ 'fatal: unrecognized %(committeremail) argument: trim,foo'
+
+test_bad_atom head 'committeremail:mailmap,localpart ' \
+ 'fatal: unrecognized %(committeremail) argument: '
+
+test_bad_atom head 'committeremail:trim_localpart' \
+ 'fatal: unrecognized %(committeremail) argument: _localpart'
+
+test_bad_atom head 'committeremail:localpart,,,trim' \
+ 'fatal: unrecognized %(committeremail) argument: ,,trim'
+
+test_bad_atom tag 'taggeremail:mailmap,trim, foo ' \
+ 'fatal: unrecognized %(taggeremail) argument: foo '
+
+test_bad_atom tag 'taggeremail:trim,localpart,' \
+ 'fatal: unrecognized %(taggeremail) argument: '
+
+test_bad_atom tag 'taggeremail:mailmap;localpart trim' \
+ 'fatal: unrecognized %(taggeremail) argument: ;localpart trim'
+
+test_bad_atom tag 'taggeremail:localpart trim' \
+ 'fatal: unrecognized %(taggeremail) argument: trim'
+
+test_bad_atom tag 'taggeremail:mailmap,mailmap,trim,qux,localpart,trim' \
+ 'fatal: unrecognized %(taggeremail) argument: qux,localpart,trim'
+
+test_date () {
+ f=$1 &&
+ committer_date=$2 &&
+ author_date=$3 &&
+ tagger_date=$4 &&
+ cat >expected <<-EOF &&
+ 'refs/heads/main' '$committer_date' '$author_date'
+ 'refs/tags/testtag' '$tagger_date'
+ EOF
+ (
+ ${git_for_each_ref} --shell \
+ --format="%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})" \
+ refs/heads &&
+ ${git_for_each_ref} --shell \
+ --format="%(refname) %(taggerdate${f:+:$f})" \
+ refs/tags
+ ) >actual &&
+ test_cmp expected actual
+}
+
+test_expect_success 'Check unformatted date fields output' '
+ test_date "" \
+ "Tue Jul 4 01:18:43 2006 +0200" \
+ "Tue Jul 4 01:18:44 2006 +0200" \
+ "Tue Jul 4 01:18:45 2006 +0200"
+'
+
+test_expect_success 'Check format "default" formatted date fields output' '
+ test_date default \
+ "Tue Jul 4 01:18:43 2006 +0200" \
+ "Tue Jul 4 01:18:44 2006 +0200" \
+ "Tue Jul 4 01:18:45 2006 +0200"
+'
+
+test_expect_success 'Check format "default-local" date fields output' '
+ test_date default-local "Mon Jul 3 23:18:43 2006" "Mon Jul 3 23:18:44 2006" "Mon Jul 3 23:18:45 2006"
+'
+
+# Don't know how to do relative check because I can't know when this script
+# is going to be run and can't fake the current time to git, and hence can't
+# provide expected output. Instead, I'll just make sure that "relative"
+# doesn't exit in error
+test_expect_success 'Check format "relative" date fields output' '
+ f=relative &&
+ (${git_for_each_ref} --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
+ ${git_for_each_ref} --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual
+'
+
+# We just check that this is the same as "relative" for now.
+test_expect_success 'Check format "relative-local" date fields output' '
+ test_date relative-local \
+ "$(${git_for_each_ref} --format="%(committerdate:relative)" refs/heads)" \
+ "$(${git_for_each_ref} --format="%(authordate:relative)" refs/heads)" \
+ "$(${git_for_each_ref} --format="%(taggerdate:relative)" refs/tags)"
+'
+
+test_expect_success 'Check format "short" date fields output' '
+ test_date short 2006-07-04 2006-07-04 2006-07-04
+'
+
+test_expect_success 'Check format "short-local" date fields output' '
+ test_date short-local 2006-07-03 2006-07-03 2006-07-03
+'
+
+test_expect_success 'Check format "local" date fields output' '
+ test_date local \
+ "Mon Jul 3 23:18:43 2006" \
+ "Mon Jul 3 23:18:44 2006" \
+ "Mon Jul 3 23:18:45 2006"
+'
+
+test_expect_success 'Check format "iso8601" date fields output' '
+ test_date iso8601 \
+ "2006-07-04 01:18:43 +0200" \
+ "2006-07-04 01:18:44 +0200" \
+ "2006-07-04 01:18:45 +0200"
+'
+
+test_expect_success 'Check format "iso8601-local" date fields output' '
+ test_date iso8601-local "2006-07-03 23:18:43 +0000" "2006-07-03 23:18:44 +0000" "2006-07-03 23:18:45 +0000"
+'
+
+test_expect_success 'Check format "rfc2822" date fields output' '
+ test_date rfc2822 \
+ "Tue, 4 Jul 2006 01:18:43 +0200" \
+ "Tue, 4 Jul 2006 01:18:44 +0200" \
+ "Tue, 4 Jul 2006 01:18:45 +0200"
+'
+
+test_expect_success 'Check format "rfc2822-local" date fields output' '
+ test_date rfc2822-local "Mon, 3 Jul 2006 23:18:43 +0000" "Mon, 3 Jul 2006 23:18:44 +0000" "Mon, 3 Jul 2006 23:18:45 +0000"
+'
+
+test_expect_success 'Check format "raw" date fields output' '
+ test_date raw "1151968723 +0200" "1151968724 +0200" "1151968725 +0200"
+'
+
+test_expect_success 'Check format "raw-local" date fields output' '
+ test_date raw-local "1151968723 +0000" "1151968724 +0000" "1151968725 +0000"
+'
+
+test_expect_success 'Check format of strftime date fields' '
+ echo "my date is 2006-07-04" >expected &&
+ ${git_for_each_ref} \
+ --format="%(authordate:format:my date is %Y-%m-%d)" \
+ refs/heads >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Check format of strftime-local date fields' '
+ echo "my date is 2006-07-03" >expected &&
+ ${git_for_each_ref} \
+ --format="%(authordate:format-local:my date is %Y-%m-%d)" \
+ refs/heads >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'exercise strftime with odd fields' '
+ echo >expected &&
+ ${git_for_each_ref} --format="%(authordate:format:)" refs/heads >actual &&
+ test_cmp expected actual &&
+ long="long format -- $ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID" &&
+ echo $long >expected &&
+ ${git_for_each_ref} --format="%(authordate:format:$long)" refs/heads >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/heads/main
+refs/remotes/origin/main
+refs/tags/testtag
+EOF
+
+test_expect_success 'Verify ascending sort' '
+ ${git_for_each_ref} --format="%(refname)" --sort=refname >actual &&
+ test_cmp expected actual
+'
+
+
+cat >expected <<\EOF
+refs/tags/testtag
+refs/remotes/origin/main
+refs/heads/main
+EOF
+
+test_expect_success 'Verify descending sort' '
+ ${git_for_each_ref} --format="%(refname)" --sort=-refname >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Give help even with invalid sort atoms' '
+ test_expect_code 129 ${git_for_each_ref} --sort=bogus -h >actual 2>&1 &&
+ grep "^usage: ${git_for_each_ref}" actual
+'
+
+cat >expected <<\EOF
+refs/tags/testtag
+refs/tags/testtag-2
+EOF
+
+test_expect_success 'exercise patterns with prefixes' '
+ git tag testtag-2 &&
+ test_when_finished "git tag -d testtag-2" &&
+ ${git_for_each_ref} --format="%(refname)" \
+ refs/tags/testtag refs/tags/testtag-2 >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/tags/testtag
+refs/tags/testtag-2
+EOF
+
+test_expect_success 'exercise glob patterns with prefixes' '
+ git tag testtag-2 &&
+ test_when_finished "git tag -d testtag-2" &&
+ ${git_for_each_ref} --format="%(refname)" \
+ refs/tags/testtag "refs/tags/testtag-*" >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/tags/bar
+refs/tags/baz
+refs/tags/testtag
+EOF
+
+test_expect_success 'exercise patterns with prefix exclusions' '
+ for tag in foo/one foo/two foo/three bar baz
+ do
+ git tag "$tag" || return 1
+ done &&
+ test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
+ ${git_for_each_ref} --format="%(refname)" \
+ refs/tags/ --exclude=refs/tags/foo >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/tags/bar
+refs/tags/baz
+refs/tags/foo/one
+refs/tags/testtag
+EOF
+
+test_expect_success 'exercise patterns with pattern exclusions' '
+ for tag in foo/one foo/two foo/three bar baz
+ do
+ git tag "$tag" || return 1
+ done &&
+ test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
+ ${git_for_each_ref} --format="%(refname)" \
+ refs/tags/ --exclude="refs/tags/foo/t*" >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+'refs/heads/main'
+'refs/remotes/origin/main'
+'refs/tags/testtag'
+EOF
+
+test_expect_success 'Quoting style: shell' '
+ ${git_for_each_ref} --shell --format="%(refname)" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Quoting style: perl' '
+ ${git_for_each_ref} --perl --format="%(refname)" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Quoting style: python' '
+ ${git_for_each_ref} --python --format="%(refname)" >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+"refs/heads/main"
+"refs/remotes/origin/main"
+"refs/tags/testtag"
+EOF
+
+test_expect_success 'Quoting style: tcl' '
+ ${git_for_each_ref} --tcl --format="%(refname)" >actual &&
+ test_cmp expected actual
+'
+
+for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
+ test_expect_success "more than one quoting style: $i" "
+ test_must_fail ${git_for_each_ref} $i 2>err &&
+ grep '^error: more than one quoting style' err
+ "
+done
+
+test_expect_success 'setup for upstream:track[short]' '
+ test_commit two
+'
+
+test_atom head upstream:track '[ahead 1]'
+test_atom head upstream:trackshort '>'
+test_atom head upstream:track,nobracket 'ahead 1'
+test_atom head upstream:nobracket,track 'ahead 1'
+
+test_expect_success 'setup for push:track[short]' '
+ test_commit third &&
+ git update-ref refs/remotes/myfork/main main &&
+ git reset main~1
+'
+
+test_atom head push:track '[behind 1]'
+test_atom head push:trackshort '<'
+
+test_expect_success 'Check that :track[short] cannot be used with other atoms' '
+ test_must_fail ${git_for_each_ref} --format="%(refname:track)" 2>/dev/null &&
+ test_must_fail ${git_for_each_ref} --format="%(refname:trackshort)" 2>/dev/null
+'
+
+test_expect_success 'Check that :track[short] works when upstream is invalid' '
+ cat >expected <<-\EOF &&
+ [gone]
+
+ EOF
+ test_when_finished "git config branch.main.merge refs/heads/main" &&
+ git config branch.main.merge refs/heads/does-not-exist &&
+ ${git_for_each_ref} \
+ --format="%(upstream:track)$LF%(upstream:trackshort)" \
+ refs/heads >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Check for invalid refname format' '
+ test_must_fail ${git_for_each_ref} --format="%(refname:INVALID)"
+'
+
+test_expect_success 'set up color tests' '
+ cat >expected.color <<-EOF &&
+ $(git rev-parse --short refs/heads/main) <GREEN>main<RESET>
+ $(git rev-parse --short refs/remotes/myfork/main) <GREEN>myfork/main<RESET>
+ $(git rev-parse --short refs/remotes/origin/main) <GREEN>origin/main<RESET>
+ $(git rev-parse --short refs/tags/testtag) <GREEN>testtag<RESET>
+ $(git rev-parse --short refs/tags/third) <GREEN>third<RESET>
+ $(git rev-parse --short refs/tags/two) <GREEN>two<RESET>
+ EOF
+ sed "s/<[^>]*>//g" <expected.color >expected.bare &&
+ color_format="%(objectname:short) %(color:green)%(refname:short)"
+'
+
+test_expect_success TTY '%(color) shows color with a tty' '
+ test_terminal ${git_for_each_ref} --format="$color_format" >actual.raw &&
+ test_decode_color <actual.raw >actual &&
+ test_cmp expected.color actual
+'
+
+test_expect_success '%(color) does not show color without tty' '
+ TERM=vt100 ${git_for_each_ref} --format="$color_format" >actual &&
+ test_cmp expected.bare actual
+'
+
+test_expect_success '--color can override tty check' '
+ ${git_for_each_ref} --color --format="$color_format" >actual.raw &&
+ test_decode_color <actual.raw >actual &&
+ test_cmp expected.color actual
+'
+
+test_expect_success 'color.ui=always does not override tty check' '
+ git -c color.ui=always ${git_for_each_ref#git} --format="$color_format" >actual &&
+ test_cmp expected.bare actual
+'
+
+test_expect_success 'setup for describe atom tests' '
+ git init -b master describe-repo &&
+ (
+ cd describe-repo &&
+
+ test_commit --no-tag one &&
+ git tag tagone &&
+
+ test_commit --no-tag two &&
+ git tag -a -m "tag two" tagtwo
+ )
+'
+
+test_expect_success 'describe atom vs git describe' '
+ (
+ cd describe-repo &&
+
+ ${git_for_each_ref} --format="%(objectname)" \
+ refs/tags/ >obj &&
+ while read hash
+ do
+ if desc=$(git describe $hash)
+ then
+ : >expect-contains-good
+ else
+ : >expect-contains-bad
+ fi &&
+ echo "$hash $desc" || return 1
+ done <obj >expect &&
+ test_path_exists expect-contains-good &&
+ test_path_exists expect-contains-bad &&
+
+ ${git_for_each_ref} --format="%(objectname) %(describe)" \
+ refs/tags/ >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
+ )
+'
+
+test_expect_success 'describe:tags vs describe --tags' '
+ (
+ cd describe-repo &&
+ git describe --tags >expect &&
+ ${git_for_each_ref} --format="%(describe:tags)" \
+ refs/heads/master >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'describe:abbrev=... vs describe --abbrev=...' '
+ (
+ cd describe-repo &&
+
+ # Case 1: We have commits between HEAD and the most
+ # recent tag reachable from it
+ test_commit --no-tag file &&
+ git describe --abbrev=14 >expect &&
+ ${git_for_each_ref} --format="%(describe:abbrev=14)" \
+ refs/heads/master >actual &&
+ test_cmp expect actual &&
+
+ # Make sure the hash used is at least 14 digits long
+ sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
+ test 15 -le $(wc -c <hexpart) &&
+
+ # Case 2: We have a tag at HEAD, describe directly gives
+ # the name of the tag
+ git tag -a -m tagged tagname &&
+ git describe --abbrev=14 >expect &&
+ ${git_for_each_ref} --format="%(describe:abbrev=14)" \
+ refs/heads/master >actual &&
+ test_cmp expect actual &&
+ test tagname = $(cat actual)
+ )
+'
+
+test_expect_success 'describe:match=... vs describe --match ...' '
+ (
+ cd describe-repo &&
+ git tag -a -m "tag foo" tag-foo &&
+ git describe --match "*-foo" >expect &&
+ ${git_for_each_ref} --format="%(describe:match="*-foo")" \
+ refs/heads/master >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'describe:exclude:... vs describe --exclude ...' '
+ (
+ cd describe-repo &&
+ git tag -a -m "tag bar" tag-bar &&
+ git describe --exclude "*-bar" >expect &&
+ ${git_for_each_ref} --format="%(describe:exclude="*-bar")" \
+ refs/heads/master >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'deref with describe atom' '
+ (
+ cd describe-repo &&
+ cat >expect <<-\EOF &&
+
+ tagname
+ tagname
+ tagname
+
+ tagtwo
+ EOF
+ ${git_for_each_ref} --format="%(*describe)" >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'err on bad describe atom arg' '
+ (
+ cd describe-repo &&
+
+ # The bad arg is the only arg passed to describe atom
+ cat >expect <<-\EOF &&
+ fatal: unrecognized %(describe) argument: baz
+ EOF
+ test_must_fail ${git_for_each_ref} --format="%(describe:baz)" \
+ refs/heads/master 2>actual &&
+ test_cmp expect actual &&
+
+ # The bad arg is in the middle of the option string
+ # passed to the describe atom
+ cat >expect <<-\EOF &&
+ fatal: unrecognized %(describe) argument: qux=1,abbrev=14
+ EOF
+ test_must_fail ${git_for_each_ref} \
+ --format="%(describe:tags,qux=1,abbrev=14)" \
+ ref/heads/master 2>actual &&
+ test_cmp expect actual
+ )
+'
+
+cat >expected <<\EOF
+heads/main
+tags/main
+EOF
+
+test_expect_success 'Check ambiguous head and tag refs (strict)' '
+ git config --bool core.warnambiguousrefs true &&
+ git checkout -b newtag &&
+ echo "Using $datestamp" > one &&
+ git add one &&
+ git commit -m "Branch" &&
+ setdate_and_increment &&
+ git tag -m "Tagging at $datestamp" main &&
+ ${git_for_each_ref} --format "%(refname:short)" refs/heads/main refs/tags/main >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+heads/main
+main
+EOF
+
+test_expect_success 'Check ambiguous head and tag refs (loose)' '
+ git config --bool core.warnambiguousrefs false &&
+ ${git_for_each_ref} --format "%(refname:short)" refs/heads/main refs/tags/main >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+heads/ambiguous
+ambiguous
+EOF
+
+test_expect_success 'Check ambiguous head and tag refs II (loose)' '
+ git checkout main &&
+ git tag ambiguous testtag^0 &&
+ git branch ambiguous testtag^0 &&
+ ${git_for_each_ref} --format "%(refname:short)" refs/heads/ambiguous refs/tags/ambiguous >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'create tag without tagger' '
+ git tag -a -m "Broken tag" taggerless &&
+ git tag -f taggerless $(git cat-file tag taggerless |
+ sed -e "/^tagger /d" |
+ git hash-object --literally --stdin -w -t tag)
+'
+
+test_atom refs/tags/taggerless type 'commit'
+test_atom refs/tags/taggerless tag 'taggerless'
+test_atom refs/tags/taggerless tagger ''
+test_atom refs/tags/taggerless taggername ''
+test_atom refs/tags/taggerless taggeremail ''
+test_atom refs/tags/taggerless taggeremail:trim ''
+test_atom refs/tags/taggerless taggeremail:localpart ''
+test_atom refs/tags/taggerless taggerdate ''
+test_atom refs/tags/taggerless committer ''
+test_atom refs/tags/taggerless committername ''
+test_atom refs/tags/taggerless committeremail ''
+test_atom refs/tags/taggerless committeremail:trim ''
+test_atom refs/tags/taggerless committeremail:localpart ''
+test_atom refs/tags/taggerless committerdate ''
+test_atom refs/tags/taggerless subject 'Broken tag'
+
+test_expect_success 'an unusual tag with an incomplete line' '
+
+ git tag -m "bogo" bogo &&
+ bogo=$(git cat-file tag bogo) &&
+ bogo=$(printf "%s" "$bogo" | git mktag) &&
+ git tag -f bogo "$bogo" &&
+ ${git_for_each_ref} --format "%(body)" refs/tags/bogo
+
+'
+
+test_expect_success 'create tag with subject and body content' '
+ cat >>msg <<-\EOF &&
+ the subject line
+
+ first body line
+ second body line
+ EOF
+ git tag -F msg subject-body
+'
+test_atom refs/tags/subject-body subject 'the subject line'
+test_atom refs/tags/subject-body subject:sanitize 'the-subject-line'
+test_atom refs/tags/subject-body body 'first body line
+second body line
+'
+test_atom refs/tags/subject-body contents 'the subject line
+
+first body line
+second body line
+'
+
+test_expect_success 'create tag with multiline subject' '
+ cat >msg <<-\EOF &&
+ first subject line
+ second subject line
+
+ first body line
+ second body line
+ EOF
+ git tag -F msg multiline
+'
+test_atom refs/tags/multiline subject 'first subject line second subject line'
+test_atom refs/tags/multiline subject:sanitize 'first-subject-line-second-subject-line'
+test_atom refs/tags/multiline contents:subject 'first subject line second subject line'
+test_atom refs/tags/multiline body 'first body line
+second body line
+'
+test_atom refs/tags/multiline contents:body 'first body line
+second body line
+'
+test_atom refs/tags/multiline contents:signature ''
+test_atom refs/tags/multiline contents 'first subject line
+second subject line
+
+first body line
+second body line
+'
+
+test_expect_success GPG 'create signed tags' '
+ git tag -s -m "" signed-empty &&
+ git tag -s -m "subject line" signed-short &&
+ cat >msg <<-\EOF &&
+ subject line
+
+ body contents
+ EOF
+ git tag -s -F msg signed-long
+'
+
+sig='-----BEGIN PGP SIGNATURE-----
+-----END PGP SIGNATURE-----
+'
+
+PREREQ=GPG
+test_atom refs/tags/signed-empty subject ''
+test_atom refs/tags/signed-empty subject:sanitize ''
+test_atom refs/tags/signed-empty contents:subject ''
+test_atom refs/tags/signed-empty body "$sig"
+test_atom refs/tags/signed-empty contents:body ''
+test_atom refs/tags/signed-empty contents:signature "$sig"
+test_atom refs/tags/signed-empty contents "$sig"
+
+test_expect_success GPG 'basic atom: refs/tags/signed-empty raw' '
+ git cat-file tag refs/tags/signed-empty >expected &&
+ ${git_for_each_ref} --format="%(raw)" refs/tags/signed-empty >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
+test_atom refs/tags/signed-short subject 'subject line'
+test_atom refs/tags/signed-short subject:sanitize 'subject-line'
+test_atom refs/tags/signed-short contents:subject 'subject line'
+test_atom refs/tags/signed-short body "$sig"
+test_atom refs/tags/signed-short contents:body ''
+test_atom refs/tags/signed-short contents:signature "$sig"
+test_atom refs/tags/signed-short contents "subject line
+$sig"
+
+test_expect_success GPG 'basic atom: refs/tags/signed-short raw' '
+ git cat-file tag refs/tags/signed-short >expected &&
+ ${git_for_each_ref} --format="%(raw)" refs/tags/signed-short >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
+test_atom refs/tags/signed-long subject 'subject line'
+test_atom refs/tags/signed-long subject:sanitize 'subject-line'
+test_atom refs/tags/signed-long contents:subject 'subject line'
+test_atom refs/tags/signed-long body "body contents
+$sig"
+test_atom refs/tags/signed-long contents:body 'body contents
+'
+test_atom refs/tags/signed-long contents:signature "$sig"
+test_atom refs/tags/signed-long contents "subject line
+
+body contents
+$sig"
+
+test_expect_success GPG 'basic atom: refs/tags/signed-long raw' '
+ git cat-file tag refs/tags/signed-long >expected &&
+ ${git_for_each_ref} --format="%(raw)" refs/tags/signed-long >actual &&
+ sanitize_pgp <expected >expected.clean &&
+ echo >>expected.clean &&
+ sanitize_pgp <actual >actual.clean &&
+ test_cmp expected.clean actual.clean
+'
+
+test_expect_success 'set up refs pointing to tree and blob' '
+ git update-ref refs/mytrees/first refs/heads/main^{tree} &&
+ git update-ref refs/myblobs/first refs/heads/main:one
+'
+
+test_atom refs/mytrees/first subject ""
+test_atom refs/mytrees/first contents:subject ""
+test_atom refs/mytrees/first body ""
+test_atom refs/mytrees/first contents:body ""
+test_atom refs/mytrees/first contents:signature ""
+test_atom refs/mytrees/first contents ""
+
+test_expect_success 'basic atom: refs/mytrees/first raw' '
+ git cat-file tree refs/mytrees/first >expected &&
+ echo >>expected &&
+ ${git_for_each_ref} --format="%(raw)" refs/mytrees/first >actual &&
+ test_cmp expected actual &&
+ git cat-file -s refs/mytrees/first >expected &&
+ ${git_for_each_ref} --format="%(raw:size)" refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
+test_atom refs/myblobs/first subject ""
+test_atom refs/myblobs/first contents:subject ""
+test_atom refs/myblobs/first body ""
+test_atom refs/myblobs/first contents:body ""
+test_atom refs/myblobs/first contents:signature ""
+test_atom refs/myblobs/first contents ""
+
+test_expect_success 'basic atom: refs/myblobs/first raw' '
+ git cat-file blob refs/myblobs/first >expected &&
+ echo >>expected &&
+ ${git_for_each_ref} --format="%(raw)" refs/myblobs/first >actual &&
+ test_cmp expected actual &&
+ git cat-file -s refs/myblobs/first >expected &&
+ ${git_for_each_ref} --format="%(raw:size)" refs/myblobs/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'set up refs pointing to binary blob' '
+ printf "a\0b\0c" >blob1 &&
+ printf "a\0c\0b" >blob2 &&
+ printf "\0a\0b\0c" >blob3 &&
+ printf "abc" >blob4 &&
+ printf "\0 \0 \0 " >blob5 &&
+ printf "\0 \0a\0 " >blob6 &&
+ printf " " >blob7 &&
+ >blob8 &&
+ obj=$(git hash-object -w blob1) &&
+ git update-ref refs/myblobs/blob1 "$obj" &&
+ obj=$(git hash-object -w blob2) &&
+ git update-ref refs/myblobs/blob2 "$obj" &&
+ obj=$(git hash-object -w blob3) &&
+ git update-ref refs/myblobs/blob3 "$obj" &&
+ obj=$(git hash-object -w blob4) &&
+ git update-ref refs/myblobs/blob4 "$obj" &&
+ obj=$(git hash-object -w blob5) &&
+ git update-ref refs/myblobs/blob5 "$obj" &&
+ obj=$(git hash-object -w blob6) &&
+ git update-ref refs/myblobs/blob6 "$obj" &&
+ obj=$(git hash-object -w blob7) &&
+ git update-ref refs/myblobs/blob7 "$obj" &&
+ obj=$(git hash-object -w blob8) &&
+ git update-ref refs/myblobs/blob8 "$obj"
+'
+
+test_expect_success 'Verify sorts with raw' '
+ cat >expected <<-EOF &&
+ refs/myblobs/blob8
+ refs/myblobs/blob5
+ refs/myblobs/blob6
+ refs/myblobs/blob3
+ refs/myblobs/blob7
+ refs/mytrees/first
+ refs/myblobs/first
+ refs/myblobs/blob1
+ refs/myblobs/blob2
+ refs/myblobs/blob4
+ refs/heads/main
+ EOF
+ ${git_for_each_ref} --format="%(refname)" --sort=raw \
+ refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Verify sorts with raw:size' '
+ cat >expected <<-EOF &&
+ refs/myblobs/blob8
+ refs/myblobs/blob7
+ refs/myblobs/blob4
+ refs/myblobs/blob1
+ refs/myblobs/blob2
+ refs/myblobs/blob3
+ refs/myblobs/blob5
+ refs/myblobs/blob6
+ refs/myblobs/first
+ refs/mytrees/first
+ refs/heads/main
+ EOF
+ ${git_for_each_ref} --format="%(refname)" --sort=raw:size \
+ refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'validate raw atom with %(if:equals)' '
+ cat >expected <<-EOF &&
+ not equals
+ not equals
+ not equals
+ not equals
+ not equals
+ not equals
+ refs/myblobs/blob4
+ not equals
+ not equals
+ not equals
+ not equals
+ not equals
+ EOF
+ ${git_for_each_ref} --format="%(if:equals=abc)%(raw)%(then)%(refname)%(else)not equals%(end)" \
+ refs/myblobs/ refs/heads/ >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'validate raw atom with %(if:notequals)' '
+ cat >expected <<-EOF &&
+ refs/heads/ambiguous
+ refs/heads/main
+ refs/heads/newtag
+ refs/myblobs/blob1
+ refs/myblobs/blob2
+ refs/myblobs/blob3
+ equals
+ refs/myblobs/blob5
+ refs/myblobs/blob6
+ refs/myblobs/blob7
+ refs/myblobs/blob8
+ refs/myblobs/first
+ EOF
+ ${git_for_each_ref} --format="%(if:notequals=abc)%(raw)%(then)%(refname)%(else)equals%(end)" \
+ refs/myblobs/ refs/heads/ >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'empty raw refs with %(if)' '
+ cat >expected <<-EOF &&
+ refs/myblobs/blob1 not empty
+ refs/myblobs/blob2 not empty
+ refs/myblobs/blob3 not empty
+ refs/myblobs/blob4 not empty
+ refs/myblobs/blob5 not empty
+ refs/myblobs/blob6 not empty
+ refs/myblobs/blob7 empty
+ refs/myblobs/blob8 empty
+ refs/myblobs/first not empty
+ EOF
+ ${git_for_each_ref} --format="%(refname) %(if)%(raw)%(then)not empty%(else)empty%(end)" \
+ refs/myblobs/ >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '%(raw) with --python must fail' '
+ test_must_fail ${git_for_each_ref} --format="%(raw)" --python
+'
+
+test_expect_success '%(raw) with --tcl must fail' '
+ test_must_fail ${git_for_each_ref} --format="%(raw)" --tcl
+'
+
+test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
+ ${git_for_each_ref} --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
+ cmp blob1 actual &&
+ ${git_for_each_ref} --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/blob3 --perl | perl >actual &&
+ cmp blob3 actual &&
+ ${git_for_each_ref} --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/blob8 --perl | perl >actual &&
+ cmp blob8 actual &&
+ ${git_for_each_ref} --format="\$name= %(raw);
+print \"\$name\"" refs/myblobs/first --perl | perl >actual &&
+ cmp one actual &&
+ git cat-file tree refs/mytrees/first > expected &&
+ ${git_for_each_ref} --format="\$name= %(raw);
+print \"\$name\"" refs/mytrees/first --perl | perl >actual &&
+ cmp expected actual
+'
+
+test_expect_success '%(raw) with --shell must fail' '
+ test_must_fail ${git_for_each_ref} --format="%(raw)" --shell
+'
+
+test_expect_success '%(raw) with --shell and --sort=raw must fail' '
+ test_must_fail ${git_for_each_ref} --format="%(raw)" --sort=raw --shell
+'
+
+test_expect_success '%(raw:size) with --shell' '
+ ${git_for_each_ref} --format="%(raw:size)" | sed "s/^/$SQ/;s/$/$SQ/" >expect &&
+ ${git_for_each_ref} --format="%(raw:size)" --shell >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success "${git_for_each_ref} --format compare with cat-file --batch" '
+ git rev-parse refs/mytrees/first | git cat-file --batch >expected &&
+ ${git_for_each_ref} --format="%(objectname) %(objecttype) %(objectsize)
+%(raw)" refs/mytrees/first >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'verify sorts with contents:size' '
+ cat >expect <<-\EOF &&
+ refs/heads/main
+ refs/heads/newtag
+ refs/heads/ambiguous
+ EOF
+ ${git_for_each_ref} --format="%(refname)" \
+ --sort=contents:size refs/heads/ >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'set up multiple-sort tags' '
+ for when in 100000 200000
+ do
+ for email in user1 user2
+ do
+ for ref in ref1 ref2
+ do
+ GIT_COMMITTER_DATE="@$when +0000" \
+ GIT_COMMITTER_EMAIL="$email@example.com" \
+ git tag -m "tag $ref-$when-$email" \
+ multi-$ref-$when-$email || return 1
+ done
+ done
+ done
+'
+
+test_expect_success 'Verify sort with multiple keys' '
+ cat >expected <<-\EOF &&
+ 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
+ 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
+ 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
+ 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
+ 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
+ EOF
+ ${git_for_each_ref} \
+ --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
+ --sort=-refname \
+ --sort=taggeremail \
+ --sort=taggerdate \
+ "refs/tags/multi-*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'equivalent sorts fall back on refname' '
+ cat >expected <<-\EOF &&
+ 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
+ 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
+ EOF
+ ${git_for_each_ref} \
+ --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
+ --sort=taggerdate \
+ "refs/tags/multi-*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '--no-sort cancels the previous sort keys' '
+ cat >expected <<-\EOF &&
+ 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
+ 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
+ EOF
+ ${git_for_each_ref} \
+ --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
+ --sort=-refname \
+ --sort=taggeremail \
+ --no-sort \
+ --sort=taggerdate \
+ "refs/tags/multi-*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '--no-sort without subsequent --sort prints expected refs' '
+ cat >expected <<-\EOF &&
+ refs/tags/multi-ref1-100000-user1
+ refs/tags/multi-ref1-100000-user2
+ refs/tags/multi-ref1-200000-user1
+ refs/tags/multi-ref1-200000-user2
+ refs/tags/multi-ref2-100000-user1
+ refs/tags/multi-ref2-100000-user2
+ refs/tags/multi-ref2-200000-user1
+ refs/tags/multi-ref2-200000-user2
+ EOF
+
+ # Sort the results with `sort` for a consistent comparison against
+ # expected
+ ${git_for_each_ref} \
+ --format="%(refname)" \
+ --no-sort \
+ "refs/tags/multi-*" | sort >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'set up custom date sorting' '
+ # Dates:
+ # - Wed Feb 07 2024 21:34:20 +0000
+ # - Tue Dec 14 1999 00:05:22 +0000
+ # - Fri Jun 04 2021 11:26:51 +0000
+ # - Mon Jan 22 2007 16:44:01 GMT+0000
+ i=1 &&
+ for when in 1707341660 945129922 1622806011 1169484241
+ do
+ GIT_COMMITTER_DATE="@$when +0000" \
+ GIT_COMMITTER_EMAIL="user@example.com" \
+ git tag -m "tag $when" custom-dates-$i &&
+ i=$(($i+1)) || return 1
+ done
+'
+
+test_expect_success 'sort by date defaults to full timestamp' '
+ cat >expected <<-\EOF &&
+ 945129922 refs/tags/custom-dates-2
+ 1169484241 refs/tags/custom-dates-4
+ 1622806011 refs/tags/custom-dates-3
+ 1707341660 refs/tags/custom-dates-1
+ EOF
+
+ ${git_for_each_ref} \
+ --format="%(creatordate:unix) %(refname)" \
+ --sort=creatordate \
+ "refs/tags/custom-dates-*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'sort by custom date format' '
+ cat >expected <<-\EOF &&
+ 00:05:22 refs/tags/custom-dates-2
+ 11:26:51 refs/tags/custom-dates-3
+ 16:44:01 refs/tags/custom-dates-4
+ 21:34:20 refs/tags/custom-dates-1
+ EOF
+
+ ${git_for_each_ref} \
+ --format="%(creatordate:format:%H:%M:%S) %(refname)" \
+ --sort="creatordate:format:%H:%M:%S" \
+ "refs/tags/custom-dates-*" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
+ test_when_finished "git checkout main" &&
+ ${git_for_each_ref} --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
+ sed -e "s/^\* / /" actual >expect &&
+ git checkout --orphan orphaned-branch &&
+ ${git_for_each_ref} --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
+ test_cmp expect actual
+'
+
+cat >trailers <<EOF
+Reviewed-by: A U Thor <author@example.com>
+Signed-off-by: A U Thor <author@example.com>
+[ v2 updated patch description ]
+Acked-by: A U Thor
+ <author@example.com>
+EOF
+
+unfold () {
+ perl -0pe 's/\n\s+/ /g'
+}
+
+test_expect_success 'set up trailers for next test' '
+ echo "Some contents" > two &&
+ git add two &&
+ git commit -F - <<-EOF
+ trailers: this commit message has trailers
+
+ Some message contents
+
+ $(cat trailers)
+ EOF
+'
+
+test_trailer_option () {
+ if test "$#" -eq 3
+ then
+ prereq="$1"
+ shift
+ fi &&
+ title=$1 option=$2
+ cat >expect
+ test_expect_success $prereq "$title" '
+ ${git_for_each_ref} --format="%($option)" refs/heads/main >actual &&
+ test_cmp expect actual &&
+ ${git_for_each_ref} --format="%(contents:$option)" refs/heads/main >actual &&
+ test_cmp expect actual
+ '
+}
+
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
+ 'trailers:unfold' <<-EOF
+ $(unfold <trailers)
+
+ EOF
+
+test_trailer_option '%(trailers:only) shows only "key: value" trailers' \
+ 'trailers:only' <<-EOF
+ $(grep -v patch.description <trailers)
+
+ EOF
+
+test_trailer_option '%(trailers:only=no,only=true) shows only "key: value" trailers' \
+ 'trailers:only=no,only=true' <<-EOF
+ $(grep -v patch.description <trailers)
+
+ EOF
+
+test_trailer_option '%(trailers:only=yes) shows only "key: value" trailers' \
+ 'trailers:only=yes' <<-EOF
+ $(grep -v patch.description <trailers)
+
+ EOF
+
+test_trailer_option '%(trailers:only=no) shows all trailers' \
+ 'trailers:only=no' <<-EOF
+ $(cat trailers)
+
+ EOF
+
+test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
+ 'trailers:only,unfold' <<-EOF
+ $(grep -v patch.description <trailers | unfold)
+
+ EOF
+
+test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
+ 'trailers:unfold,only' <<-EOF
+ $(grep -v patch.description <trailers | unfold)
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo) shows that trailer' \
+ 'trailers:key=Signed-off-by' <<-EOF
+ Signed-off-by: A U Thor <author@example.com>
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo) is case insensitive' \
+ 'trailers:key=SiGned-oFf-bY' <<-EOF
+ Signed-off-by: A U Thor <author@example.com>
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo:) trailing colon also works' \
+ 'trailers:key=Signed-off-by:' <<-EOF
+ Signed-off-by: A U Thor <author@example.com>
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo) multiple keys' \
+ 'trailers:key=Reviewed-by:,key=Signed-off-by' <<-EOF
+ Reviewed-by: A U Thor <author@example.com>
+ Signed-off-by: A U Thor <author@example.com>
+
+ EOF
+
+test_trailer_option '%(trailers:key=nonexistent) becomes empty' \
+ 'trailers:key=Shined-off-by:' <<-EOF
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo) handles multiple lines even if folded' \
+ 'trailers:key=Acked-by' <<-EOF
+ $(grep -v patch.description <trailers | grep -v Signed-off-by | grep -v Reviewed-by)
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo,unfold) properly unfolds' \
+ 'trailers:key=Signed-Off-by,unfold' <<-EOF
+ $(unfold <trailers | grep Signed-off-by)
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo,only=no) also includes nontrailer lines' \
+ 'trailers:key=Signed-off-by,only=no' <<-EOF
+ Signed-off-by: A U Thor <author@example.com>
+ $(grep patch.description <trailers)
+
+ EOF
+
+test_trailer_option '%(trailers:key=foo,valueonly) shows only value' \
+ 'trailers:key=Signed-off-by,valueonly' <<-EOF
+ A U Thor <author@example.com>
+
+ EOF
+
+test_trailer_option '%(trailers:separator) changes separator' \
+ 'trailers:separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
+ Reviewed-by: A U Thor <author@example.com>,Signed-off-by: A U Thor <author@example.com>
+ EOF
+
+test_trailer_option '%(trailers:key_value_separator) changes key-value separator' \
+ 'trailers:key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
+ Reviewed-by,A U Thor <author@example.com>
+ Signed-off-by,A U Thor <author@example.com>
+
+ EOF
+
+test_trailer_option '%(trailers:separator,key_value_separator) changes both separators' \
+ 'trailers:separator=%x2C,key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
+ Reviewed-by,A U Thor <author@example.com>,Signed-off-by,A U Thor <author@example.com>
+ EOF
+
+test_expect_success 'multiple %(trailers) use their own options' '
+ git tag -F - tag-with-trailers <<-\EOF &&
+ body
+
+ one: foo
+ one: bar
+ two: baz
+ two: qux
+ EOF
+ t1="%(trailers:key=one,key_value_separator=W,separator=X)" &&
+ t2="%(trailers:key=two,key_value_separator=Y,separator=Z)" &&
+ ${git_for_each_ref} --format="$t1%0a$t2" refs/tags/tag-with-trailers >actual &&
+ cat >expect <<-\EOF &&
+ oneWfooXoneWbar
+ twoYbazZtwoYqux
+ EOF
+ test_cmp expect actual
+'
+
+test_failing_trailer_option () {
+ title=$1 option=$2
+ cat >expect
+ test_expect_success "$title" '
+ # error message cannot be checked under i18n
+ test_must_fail ${git_for_each_ref} --format="%($option)" refs/heads/main 2>actual &&
+ test_cmp expect actual &&
+ test_must_fail ${git_for_each_ref} --format="%(contents:$option)" refs/heads/main 2>actual &&
+ test_cmp expect actual
+ '
+}
+
+test_failing_trailer_option '%(trailers) rejects unknown trailers arguments' \
+ 'trailers:unsupported' <<-\EOF
+ fatal: unknown %(trailers) argument: unsupported
+ EOF
+
+test_failing_trailer_option '%(trailers:key) without value is error' \
+ 'trailers:key' <<-\EOF
+ fatal: expected %(trailers:key=<value>)
+ EOF
+
+test_expect_success 'if arguments, %(contents:trailers) shows error if colon is missing' '
+ cat >expect <<-EOF &&
+ fatal: unrecognized %(contents) argument: trailersonly
+ EOF
+ test_must_fail ${git_for_each_ref} --format="%(contents:trailersonly)" 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'basic atom: head contents:trailers' '
+ ${git_for_each_ref} --format="%(contents:trailers)" refs/heads/main >actual &&
+ sanitize_pgp <actual >actual.clean &&
+ # ${git_for_each_ref} ends with a blank line
+ cat >expect <<-EOF &&
+ $(cat trailers)
+
+ EOF
+ test_cmp expect actual.clean
+'
+
+test_expect_success 'basic atom: rest must fail' '
+ test_must_fail ${git_for_each_ref} --format="%(rest)" refs/heads/main
+'
+
+test_expect_success 'HEAD atom does not take arguments' '
+ test_must_fail ${git_for_each_ref} --format="%(HEAD:foo)" 2>err &&
+ echo "fatal: %(HEAD) does not take arguments" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'subject atom rejects unknown arguments' '
+ test_must_fail ${git_for_each_ref} --format="%(subject:foo)" 2>err &&
+ echo "fatal: unrecognized %(subject) argument: foo" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'refname atom rejects unknown arguments' '
+ test_must_fail ${git_for_each_ref} --format="%(refname:foo)" 2>err &&
+ echo "fatal: unrecognized %(refname) argument: foo" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'trailer parsing not fooled by --- line' '
+ git commit --allow-empty -F - <<-\EOF &&
+ this is the subject
+
+ This is the body. The message has a "---" line which would confuse a
+ message+patch parser. But here we know we have only a commit message,
+ so we get it right.
+
+ trailer: wrong
+ ---
+ This is more body.
+
+ trailer: right
+ EOF
+
+ {
+ echo "trailer: right" &&
+ echo
+ } >expect &&
+ ${git_for_each_ref} --format="%(trailers)" refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'Add symbolic ref for the following tests' '
+ git symbolic-ref refs/heads/sym refs/heads/main
+'
+
+cat >expected <<EOF
+refs/heads/main
+EOF
+
+test_expect_success 'Verify usage of %(symref) atom' '
+ ${git_for_each_ref} --format="%(symref)" refs/heads/sym >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+heads/main
+EOF
+
+test_expect_success 'Verify usage of %(symref:short) atom' '
+ ${git_for_each_ref} --format="%(symref:short)" refs/heads/sym >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+main
+heads/main
+EOF
+
+test_expect_success 'Verify usage of %(symref:lstrip) atom' '
+ ${git_for_each_ref} --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
+ ${git_for_each_ref} --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual &&
+
+ ${git_for_each_ref} --format="%(symref:strip=2)" refs/heads/sym > actual &&
+ ${git_for_each_ref} --format="%(symref:strip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+refs
+refs/heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:rstrip) atom' '
+ ${git_for_each_ref} --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
+ ${git_for_each_ref} --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual
+'
+
+test_expect_success ':remotename and :remoteref' '
+ git init remote-tests &&
+ (
+ cd remote-tests &&
+ test_commit initial &&
+ git branch -M main &&
+ git remote add from fifth.coffee:blub &&
+ git config branch.main.remote from &&
+ git config branch.main.merge refs/heads/stable &&
+ git remote add to southridge.audio:repo &&
+ git config remote.to.push "refs/heads/*:refs/heads/pushed/*" &&
+ git config branch.main.pushRemote to &&
+ for pair in "%(upstream)=refs/remotes/from/stable" \
+ "%(upstream:remotename)=from" \
+ "%(upstream:remoteref)=refs/heads/stable" \
+ "%(push)=refs/remotes/to/pushed/main" \
+ "%(push:remotename)=to" \
+ "%(push:remoteref)=refs/heads/pushed/main"
+ do
+ echo "${pair#*=}" >expect &&
+ ${git_for_each_ref} --format="${pair%=*}" \
+ refs/heads/main >actual &&
+ test_cmp expect actual || exit 1
+ done &&
+ git branch push-simple &&
+ git config branch.push-simple.pushRemote from &&
+ actual="$(${git_for_each_ref} \
+ --format="%(push:remotename),%(push:remoteref)" \
+ refs/heads/push-simple)" &&
+ test from, = "$actual"
+ )
+'
+
+test_expect_success "${git_for_each_ref} --ignore-case ignores case" '
+ ${git_for_each_ref} --format="%(refname)" refs/heads/MAIN >actual &&
+ test_must_be_empty actual &&
+
+ echo refs/heads/main >expect &&
+ ${git_for_each_ref} --format="%(refname)" --ignore-case \
+ refs/heads/MAIN >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success "${git_for_each_ref} --omit-empty works" '
+ ${git_for_each_ref} --format="%(refname)" >actual &&
+ test_line_count -gt 1 actual &&
+ ${git_for_each_ref} --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual &&
+ echo refs/heads/main >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success "${git_for_each_ref} --ignore-case works on multiple sort keys" '
+ # name refs numerically to avoid case-insensitive filesystem conflicts
+ nr=0 &&
+ for email in a A b B
+ do
+ for subject in a A b B
+ do
+ GIT_COMMITTER_EMAIL="$email@example.com" \
+ git tag -m "tag $subject" icase-$(printf %02d $nr) &&
+ nr=$((nr+1))||
+ return 1
+ done
+ done &&
+ ${git_for_each_ref} --ignore-case \
+ --format="%(taggeremail) %(subject) %(refname)" \
+ --sort=refname \
+ --sort=subject \
+ --sort=taggeremail \
+ refs/tags/icase-* >actual &&
+ cat >expect <<-\EOF &&
+ <a@example.com> tag a refs/tags/icase-00
+ <a@example.com> tag A refs/tags/icase-01
+ <A@example.com> tag a refs/tags/icase-04
+ <A@example.com> tag A refs/tags/icase-05
+ <a@example.com> tag b refs/tags/icase-02
+ <a@example.com> tag B refs/tags/icase-03
+ <A@example.com> tag b refs/tags/icase-06
+ <A@example.com> tag B refs/tags/icase-07
+ <b@example.com> tag a refs/tags/icase-08
+ <b@example.com> tag A refs/tags/icase-09
+ <B@example.com> tag a refs/tags/icase-12
+ <B@example.com> tag A refs/tags/icase-13
+ <b@example.com> tag b refs/tags/icase-10
+ <b@example.com> tag B refs/tags/icase-11
+ <B@example.com> tag b refs/tags/icase-14
+ <B@example.com> tag B refs/tags/icase-15
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "${git_for_each_ref} reports broken tags" '
+ git tag -m "good tag" broken-tag-good HEAD &&
+ git cat-file tag broken-tag-good >good &&
+ sed s/commit/blob/ <good >bad &&
+ bad=$(git hash-object -w -t tag bad) &&
+ git update-ref refs/tags/broken-tag-bad $bad &&
+ test_must_fail ${git_for_each_ref} --format="%(*objectname)" \
+ refs/tags/broken-tag-*
+'
+
+test_expect_success 'set up tag with signature and no blank lines' '
+ git tag -F - fake-sig-no-blanks <<-\EOF
+ this is the subject
+ -----BEGIN PGP SIGNATURE-----
+ not a real signature, but we just care about the
+ subject/body parsing. It is important here that
+ there are no blank lines in the signature.
+ -----END PGP SIGNATURE-----
+ EOF
+'
+
+test_atom refs/tags/fake-sig-no-blanks contents:subject 'this is the subject'
+test_atom refs/tags/fake-sig-no-blanks contents:body ''
+test_atom refs/tags/fake-sig-no-blanks contents:signature "$sig"
+
+test_expect_success 'set up tag with CRLF signature' '
+ append_cr <<-\EOF |
+ this is the subject
+ -----BEGIN PGP SIGNATURE-----
+
+ not a real signature, but we just care about
+ the subject/body parsing. It is important here
+ that there is a blank line separating this
+ from the signature header.
+ -----END PGP SIGNATURE-----
+ EOF
+ git tag -F - --cleanup=verbatim fake-sig-crlf
+'
+
+test_atom refs/tags/fake-sig-crlf contents:subject 'this is the subject'
+test_atom refs/tags/fake-sig-crlf contents:body ''
+
+# CRLF is retained in the signature, so we have to pass our expected value
+# through append_cr. But test_atom requires a shell string, which means command
+# substitution, and the shell will strip trailing newlines from the output of
+# the substitution. Hack around it by adding and then removing a dummy line.
+sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)"
+sig_crlf=${sig_crlf%dummy}
+test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
+
+test_expect_success 'set up tag with signature and trailers' '
+ git tag -F - fake-sig-trailer <<-\EOF
+ this is the subject
+
+ this is the body
+
+ My-Trailer: foo
+ -----BEGIN PGP SIGNATURE-----
+
+ not a real signature, but we just care about the
+ subject/body/trailer parsing.
+ -----END PGP SIGNATURE-----
+ EOF
+'
+
+# use "separator=" here to suppress the terminating newline
+test_atom refs/tags/fake-sig-trailer trailers:separator= 'My-Trailer: foo'
+
+test_expect_success "${git_for_each_ref} --stdin: empty" '
+ >in &&
+ ${git_for_each_ref} --format="%(refname)" --stdin <in >actual &&
+ ${git_for_each_ref} --format="%(refname)" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success "${git_for_each_ref} --stdin: fails if extra args" '
+ >in &&
+ test_must_fail ${git_for_each_ref} --format="%(refname)" \
+ --stdin refs/heads/extra <in 2>err &&
+ grep "unknown arguments supplied with --stdin" err
+'
+
+test_expect_success "${git_for_each_ref} --stdin: matches" '
+ cat >in <<-EOF &&
+ refs/tags/multi*
+ refs/heads/amb*
+ EOF
+
+ cat >expect <<-EOF &&
+ refs/heads/ambiguous
+ refs/tags/multi-ref1-100000-user1
+ refs/tags/multi-ref1-100000-user2
+ refs/tags/multi-ref1-200000-user1
+ refs/tags/multi-ref1-200000-user2
+ refs/tags/multi-ref2-100000-user1
+ refs/tags/multi-ref2-100000-user2
+ refs/tags/multi-ref2-200000-user1
+ refs/tags/multi-ref2-200000-user2
+ refs/tags/multiline
+ EOF
+
+ ${git_for_each_ref} --format="%(refname)" --stdin <in >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success "${git_for_each_ref} with non-existing refs" '
+ cat >in <<-EOF &&
+ refs/heads/this-ref-does-not-exist
+ refs/tags/bogus
+ EOF
+
+ ${git_for_each_ref} --format="%(refname)" --stdin <in >actual &&
+ test_must_be_empty actual &&
+
+ xargs ${git_for_each_ref} --format="%(refname)" <in >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success "${git_for_each_ref} with nested tags" '
+ git tag -am "Normal tag" nested/base HEAD &&
+ git tag -am "Nested tag" nested/nest1 refs/tags/nested/base &&
+ git tag -am "Double nested tag" nested/nest2 refs/tags/nested/nest1 &&
+
+ head_oid="$(git rev-parse HEAD)" &&
+ base_tag_oid="$(git rev-parse refs/tags/nested/base)" &&
+ nest1_tag_oid="$(git rev-parse refs/tags/nested/nest1)" &&
+ nest2_tag_oid="$(git rev-parse refs/tags/nested/nest2)" &&
+
+ cat >expect <<-EOF &&
+ refs/tags/nested/base $base_tag_oid tag $head_oid commit
+ refs/tags/nested/nest1 $nest1_tag_oid tag $head_oid commit
+ refs/tags/nested/nest2 $nest2_tag_oid tag $head_oid commit
+ EOF
+
+ ${git_for_each_ref} \
+ --format="%(refname) %(objectname) %(objecttype) %(*objectname) %(*objecttype)" \
+ refs/tags/nested/ >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'is-base atom with non-commits' '
+ ${git_for_each_ref} --format="%(is-base:HEAD) %(refname)" >out 2>err &&
+ grep "(HEAD) refs/heads/main" out &&
+
+ test_line_count = 2 err &&
+ grep "error: object .* is a commit, not a blob" err &&
+ grep "error: bad tag pointer to" err
+'
+
+GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
+TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
+
+test_expect_success GPG 'setup for signature atom using gpg' '
+ git checkout -b signed &&
+
+ test_when_finished "test_unconfig commit.gpgSign" &&
+
+ echo "1" >file &&
+ git add file &&
+ test_tick &&
+ git commit -S -m "file: 1" &&
+ git tag first-signed &&
+
+ echo "2" >file &&
+ test_tick &&
+ git commit -a -m "file: 2" &&
+ git tag second-unsigned &&
+
+ git config commit.gpgSign 1 &&
+ echo "3" >file &&
+ test_tick &&
+ git commit -a --no-gpg-sign -m "file: 3" &&
+ git tag third-unsigned &&
+
+ test_tick &&
+ git rebase -f HEAD^^ && git tag second-signed HEAD^ &&
+ git tag third-signed &&
+
+ echo "4" >file &&
+ test_tick &&
+ git commit -a -SB7227189 -m "file: 4" &&
+ git tag fourth-signed &&
+
+ echo "5" >file &&
+ test_tick &&
+ git commit -a --no-gpg-sign -m "file: 5" &&
+ git tag fifth-unsigned &&
+
+ echo "6" >file &&
+ test_tick &&
+ git commit -a --no-gpg-sign -m "file: 6" &&
+
+ test_tick &&
+ git rebase -f HEAD^^ &&
+ git tag fifth-signed HEAD^ &&
+ git tag sixth-signed &&
+
+ echo "7" >file &&
+ test_tick &&
+ git commit -a --no-gpg-sign -m "file: 7" &&
+ git tag seventh-unsigned
+'
+
+test_expect_success GPGSSH 'setup for signature atom using ssh' '
+ test_when_finished "test_unconfig gpg.format user.signingkey" &&
+
+ test_config gpg.format ssh &&
+ test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
+ echo "8" >file &&
+ test_tick &&
+ git add file &&
+ git commit -S -m "file: 8" &&
+ git tag eighth-signed-ssh
+'
+
+test_expect_success GPG2 'bare signature atom' '
+ git verify-commit first-signed 2>expect &&
+ echo >>expect &&
+ ${git_for_each_ref} refs/tags/first-signed \
+ --format="%(signature)" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'show good signature with custom format' '
+ git verify-commit first-signed &&
+ cat >expect <<-\EOF &&
+ G
+ 13B6F51ECDDE430D
+ C O Mitter <committer@example.com>
+ 73D758744BE721698EC54E8713B6F51ECDDE430D
+ 73D758744BE721698EC54E8713B6F51ECDDE430D
+ EOF
+ ${git_for_each_ref} refs/tags/first-signed \
+ --format="$GRADE_FORMAT" >actual &&
+ test_cmp expect actual
+'
+test_expect_success GPGSSH 'show good signature with custom format with ssh' '
+ test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+ FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
+ cat >expect.tmpl <<-\EOF &&
+ G
+ FINGERPRINT
+ principal with number 1
+ FINGERPRINT
+
+ EOF
+ sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect &&
+ ${git_for_each_ref} refs/tags/eighth-signed-ssh \
+ --format="$GRADE_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'signature atom with grade option and bad signature' '
+ git cat-file commit third-signed >raw &&
+ sed -e "s/^file: 3/file: 3 forged/" raw >forged1 &&
+ FORGED1=$(git hash-object -w -t commit forged1) &&
+ git update-ref refs/tags/third-signed "$FORGED1" &&
+ test_must_fail git verify-commit "$FORGED1" &&
+
+ cat >expect <<-\EOF &&
+ B
+ 13B6F51ECDDE430D
+ C O Mitter <committer@example.com>
+
+
+ EOF
+ ${git_for_each_ref} refs/tags/third-signed \
+ --format="$GRADE_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'show untrusted signature with custom format' '
+ cat >expect <<-\EOF &&
+ U
+ 65A0EEA02E30CAD7
+ Eris Discordia <discord@example.net>
+ F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
+ D4BE22311AD3131E5EDA29A461092E85B7227189
+ EOF
+ ${git_for_each_ref} refs/tags/fourth-signed \
+ --format="$GRADE_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'show untrusted signature with undefined trust level' '
+ cat >expect <<-\EOF &&
+ undefined
+ 65A0EEA02E30CAD7
+ Eris Discordia <discord@example.net>
+ F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
+ D4BE22311AD3131E5EDA29A461092E85B7227189
+ EOF
+ ${git_for_each_ref} refs/tags/fourth-signed \
+ --format="$TRUSTLEVEL_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'show untrusted signature with ultimate trust level' '
+ cat >expect <<-\EOF &&
+ ultimate
+ 13B6F51ECDDE430D
+ C O Mitter <committer@example.com>
+ 73D758744BE721698EC54E8713B6F51ECDDE430D
+ 73D758744BE721698EC54E8713B6F51ECDDE430D
+ EOF
+ ${git_for_each_ref} refs/tags/sixth-signed \
+ --format="$TRUSTLEVEL_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'show unknown signature with custom format' '
+ cat >expect <<-\EOF &&
+ E
+ 13B6F51ECDDE430D
+
+
+
+ EOF
+ GNUPGHOME="$GNUPGHOME_NOT_USED" ${git_for_each_ref} \
+ refs/tags/sixth-signed --format="$GRADE_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success GPG 'show lack of signature with custom format' '
+ cat >expect <<-\EOF &&
+ N
+
+
+
+
+ EOF
+ ${git_for_each_ref} refs/tags/seventh-unsigned \
+ --format="$GRADE_FORMAT" >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
index 6967c8e25c..81ed93a05c 100644
--- a/t/helper/test-advise.c
+++ b/t/helper/test-advise.c
@@ -3,6 +3,7 @@
#include "test-tool.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "setup.h"
int cmd__advise_if_enabled(int argc, const char **argv)
@@ -11,7 +12,7 @@ int cmd__advise_if_enabled(int argc, const char **argv)
die("usage: %s <advice>", argv[0]);
setup_git_directory();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
/*
* Any advice type can be used for testing, but NESTED_TAG was
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 75e028ab2a..9f8cca7c48 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -32,10 +32,10 @@
* ascending order of priority from a config_set
* constructed from files entered as arguments.
*
- * iterate -> iterate over all values using git_config(), and print some
+ * iterate -> iterate over all values using repo_config(), and print some
* data for each
*
- * git_config_int -> iterate over all values using git_config() and print the
+ * git_config_int -> iterate over all values using repo_config() and print the
* integer value for the entered key or die
*
* Examples:
@@ -110,7 +110,7 @@ int cmd__config(int argc, const char **argv)
fprintf(stderr, "Please, provide a command name on the command-line\n");
goto exit1;
} else if (argc == 3 && !strcmp(argv[1], "get_value")) {
- if (!git_config_get_value(argv[2], &v)) {
+ if (!repo_config_get_value(the_repository, argv[2], &v)) {
if (!v)
printf("(NULL)\n");
else
@@ -121,7 +121,7 @@ int cmd__config(int argc, const char **argv)
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) {
- if (!git_config_get_value_multi(argv[2], &strptr)) {
+ if (!repo_config_get_value_multi(the_repository, argv[2], &strptr)) {
for (i = 0; i < strptr->nr; i++) {
v = strptr->items[i].string;
if (!v)
@@ -137,7 +137,7 @@ int cmd__config(int argc, const char **argv)
} else if (argc == 3 && !strcmp(argv[1], "get")) {
int ret;
- if (!(ret = git_config_get(argv[2])))
+ if (!(ret = repo_config_get(the_repository, argv[2])))
goto exit0;
else if (ret == 1)
printf("Value not found for \"%s\"\n", argv[2]);
@@ -155,7 +155,7 @@ int cmd__config(int argc, const char **argv)
BUG("Key \"%s\" has unknown return %d", argv[2], ret);
goto exit1;
} else if (argc == 3 && !strcmp(argv[1], "get_int")) {
- if (!git_config_get_int(argv[2], &val)) {
+ if (!repo_config_get_int(the_repository, argv[2], &val)) {
printf("%d\n", val);
goto exit0;
} else {
@@ -163,7 +163,7 @@ int cmd__config(int argc, const char **argv)
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_bool")) {
- if (!git_config_get_bool(argv[2], &val)) {
+ if (!repo_config_get_bool(the_repository, argv[2], &val)) {
printf("%d\n", val);
goto exit0;
} else {
@@ -171,7 +171,7 @@ int cmd__config(int argc, const char **argv)
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_string")) {
- if (!git_config_get_string_tmp(argv[2], &v)) {
+ if (!repo_config_get_string_tmp(the_repository, argv[2], &v)) {
printf("%s\n", v);
goto exit0;
} else {
@@ -218,10 +218,10 @@ int cmd__config(int argc, const char **argv)
goto exit1;
}
} else if (!strcmp(argv[1], "iterate")) {
- git_config(iterate_cb, NULL);
+ repo_config(the_repository, iterate_cb, NULL);
goto exit0;
} else if (argc == 3 && !strcmp(argv[1], "git_config_int")) {
- git_config(parse_int_cb, (void *) argv[2]);
+ repo_config(the_repository, parse_int_cb, (void *) argv[2]);
goto exit0;
}
diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c
index 6bc787a474..52ea00c937 100644
--- a/t/helper/test-delta.c
+++ b/t/helper/test-delta.c
@@ -11,6 +11,7 @@
#include "test-tool.h"
#include "git-compat-util.h"
#include "delta.h"
+#include "strbuf.h"
static const char usage_str[] =
"test-tool delta (-d|-p) <from_file> <data_file> <out_file>";
@@ -18,68 +19,38 @@ static const char usage_str[] =
int cmd__delta(int argc, const char **argv)
{
int fd;
- struct stat st;
- void *from_buf = NULL, *data_buf = NULL, *out_buf = NULL;
- unsigned long from_size, data_size, out_size;
- int ret = 1;
+ struct strbuf from = STRBUF_INIT, data = STRBUF_INIT;
+ char *out_buf;
+ unsigned long out_size;
- if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) {
- fprintf(stderr, "usage: %s\n", usage_str);
- return 1;
- }
+ if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p")))
+ usage(usage_str);
- fd = open(argv[2], O_RDONLY);
- if (fd < 0 || fstat(fd, &st)) {
- perror(argv[2]);
- return 1;
- }
- from_size = st.st_size;
- from_buf = xmalloc(from_size);
- if (read_in_full(fd, from_buf, from_size) < 0) {
- perror(argv[2]);
- close(fd);
- goto cleanup;
- }
- close(fd);
-
- fd = open(argv[3], O_RDONLY);
- if (fd < 0 || fstat(fd, &st)) {
- perror(argv[3]);
- goto cleanup;
- }
- data_size = st.st_size;
- data_buf = xmalloc(data_size);
- if (read_in_full(fd, data_buf, data_size) < 0) {
- perror(argv[3]);
- close(fd);
- goto cleanup;
- }
- close(fd);
+ if (strbuf_read_file(&from, argv[2], 0) < 0)
+ die_errno("unable to read '%s'", argv[2]);
+ if (strbuf_read_file(&data, argv[3], 0) < 0)
+ die_errno("unable to read '%s'", argv[3]);
if (argv[1][1] == 'd')
- out_buf = diff_delta(from_buf, from_size,
- data_buf, data_size,
+ out_buf = diff_delta(from.buf, from.len,
+ data.buf, data.len,
&out_size, 0);
else
- out_buf = patch_delta(from_buf, from_size,
- data_buf, data_size,
+ out_buf = patch_delta(from.buf, from.len,
+ data.buf, data.len,
&out_size);
- if (!out_buf) {
- fprintf(stderr, "delta operation failed (returned NULL)\n");
- goto cleanup;
- }
+ if (!out_buf)
+ die("delta operation failed (returned NULL)");
- fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) {
- perror(argv[4]);
- goto cleanup;
- }
+ fd = xopen(argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (write_in_full(fd, out_buf, out_size) < 0)
+ die_errno("write(%s)", argv[4]);
+ if (close(fd) < 0)
+ die_errno("close(%s)", argv[4]);
- ret = 0;
-cleanup:
- free(from_buf);
- free(data_buf);
+ strbuf_release(&from);
+ strbuf_release(&data);
free(out_buf);
- return ret;
+ return 0;
}
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 7782ae585e..56d223a283 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -137,6 +137,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
* Read stdin line by line and print result of commands to stdout:
*
* perfhashmap method rounds -> test hashmap.[ch] performance
+ *
+ * NOTE: this is not used by any of our mechanized build & test
+ * procedure, after 3469a236 (t: port helper/test-hashmap.c to
+ * unit-tests/t-hashmap.c, 2024-08-03). See the log message of that
+ * commit for the reason why this is still here.
*/
int cmd__hashmap(int argc UNUSED, const char **argv UNUSED)
{
@@ -149,8 +154,8 @@ int cmd__hashmap(int argc UNUSED, const char **argv UNUSED)
/* break line into command and up to two parameters */
string_list_setlen(&parts, 0);
- string_list_split_in_place(&parts, line.buf, DELIM, 2);
- string_list_remove_empty_items(&parts, 0);
+ string_list_split_in_place_f(&parts, line.buf, DELIM, 2,
+ STRING_LIST_SPLIT_NONEMPTY);
/* ignore empty lines */
if (!parts.nr)
diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c
index a288069b04..f8316a7d29 100644
--- a/t/helper/test-json-writer.c
+++ b/t/helper/test-json-writer.c
@@ -492,8 +492,8 @@ static int scripted(void)
/* break line into command and zero or more tokens */
string_list_setlen(&parts, 0);
- string_list_split_in_place(&parts, line, " ", -1);
- string_list_remove_empty_items(&parts, 0);
+ string_list_split_in_place_f(&parts, line, " ", -1,
+ STRING_LIST_SPLIT_NONEMPTY);
/* ignore empty lines */
if (!parts.nr || !*parts.items[0].string)
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 086238c826..f5f33751da 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -348,6 +348,7 @@ int cmd__path_utils(int argc, const char **argv)
if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
int len;
struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
+ const char path_sep[] = { PATH_SEP, '\0' };
char *path = xstrdup(argv[2]);
/*
@@ -362,7 +363,7 @@ int cmd__path_utils(int argc, const char **argv)
*/
if (normalize_path_copy(path, path))
die("Path \"%s\" could not be normalized", argv[2]);
- string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1);
+ string_list_split(&ceiling_dirs, argv[3], path_sep, -1);
filter_string_list(&ceiling_dirs, 0,
normalize_ceiling_entry, NULL);
len = longest_ancestor_length(path, &ceiling_dirs);
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index e277dde8e7..9ae71cefb3 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -2,6 +2,7 @@
#include "test-tool.h"
#include "config.h"
+#include "environment.h"
#include "read-cache-ll.h"
#include "repository.h"
#include "setup.h"
@@ -19,7 +20,7 @@ int cmd__read_cache(int argc, const char **argv)
if (argc == 2)
cnt = strtol(argv[1], NULL, 0);
setup_git_directory();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
for (i = 0; i < cnt; i++) {
repo_read_index(the_repository);
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 8d9a271845..83b06d39a3 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -29,7 +29,7 @@ static unsigned int parse_flags(const char *str, struct flag_definition *defs)
if (!strcmp(str, "0"))
return 0;
- string_list_split(&masks, str, ',', 64);
+ string_list_split(&masks, str, ",", 64);
for (size_t i = 0; i < masks.nr; i++) {
const char *name = masks.items[i].string;
struct flag_definition *def = defs;
@@ -215,7 +215,8 @@ static int cmd_for_each_reflog(struct ref_store *refs,
return refs_for_each_reflog(refs, each_reflog, NULL);
}
-static int each_reflog_ent(struct object_id *old_oid, struct object_id *new_oid,
+static int each_reflog_ent(const char *refname UNUSED,
+ struct object_id *old_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data UNUSED)
{
diff --git a/t/helper/test-truncate.c b/t/helper/test-truncate.c
index 3931deaec7..2820cc7ed7 100644
--- a/t/helper/test-truncate.c
+++ b/t/helper/test-truncate.c
@@ -21,5 +21,8 @@ int cmd__truncate(int argc, const char **argv)
if (ftruncate(fd, (off_t) sz) < 0)
die_errno("failed to truncate file");
+
+ close(fd);
+
return 0;
}
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
index 94c48ababb..aa3a9894d2 100644
--- a/t/helper/test-userdiff.c
+++ b/t/helper/test-userdiff.c
@@ -41,7 +41,7 @@ int cmd__userdiff(int argc, const char **argv)
if (want & USERDIFF_DRIVER_TYPE_CUSTOM) {
setup_git_directory();
- git_config(cmd__userdiff_config, NULL);
+ repo_config(the_repository, cmd__userdiff_config, NULL);
}
for_each_userdiff_driver(driver_cb, &want);
diff --git a/t/meson.build b/t/meson.build
index 09f3068f98..f1c09cba55 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -1,5 +1,6 @@
clar_test_suites = [
'unit-tests/u-ctype.c',
+ 'unit-tests/u-dir.c',
'unit-tests/u-example-decorate.c',
'unit-tests/u-hash.c',
'unit-tests/u-hashmap.c',
@@ -59,6 +60,9 @@ clar_sources += custom_target(
clar_unit_tests = executable('unit-tests',
sources: clar_sources + clar_test_suites,
+ c_args: [
+ '-DGIT_CLAR_DECLS_H="' + clar_decls_h.full_path() + '"',
+ ],
dependencies: [libgit_commonmain],
)
test('unit-tests', clar_unit_tests, kwargs: test_kwargs)
@@ -201,10 +205,12 @@ integration_tests = [
't1418-reflog-exists.sh',
't1419-exclude-refs.sh',
't1420-lost-found.sh',
+ 't1421-reflog-write.sh',
't1430-bad-ref-name.sh',
't1450-fsck.sh',
't1451-fsck-buffer.sh',
't1460-refs-migrate.sh',
+ 't1461-refs-list.sh',
't1500-rev-parse.sh',
't1501-work-tree.sh',
't1502-rev-parse-parseopt.sh',
@@ -483,6 +489,7 @@ integration_tests = [
't4069-remerge-diff.sh',
't4070-diff-pairs.sh',
't4071-diff-minimal.sh',
+ 't4072-diff-max-depth.sh',
't4100-apply-stat.sh',
't4101-apply-nonl.sh',
't4102-apply-rename.sh',
diff --git a/t/t0450/adoc-help-mismatches b/t/t0450/adoc-help-mismatches
index 06b469bdee..2c6ecd5fc8 100644
--- a/t/t0450/adoc-help-mismatches
+++ b/t/t0450/adoc-help-mismatches
@@ -17,7 +17,6 @@ fast-export
fast-import
fetch-pack
fmt-merge-msg
-for-each-ref
format-patch
fsck-objects
fsmonitor--daemon
diff --git a/t/t1421-reflog-write.sh b/t/t1421-reflog-write.sh
new file mode 100755
index 0000000000..46df64c176
--- /dev/null
+++ b/t/t1421-reflog-write.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+test_description='Manually write reflog entries'
+
+. ./test-lib.sh
+
+SIGNATURE="C O Mitter <committer@example.com> 1112911993 -0700"
+
+test_reflog_matches () {
+ repo="$1" &&
+ refname="$2" &&
+ cat >actual &&
+ test-tool -C "$repo" ref-store main for-each-reflog-ent "$refname" >expected &&
+ test_cmp expected actual
+}
+
+test_expect_success 'invalid number of arguments' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ for args in "" "1" "1 2" "1 2 3" "1 2 3 4 5"
+ do
+ test_must_fail git reflog write $args 2>err &&
+ test_grep "usage: git reflog write" err || return 1
+ done
+ )
+'
+
+test_expect_success 'invalid refname' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_must_fail git reflog write "refs/heads/ invalid" $ZERO_OID $ZERO_OID first 2>err &&
+ test_grep "invalid reference name: " err
+ )
+'
+
+test_expect_success 'unqualified refname is rejected' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_must_fail git reflog write unqualified $ZERO_OID $ZERO_OID first 2>err &&
+ test_grep "invalid reference name: " err
+ )
+'
+
+test_expect_success 'nonexistent object IDs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_must_fail git reflog write refs/heads/something $(test_oid deadbeef) $ZERO_OID old-object-id 2>err &&
+ test_grep "old object .* does not exist" err &&
+ test_must_fail git reflog write refs/heads/something $ZERO_OID $(test_oid deadbeef) new-object-id 2>err &&
+ test_grep "new object .* does not exist" err
+ )
+'
+
+test_expect_success 'abbreviated object IDs' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ abbreviated_oid=$(git rev-parse HEAD | test_copy_bytes 8) &&
+ test_must_fail git reflog write refs/heads/something $abbreviated_oid $ZERO_OID old-object-id 2>err &&
+ test_grep "invalid old object ID" err &&
+ test_must_fail git reflog write refs/heads/something $ZERO_OID $abbreviated_oid new-object-id 2>err &&
+ test_grep "invalid new object ID" err
+ )
+'
+
+test_expect_success 'reflog message gets normalized' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ COMMIT_OID=$(git rev-parse HEAD) &&
+ git reflog write HEAD $COMMIT_OID $COMMIT_OID "$(printf "message\nwith\nnewlines")" &&
+ git reflog show -1 --format=%gs HEAD >actual &&
+ echo "message with newlines" >expected &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'simple writes' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ COMMIT_OID=$(git rev-parse HEAD) &&
+
+ git reflog write refs/heads/something $ZERO_OID $COMMIT_OID first &&
+ test_reflog_matches . refs/heads/something <<-EOF &&
+ $ZERO_OID $COMMIT_OID $SIGNATURE first
+ EOF
+
+ git reflog write refs/heads/something $COMMIT_OID $COMMIT_OID second &&
+ test_reflog_matches . refs/heads/something <<-EOF
+ $ZERO_OID $COMMIT_OID $SIGNATURE first
+ $COMMIT_OID $COMMIT_OID $SIGNATURE second
+ EOF
+ )
+'
+
+test_expect_success 'can write to root ref' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit initial &&
+ COMMIT_OID=$(git rev-parse HEAD) &&
+
+ git reflog write ROOT_REF_HEAD $ZERO_OID $COMMIT_OID first &&
+ test_reflog_matches . ROOT_REF_HEAD <<-EOF
+ $ZERO_OID $COMMIT_OID $SIGNATURE first
+ EOF
+ )
+'
+
+test_done
diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh
index 2ab97e1b7d..0e1116a319 100755
--- a/t/t1460-refs-migrate.sh
+++ b/t/t1460-refs-migrate.sh
@@ -7,6 +7,17 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+print_all_reflog_entries () {
+ repo=$1 &&
+ test-tool -C "$repo" ref-store main for-each-reflog >reflogs &&
+ while read reflog
+ do
+ echo "REFLOG: $reflog" &&
+ test-tool -C "$repo" ref-store main for-each-reflog-ent "$reflog" ||
+ return 1
+ done <reflogs
+}
+
# Migrate the provided repository from one format to the other and
# verify that the references and logs are migrated over correctly.
# Usage: test_migration <repo> <format> [<skip_reflog_verify> [<options...>]]
@@ -28,8 +39,7 @@ test_migration () {
--format='%(refname) %(objectname) %(symref)' >expect &&
if ! $skip_reflog_verify
then
- git -C "$repo" reflog --all >expect_logs &&
- git -C "$repo" reflog list >expect_log_list
+ print_all_reflog_entries "$repo" >expect_logs
fi &&
git -C "$repo" refs migrate --ref-format="$format" "$@" &&
@@ -39,10 +49,8 @@ test_migration () {
test_cmp expect actual &&
if ! $skip_reflog_verify
then
- git -C "$repo" reflog --all >actual_logs &&
- git -C "$repo" reflog list >actual_log_list &&
- test_cmp expect_logs actual_logs &&
- test_cmp expect_log_list actual_log_list
+ print_all_reflog_entries "$repo" >actual_logs &&
+ test_cmp expect_logs actual_logs
fi &&
git -C "$repo" rev-parse --show-ref-format >actual &&
@@ -273,7 +281,7 @@ test_expect_success 'multiple reftable blocks with multiple entries' '
test_commit -C repo second &&
printf "update refs/heads/ref-%d HEAD\n" $(test_seq 3000) >stdin &&
git -C repo update-ref --stdin <stdin &&
- test_migration repo reftable
+ test_migration repo reftable true
'
test_expect_success 'migrating from files format deletes backend files' '
diff --git a/t/t1461-refs-list.sh b/t/t1461-refs-list.sh
new file mode 100755
index 0000000000..36e3d81e59
--- /dev/null
+++ b/t/t1461-refs-list.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+test_description='git refs list tests'
+
+. ./test-lib.sh
+
+git_for_each_ref='git refs list'
+. "$TEST_DIRECTORY"/for-each-ref-tests.sh
diff --git a/t/t1517-outside-repo.sh b/t/t1517-outside-repo.sh
index e8857ca68c..61fdd0170c 100755
--- a/t/t1517-outside-repo.sh
+++ b/t/t1517-outside-repo.sh
@@ -134,6 +134,17 @@ do
test_expect_code 129 nongit git $cmd -h >usage &&
test_grep "[Uu]sage: git $cmd " usage
'
+ test_$expect_outcome $prereq "'git $cmd --help-all' outside a repository" '
+ test_expect_code 129 nongit git $cmd --help-all >usage &&
+ test_grep "[Uu]sage: git $cmd " usage
+ '
done
+test_expect_success 'fmt-merge-msg does not crash with -h' '
+ test_expect_code 129 git fmt-merge-msg -h >usage &&
+ test_grep "[Uu]sage: git fmt-merge-msg " usage &&
+ test_expect_code 129 nongit git fmt-merge-msg -h >usage &&
+ test_grep "[Uu]sage: git fmt-merge-msg " usage
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 6bac217ed3..34d6ad0770 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -2263,6 +2263,7 @@ test_expect_success 'non-merge commands reject merge commits' '
edit $oid
fixup $oid
squash $oid
+ drop $oid # acceptable, no advice
EOF
(
set_replace_editor todo &&
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index 26b42a526a..5d093e3a7a 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -394,6 +394,16 @@ test_expect_success 'autosquash with empty custom instructionFormat' '
)
'
+test_expect_success 'autosquash with invalid custom instructionFormat' '
+ git reset --hard base &&
+ test_commit invalid-instructionFormat-test &&
+ (
+ test_must_fail git -c rebase.instructionFormat=blah \
+ rebase --autosquash --force-rebase -i HEAD^ &&
+ test_path_is_missing .git/rebase-merge
+ )
+'
+
set_backup_editor () {
write_script backup-editor.sh <<-\EOF
cp "$1" .git/backup-"$(basename "$1")"
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index b8a05d95f3..04d2a19835 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -63,7 +63,7 @@ test_expect_success 'setup (initial)' '
'
test_expect_success 'status works (initial)' '
git add -i </dev/null >output &&
- grep "+1/-0 *+2/-0 file" output
+ test_grep "+1/-0 *+2/-0 file" output
'
test_expect_success 'setup expected' '
@@ -86,7 +86,7 @@ test_expect_success 'revert works (initial)' '
git add file &&
test_write_lines r 1 | git add -i &&
git ls-files >output &&
- ! grep . output
+ test_grep ! . output
'
test_expect_success 'add untracked (multiple)' '
@@ -109,7 +109,7 @@ test_expect_success 'setup (commit)' '
'
test_expect_success 'status works (commit)' '
git add -i </dev/null >output &&
- grep "+1/-0 *+2/-0 file" output
+ test_grep "+1/-0 *+2/-0 file" output
'
test_expect_success 'update can stage deletions' '
@@ -141,7 +141,7 @@ test_expect_success 'revert works (commit)' '
git add file &&
test_write_lines r 1 | git add -i &&
git add -i </dev/null >output &&
- grep "unchanged *+3/-0 file" output
+ test_grep "unchanged *+3/-0 file" output
'
test_expect_success 'reject multi-key input' '
@@ -185,7 +185,7 @@ test_expect_success 'setup fake editor' '
test_expect_success 'bad edit rejected' '
git reset &&
test_write_lines e n d | git add -p >output &&
- grep "hunk does not apply" output
+ test_grep "hunk does not apply" output
'
test_expect_success 'setup patch' '
@@ -198,7 +198,7 @@ test_expect_success 'setup patch' '
test_expect_success 'garbage edit rejected' '
git reset &&
test_write_lines e n d | git add -p >output &&
- grep "hunk does not apply" output
+ test_grep "hunk does not apply" output
'
test_expect_success 'setup patch' '
@@ -313,8 +313,8 @@ test_expect_success FILEMODE 'stage mode and hunk' '
chmod +x file &&
printf "y\\ny\\n" | git add -p &&
git diff --cached file >out &&
- grep "new mode" out &&
- grep "+content" out &&
+ test_grep "new mode" out &&
+ test_grep "+content" out &&
git diff file >out &&
test_must_be_empty out
'
@@ -636,7 +636,7 @@ test_expect_success 'split hunk "add -p (edit)"' '
printf "%s\n" s e q n q q |
EDITOR=: git add -p &&
git diff >actual &&
- ! grep "^+15" actual
+ test_grep ! "^+15" actual
'
test_expect_success 'split hunk "add -p (no, yes, edit)"' '
@@ -648,7 +648,7 @@ test_expect_success 'split hunk "add -p (no, yes, edit)"' '
EDITOR=: git add -p 2>error &&
test_must_be_empty error &&
git diff >actual &&
- ! grep "^+31" actual
+ test_grep ! "^+31" actual
'
test_expect_success 'split hunk with incomplete line at end' '
@@ -682,7 +682,7 @@ test_expect_success 'edit, adding lines to the first hunk' '
EDITOR=./fake_editor.sh git add -p 2>error &&
test_must_be_empty error &&
git diff --cached >actual &&
- grep "^+22" actual
+ test_grep "^+22" actual
'
test_expect_success 'patch mode ignores unmerged entries' '
@@ -696,7 +696,7 @@ test_expect_success 'patch mode ignores unmerged entries' '
test_must_fail git merge side &&
echo changed >non-conflict.t &&
echo y | git add -p >output &&
- ! grep a/conflict.t output &&
+ test_grep ! a/conflict.t output &&
cat >expected <<-\EOF &&
* Unmerged path conflict.t
diff --git a/non-conflict.t b/non-conflict.t
@@ -728,7 +728,7 @@ test_expect_success 'diffs can be colorized' '
# We do not want to depend on the exact coloring scheme
# git uses for diffs, so just check that we saw some kind of color.
- grep "$(printf "\\033")" output
+ test_grep "$(printf "\\033")" output
'
test_expect_success 'colors can be overridden' '
@@ -743,7 +743,7 @@ test_expect_success 'colors can be overridden' '
-c color.interactive.error=blue \
add -i 2>err.raw <input &&
test_decode_color <err.raw >err &&
- grep "<BLUE>Huh (trigger)?<RESET>" err &&
+ test_grep "<BLUE>Huh (trigger)?<RESET>" err &&
test_write_lines help quit >input &&
force_color git \
@@ -863,7 +863,7 @@ test_expect_success 'colorized diffs respect diff.wsErrorHighlight' '
printf y >y &&
force_color git -c diff.wsErrorHighlight=all add -p >output.raw 2>&1 <y &&
test_decode_color <output.raw >output &&
- grep "old<" output
+ test_grep "old<" output
'
test_expect_success 'diffFilter filters diff' '
@@ -876,7 +876,7 @@ test_expect_success 'diffFilter filters diff' '
# avoid depending on the exact coloring or content of the prompts,
# and just make sure we saw our diff prefixed
- grep foo:.*content output
+ test_grep foo:.*content output
'
test_expect_success 'detect bogus diffFilter output' '
@@ -886,7 +886,7 @@ test_expect_success 'detect bogus diffFilter output' '
test_config interactive.diffFilter "sed 6d" &&
printf y >y &&
force_color test_must_fail git add -p <y >output 2>&1 &&
- grep "mismatched output" output
+ test_grep "mismatched output" output
'
test_expect_success 'handle iffy colored hunk headers' '
@@ -896,7 +896,7 @@ test_expect_success 'handle iffy colored hunk headers' '
printf n >n &&
force_color git -c interactive.diffFilter="sed s/.*@@.*/XX/" \
add -p >output 2>&1 <n &&
- grep "^XX$" output
+ test_grep "^XX$" output
'
test_expect_success 'handle very large filtered diff' '
@@ -1002,7 +1002,7 @@ test_expect_success 'add -p does not expand argument lists' '
# update it, but we want to be sure that our "." pathspec
# was not expanded into the argument list of any command.
# So look only for "not-changed".
- ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
+ test_grep ! -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
'
test_expect_success 'hunk-editing handles custom comment char' '
@@ -1072,21 +1072,21 @@ test_expect_success 'setup different kinds of dirty submodules' '
test_expect_success 'status ignores dirty submodules (except HEAD)' '
git -C for-submodules add -i </dev/null >output &&
- grep dirty-head output &&
- grep dirty-both-ways output &&
- ! grep dirty-otherwise output
+ test_grep dirty-head output &&
+ test_grep dirty-both-ways output &&
+ test_grep ! dirty-otherwise output
'
test_expect_success 'handle submodules' '
echo 123 >>for-submodules/dirty-otherwise/initial.t &&
force_color git -C for-submodules add -p dirty-otherwise >output 2>&1 &&
- grep "No changes" output &&
+ test_grep "No changes" output &&
force_color git -C for-submodules add -p dirty-head >output 2>&1 <y &&
git -C for-submodules ls-files --stage dirty-head >actual &&
rev="$(git -C for-submodules/dirty-head rev-parse HEAD)" &&
- grep "$rev" actual
+ test_grep "$rev" actual
'
test_expect_success 'set up pathological context' '
@@ -1230,4 +1230,75 @@ test_expect_success 'hunk splitting works with diff.suppressBlankEmpty' '
test_cmp expect actual
'
+test_expect_success 'add -p respects diff.context' '
+ test_write_lines a b c d e f g h i j k l m >file &&
+ git add file &&
+ test_write_lines a b c d e f G h i j k l m >file &&
+ echo y | git -c diff.context=5 add -p >actual &&
+ test_grep "@@ -2,11 +2,11 @@" actual
+'
+
+test_expect_success 'add -p respects diff.interHunkContext' '
+ test_write_lines a b c d e f g h i j k l m n o p q r s >file &&
+ git add file &&
+ test_write_lines a b c d E f g i i j k l m N o p q r s >file &&
+ echo y | git -c diff.interhunkcontext=2 add -p >actual &&
+ test_grep "@@ -2,16 +2,16 @@" actual
+'
+
+test_expect_success 'add -p rejects negative diff.context' '
+ test_config diff.context -1 &&
+ test_must_fail git add -p 2>output &&
+ test_grep "diff.context cannot be negative" output
+'
+
+for cmd in add checkout restore 'commit -m file'
+do
+ test_expect_success "${cmd%% *} accepts -U and --inter-hunk-context" '
+ test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file &&
+ git add file &&
+ test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file &&
+ echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \
+ $cmd -p -U 4 --inter-hunk-context 2 >actual &&
+ test_grep "@@ -2,20 +2,20 @@" actual
+ '
+done
+
+test_expect_success 'reset accepts -U and --inter-hunk-context' '
+ test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file &&
+ git commit -m file file &&
+ test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file &&
+ git add file &&
+ echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \
+ reset -p -U 4 --inter-hunk-context 2 >actual &&
+ test_grep "@@ -2,20 +2,20 @@" actual
+'
+
+test_expect_success 'stash accepts -U and --inter-hunk-context' '
+ test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file &&
+ git commit -m file file &&
+ test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file &&
+ echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \
+ stash -p -U 4 --inter-hunk-context 2 >actual &&
+ test_grep "@@ -2,20 +2,20 @@" actual
+'
+
+for cmd in add checkout commit reset restore "stash save" "stash push"
+do
+ test_expect_success "$cmd rejects invalid context options" '
+ test_must_fail git $cmd -p -U -3 2>actual &&
+ cat actual | echo &&
+ test_grep -e ".--unified. cannot be negative" actual &&
+
+ test_must_fail git $cmd -p --inter-hunk-context -3 2>actual &&
+ test_grep -e ".--inter-hunk-context. cannot be negative" actual &&
+
+ test_must_fail git $cmd -U 7 2>actual &&
+ test_grep -E ".--unified. requires .(--interactive/)?--patch." actual &&
+
+ test_must_fail git $cmd --inter-hunk-context 2 2>actual &&
+ test_grep -E ".--inter-hunk-context. requires .(--interactive/)?--patch." actual
+ '
+done
+
test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 8ebd170451..cfeec239e0 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -648,6 +648,19 @@ test_expect_success 'diff -I<regex>: detect malformed regex' '
test_grep "invalid regex given to -I: " error
'
+test_expect_success 'diff -I<regex>: ignore matching file' '
+ test_when_finished "git rm -f file1" &&
+ test_seq 50 >file1 &&
+ git add file1 &&
+ test_seq 50 | sed -e "s/13/ten and three/" -e "s/^[124-9].*/& /" >file1 &&
+
+ : >actual &&
+ git diff --raw --ignore-blank-lines -I"ten.*e" -I"^[124-9]" >>actual &&
+ git diff --name-only --ignore-blank-lines -I"ten.*e" -I"^[124-9]" >>actual &&
+ git diff --name-status --ignore-blank-lines -I"ten.*e" -I"^[124-9]" >>actual &&
+ test_grep ! "file1" actual
+'
+
# check_prefix <patch> <src> <dst>
# check only lines with paths to avoid dependency on exact oid/contents
check_prefix () {
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 52e3e476ff..9de7f73f42 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -11,12 +11,8 @@ test_description='Test special whitespace in diff engine.
. "$TEST_DIRECTORY"/lib-diff.sh
for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \
- --raw! --name-only! --name-status!
+ --raw --name-only --name-status
do
- opts=${opt_res%!} expect_failure=
- test "$opts" = "$opt_res" ||
- expect_failure="test_expect_code 1"
-
test_expect_success "status with $opts (different)" '
echo foo >x &&
git add x &&
@@ -43,7 +39,7 @@ do
echo foo >x &&
git add x &&
echo " foo" >x &&
- $expect_failure git diff -w $opts --exit-code x
+ git diff -w $opts --exit-code x
'
done
diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 01db9243ab..44b4b13f5d 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -26,6 +26,23 @@ test_expect_success 'git diff --no-index directories' '
test_line_count = 14 cnt
'
+test_expect_success 'git diff --no-index with -' '
+ cat >expect <<-\EOF &&
+ diff --git a/- b/-
+ new file mode 100644
+ --- /dev/null
+ +++ b/-
+ @@ -0,0 +1 @@
+ +frotz
+ EOF
+ (
+ cd a &&
+ echo frotz |
+ test_expect_code 1 git diff --no-index /dev/null - >../actual
+ ) &&
+ test_cmp expect actual
+'
+
test_expect_success 'git diff --no-index relative path outside repo' '
(
cd repo &&
diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh
index ec2804eea6..1384a81957 100755
--- a/t/t4055-diff-context.sh
+++ b/t/t4055-diff-context.sh
@@ -38,55 +38,55 @@ test_expect_success 'setup' '
test_expect_success 'the default number of context lines is 3' '
git diff >output &&
- ! grep "^ d" output &&
- grep "^ e" output &&
- grep "^ j" output &&
- ! grep "^ k" output
+ test_grep ! "^ d" output &&
+ test_grep "^ e" output &&
+ test_grep "^ j" output &&
+ test_grep ! "^ k" output
'
test_expect_success 'diff.context honored by "log"' '
git log -1 -p >output &&
- ! grep firstline output &&
- git config diff.context 8 &&
+ test_grep ! firstline output &&
+ test_config diff.context 8 &&
git log -1 -p >output &&
- grep "^ firstline" output
+ test_grep "^ firstline" output
'
test_expect_success 'The -U option overrides diff.context' '
- git config diff.context 8 &&
+ test_config diff.context 8 &&
git log -U4 -1 >output &&
- ! grep "^ firstline" output
+ test_grep ! "^ firstline" output
'
test_expect_success 'diff.context honored by "diff"' '
- git config diff.context 8 &&
+ test_config diff.context 8 &&
git diff >output &&
- grep "^ firstline" output
+ test_grep "^ firstline" output
'
test_expect_success 'plumbing not affected' '
- git config diff.context 8 &&
+ test_config diff.context 8 &&
git diff-files -p >output &&
- ! grep "^ firstline" output
+ test_grep ! "^ firstline" output
'
test_expect_success 'non-integer config parsing' '
- git config diff.context no &&
+ test_config diff.context no &&
test_must_fail git diff 2>output &&
test_grep "bad numeric config value" output
'
test_expect_success 'negative integer config parsing' '
- git config diff.context -1 &&
+ test_config diff.context -1 &&
test_must_fail git diff 2>output &&
test_grep "bad config variable" output
'
test_expect_success '-U0 is valid, so is diff.context=0' '
- git config diff.context 0 &&
+ test_config diff.context 0 &&
git diff >output &&
- grep "^-ADDED" output &&
- grep "^+MODIFIED" output
+ test_grep "^-ADDED" output &&
+ test_grep "^+MODIFIED" output
'
test_expect_success '-U2147483647 works' '
@@ -94,9 +94,9 @@ test_expect_success '-U2147483647 works' '
test_line_count = 16 x &&
git diff -U2147483647 >output &&
test_line_count = 22 output &&
- grep "^-ADDED" output &&
- grep "^+MODIFIED" output &&
- grep "^+APPENDED" output
+ test_grep "^-ADDED" output &&
+ test_grep "^+MODIFIED" output &&
+ test_grep "^+APPENDED" output
'
test_done
diff --git a/t/t4072-diff-max-depth.sh b/t/t4072-diff-max-depth.sh
new file mode 100755
index 0000000000..0fbf1321f7
--- /dev/null
+++ b/t/t4072-diff-max-depth.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+test_description='check that diff --max-depth will limit recursion'
+. ./test-lib.sh
+
+make_dir() {
+ mkdir -p "$1" &&
+ echo "$2" >"$1/file"
+}
+
+make_files() {
+ echo "$1" >file &&
+ make_dir one "$1" &&
+ make_dir one/two "$1" &&
+ make_dir one/two/three "$1"
+}
+
+test_expect_success 'setup' '
+ git commit --allow-empty -m empty &&
+ git tag empty &&
+ make_files added &&
+ git add . &&
+ git commit -m added &&
+ make_files modified &&
+ git add . &&
+ git commit -m modified &&
+ make_files index &&
+ git add . &&
+ make_files worktree
+'
+
+test_expect_success '--max-depth is disallowed with wildcard pathspecs' '
+ test_must_fail git diff-tree --max-depth=0 HEAD^ HEAD -- "f*"
+'
+
+check_one() {
+ type=$1; shift
+ args=$1; shift
+ path=$1; shift
+ depth=$1; shift
+ test_expect_${expect:-success} "diff-$type $args, path=$path, depth=$depth" "
+ for i in $*; do echo \$i; done >expect &&
+ git diff-$type --max-depth=$depth --name-only $args -- $path >actual &&
+ test_cmp expect actual
+ "
+}
+
+# For tree comparisons, we expect to see subtrees at the boundary
+# get their own entry.
+check_trees() {
+ check_one tree "$*" '' 0 file one
+ check_one tree "$*" '' 1 file one/file one/two
+ check_one tree "$*" '' 2 file one/file one/two/file one/two/three
+ check_one tree "$*" '' 3 file one/file one/two/file one/two/three/file
+ check_one tree "$*" '' -1 file one/file one/two/file one/two/three/file
+ check_one tree "$*" one 0 one
+ check_one tree "$*" one 1 one/file one/two
+ check_one tree "$*" one 2 one/file one/two/file one/two/three
+ check_one tree "$*" one 3 one/file one/two/file one/two/three/file
+ check_one tree "$*" one/two 0 one/two
+ check_one tree "$*" one/two 1 one/two/file one/two/three
+ check_one tree "$*" one/two 2 one/two/file one/two/three/file
+ check_one tree "$*" one/two 2 one/two/file one/two/three/file
+ check_one tree "$*" one/two/three 0 one/two/three
+ check_one tree "$*" one/two/three 1 one/two/three/file
+}
+
+# But for index comparisons, we do not store subtrees at all, so we do not
+# expect them.
+check_index() {
+ check_one "$@" '' 0 file
+ check_one "$@" '' 1 file one/file
+ check_one "$@" '' 2 file one/file one/two/file
+ check_one "$@" '' 3 file one/file one/two/file one/two/three/file
+ check_one "$@" one 0
+ check_one "$@" one 1 one/file
+ check_one "$@" one 2 one/file one/two/file
+ check_one "$@" one 3 one/file one/two/file one/two/three/file
+ check_one "$@" one/two 0
+ check_one "$@" one/two 1 one/two/file
+ check_one "$@" one/two 2 one/two/file one/two/three/file
+ check_one "$@" one/two/three 0
+ check_one "$@" one/two/three 1 one/two/three/file
+
+ # Value '-1' for '--max-depth is the same as recursion without limit,
+ # and thus should always succeed.
+ local expect=
+ check_one "$@" '' -1 file one/file one/two/file one/two/three/file
+}
+
+# Check as a modification...
+check_trees HEAD^ HEAD
+# ...and as an addition...
+check_trees empty HEAD
+# ...and as a deletion.
+check_trees HEAD empty
+
+# We currently only implement max-depth for trees.
+expect=failure
+# Check index against a tree
+check_index index "--cached HEAD"
+# and index against the worktree
+check_index files ""
+expect=
+
+test_expect_success 'find shortest path within embedded pathspecs' '
+ cat >expect <<-\EOF &&
+ one/file
+ one/two/file
+ one/two/three/file
+ EOF
+ git diff-tree --max-depth=2 --name-only HEAD^ HEAD -- one one/two >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 639868ac56..1064990de3 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -154,11 +154,34 @@ test_expect_success 'git log with multiple literal paths uses Bloom filter' '
test_bloom_filters_used "-- file*"
'
-test_expect_success 'git log with path contains a wildcard does not use Bloom filter' '
+test_expect_success 'git log with paths all contain non-wildcard part uses Bloom filter' '
+ test_bloom_filters_used "-- A/\* file4" &&
+ test_bloom_filters_used "-- A/file\*" &&
+ test_bloom_filters_used "-- * A/\*"
+'
+
+test_expect_success 'git log with path only contains wildcard part does not use Bloom filter' '
test_bloom_filters_not_used "-- file\*" &&
- test_bloom_filters_not_used "-- A/\* file4" &&
- test_bloom_filters_not_used "-- file4 A/\*" &&
- test_bloom_filters_not_used "-- * A/\*"
+ test_bloom_filters_not_used "-- file\* A/\*" &&
+ test_bloom_filters_not_used "-- file\* *" &&
+ test_bloom_filters_not_used "-- \*"
+'
+
+test_expect_success 'git log with path contains various magic signatures' '
+ cd A &&
+ test_bloom_filters_used "-- \:\(top\)B" &&
+ cd .. &&
+
+ test_bloom_filters_used "-- \:\(glob\)A/\*\*/C" &&
+ test_bloom_filters_not_used "-- \:\(icase\)FILE4" &&
+ test_bloom_filters_not_used "-- \:\(exclude\)A/B/C" &&
+
+ test_when_finished "rm -f .gitattributes" &&
+ cat >.gitattributes <<-EOF &&
+ A/file1 text
+ A/B/file2 -text
+ EOF
+ test_bloom_filters_used "-- \:\(attr\:text\)A"
'
test_expect_success 'setup - add commit-graph to the chain without Bloom filters' '
diff --git a/t/t4256/1/mailinfo.c b/t/t4256/1/mailinfo.c
index b395adbdf2..39caeba865 100644
--- a/t/t4256/1/mailinfo.c
+++ b/t/t4256/1/mailinfo.c
@@ -1214,7 +1214,7 @@ void setup_mailinfo(struct mailinfo *mi)
mi->header_stage = 1;
mi->use_inbody_headers = 1;
mi->content_top = mi->content;
- git_config(git_mailinfo_config, mi);
+ repo_config(the_repository, git_mailinfo_config, mi);
}
void clear_mailinfo(struct mailinfo *mi)
diff --git a/t/t4256/1/mailinfo.c.orig b/t/t4256/1/mailinfo.c.orig
index 3281a37d51..b76eb866aa 100644
--- a/t/t4256/1/mailinfo.c.orig
+++ b/t/t4256/1/mailinfo.c.orig
@@ -1154,7 +1154,7 @@ void setup_mailinfo(struct mailinfo *mi)
mi->header_stage = 1;
mi->use_inbody_headers = 1;
mi->content_top = mi->content;
- git_config(git_mailinfo_config, mi);
+ repo_config(the_repository, git_mailinfo_config, mi);
}
void clear_mailinfo(struct mailinfo *mi)
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 2701eef85e..e592c0bcde 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -1658,4 +1658,77 @@ test_expect_success 'forbid adding superset of existing remote' '
test_grep ".outer. is a superset of existing remote .outer/inner." err
'
+test_expect_success 'rename handles unborn HEAD' '
+ test_when_finished "git remote remove unborn-renamed" &&
+ git remote add unborn url &&
+ git symbolic-ref refs/remotes/unborn/HEAD refs/remotes/unborn/nonexistent &&
+ git remote rename unborn unborn-renamed &&
+ git symbolic-ref refs/remotes/unborn-renamed/HEAD >actual &&
+ echo refs/remotes/unborn-renamed/nonexistent >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'rename can nest a remote into itself' '
+ test_commit parent-commit &&
+ COMMIT_ID=$(git rev-parse HEAD) &&
+ test_when_finished "git remote remove parent || true" &&
+ git remote add parent url &&
+ git update-ref refs/remotes/parent/branch $COMMIT_ID &&
+ test_when_finished "git remote remove parent/child" &&
+ git remote rename parent parent/child &&
+ git for-each-ref refs/remotes/ >actual &&
+ printf "$COMMIT_ID commit\trefs/remotes/parent/child/branch\n" >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'rename can nest a remote into itself with a conflicting branch name' '
+ test_commit parent-conflict &&
+ COMMIT_ID=$(git rev-parse HEAD) &&
+ test_when_finished "git remote remove parent || true" &&
+ git remote add parent url &&
+ git update-ref refs/remotes/parent/child $COMMIT_ID &&
+ test_when_finished "git remote remove parent/child" &&
+ test_must_fail git remote rename parent parent/child 2>err &&
+ test_grep "renaming remote references failed" err &&
+ test_grep "The remote you are trying to rename has conflicting references" err &&
+ git for-each-ref refs/remotes/ >actual &&
+ printf "$COMMIT_ID commit\trefs/remotes/parent/child\n" >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'rename can unnest a remote' '
+ test_commit parent-child-commit &&
+ COMMIT_ID=$(git rev-parse HEAD) &&
+ test_when_finished "git remote remove parent/child || true" &&
+ git remote add parent/child url &&
+ git update-ref refs/remotes/parent/child/branch $COMMIT_ID &&
+ git remote rename parent/child parent &&
+ git for-each-ref refs/remotes/ >actual &&
+ printf "$COMMIT_ID commit\trefs/remotes/parent/branch\n" >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'rename moves around the reflog' '
+ test_commit reflog-old &&
+ COMMIT_ID=$(git rev-parse HEAD) &&
+ test_config core.logAllRefUpdates true &&
+ test_when_finished "git remote remove reflog-old || true" &&
+ git remote add reflog-old url &&
+ git update-ref refs/remotes/reflog-old/branch $COMMIT_ID &&
+ test-tool ref-store main for-each-reflog >actual &&
+ test_grep refs/remotes/reflog-old/branch actual &&
+ test-tool ref-store main for-each-reflog-ent refs/remotes/reflog-old/branch >reflog-entries-old &&
+ test_line_count = 1 reflog-entries-old &&
+ git remote rename reflog-old reflog-new &&
+ test-tool ref-store main for-each-reflog >actual &&
+ test_grep ! refs/remotes/reflog-old actual &&
+ test_grep refs/remotes/reflog-new/branch actual &&
+ test-tool ref-store main for-each-reflog-ent refs/remotes/reflog-new/branch >reflog-entries-new &&
+ cat >expect <<-EOF &&
+ $(cat reflog-entries-old)
+ $COMMIT_ID $COMMIT_ID $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1112912173 -0700 remote: renamed refs/remotes/reflog-old/branch to refs/remotes/reflog-new/branch
+ EOF
+ test_cmp expect reflog-entries-new
+'
+
test_done
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 4e9c27b0f2..46926e7bbd 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -105,7 +105,6 @@ check_push_result () {
}
test_expect_success setup '
-
>path1 &&
git add path1 &&
test_tick &&
@@ -117,7 +116,6 @@ test_expect_success setup '
test_tick &&
git commit -a -m second &&
the_commit=$(git show-ref -s --verify refs/heads/main)
-
'
for cmd in push fetch
@@ -322,104 +320,82 @@ test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf
'
test_expect_success 'push with matching heads' '
-
mk_test testrepo heads/main &&
git push testrepo : &&
check_push_result testrepo $the_commit heads/main
-
'
test_expect_success 'push with matching heads on the command line' '
-
mk_test testrepo heads/main &&
git push testrepo : &&
check_push_result testrepo $the_commit heads/main
-
'
test_expect_success 'failed (non-fast-forward) push with matching heads' '
-
mk_test testrepo heads/main &&
git push testrepo : &&
git commit --amend -massaged &&
test_must_fail git push testrepo &&
check_push_result testrepo $the_commit heads/main &&
git reset --hard $the_commit
-
'
test_expect_success 'push --force with matching heads' '
-
mk_test testrepo heads/main &&
git push testrepo : &&
git commit --amend -massaged &&
git push --force testrepo : &&
! check_push_result testrepo $the_commit heads/main &&
git reset --hard $the_commit
-
'
test_expect_success 'push with matching heads and forced update' '
-
mk_test testrepo heads/main &&
git push testrepo : &&
git commit --amend -massaged &&
git push testrepo +: &&
! check_push_result testrepo $the_commit heads/main &&
git reset --hard $the_commit
-
'
test_expect_success 'push with no ambiguity (1)' '
-
mk_test testrepo heads/main &&
git push testrepo main:main &&
check_push_result testrepo $the_commit heads/main
-
'
test_expect_success 'push with no ambiguity (2)' '
-
mk_test testrepo remotes/origin/main &&
git push testrepo main:origin/main &&
check_push_result testrepo $the_commit remotes/origin/main
-
'
test_expect_success 'push with colon-less refspec, no ambiguity' '
-
mk_test testrepo heads/main heads/t/main &&
git branch -f t/main main &&
git push testrepo main &&
check_push_result testrepo $the_commit heads/main &&
check_push_result testrepo $the_first_commit heads/t/main
-
'
test_expect_success 'push with weak ambiguity (1)' '
-
mk_test testrepo heads/main remotes/origin/main &&
git push testrepo main:main &&
check_push_result testrepo $the_commit heads/main &&
check_push_result testrepo $the_first_commit remotes/origin/main
-
'
test_expect_success 'push with weak ambiguity (2)' '
-
mk_test testrepo heads/main remotes/origin/main remotes/another/main &&
git push testrepo main:main &&
check_push_result testrepo $the_commit heads/main &&
check_push_result testrepo $the_first_commit remotes/origin/main remotes/another/main
-
'
test_expect_success 'push with ambiguity' '
-
mk_test testrepo heads/frotz tags/frotz &&
test_must_fail git push testrepo main:frotz &&
check_push_result testrepo $the_first_commit heads/frotz tags/frotz
-
'
test_expect_success 'push with onelevel ref' '
@@ -428,17 +404,14 @@ test_expect_success 'push with onelevel ref' '
'
test_expect_success 'push with colon-less refspec (1)' '
-
mk_test testrepo heads/frotz tags/frotz &&
git branch -f frotz main &&
git push testrepo frotz &&
check_push_result testrepo $the_commit heads/frotz &&
check_push_result testrepo $the_first_commit tags/frotz
-
'
test_expect_success 'push with colon-less refspec (2)' '
-
mk_test testrepo heads/frotz tags/frotz &&
if git show-ref --verify -q refs/heads/frotz
then
@@ -448,7 +421,6 @@ test_expect_success 'push with colon-less refspec (2)' '
git push -f testrepo frotz &&
check_push_result testrepo $the_commit tags/frotz &&
check_push_result testrepo $the_first_commit heads/frotz
-
'
test_expect_success 'push with colon-less refspec (3)' '
@@ -465,7 +437,6 @@ test_expect_success 'push with colon-less refspec (3)' '
'
test_expect_success 'push with colon-less refspec (4)' '
-
mk_test testrepo &&
if git show-ref --verify -q refs/heads/frotz
then
@@ -475,38 +446,34 @@ test_expect_success 'push with colon-less refspec (4)' '
git push testrepo frotz &&
check_push_result testrepo $the_commit tags/frotz &&
test 1 = $( cd testrepo && git show-ref | wc -l )
-
'
test_expect_success 'push head with non-existent, incomplete dest' '
-
mk_test testrepo &&
git push testrepo main:branch &&
check_push_result testrepo $the_commit heads/branch
-
'
test_expect_success 'push tag with non-existent, incomplete dest' '
-
mk_test testrepo &&
git tag -f v1.0 &&
git push testrepo v1.0:tag &&
check_push_result testrepo $the_commit tags/tag
-
'
test_expect_success 'push oid with non-existent, incomplete dest' '
-
mk_test testrepo &&
test_must_fail git push testrepo $(git rev-parse main):foo
-
'
test_expect_success 'push ref expression with non-existent, incomplete dest' '
-
mk_test testrepo &&
test_must_fail git push testrepo main^:branch
+'
+test_expect_success 'push ref expression with non-existent oid src' '
+ mk_test testrepo &&
+ test_must_fail git push testrepo $(test_oid 001):branch
'
for head in HEAD @
@@ -550,7 +517,6 @@ do
git checkout main &&
git push testrepo $head:branch &&
check_push_result testrepo $the_commit heads/branch
-
'
test_expect_success "push with config remote.*.push = $head" '
@@ -596,7 +562,6 @@ test_expect_success 'push with remote.pushdefault' '
'
test_expect_success 'push with config remote.*.pushurl' '
-
mk_test testrepo heads/main &&
git checkout main &&
test_config remote.there.url test2repo &&
@@ -655,7 +620,6 @@ test_expect_success 'push ignores "branch." config without subsection' '
'
test_expect_success 'push with dry-run' '
-
mk_test testrepo heads/main &&
old_commit=$(git -C testrepo show-ref -s --verify refs/heads/main) &&
git push --dry-run testrepo : &&
@@ -663,7 +627,6 @@ test_expect_success 'push with dry-run' '
'
test_expect_success 'push updates local refs' '
-
mk_test testrepo heads/main &&
mk_child testrepo child &&
(
@@ -673,11 +636,9 @@ test_expect_success 'push updates local refs' '
test $(git rev-parse main) = \
$(git rev-parse remotes/origin/main)
)
-
'
test_expect_success 'push updates up-to-date local refs' '
-
mk_test testrepo heads/main &&
mk_child testrepo child1 &&
mk_child testrepo child2 &&
@@ -689,11 +650,9 @@ test_expect_success 'push updates up-to-date local refs' '
test $(git rev-parse main) = \
$(git rev-parse remotes/origin/main)
)
-
'
test_expect_success 'push preserves up-to-date packed refs' '
-
mk_test testrepo heads/main &&
mk_child testrepo child &&
(
@@ -701,11 +660,9 @@ test_expect_success 'push preserves up-to-date packed refs' '
git push &&
! test -f .git/refs/remotes/origin/main
)
-
'
test_expect_success 'push does not update local refs on failure' '
-
mk_test testrepo heads/main &&
mk_child testrepo child &&
echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive &&
@@ -717,16 +674,13 @@ test_expect_success 'push does not update local refs on failure' '
test $(git rev-parse main) != \
$(git rev-parse remotes/origin/main)
)
-
'
test_expect_success 'allow deleting an invalid remote ref' '
-
mk_test testrepo heads/branch &&
rm -f testrepo/.git/objects/??/* &&
git push testrepo :refs/heads/branch &&
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/branch)
-
'
test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' '
diff --git a/t/t6137-pathspec-wildcards-literal.sh b/t/t6137-pathspec-wildcards-literal.sh
index 20abad5667..17a03085ef 100755
--- a/t/t6137-pathspec-wildcards-literal.sh
+++ b/t/t6137-pathspec-wildcards-literal.sh
@@ -3,8 +3,8 @@ test_description='test wildcards and literals with git add/commit (subshell styl
. ./test-lib.sh
-test_have_prereq FUNNYNAMES || {
- skip_all='skipping: needs FUNNYNAMES (non-Windows only)'
+test_have_prereq BSLASHPSPEC || {
+ skip_all='skipping: needs BSLASHPSPEC (backslashes in pathspecs)'
test_done
}
@@ -184,7 +184,7 @@ test_expect_success 'add wildcard f?z' '
)
'
-test_expect_success 'add literal \? literal' '
+test_expect_success 'add literal \?' '
git init test-q-lit &&
(
cd test-q-lit &&
@@ -241,7 +241,7 @@ test_expect_success 'add literal hello\?world' '
)
'
-test_expect_success 'add literal [abc]' '
+test_expect_success 'add literal \[abc\]' '
git init test-brackets-lit &&
(
cd test-brackets-lit &&
@@ -280,7 +280,7 @@ test_expect_success 'commit: wildcard *' '
)
'
-test_expect_success 'commit: literal *' '
+test_expect_success 'commit: literal \*' '
git init test-c-asterisk-lit &&
(
cd test-c-asterisk-lit &&
@@ -328,7 +328,7 @@ test_expect_success 'commit: literal f\*' '
)
'
-test_expect_success 'commit: wildcard pathspec limits commit' '
+test_expect_success 'commit: wildcard f**' '
git init test-c-pathlimit &&
(
cd test-c-pathlimit &&
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index ce9af79ab1..1d9809114d 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -6,2150 +6,14 @@
test_description='for-each-ref test'
. ./test-lib.sh
-GNUPGHOME_NOT_USED=$GNUPGHOME
-. "$TEST_DIRECTORY"/lib-gpg.sh
-. "$TEST_DIRECTORY"/lib-terminal.sh
-# Mon Jul 3 23:18:43 2006 +0000
-datestamp=1151968723
-setdate_and_increment () {
- GIT_COMMITTER_DATE="$datestamp +0200"
- datestamp=$(expr "$datestamp" + 1)
- GIT_AUTHOR_DATE="$datestamp +0200"
- datestamp=$(expr "$datestamp" + 1)
- export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-}
-
-test_object_file_size () {
- oid=$(git rev-parse "$1")
- path=".git/objects/$(test_oid_to_path $oid)"
- test_file_size "$path"
-}
-
-test_expect_success setup '
- # setup .mailmap
- cat >.mailmap <<-EOF &&
- A Thor <athor@example.com> A U Thor <author@example.com>
- C Mitter <cmitter@example.com> C O Mitter <committer@example.com>
- EOF
-
- setdate_and_increment &&
- echo "Using $datestamp" > one &&
- git add one &&
- git commit -m "Initial" &&
- git branch -M main &&
- setdate_and_increment &&
- git tag -a -m "Tagging at $datestamp" testtag &&
- git update-ref refs/remotes/origin/main main &&
- git remote add origin nowhere &&
- git config branch.main.remote origin &&
- git config branch.main.merge refs/heads/main &&
- git remote add myfork elsewhere &&
- git config remote.pushdefault myfork &&
- git config push.default current
-'
-
-test_atom () {
- case "$1" in
- head) ref=refs/heads/main ;;
- tag) ref=refs/tags/testtag ;;
- sym) ref=refs/heads/sym ;;
- *) ref=$1 ;;
- esac
- format=$2
- test_do=test_expect_${4:-success}
-
- printf '%s\n' "$3" >expected
- $test_do $PREREQ "basic atom: $ref $format" '
- git for-each-ref --format="%($format)" "$ref" >actual &&
- sanitize_pgp <actual >actual.clean &&
- test_cmp expected actual.clean
- '
-
- # Automatically test "contents:size" atom after testing "contents"
- if test "$format" = "contents"
- then
- # for commit leg, $3 is changed there
- expect=$(printf '%s' "$3" | wc -c)
- $test_do $PREREQ "basic atom: $ref contents:size" '
- type=$(git cat-file -t "$ref") &&
- case $type in
- tag)
- # We cannot use $3 as it expects sanitize_pgp to run
- git cat-file tag $ref >out &&
- expect=$(tail -n +6 out | wc -c) &&
- rm -f out ;;
- tree | blob)
- expect="" ;;
- commit)
- : "use the calculated expect" ;;
- *)
- BUG "unknown object type" ;;
- esac &&
- # Leave $expect unquoted to lose possible leading whitespaces
- echo $expect >expected &&
- git for-each-ref --format="%(contents:size)" "$ref" >actual &&
- test_cmp expected actual
- '
- fi
-}
-
-hexlen=$(test_oid hexsz)
-
-test_atom head refname refs/heads/main
-test_atom head refname: refs/heads/main
-test_atom head refname:short main
-test_atom head refname:lstrip=1 heads/main
-test_atom head refname:lstrip=2 main
-test_atom head refname:lstrip=-1 main
-test_atom head refname:lstrip=-2 heads/main
-test_atom head refname:rstrip=1 refs/heads
-test_atom head refname:rstrip=2 refs
-test_atom head refname:rstrip=-1 refs
-test_atom head refname:rstrip=-2 refs/heads
-test_atom head refname:strip=1 heads/main
-test_atom head refname:strip=2 main
-test_atom head refname:strip=-1 main
-test_atom head refname:strip=-2 heads/main
-test_atom head upstream refs/remotes/origin/main
-test_atom head upstream:short origin/main
-test_atom head upstream:lstrip=2 origin/main
-test_atom head upstream:lstrip=-2 origin/main
-test_atom head upstream:rstrip=2 refs/remotes
-test_atom head upstream:rstrip=-2 refs/remotes
-test_atom head upstream:strip=2 origin/main
-test_atom head upstream:strip=-2 origin/main
-test_atom head push refs/remotes/myfork/main
-test_atom head push:short myfork/main
-test_atom head push:lstrip=1 remotes/myfork/main
-test_atom head push:lstrip=-1 main
-test_atom head push:rstrip=1 refs/remotes/myfork
-test_atom head push:rstrip=-1 refs
-test_atom head push:strip=1 remotes/myfork/main
-test_atom head push:strip=-1 main
-test_atom head objecttype commit
-test_atom head objectsize $((131 + hexlen))
-test_atom head objectsize:disk $(test_object_file_size refs/heads/main)
-test_atom head deltabase $ZERO_OID
-test_atom head objectname $(git rev-parse refs/heads/main)
-test_atom head objectname:short $(git rev-parse --short refs/heads/main)
-test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/main)
-test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/main)
-test_atom head tree $(git rev-parse refs/heads/main^{tree})
-test_atom head tree:short $(git rev-parse --short refs/heads/main^{tree})
-test_atom head tree:short=1 $(git rev-parse --short=1 refs/heads/main^{tree})
-test_atom head tree:short=10 $(git rev-parse --short=10 refs/heads/main^{tree})
-test_atom head parent ''
-test_atom head parent:short ''
-test_atom head parent:short=1 ''
-test_atom head parent:short=10 ''
-test_atom head numparent 0
-test_atom head object ''
-test_atom head type ''
-test_atom head raw "$(git cat-file commit refs/heads/main)
-"
-test_atom head '*objectname' ''
-test_atom head '*objecttype' ''
-test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
-test_atom head authorname 'A U Thor'
-test_atom head authorname:mailmap 'A Thor'
-test_atom head authoremail '<author@example.com>'
-test_atom head authoremail:trim 'author@example.com'
-test_atom head authoremail:localpart 'author'
-test_atom head authoremail:trim,localpart 'author'
-test_atom head authoremail:mailmap '<athor@example.com>'
-test_atom head authoremail:mailmap,trim 'athor@example.com'
-test_atom head authoremail:trim,mailmap 'athor@example.com'
-test_atom head authoremail:mailmap,localpart 'athor'
-test_atom head authoremail:localpart,mailmap 'athor'
-test_atom head authoremail:mailmap,trim,localpart,mailmap,trim 'athor'
-test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'
-test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'
-test_atom head committername 'C O Mitter'
-test_atom head committername:mailmap 'C Mitter'
-test_atom head committeremail '<committer@example.com>'
-test_atom head committeremail:trim 'committer@example.com'
-test_atom head committeremail:localpart 'committer'
-test_atom head committeremail:localpart,trim 'committer'
-test_atom head committeremail:mailmap '<cmitter@example.com>'
-test_atom head committeremail:mailmap,trim 'cmitter@example.com'
-test_atom head committeremail:trim,mailmap 'cmitter@example.com'
-test_atom head committeremail:mailmap,localpart 'cmitter'
-test_atom head committeremail:localpart,mailmap 'cmitter'
-test_atom head committeremail:trim,mailmap,trim,trim,localpart 'cmitter'
-test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'
-test_atom head tag ''
-test_atom head tagger ''
-test_atom head taggername ''
-test_atom head taggeremail ''
-test_atom head taggeremail:trim ''
-test_atom head taggeremail:localpart ''
-test_atom head taggerdate ''
-test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200'
-test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200'
-test_atom head subject 'Initial'
-test_atom head subject:sanitize 'Initial'
-test_atom head contents:subject 'Initial'
-test_atom head body ''
-test_atom head contents:body ''
-test_atom head contents:signature ''
-test_atom head contents 'Initial
-'
-test_atom head HEAD '*'
-
-test_atom tag refname refs/tags/testtag
-test_atom tag refname:short testtag
-test_atom tag upstream ''
-test_atom tag push ''
-test_atom tag objecttype tag
-test_atom tag objectsize $((114 + hexlen))
-test_atom tag objectsize:disk $(test_object_file_size refs/tags/testtag)
-test_atom tag '*objectsize:disk' $(test_object_file_size refs/heads/main)
-test_atom tag deltabase $ZERO_OID
-test_atom tag '*deltabase' $ZERO_OID
-test_atom tag objectname $(git rev-parse refs/tags/testtag)
-test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
-test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/main)
-test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/main)
-test_atom tag tree ''
-test_atom tag tree:short ''
-test_atom tag tree:short=1 ''
-test_atom tag tree:short=10 ''
-test_atom tag parent ''
-test_atom tag parent:short ''
-test_atom tag parent:short=1 ''
-test_atom tag parent:short=10 ''
-test_atom tag numparent ''
-test_atom tag object $(git rev-parse refs/tags/testtag^0)
-test_atom tag type 'commit'
-test_atom tag '*objectname' $(git rev-parse refs/tags/testtag^{})
-test_atom tag '*objecttype' 'commit'
-test_atom tag author ''
-test_atom tag authorname ''
-test_atom tag authorname:mailmap ''
-test_atom tag authoremail ''
-test_atom tag authoremail:trim ''
-test_atom tag authoremail:localpart ''
-test_atom tag authoremail:trim,localpart ''
-test_atom tag authoremail:mailmap ''
-test_atom tag authoremail:mailmap,trim ''
-test_atom tag authoremail:trim,mailmap ''
-test_atom tag authoremail:mailmap,localpart ''
-test_atom tag authoremail:localpart,mailmap ''
-test_atom tag authoremail:mailmap,trim,localpart,mailmap,trim ''
-test_atom tag authordate ''
-test_atom tag committer ''
-test_atom tag committername ''
-test_atom tag committername:mailmap ''
-test_atom tag committeremail ''
-test_atom tag committeremail:trim ''
-test_atom tag committeremail:localpart ''
-test_atom tag committeremail:localpart,trim ''
-test_atom tag committeremail:mailmap ''
-test_atom tag committeremail:mailmap,trim ''
-test_atom tag committeremail:trim,mailmap ''
-test_atom tag committeremail:mailmap,localpart ''
-test_atom tag committeremail:localpart,mailmap ''
-test_atom tag committeremail:trim,mailmap,trim,trim,localpart ''
-test_atom tag committerdate ''
-test_atom tag tag 'testtag'
-test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'
-test_atom tag taggername 'C O Mitter'
-test_atom tag taggername:mailmap 'C Mitter'
-test_atom tag taggeremail '<committer@example.com>'
-test_atom tag taggeremail:trim 'committer@example.com'
-test_atom tag taggeremail:localpart 'committer'
-test_atom tag taggeremail:trim,localpart 'committer'
-test_atom tag taggeremail:mailmap '<cmitter@example.com>'
-test_atom tag taggeremail:mailmap,trim 'cmitter@example.com'
-test_atom tag taggeremail:trim,mailmap 'cmitter@example.com'
-test_atom tag taggeremail:mailmap,localpart 'cmitter'
-test_atom tag taggeremail:localpart,mailmap 'cmitter'
-test_atom tag taggeremail:trim,mailmap,trim,localpart,localpart 'cmitter'
-test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'
-test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'
-test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'
-test_atom tag subject 'Tagging at 1151968727'
-test_atom tag subject:sanitize 'Tagging-at-1151968727'
-test_atom tag contents:subject 'Tagging at 1151968727'
-test_atom tag body ''
-test_atom tag contents:body ''
-test_atom tag contents:signature ''
-test_atom tag contents 'Tagging at 1151968727
-'
-test_atom tag HEAD ' '
-
-test_expect_success 'basic atom: refs/tags/testtag *raw' '
- git cat-file commit refs/tags/testtag^{} >expected &&
- git for-each-ref --format="%(*raw)" refs/tags/testtag >actual &&
- sanitize_pgp <expected >expected.clean &&
- echo >>expected.clean &&
- sanitize_pgp <actual >actual.clean &&
- test_cmp expected.clean actual.clean
-'
-
-test_expect_success 'Check invalid atoms names are errors' '
- test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
-'
-
-test_expect_success 'for-each-ref does not crash with -h' '
+test_expect_success "for-each-ref does not crash with -h" '
test_expect_code 129 git for-each-ref -h >usage &&
test_grep "[Uu]sage: git for-each-ref " usage &&
test_expect_code 129 nongit git for-each-ref -h >usage &&
test_grep "[Uu]sage: git for-each-ref " usage
'
-test_expect_success 'Check format specifiers are ignored in naming date atoms' '
- git for-each-ref --format="%(authordate)" refs/heads &&
- git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
- git for-each-ref --format="%(authordate) %(authordate:default)" refs/heads &&
- git for-each-ref --format="%(authordate:default) %(authordate:default)" refs/heads
-'
-
-test_expect_success 'Check valid format specifiers for date fields' '
- git for-each-ref --format="%(authordate:default)" refs/heads &&
- git for-each-ref --format="%(authordate:relative)" refs/heads &&
- git for-each-ref --format="%(authordate:short)" refs/heads &&
- git for-each-ref --format="%(authordate:local)" refs/heads &&
- git for-each-ref --format="%(authordate:iso8601)" refs/heads &&
- git for-each-ref --format="%(authordate:rfc2822)" refs/heads
-'
-
-test_expect_success 'Check invalid format specifiers are errors' '
- test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads
-'
-
-test_expect_success 'arguments to %(objectname:short=) must be positive integers' '
- test_must_fail git for-each-ref --format="%(objectname:short=0)" &&
- test_must_fail git for-each-ref --format="%(objectname:short=-1)" &&
- test_must_fail git for-each-ref --format="%(objectname:short=foo)"
-'
-
-test_bad_atom () {
- case "$1" in
- head) ref=refs/heads/main ;;
- tag) ref=refs/tags/testtag ;;
- sym) ref=refs/heads/sym ;;
- *) ref=$1 ;;
- esac
- format=$2
- test_do=test_expect_${4:-success}
-
- printf '%s\n' "$3" >expect
- $test_do $PREREQ "err basic atom: $ref $format" '
- test_must_fail git for-each-ref \
- --format="%($format)" "$ref" 2>error &&
- test_cmp expect error
- '
-}
-
-test_bad_atom head 'authoremail:foo' \
- 'fatal: unrecognized %(authoremail) argument: foo'
-
-test_bad_atom head 'authoremail:mailmap,trim,bar' \
- 'fatal: unrecognized %(authoremail) argument: bar'
-
-test_bad_atom head 'authoremail:trim,' \
- 'fatal: unrecognized %(authoremail) argument: '
-
-test_bad_atom head 'authoremail:mailmaptrim' \
- 'fatal: unrecognized %(authoremail) argument: trim'
-
-test_bad_atom head 'committeremail: ' \
- 'fatal: unrecognized %(committeremail) argument: '
-
-test_bad_atom head 'committeremail: trim,foo' \
- 'fatal: unrecognized %(committeremail) argument: trim,foo'
-
-test_bad_atom head 'committeremail:mailmap,localpart ' \
- 'fatal: unrecognized %(committeremail) argument: '
-
-test_bad_atom head 'committeremail:trim_localpart' \
- 'fatal: unrecognized %(committeremail) argument: _localpart'
-
-test_bad_atom head 'committeremail:localpart,,,trim' \
- 'fatal: unrecognized %(committeremail) argument: ,,trim'
-
-test_bad_atom tag 'taggeremail:mailmap,trim, foo ' \
- 'fatal: unrecognized %(taggeremail) argument: foo '
-
-test_bad_atom tag 'taggeremail:trim,localpart,' \
- 'fatal: unrecognized %(taggeremail) argument: '
-
-test_bad_atom tag 'taggeremail:mailmap;localpart trim' \
- 'fatal: unrecognized %(taggeremail) argument: ;localpart trim'
-
-test_bad_atom tag 'taggeremail:localpart trim' \
- 'fatal: unrecognized %(taggeremail) argument: trim'
-
-test_bad_atom tag 'taggeremail:mailmap,mailmap,trim,qux,localpart,trim' \
- 'fatal: unrecognized %(taggeremail) argument: qux,localpart,trim'
-
-test_date () {
- f=$1 &&
- committer_date=$2 &&
- author_date=$3 &&
- tagger_date=$4 &&
- cat >expected <<-EOF &&
- 'refs/heads/main' '$committer_date' '$author_date'
- 'refs/tags/testtag' '$tagger_date'
- EOF
- (
- git for-each-ref --shell \
- --format="%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})" \
- refs/heads &&
- git for-each-ref --shell \
- --format="%(refname) %(taggerdate${f:+:$f})" \
- refs/tags
- ) >actual &&
- test_cmp expected actual
-}
-
-test_expect_success 'Check unformatted date fields output' '
- test_date "" \
- "Tue Jul 4 01:18:43 2006 +0200" \
- "Tue Jul 4 01:18:44 2006 +0200" \
- "Tue Jul 4 01:18:45 2006 +0200"
-'
-
-test_expect_success 'Check format "default" formatted date fields output' '
- test_date default \
- "Tue Jul 4 01:18:43 2006 +0200" \
- "Tue Jul 4 01:18:44 2006 +0200" \
- "Tue Jul 4 01:18:45 2006 +0200"
-'
-
-test_expect_success 'Check format "default-local" date fields output' '
- test_date default-local "Mon Jul 3 23:18:43 2006" "Mon Jul 3 23:18:44 2006" "Mon Jul 3 23:18:45 2006"
-'
-
-# Don't know how to do relative check because I can't know when this script
-# is going to be run and can't fake the current time to git, and hence can't
-# provide expected output. Instead, I'll just make sure that "relative"
-# doesn't exit in error
-test_expect_success 'Check format "relative" date fields output' '
- f=relative &&
- (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
- git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual
-'
-
-# We just check that this is the same as "relative" for now.
-test_expect_success 'Check format "relative-local" date fields output' '
- test_date relative-local \
- "$(git for-each-ref --format="%(committerdate:relative)" refs/heads)" \
- "$(git for-each-ref --format="%(authordate:relative)" refs/heads)" \
- "$(git for-each-ref --format="%(taggerdate:relative)" refs/tags)"
-'
-
-test_expect_success 'Check format "short" date fields output' '
- test_date short 2006-07-04 2006-07-04 2006-07-04
-'
-
-test_expect_success 'Check format "short-local" date fields output' '
- test_date short-local 2006-07-03 2006-07-03 2006-07-03
-'
-
-test_expect_success 'Check format "local" date fields output' '
- test_date local \
- "Mon Jul 3 23:18:43 2006" \
- "Mon Jul 3 23:18:44 2006" \
- "Mon Jul 3 23:18:45 2006"
-'
-
-test_expect_success 'Check format "iso8601" date fields output' '
- test_date iso8601 \
- "2006-07-04 01:18:43 +0200" \
- "2006-07-04 01:18:44 +0200" \
- "2006-07-04 01:18:45 +0200"
-'
-
-test_expect_success 'Check format "iso8601-local" date fields output' '
- test_date iso8601-local "2006-07-03 23:18:43 +0000" "2006-07-03 23:18:44 +0000" "2006-07-03 23:18:45 +0000"
-'
-
-test_expect_success 'Check format "rfc2822" date fields output' '
- test_date rfc2822 \
- "Tue, 4 Jul 2006 01:18:43 +0200" \
- "Tue, 4 Jul 2006 01:18:44 +0200" \
- "Tue, 4 Jul 2006 01:18:45 +0200"
-'
-
-test_expect_success 'Check format "rfc2822-local" date fields output' '
- test_date rfc2822-local "Mon, 3 Jul 2006 23:18:43 +0000" "Mon, 3 Jul 2006 23:18:44 +0000" "Mon, 3 Jul 2006 23:18:45 +0000"
-'
-
-test_expect_success 'Check format "raw" date fields output' '
- test_date raw "1151968723 +0200" "1151968724 +0200" "1151968725 +0200"
-'
-
-test_expect_success 'Check format "raw-local" date fields output' '
- test_date raw-local "1151968723 +0000" "1151968724 +0000" "1151968725 +0000"
-'
-
-test_expect_success 'Check format of strftime date fields' '
- echo "my date is 2006-07-04" >expected &&
- git for-each-ref \
- --format="%(authordate:format:my date is %Y-%m-%d)" \
- refs/heads >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'Check format of strftime-local date fields' '
- echo "my date is 2006-07-03" >expected &&
- git for-each-ref \
- --format="%(authordate:format-local:my date is %Y-%m-%d)" \
- refs/heads >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'exercise strftime with odd fields' '
- echo >expected &&
- git for-each-ref --format="%(authordate:format:)" refs/heads >actual &&
- test_cmp expected actual &&
- long="long format -- $ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID" &&
- echo $long >expected &&
- git for-each-ref --format="%(authordate:format:$long)" refs/heads >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-refs/heads/main
-refs/remotes/origin/main
-refs/tags/testtag
-EOF
-
-test_expect_success 'Verify ascending sort' '
- git for-each-ref --format="%(refname)" --sort=refname >actual &&
- test_cmp expected actual
-'
-
-
-cat >expected <<\EOF
-refs/tags/testtag
-refs/remotes/origin/main
-refs/heads/main
-EOF
-
-test_expect_success 'Verify descending sort' '
- git for-each-ref --format="%(refname)" --sort=-refname >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'Give help even with invalid sort atoms' '
- test_expect_code 129 git for-each-ref --sort=bogus -h >actual 2>&1 &&
- grep "^usage: git for-each-ref" actual
-'
-
-cat >expected <<\EOF
-refs/tags/testtag
-refs/tags/testtag-2
-EOF
-
-test_expect_success 'exercise patterns with prefixes' '
- git tag testtag-2 &&
- test_when_finished "git tag -d testtag-2" &&
- git for-each-ref --format="%(refname)" \
- refs/tags/testtag refs/tags/testtag-2 >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-refs/tags/testtag
-refs/tags/testtag-2
-EOF
-
-test_expect_success 'exercise glob patterns with prefixes' '
- git tag testtag-2 &&
- test_when_finished "git tag -d testtag-2" &&
- git for-each-ref --format="%(refname)" \
- refs/tags/testtag "refs/tags/testtag-*" >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-refs/tags/bar
-refs/tags/baz
-refs/tags/testtag
-EOF
-
-test_expect_success 'exercise patterns with prefix exclusions' '
- for tag in foo/one foo/two foo/three bar baz
- do
- git tag "$tag" || return 1
- done &&
- test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
- git for-each-ref --format="%(refname)" \
- refs/tags/ --exclude=refs/tags/foo >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-refs/tags/bar
-refs/tags/baz
-refs/tags/foo/one
-refs/tags/testtag
-EOF
-
-test_expect_success 'exercise patterns with pattern exclusions' '
- for tag in foo/one foo/two foo/three bar baz
- do
- git tag "$tag" || return 1
- done &&
- test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
- git for-each-ref --format="%(refname)" \
- refs/tags/ --exclude="refs/tags/foo/t*" >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-'refs/heads/main'
-'refs/remotes/origin/main'
-'refs/tags/testtag'
-EOF
-
-test_expect_success 'Quoting style: shell' '
- git for-each-ref --shell --format="%(refname)" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'Quoting style: perl' '
- git for-each-ref --perl --format="%(refname)" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'Quoting style: python' '
- git for-each-ref --python --format="%(refname)" >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-"refs/heads/main"
-"refs/remotes/origin/main"
-"refs/tags/testtag"
-EOF
-
-test_expect_success 'Quoting style: tcl' '
- git for-each-ref --tcl --format="%(refname)" >actual &&
- test_cmp expected actual
-'
-
-for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
- test_expect_success "more than one quoting style: $i" "
- test_must_fail git for-each-ref $i 2>err &&
- grep '^error: more than one quoting style' err
- "
-done
-
-test_expect_success 'setup for upstream:track[short]' '
- test_commit two
-'
-
-test_atom head upstream:track '[ahead 1]'
-test_atom head upstream:trackshort '>'
-test_atom head upstream:track,nobracket 'ahead 1'
-test_atom head upstream:nobracket,track 'ahead 1'
-
-test_expect_success 'setup for push:track[short]' '
- test_commit third &&
- git update-ref refs/remotes/myfork/main main &&
- git reset main~1
-'
-
-test_atom head push:track '[behind 1]'
-test_atom head push:trackshort '<'
-
-test_expect_success 'Check that :track[short] cannot be used with other atoms' '
- test_must_fail git for-each-ref --format="%(refname:track)" 2>/dev/null &&
- test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null
-'
-
-test_expect_success 'Check that :track[short] works when upstream is invalid' '
- cat >expected <<-\EOF &&
- [gone]
-
- EOF
- test_when_finished "git config branch.main.merge refs/heads/main" &&
- git config branch.main.merge refs/heads/does-not-exist &&
- git for-each-ref \
- --format="%(upstream:track)$LF%(upstream:trackshort)" \
- refs/heads >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'Check for invalid refname format' '
- test_must_fail git for-each-ref --format="%(refname:INVALID)"
-'
-
-test_expect_success 'set up color tests' '
- cat >expected.color <<-EOF &&
- $(git rev-parse --short refs/heads/main) <GREEN>main<RESET>
- $(git rev-parse --short refs/remotes/myfork/main) <GREEN>myfork/main<RESET>
- $(git rev-parse --short refs/remotes/origin/main) <GREEN>origin/main<RESET>
- $(git rev-parse --short refs/tags/testtag) <GREEN>testtag<RESET>
- $(git rev-parse --short refs/tags/third) <GREEN>third<RESET>
- $(git rev-parse --short refs/tags/two) <GREEN>two<RESET>
- EOF
- sed "s/<[^>]*>//g" <expected.color >expected.bare &&
- color_format="%(objectname:short) %(color:green)%(refname:short)"
-'
-
-test_expect_success TTY '%(color) shows color with a tty' '
- test_terminal git for-each-ref --format="$color_format" >actual.raw &&
- test_decode_color <actual.raw >actual &&
- test_cmp expected.color actual
-'
-
-test_expect_success '%(color) does not show color without tty' '
- TERM=vt100 git for-each-ref --format="$color_format" >actual &&
- test_cmp expected.bare actual
-'
-
-test_expect_success '--color can override tty check' '
- git for-each-ref --color --format="$color_format" >actual.raw &&
- test_decode_color <actual.raw >actual &&
- test_cmp expected.color actual
-'
-
-test_expect_success 'color.ui=always does not override tty check' '
- git -c color.ui=always for-each-ref --format="$color_format" >actual &&
- test_cmp expected.bare actual
-'
-
-test_expect_success 'setup for describe atom tests' '
- git init -b master describe-repo &&
- (
- cd describe-repo &&
-
- test_commit --no-tag one &&
- git tag tagone &&
-
- test_commit --no-tag two &&
- git tag -a -m "tag two" tagtwo
- )
-'
-
-test_expect_success 'describe atom vs git describe' '
- (
- cd describe-repo &&
-
- git for-each-ref --format="%(objectname)" \
- refs/tags/ >obj &&
- while read hash
- do
- if desc=$(git describe $hash)
- then
- : >expect-contains-good
- else
- : >expect-contains-bad
- fi &&
- echo "$hash $desc" || return 1
- done <obj >expect &&
- test_path_exists expect-contains-good &&
- test_path_exists expect-contains-bad &&
-
- git for-each-ref --format="%(objectname) %(describe)" \
- refs/tags/ >actual 2>err &&
- test_cmp expect actual &&
- test_must_be_empty err
- )
-'
-
-test_expect_success 'describe:tags vs describe --tags' '
- (
- cd describe-repo &&
- git describe --tags >expect &&
- git for-each-ref --format="%(describe:tags)" \
- refs/heads/master >actual &&
- test_cmp expect actual
- )
-'
-
-test_expect_success 'describe:abbrev=... vs describe --abbrev=...' '
- (
- cd describe-repo &&
-
- # Case 1: We have commits between HEAD and the most
- # recent tag reachable from it
- test_commit --no-tag file &&
- git describe --abbrev=14 >expect &&
- git for-each-ref --format="%(describe:abbrev=14)" \
- refs/heads/master >actual &&
- test_cmp expect actual &&
-
- # Make sure the hash used is at least 14 digits long
- sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
- test 15 -le $(wc -c <hexpart) &&
-
- # Case 2: We have a tag at HEAD, describe directly gives
- # the name of the tag
- git tag -a -m tagged tagname &&
- git describe --abbrev=14 >expect &&
- git for-each-ref --format="%(describe:abbrev=14)" \
- refs/heads/master >actual &&
- test_cmp expect actual &&
- test tagname = $(cat actual)
- )
-'
-
-test_expect_success 'describe:match=... vs describe --match ...' '
- (
- cd describe-repo &&
- git tag -a -m "tag foo" tag-foo &&
- git describe --match "*-foo" >expect &&
- git for-each-ref --format="%(describe:match="*-foo")" \
- refs/heads/master >actual &&
- test_cmp expect actual
- )
-'
-
-test_expect_success 'describe:exclude:... vs describe --exclude ...' '
- (
- cd describe-repo &&
- git tag -a -m "tag bar" tag-bar &&
- git describe --exclude "*-bar" >expect &&
- git for-each-ref --format="%(describe:exclude="*-bar")" \
- refs/heads/master >actual &&
- test_cmp expect actual
- )
-'
-
-test_expect_success 'deref with describe atom' '
- (
- cd describe-repo &&
- cat >expect <<-\EOF &&
-
- tagname
- tagname
- tagname
-
- tagtwo
- EOF
- git for-each-ref --format="%(*describe)" >actual &&
- test_cmp expect actual
- )
-'
-
-test_expect_success 'err on bad describe atom arg' '
- (
- cd describe-repo &&
-
- # The bad arg is the only arg passed to describe atom
- cat >expect <<-\EOF &&
- fatal: unrecognized %(describe) argument: baz
- EOF
- test_must_fail git for-each-ref --format="%(describe:baz)" \
- refs/heads/master 2>actual &&
- test_cmp expect actual &&
-
- # The bad arg is in the middle of the option string
- # passed to the describe atom
- cat >expect <<-\EOF &&
- fatal: unrecognized %(describe) argument: qux=1,abbrev=14
- EOF
- test_must_fail git for-each-ref \
- --format="%(describe:tags,qux=1,abbrev=14)" \
- ref/heads/master 2>actual &&
- test_cmp expect actual
- )
-'
-
-cat >expected <<\EOF
-heads/main
-tags/main
-EOF
-
-test_expect_success 'Check ambiguous head and tag refs (strict)' '
- git config --bool core.warnambiguousrefs true &&
- git checkout -b newtag &&
- echo "Using $datestamp" > one &&
- git add one &&
- git commit -m "Branch" &&
- setdate_and_increment &&
- git tag -m "Tagging at $datestamp" main &&
- git for-each-ref --format "%(refname:short)" refs/heads/main refs/tags/main >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-heads/main
-main
-EOF
-
-test_expect_success 'Check ambiguous head and tag refs (loose)' '
- git config --bool core.warnambiguousrefs false &&
- git for-each-ref --format "%(refname:short)" refs/heads/main refs/tags/main >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<\EOF
-heads/ambiguous
-ambiguous
-EOF
-
-test_expect_success 'Check ambiguous head and tag refs II (loose)' '
- git checkout main &&
- git tag ambiguous testtag^0 &&
- git branch ambiguous testtag^0 &&
- git for-each-ref --format "%(refname:short)" refs/heads/ambiguous refs/tags/ambiguous >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'create tag without tagger' '
- git tag -a -m "Broken tag" taggerless &&
- git tag -f taggerless $(git cat-file tag taggerless |
- sed -e "/^tagger /d" |
- git hash-object --literally --stdin -w -t tag)
-'
-
-test_atom refs/tags/taggerless type 'commit'
-test_atom refs/tags/taggerless tag 'taggerless'
-test_atom refs/tags/taggerless tagger ''
-test_atom refs/tags/taggerless taggername ''
-test_atom refs/tags/taggerless taggeremail ''
-test_atom refs/tags/taggerless taggeremail:trim ''
-test_atom refs/tags/taggerless taggeremail:localpart ''
-test_atom refs/tags/taggerless taggerdate ''
-test_atom refs/tags/taggerless committer ''
-test_atom refs/tags/taggerless committername ''
-test_atom refs/tags/taggerless committeremail ''
-test_atom refs/tags/taggerless committeremail:trim ''
-test_atom refs/tags/taggerless committeremail:localpart ''
-test_atom refs/tags/taggerless committerdate ''
-test_atom refs/tags/taggerless subject 'Broken tag'
-
-test_expect_success 'an unusual tag with an incomplete line' '
-
- git tag -m "bogo" bogo &&
- bogo=$(git cat-file tag bogo) &&
- bogo=$(printf "%s" "$bogo" | git mktag) &&
- git tag -f bogo "$bogo" &&
- git for-each-ref --format "%(body)" refs/tags/bogo
-
-'
-
-test_expect_success 'create tag with subject and body content' '
- cat >>msg <<-\EOF &&
- the subject line
-
- first body line
- second body line
- EOF
- git tag -F msg subject-body
-'
-test_atom refs/tags/subject-body subject 'the subject line'
-test_atom refs/tags/subject-body subject:sanitize 'the-subject-line'
-test_atom refs/tags/subject-body body 'first body line
-second body line
-'
-test_atom refs/tags/subject-body contents 'the subject line
-
-first body line
-second body line
-'
-
-test_expect_success 'create tag with multiline subject' '
- cat >msg <<-\EOF &&
- first subject line
- second subject line
-
- first body line
- second body line
- EOF
- git tag -F msg multiline
-'
-test_atom refs/tags/multiline subject 'first subject line second subject line'
-test_atom refs/tags/multiline subject:sanitize 'first-subject-line-second-subject-line'
-test_atom refs/tags/multiline contents:subject 'first subject line second subject line'
-test_atom refs/tags/multiline body 'first body line
-second body line
-'
-test_atom refs/tags/multiline contents:body 'first body line
-second body line
-'
-test_atom refs/tags/multiline contents:signature ''
-test_atom refs/tags/multiline contents 'first subject line
-second subject line
-
-first body line
-second body line
-'
-
-test_expect_success GPG 'create signed tags' '
- git tag -s -m "" signed-empty &&
- git tag -s -m "subject line" signed-short &&
- cat >msg <<-\EOF &&
- subject line
-
- body contents
- EOF
- git tag -s -F msg signed-long
-'
-
-sig='-----BEGIN PGP SIGNATURE-----
------END PGP SIGNATURE-----
-'
-
-PREREQ=GPG
-test_atom refs/tags/signed-empty subject ''
-test_atom refs/tags/signed-empty subject:sanitize ''
-test_atom refs/tags/signed-empty contents:subject ''
-test_atom refs/tags/signed-empty body "$sig"
-test_atom refs/tags/signed-empty contents:body ''
-test_atom refs/tags/signed-empty contents:signature "$sig"
-test_atom refs/tags/signed-empty contents "$sig"
-
-test_expect_success GPG 'basic atom: refs/tags/signed-empty raw' '
- git cat-file tag refs/tags/signed-empty >expected &&
- git for-each-ref --format="%(raw)" refs/tags/signed-empty >actual &&
- sanitize_pgp <expected >expected.clean &&
- echo >>expected.clean &&
- sanitize_pgp <actual >actual.clean &&
- test_cmp expected.clean actual.clean
-'
-
-test_atom refs/tags/signed-short subject 'subject line'
-test_atom refs/tags/signed-short subject:sanitize 'subject-line'
-test_atom refs/tags/signed-short contents:subject 'subject line'
-test_atom refs/tags/signed-short body "$sig"
-test_atom refs/tags/signed-short contents:body ''
-test_atom refs/tags/signed-short contents:signature "$sig"
-test_atom refs/tags/signed-short contents "subject line
-$sig"
-
-test_expect_success GPG 'basic atom: refs/tags/signed-short raw' '
- git cat-file tag refs/tags/signed-short >expected &&
- git for-each-ref --format="%(raw)" refs/tags/signed-short >actual &&
- sanitize_pgp <expected >expected.clean &&
- echo >>expected.clean &&
- sanitize_pgp <actual >actual.clean &&
- test_cmp expected.clean actual.clean
-'
-
-test_atom refs/tags/signed-long subject 'subject line'
-test_atom refs/tags/signed-long subject:sanitize 'subject-line'
-test_atom refs/tags/signed-long contents:subject 'subject line'
-test_atom refs/tags/signed-long body "body contents
-$sig"
-test_atom refs/tags/signed-long contents:body 'body contents
-'
-test_atom refs/tags/signed-long contents:signature "$sig"
-test_atom refs/tags/signed-long contents "subject line
-
-body contents
-$sig"
-
-test_expect_success GPG 'basic atom: refs/tags/signed-long raw' '
- git cat-file tag refs/tags/signed-long >expected &&
- git for-each-ref --format="%(raw)" refs/tags/signed-long >actual &&
- sanitize_pgp <expected >expected.clean &&
- echo >>expected.clean &&
- sanitize_pgp <actual >actual.clean &&
- test_cmp expected.clean actual.clean
-'
-
-test_expect_success 'set up refs pointing to tree and blob' '
- git update-ref refs/mytrees/first refs/heads/main^{tree} &&
- git update-ref refs/myblobs/first refs/heads/main:one
-'
-
-test_atom refs/mytrees/first subject ""
-test_atom refs/mytrees/first contents:subject ""
-test_atom refs/mytrees/first body ""
-test_atom refs/mytrees/first contents:body ""
-test_atom refs/mytrees/first contents:signature ""
-test_atom refs/mytrees/first contents ""
-
-test_expect_success 'basic atom: refs/mytrees/first raw' '
- git cat-file tree refs/mytrees/first >expected &&
- echo >>expected &&
- git for-each-ref --format="%(raw)" refs/mytrees/first >actual &&
- test_cmp expected actual &&
- git cat-file -s refs/mytrees/first >expected &&
- git for-each-ref --format="%(raw:size)" refs/mytrees/first >actual &&
- test_cmp expected actual
-'
-
-test_atom refs/myblobs/first subject ""
-test_atom refs/myblobs/first contents:subject ""
-test_atom refs/myblobs/first body ""
-test_atom refs/myblobs/first contents:body ""
-test_atom refs/myblobs/first contents:signature ""
-test_atom refs/myblobs/first contents ""
-
-test_expect_success 'basic atom: refs/myblobs/first raw' '
- git cat-file blob refs/myblobs/first >expected &&
- echo >>expected &&
- git for-each-ref --format="%(raw)" refs/myblobs/first >actual &&
- test_cmp expected actual &&
- git cat-file -s refs/myblobs/first >expected &&
- git for-each-ref --format="%(raw:size)" refs/myblobs/first >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'set up refs pointing to binary blob' '
- printf "a\0b\0c" >blob1 &&
- printf "a\0c\0b" >blob2 &&
- printf "\0a\0b\0c" >blob3 &&
- printf "abc" >blob4 &&
- printf "\0 \0 \0 " >blob5 &&
- printf "\0 \0a\0 " >blob6 &&
- printf " " >blob7 &&
- >blob8 &&
- obj=$(git hash-object -w blob1) &&
- git update-ref refs/myblobs/blob1 "$obj" &&
- obj=$(git hash-object -w blob2) &&
- git update-ref refs/myblobs/blob2 "$obj" &&
- obj=$(git hash-object -w blob3) &&
- git update-ref refs/myblobs/blob3 "$obj" &&
- obj=$(git hash-object -w blob4) &&
- git update-ref refs/myblobs/blob4 "$obj" &&
- obj=$(git hash-object -w blob5) &&
- git update-ref refs/myblobs/blob5 "$obj" &&
- obj=$(git hash-object -w blob6) &&
- git update-ref refs/myblobs/blob6 "$obj" &&
- obj=$(git hash-object -w blob7) &&
- git update-ref refs/myblobs/blob7 "$obj" &&
- obj=$(git hash-object -w blob8) &&
- git update-ref refs/myblobs/blob8 "$obj"
-'
-
-test_expect_success 'Verify sorts with raw' '
- cat >expected <<-EOF &&
- refs/myblobs/blob8
- refs/myblobs/blob5
- refs/myblobs/blob6
- refs/myblobs/blob3
- refs/myblobs/blob7
- refs/mytrees/first
- refs/myblobs/first
- refs/myblobs/blob1
- refs/myblobs/blob2
- refs/myblobs/blob4
- refs/heads/main
- EOF
- git for-each-ref --format="%(refname)" --sort=raw \
- refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'Verify sorts with raw:size' '
- cat >expected <<-EOF &&
- refs/myblobs/blob8
- refs/myblobs/blob7
- refs/myblobs/blob4
- refs/myblobs/blob1
- refs/myblobs/blob2
- refs/myblobs/blob3
- refs/myblobs/blob5
- refs/myblobs/blob6
- refs/myblobs/first
- refs/mytrees/first
- refs/heads/main
- EOF
- git for-each-ref --format="%(refname)" --sort=raw:size \
- refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'validate raw atom with %(if:equals)' '
- cat >expected <<-EOF &&
- not equals
- not equals
- not equals
- not equals
- not equals
- not equals
- refs/myblobs/blob4
- not equals
- not equals
- not equals
- not equals
- not equals
- EOF
- git for-each-ref --format="%(if:equals=abc)%(raw)%(then)%(refname)%(else)not equals%(end)" \
- refs/myblobs/ refs/heads/ >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'validate raw atom with %(if:notequals)' '
- cat >expected <<-EOF &&
- refs/heads/ambiguous
- refs/heads/main
- refs/heads/newtag
- refs/myblobs/blob1
- refs/myblobs/blob2
- refs/myblobs/blob3
- equals
- refs/myblobs/blob5
- refs/myblobs/blob6
- refs/myblobs/blob7
- refs/myblobs/blob8
- refs/myblobs/first
- EOF
- git for-each-ref --format="%(if:notequals=abc)%(raw)%(then)%(refname)%(else)equals%(end)" \
- refs/myblobs/ refs/heads/ >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'empty raw refs with %(if)' '
- cat >expected <<-EOF &&
- refs/myblobs/blob1 not empty
- refs/myblobs/blob2 not empty
- refs/myblobs/blob3 not empty
- refs/myblobs/blob4 not empty
- refs/myblobs/blob5 not empty
- refs/myblobs/blob6 not empty
- refs/myblobs/blob7 empty
- refs/myblobs/blob8 empty
- refs/myblobs/first not empty
- EOF
- git for-each-ref --format="%(refname) %(if)%(raw)%(then)not empty%(else)empty%(end)" \
- refs/myblobs/ >actual &&
- test_cmp expected actual
-'
-
-test_expect_success '%(raw) with --python must fail' '
- test_must_fail git for-each-ref --format="%(raw)" --python
-'
-
-test_expect_success '%(raw) with --tcl must fail' '
- test_must_fail git for-each-ref --format="%(raw)" --tcl
-'
-
-test_expect_success PERL_TEST_HELPERS '%(raw) with --perl' '
- git for-each-ref --format="\$name= %(raw);
-print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual &&
- cmp blob1 actual &&
- git for-each-ref --format="\$name= %(raw);
-print \"\$name\"" refs/myblobs/blob3 --perl | perl >actual &&
- cmp blob3 actual &&
- git for-each-ref --format="\$name= %(raw);
-print \"\$name\"" refs/myblobs/blob8 --perl | perl >actual &&
- cmp blob8 actual &&
- git for-each-ref --format="\$name= %(raw);
-print \"\$name\"" refs/myblobs/first --perl | perl >actual &&
- cmp one actual &&
- git cat-file tree refs/mytrees/first > expected &&
- git for-each-ref --format="\$name= %(raw);
-print \"\$name\"" refs/mytrees/first --perl | perl >actual &&
- cmp expected actual
-'
-
-test_expect_success '%(raw) with --shell must fail' '
- test_must_fail git for-each-ref --format="%(raw)" --shell
-'
-
-test_expect_success '%(raw) with --shell and --sort=raw must fail' '
- test_must_fail git for-each-ref --format="%(raw)" --sort=raw --shell
-'
-
-test_expect_success '%(raw:size) with --shell' '
- git for-each-ref --format="%(raw:size)" | sed "s/^/$SQ/;s/$/$SQ/" >expect &&
- git for-each-ref --format="%(raw:size)" --shell >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'for-each-ref --format compare with cat-file --batch' '
- git rev-parse refs/mytrees/first | git cat-file --batch >expected &&
- git for-each-ref --format="%(objectname) %(objecttype) %(objectsize)
-%(raw)" refs/mytrees/first >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'verify sorts with contents:size' '
- cat >expect <<-\EOF &&
- refs/heads/main
- refs/heads/newtag
- refs/heads/ambiguous
- EOF
- git for-each-ref --format="%(refname)" \
- --sort=contents:size refs/heads/ >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'set up multiple-sort tags' '
- for when in 100000 200000
- do
- for email in user1 user2
- do
- for ref in ref1 ref2
- do
- GIT_COMMITTER_DATE="@$when +0000" \
- GIT_COMMITTER_EMAIL="$email@example.com" \
- git tag -m "tag $ref-$when-$email" \
- multi-$ref-$when-$email || return 1
- done
- done
- done
-'
-
-test_expect_success 'Verify sort with multiple keys' '
- cat >expected <<-\EOF &&
- 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
- 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
- 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
- 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
- 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
- 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
- 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
- 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
- EOF
- git for-each-ref \
- --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
- --sort=-refname \
- --sort=taggeremail \
- --sort=taggerdate \
- "refs/tags/multi-*" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'equivalent sorts fall back on refname' '
- cat >expected <<-\EOF &&
- 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
- 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
- 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
- 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
- 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
- 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
- 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
- 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
- EOF
- git for-each-ref \
- --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
- --sort=taggerdate \
- "refs/tags/multi-*" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success '--no-sort cancels the previous sort keys' '
- cat >expected <<-\EOF &&
- 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
- 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
- 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
- 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
- 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
- 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
- 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
- 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
- EOF
- git for-each-ref \
- --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
- --sort=-refname \
- --sort=taggeremail \
- --no-sort \
- --sort=taggerdate \
- "refs/tags/multi-*" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success '--no-sort without subsequent --sort prints expected refs' '
- cat >expected <<-\EOF &&
- refs/tags/multi-ref1-100000-user1
- refs/tags/multi-ref1-100000-user2
- refs/tags/multi-ref1-200000-user1
- refs/tags/multi-ref1-200000-user2
- refs/tags/multi-ref2-100000-user1
- refs/tags/multi-ref2-100000-user2
- refs/tags/multi-ref2-200000-user1
- refs/tags/multi-ref2-200000-user2
- EOF
-
- # Sort the results with `sort` for a consistent comparison against
- # expected
- git for-each-ref \
- --format="%(refname)" \
- --no-sort \
- "refs/tags/multi-*" | sort >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'set up custom date sorting' '
- # Dates:
- # - Wed Feb 07 2024 21:34:20 +0000
- # - Tue Dec 14 1999 00:05:22 +0000
- # - Fri Jun 04 2021 11:26:51 +0000
- # - Mon Jan 22 2007 16:44:01 GMT+0000
- i=1 &&
- for when in 1707341660 945129922 1622806011 1169484241
- do
- GIT_COMMITTER_DATE="@$when +0000" \
- GIT_COMMITTER_EMAIL="user@example.com" \
- git tag -m "tag $when" custom-dates-$i &&
- i=$(($i+1)) || return 1
- done
-'
-
-test_expect_success 'sort by date defaults to full timestamp' '
- cat >expected <<-\EOF &&
- 945129922 refs/tags/custom-dates-2
- 1169484241 refs/tags/custom-dates-4
- 1622806011 refs/tags/custom-dates-3
- 1707341660 refs/tags/custom-dates-1
- EOF
-
- git for-each-ref \
- --format="%(creatordate:unix) %(refname)" \
- --sort=creatordate \
- "refs/tags/custom-dates-*" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'sort by custom date format' '
- cat >expected <<-\EOF &&
- 00:05:22 refs/tags/custom-dates-2
- 11:26:51 refs/tags/custom-dates-3
- 16:44:01 refs/tags/custom-dates-4
- 21:34:20 refs/tags/custom-dates-1
- EOF
-
- git for-each-ref \
- --format="%(creatordate:format:%H:%M:%S) %(refname)" \
- --sort="creatordate:format:%H:%M:%S" \
- "refs/tags/custom-dates-*" >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
- test_when_finished "git checkout main" &&
- git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
- sed -e "s/^\* / /" actual >expect &&
- git checkout --orphan orphaned-branch &&
- git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
- test_cmp expect actual
-'
-
-cat >trailers <<EOF
-Reviewed-by: A U Thor <author@example.com>
-Signed-off-by: A U Thor <author@example.com>
-[ v2 updated patch description ]
-Acked-by: A U Thor
- <author@example.com>
-EOF
-
-unfold () {
- perl -0pe 's/\n\s+/ /g'
-}
-
-test_expect_success 'set up trailers for next test' '
- echo "Some contents" > two &&
- git add two &&
- git commit -F - <<-EOF
- trailers: this commit message has trailers
-
- Some message contents
-
- $(cat trailers)
- EOF
-'
-
-test_trailer_option () {
- if test "$#" -eq 3
- then
- prereq="$1"
- shift
- fi &&
- title=$1 option=$2
- cat >expect
- test_expect_success $prereq "$title" '
- git for-each-ref --format="%($option)" refs/heads/main >actual &&
- test_cmp expect actual &&
- git for-each-ref --format="%(contents:$option)" refs/heads/main >actual &&
- test_cmp expect actual
- '
-}
-
-test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) unfolds trailers' \
- 'trailers:unfold' <<-EOF
- $(unfold <trailers)
-
- EOF
-
-test_trailer_option '%(trailers:only) shows only "key: value" trailers' \
- 'trailers:only' <<-EOF
- $(grep -v patch.description <trailers)
-
- EOF
-
-test_trailer_option '%(trailers:only=no,only=true) shows only "key: value" trailers' \
- 'trailers:only=no,only=true' <<-EOF
- $(grep -v patch.description <trailers)
-
- EOF
-
-test_trailer_option '%(trailers:only=yes) shows only "key: value" trailers' \
- 'trailers:only=yes' <<-EOF
- $(grep -v patch.description <trailers)
-
- EOF
-
-test_trailer_option '%(trailers:only=no) shows all trailers' \
- 'trailers:only=no' <<-EOF
- $(cat trailers)
-
- EOF
-
-test_trailer_option PERL_TEST_HELPERS '%(trailers:only) and %(trailers:unfold) work together' \
- 'trailers:only,unfold' <<-EOF
- $(grep -v patch.description <trailers | unfold)
-
- EOF
-
-test_trailer_option PERL_TEST_HELPERS '%(trailers:unfold) and %(trailers:only) work together' \
- 'trailers:unfold,only' <<-EOF
- $(grep -v patch.description <trailers | unfold)
-
- EOF
-
-test_trailer_option '%(trailers:key=foo) shows that trailer' \
- 'trailers:key=Signed-off-by' <<-EOF
- Signed-off-by: A U Thor <author@example.com>
-
- EOF
-
-test_trailer_option '%(trailers:key=foo) is case insensitive' \
- 'trailers:key=SiGned-oFf-bY' <<-EOF
- Signed-off-by: A U Thor <author@example.com>
-
- EOF
-
-test_trailer_option '%(trailers:key=foo:) trailing colon also works' \
- 'trailers:key=Signed-off-by:' <<-EOF
- Signed-off-by: A U Thor <author@example.com>
-
- EOF
-
-test_trailer_option '%(trailers:key=foo) multiple keys' \
- 'trailers:key=Reviewed-by:,key=Signed-off-by' <<-EOF
- Reviewed-by: A U Thor <author@example.com>
- Signed-off-by: A U Thor <author@example.com>
-
- EOF
-
-test_trailer_option '%(trailers:key=nonexistent) becomes empty' \
- 'trailers:key=Shined-off-by:' <<-EOF
-
- EOF
-
-test_trailer_option '%(trailers:key=foo) handles multiple lines even if folded' \
- 'trailers:key=Acked-by' <<-EOF
- $(grep -v patch.description <trailers | grep -v Signed-off-by | grep -v Reviewed-by)
-
- EOF
-
-test_trailer_option '%(trailers:key=foo,unfold) properly unfolds' \
- 'trailers:key=Signed-Off-by,unfold' <<-EOF
- $(unfold <trailers | grep Signed-off-by)
-
- EOF
-
-test_trailer_option '%(trailers:key=foo,only=no) also includes nontrailer lines' \
- 'trailers:key=Signed-off-by,only=no' <<-EOF
- Signed-off-by: A U Thor <author@example.com>
- $(grep patch.description <trailers)
-
- EOF
-
-test_trailer_option '%(trailers:key=foo,valueonly) shows only value' \
- 'trailers:key=Signed-off-by,valueonly' <<-EOF
- A U Thor <author@example.com>
-
- EOF
-
-test_trailer_option '%(trailers:separator) changes separator' \
- 'trailers:separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
- Reviewed-by: A U Thor <author@example.com>,Signed-off-by: A U Thor <author@example.com>
- EOF
-
-test_trailer_option '%(trailers:key_value_separator) changes key-value separator' \
- 'trailers:key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
- Reviewed-by,A U Thor <author@example.com>
- Signed-off-by,A U Thor <author@example.com>
-
- EOF
-
-test_trailer_option '%(trailers:separator,key_value_separator) changes both separators' \
- 'trailers:separator=%x2C,key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
- Reviewed-by,A U Thor <author@example.com>,Signed-off-by,A U Thor <author@example.com>
- EOF
-
-test_expect_success 'multiple %(trailers) use their own options' '
- git tag -F - tag-with-trailers <<-\EOF &&
- body
-
- one: foo
- one: bar
- two: baz
- two: qux
- EOF
- t1="%(trailers:key=one,key_value_separator=W,separator=X)" &&
- t2="%(trailers:key=two,key_value_separator=Y,separator=Z)" &&
- git for-each-ref --format="$t1%0a$t2" refs/tags/tag-with-trailers >actual &&
- cat >expect <<-\EOF &&
- oneWfooXoneWbar
- twoYbazZtwoYqux
- EOF
- test_cmp expect actual
-'
-
-test_failing_trailer_option () {
- title=$1 option=$2
- cat >expect
- test_expect_success "$title" '
- # error message cannot be checked under i18n
- test_must_fail git for-each-ref --format="%($option)" refs/heads/main 2>actual &&
- test_cmp expect actual &&
- test_must_fail git for-each-ref --format="%(contents:$option)" refs/heads/main 2>actual &&
- test_cmp expect actual
- '
-}
-
-test_failing_trailer_option '%(trailers) rejects unknown trailers arguments' \
- 'trailers:unsupported' <<-\EOF
- fatal: unknown %(trailers) argument: unsupported
- EOF
-
-test_failing_trailer_option '%(trailers:key) without value is error' \
- 'trailers:key' <<-\EOF
- fatal: expected %(trailers:key=<value>)
- EOF
-
-test_expect_success 'if arguments, %(contents:trailers) shows error if colon is missing' '
- cat >expect <<-EOF &&
- fatal: unrecognized %(contents) argument: trailersonly
- EOF
- test_must_fail git for-each-ref --format="%(contents:trailersonly)" 2>actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'basic atom: head contents:trailers' '
- git for-each-ref --format="%(contents:trailers)" refs/heads/main >actual &&
- sanitize_pgp <actual >actual.clean &&
- # git for-each-ref ends with a blank line
- cat >expect <<-EOF &&
- $(cat trailers)
-
- EOF
- test_cmp expect actual.clean
-'
-
-test_expect_success 'basic atom: rest must fail' '
- test_must_fail git for-each-ref --format="%(rest)" refs/heads/main
-'
-
-test_expect_success 'HEAD atom does not take arguments' '
- test_must_fail git for-each-ref --format="%(HEAD:foo)" 2>err &&
- echo "fatal: %(HEAD) does not take arguments" >expect &&
- test_cmp expect err
-'
-
-test_expect_success 'subject atom rejects unknown arguments' '
- test_must_fail git for-each-ref --format="%(subject:foo)" 2>err &&
- echo "fatal: unrecognized %(subject) argument: foo" >expect &&
- test_cmp expect err
-'
-
-test_expect_success 'refname atom rejects unknown arguments' '
- test_must_fail git for-each-ref --format="%(refname:foo)" 2>err &&
- echo "fatal: unrecognized %(refname) argument: foo" >expect &&
- test_cmp expect err
-'
-
-test_expect_success 'trailer parsing not fooled by --- line' '
- git commit --allow-empty -F - <<-\EOF &&
- this is the subject
-
- This is the body. The message has a "---" line which would confuse a
- message+patch parser. But here we know we have only a commit message,
- so we get it right.
-
- trailer: wrong
- ---
- This is more body.
-
- trailer: right
- EOF
-
- {
- echo "trailer: right" &&
- echo
- } >expect &&
- git for-each-ref --format="%(trailers)" refs/heads/main >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'Add symbolic ref for the following tests' '
- git symbolic-ref refs/heads/sym refs/heads/main
-'
-
-cat >expected <<EOF
-refs/heads/main
-EOF
-
-test_expect_success 'Verify usage of %(symref) atom' '
- git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<EOF
-heads/main
-EOF
-
-test_expect_success 'Verify usage of %(symref:short) atom' '
- git for-each-ref --format="%(symref:short)" refs/heads/sym >actual &&
- test_cmp expected actual
-'
-
-cat >expected <<EOF
-main
-heads/main
-EOF
-
-test_expect_success 'Verify usage of %(symref:lstrip) atom' '
- git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
- git for-each-ref --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
- test_cmp expected actual &&
-
- git for-each-ref --format="%(symref:strip=2)" refs/heads/sym > actual &&
- git for-each-ref --format="%(symref:strip=-2)" refs/heads/sym >> actual &&
- test_cmp expected actual
-'
-
-cat >expected <<EOF
-refs
-refs/heads
-EOF
-
-test_expect_success 'Verify usage of %(symref:rstrip) atom' '
- git for-each-ref --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
- git for-each-ref --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
- test_cmp expected actual
-'
-
-test_expect_success ':remotename and :remoteref' '
- git init remote-tests &&
- (
- cd remote-tests &&
- test_commit initial &&
- git branch -M main &&
- git remote add from fifth.coffee:blub &&
- git config branch.main.remote from &&
- git config branch.main.merge refs/heads/stable &&
- git remote add to southridge.audio:repo &&
- git config remote.to.push "refs/heads/*:refs/heads/pushed/*" &&
- git config branch.main.pushRemote to &&
- for pair in "%(upstream)=refs/remotes/from/stable" \
- "%(upstream:remotename)=from" \
- "%(upstream:remoteref)=refs/heads/stable" \
- "%(push)=refs/remotes/to/pushed/main" \
- "%(push:remotename)=to" \
- "%(push:remoteref)=refs/heads/pushed/main"
- do
- echo "${pair#*=}" >expect &&
- git for-each-ref --format="${pair%=*}" \
- refs/heads/main >actual &&
- test_cmp expect actual || exit 1
- done &&
- git branch push-simple &&
- git config branch.push-simple.pushRemote from &&
- actual="$(git for-each-ref \
- --format="%(push:remotename),%(push:remoteref)" \
- refs/heads/push-simple)" &&
- test from, = "$actual"
- )
-'
-
-test_expect_success 'for-each-ref --ignore-case ignores case' '
- git for-each-ref --format="%(refname)" refs/heads/MAIN >actual &&
- test_must_be_empty actual &&
-
- echo refs/heads/main >expect &&
- git for-each-ref --format="%(refname)" --ignore-case \
- refs/heads/MAIN >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'for-each-ref --omit-empty works' '
- git for-each-ref --format="%(refname)" >actual &&
- test_line_count -gt 1 actual &&
- git for-each-ref --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual &&
- echo refs/heads/main >expect &&
- test_cmp expect actual
-'
-
-test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '
- # name refs numerically to avoid case-insensitive filesystem conflicts
- nr=0 &&
- for email in a A b B
- do
- for subject in a A b B
- do
- GIT_COMMITTER_EMAIL="$email@example.com" \
- git tag -m "tag $subject" icase-$(printf %02d $nr) &&
- nr=$((nr+1))||
- return 1
- done
- done &&
- git for-each-ref --ignore-case \
- --format="%(taggeremail) %(subject) %(refname)" \
- --sort=refname \
- --sort=subject \
- --sort=taggeremail \
- refs/tags/icase-* >actual &&
- cat >expect <<-\EOF &&
- <a@example.com> tag a refs/tags/icase-00
- <a@example.com> tag A refs/tags/icase-01
- <A@example.com> tag a refs/tags/icase-04
- <A@example.com> tag A refs/tags/icase-05
- <a@example.com> tag b refs/tags/icase-02
- <a@example.com> tag B refs/tags/icase-03
- <A@example.com> tag b refs/tags/icase-06
- <A@example.com> tag B refs/tags/icase-07
- <b@example.com> tag a refs/tags/icase-08
- <b@example.com> tag A refs/tags/icase-09
- <B@example.com> tag a refs/tags/icase-12
- <B@example.com> tag A refs/tags/icase-13
- <b@example.com> tag b refs/tags/icase-10
- <b@example.com> tag B refs/tags/icase-11
- <B@example.com> tag b refs/tags/icase-14
- <B@example.com> tag B refs/tags/icase-15
- EOF
- test_cmp expect actual
-'
-
-test_expect_success 'for-each-ref reports broken tags' '
- git tag -m "good tag" broken-tag-good HEAD &&
- git cat-file tag broken-tag-good >good &&
- sed s/commit/blob/ <good >bad &&
- bad=$(git hash-object -w -t tag bad) &&
- git update-ref refs/tags/broken-tag-bad $bad &&
- test_must_fail git for-each-ref --format="%(*objectname)" \
- refs/tags/broken-tag-*
-'
-
-test_expect_success 'set up tag with signature and no blank lines' '
- git tag -F - fake-sig-no-blanks <<-\EOF
- this is the subject
- -----BEGIN PGP SIGNATURE-----
- not a real signature, but we just care about the
- subject/body parsing. It is important here that
- there are no blank lines in the signature.
- -----END PGP SIGNATURE-----
- EOF
-'
-
-test_atom refs/tags/fake-sig-no-blanks contents:subject 'this is the subject'
-test_atom refs/tags/fake-sig-no-blanks contents:body ''
-test_atom refs/tags/fake-sig-no-blanks contents:signature "$sig"
-
-test_expect_success 'set up tag with CRLF signature' '
- append_cr <<-\EOF |
- this is the subject
- -----BEGIN PGP SIGNATURE-----
-
- not a real signature, but we just care about
- the subject/body parsing. It is important here
- that there is a blank line separating this
- from the signature header.
- -----END PGP SIGNATURE-----
- EOF
- git tag -F - --cleanup=verbatim fake-sig-crlf
-'
-
-test_atom refs/tags/fake-sig-crlf contents:subject 'this is the subject'
-test_atom refs/tags/fake-sig-crlf contents:body ''
-
-# CRLF is retained in the signature, so we have to pass our expected value
-# through append_cr. But test_atom requires a shell string, which means command
-# substitution, and the shell will strip trailing newlines from the output of
-# the substitution. Hack around it by adding and then removing a dummy line.
-sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)"
-sig_crlf=${sig_crlf%dummy}
-test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf"
-
-test_expect_success 'set up tag with signature and trailers' '
- git tag -F - fake-sig-trailer <<-\EOF
- this is the subject
-
- this is the body
-
- My-Trailer: foo
- -----BEGIN PGP SIGNATURE-----
-
- not a real signature, but we just care about the
- subject/body/trailer parsing.
- -----END PGP SIGNATURE-----
- EOF
-'
-
-# use "separator=" here to suppress the terminating newline
-test_atom refs/tags/fake-sig-trailer trailers:separator= 'My-Trailer: foo'
-
-test_expect_success 'git for-each-ref --stdin: empty' '
- >in &&
- git for-each-ref --format="%(refname)" --stdin <in >actual &&
- git for-each-ref --format="%(refname)" >expect &&
- test_cmp expect actual
-'
-
-test_expect_success 'git for-each-ref --stdin: fails if extra args' '
- >in &&
- test_must_fail git for-each-ref --format="%(refname)" \
- --stdin refs/heads/extra <in 2>err &&
- grep "unknown arguments supplied with --stdin" err
-'
-
-test_expect_success 'git for-each-ref --stdin: matches' '
- cat >in <<-EOF &&
- refs/tags/multi*
- refs/heads/amb*
- EOF
-
- cat >expect <<-EOF &&
- refs/heads/ambiguous
- refs/tags/multi-ref1-100000-user1
- refs/tags/multi-ref1-100000-user2
- refs/tags/multi-ref1-200000-user1
- refs/tags/multi-ref1-200000-user2
- refs/tags/multi-ref2-100000-user1
- refs/tags/multi-ref2-100000-user2
- refs/tags/multi-ref2-200000-user1
- refs/tags/multi-ref2-200000-user2
- refs/tags/multiline
- EOF
-
- git for-each-ref --format="%(refname)" --stdin <in >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'git for-each-ref with non-existing refs' '
- cat >in <<-EOF &&
- refs/heads/this-ref-does-not-exist
- refs/tags/bogus
- EOF
-
- git for-each-ref --format="%(refname)" --stdin <in >actual &&
- test_must_be_empty actual &&
-
- xargs git for-each-ref --format="%(refname)" <in >actual &&
- test_must_be_empty actual
-'
-
-test_expect_success 'git for-each-ref with nested tags' '
- git tag -am "Normal tag" nested/base HEAD &&
- git tag -am "Nested tag" nested/nest1 refs/tags/nested/base &&
- git tag -am "Double nested tag" nested/nest2 refs/tags/nested/nest1 &&
-
- head_oid="$(git rev-parse HEAD)" &&
- base_tag_oid="$(git rev-parse refs/tags/nested/base)" &&
- nest1_tag_oid="$(git rev-parse refs/tags/nested/nest1)" &&
- nest2_tag_oid="$(git rev-parse refs/tags/nested/nest2)" &&
-
- cat >expect <<-EOF &&
- refs/tags/nested/base $base_tag_oid tag $head_oid commit
- refs/tags/nested/nest1 $nest1_tag_oid tag $head_oid commit
- refs/tags/nested/nest2 $nest2_tag_oid tag $head_oid commit
- EOF
-
- git for-each-ref \
- --format="%(refname) %(objectname) %(objecttype) %(*objectname) %(*objecttype)" \
- refs/tags/nested/ >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'is-base atom with non-commits' '
- git for-each-ref --format="%(is-base:HEAD) %(refname)" >out 2>err &&
- grep "(HEAD) refs/heads/main" out &&
-
- test_line_count = 2 err &&
- grep "error: object .* is a commit, not a blob" err &&
- grep "error: bad tag pointer to" err
-'
-
-GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
-TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
-
-test_expect_success GPG 'setup for signature atom using gpg' '
- git checkout -b signed &&
-
- test_when_finished "test_unconfig commit.gpgSign" &&
-
- echo "1" >file &&
- git add file &&
- test_tick &&
- git commit -S -m "file: 1" &&
- git tag first-signed &&
-
- echo "2" >file &&
- test_tick &&
- git commit -a -m "file: 2" &&
- git tag second-unsigned &&
-
- git config commit.gpgSign 1 &&
- echo "3" >file &&
- test_tick &&
- git commit -a --no-gpg-sign -m "file: 3" &&
- git tag third-unsigned &&
-
- test_tick &&
- git rebase -f HEAD^^ && git tag second-signed HEAD^ &&
- git tag third-signed &&
-
- echo "4" >file &&
- test_tick &&
- git commit -a -SB7227189 -m "file: 4" &&
- git tag fourth-signed &&
-
- echo "5" >file &&
- test_tick &&
- git commit -a --no-gpg-sign -m "file: 5" &&
- git tag fifth-unsigned &&
-
- echo "6" >file &&
- test_tick &&
- git commit -a --no-gpg-sign -m "file: 6" &&
-
- test_tick &&
- git rebase -f HEAD^^ &&
- git tag fifth-signed HEAD^ &&
- git tag sixth-signed &&
-
- echo "7" >file &&
- test_tick &&
- git commit -a --no-gpg-sign -m "file: 7" &&
- git tag seventh-unsigned
-'
-
-test_expect_success GPGSSH 'setup for signature atom using ssh' '
- test_when_finished "test_unconfig gpg.format user.signingkey" &&
-
- test_config gpg.format ssh &&
- test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
- echo "8" >file &&
- test_tick &&
- git add file &&
- git commit -S -m "file: 8" &&
- git tag eighth-signed-ssh
-'
-
-test_expect_success GPG2 'bare signature atom' '
- git verify-commit first-signed 2>expect &&
- echo >>expect &&
- git for-each-ref refs/tags/first-signed \
- --format="%(signature)" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'show good signature with custom format' '
- git verify-commit first-signed &&
- cat >expect <<-\EOF &&
- G
- 13B6F51ECDDE430D
- C O Mitter <committer@example.com>
- 73D758744BE721698EC54E8713B6F51ECDDE430D
- 73D758744BE721698EC54E8713B6F51ECDDE430D
- EOF
- git for-each-ref refs/tags/first-signed \
- --format="$GRADE_FORMAT" >actual &&
- test_cmp expect actual
-'
-test_expect_success GPGSSH 'show good signature with custom format with ssh' '
- test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
- FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
- cat >expect.tmpl <<-\EOF &&
- G
- FINGERPRINT
- principal with number 1
- FINGERPRINT
-
- EOF
- sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect &&
- git for-each-ref refs/tags/eighth-signed-ssh \
- --format="$GRADE_FORMAT" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'signature atom with grade option and bad signature' '
- git cat-file commit third-signed >raw &&
- sed -e "s/^file: 3/file: 3 forged/" raw >forged1 &&
- FORGED1=$(git hash-object -w -t commit forged1) &&
- git update-ref refs/tags/third-signed "$FORGED1" &&
- test_must_fail git verify-commit "$FORGED1" &&
-
- cat >expect <<-\EOF &&
- B
- 13B6F51ECDDE430D
- C O Mitter <committer@example.com>
-
-
- EOF
- git for-each-ref refs/tags/third-signed \
- --format="$GRADE_FORMAT" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'show untrusted signature with custom format' '
- cat >expect <<-\EOF &&
- U
- 65A0EEA02E30CAD7
- Eris Discordia <discord@example.net>
- F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
- D4BE22311AD3131E5EDA29A461092E85B7227189
- EOF
- git for-each-ref refs/tags/fourth-signed \
- --format="$GRADE_FORMAT" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'show untrusted signature with undefined trust level' '
- cat >expect <<-\EOF &&
- undefined
- 65A0EEA02E30CAD7
- Eris Discordia <discord@example.net>
- F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
- D4BE22311AD3131E5EDA29A461092E85B7227189
- EOF
- git for-each-ref refs/tags/fourth-signed \
- --format="$TRUSTLEVEL_FORMAT" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'show untrusted signature with ultimate trust level' '
- cat >expect <<-\EOF &&
- ultimate
- 13B6F51ECDDE430D
- C O Mitter <committer@example.com>
- 73D758744BE721698EC54E8713B6F51ECDDE430D
- 73D758744BE721698EC54E8713B6F51ECDDE430D
- EOF
- git for-each-ref refs/tags/sixth-signed \
- --format="$TRUSTLEVEL_FORMAT" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'show unknown signature with custom format' '
- cat >expect <<-\EOF &&
- E
- 13B6F51ECDDE430D
-
-
-
- EOF
- GNUPGHOME="$GNUPGHOME_NOT_USED" git for-each-ref \
- refs/tags/sixth-signed --format="$GRADE_FORMAT" >actual &&
- test_cmp expect actual
-'
-
-test_expect_success GPG 'show lack of signature with custom format' '
- cat >expect <<-\EOF &&
- N
-
-
-
-
- EOF
- git for-each-ref refs/tags/seventh-unsigned \
- --format="$GRADE_FORMAT" >actual &&
- test_cmp expect actual
-'
+. "$TEST_DIRECTORY"/for-each-ref-tests.sh
test_done
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index bb02b86c16..9b80ea1e3b 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -541,4 +541,217 @@ test_expect_success 'validate worktree atom' '
test_cmp expect actual
'
+test_expect_success 'start after with empty value' '
+ cat >expect <<-\EOF &&
+ refs/heads/main
+ refs/heads/main_worktree
+ refs/heads/side
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after="" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after a specific reference' '
+ cat >expect <<-\EOF &&
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/spot >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after a specific reference with partial match' '
+ cat >expect <<-\EOF &&
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/sp >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after, just behind a specific reference' '
+ cat >expect <<-\EOF &&
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/parrot >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after with specific directory match' '
+ cat >expect <<-\EOF &&
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after with specific directory and trailing slash' '
+ cat >expect <<-\EOF &&
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/ >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after, just behind a specific directory' '
+ cat >expect <<-\EOF &&
+ refs/odd/spot
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/lost >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after, overflow specific reference length' '
+ cat >expect <<-\EOF &&
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/spotnew >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after, overflow specific reference path' '
+ cat >expect <<-\EOF &&
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/spot/new >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after, with exclude pattern' '
+ cat >expect <<-\EOF &&
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10
+ refs/tags/foo1.3
+ refs/tags/foo1.6
+ refs/tags/four
+ refs/tags/one
+ refs/tags/signed-tag
+ refs/tags/three
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/odd/spot \
+ --exclude=refs/tags/foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after, last reference' '
+ cat >expect <<-\EOF &&
+ EOF
+ git for-each-ref --format="%(refname)" --start-after=refs/tags/two >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after used with a pattern' '
+ cat >expect <<-\EOF &&
+ fatal: cannot use --start-after with patterns
+ EOF
+ test_must_fail git for-each-ref --format="%(refname)" --start-after=refs/odd/spot refs/tags 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'start after used with custom sort order' '
+ cat >expect <<-\EOF &&
+ fatal: cannot use --start-after with custom sort options
+ EOF
+ test_must_fail git for-each-ref --format="%(refname)" --start-after=refs/odd/spot --sort=author 2>actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh
index f48ed6d035..533ac85dc8 100755
--- a/t/t6423-merge-rename-directories.sh
+++ b/t/t6423-merge-rename-directories.sh
@@ -4731,7 +4731,7 @@ test_setup_12i () {
mkdir -p source/subdir &&
echo foo >source/subdir/foo &&
- echo bar >source/bar &&
+ printf "%d\n" 1 2 3 4 5 6 7 >source/bar &&
echo baz >source/baz &&
git add source &&
git commit -m orig &&
@@ -4747,6 +4747,7 @@ test_setup_12i () {
git switch B &&
git mv source/bar source/subdir/bar &&
echo more baz >>source/baz &&
+ git add source/baz &&
git commit -m B
)
}
@@ -4758,6 +4759,88 @@ test_expect_success '12i: Directory rename causes rename-to-self' '
git checkout A^0 &&
+ # NOTE: A potentially better resolution would be for
+ # source/bar -> source/subdir/bar
+ # to use the directory rename to become
+ # source/bar -> source/bar
+ # (a rename to self), and thus we end up with bar with
+ # a path conflict (given merge.directoryRenames=conflict).
+ # However, since the relevant renames optimization
+ # prevents us from noticing
+ # source/bar -> source/subdir/bar
+ # as a rename and looking at it just as
+ # delete source/bar
+ # add source/subdir/bar
+ # the directory rename of source/subdir/bar -> source/bar does
+ # not look like a rename-to-self situation but a
+ # rename-on-top-of-other-file situation. We do not want
+ # stage 1 entries from an unrelated file, so we expect an
+ # error about there being a file in the way.
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 >out &&
+
+ grep "CONFLICT (implicit dir rename).*source/bar in the way" out &&
+ test_path_is_missing source/bar &&
+ test_path_is_file source/subdir/bar &&
+ test_path_is_file source/baz &&
+
+ git ls-files >actual &&
+ uniq <actual >tracked &&
+ test_line_count = 3 tracked &&
+
+ git status --porcelain -uno >actual &&
+ cat >expect <<-\EOF &&
+ M source/baz
+ R source/bar -> source/subdir/bar
+ EOF
+ test_cmp expect actual
+ )
+'
+
+# Testcase 12i2, Identical to 12i except that source/subdir/bar modified on unrenamed side
+# Commit O: source/{subdir/foo, bar, baz_1}
+# Commit A: source/{foo, bar_2, baz_1}
+# Commit B: source/{subdir/{foo, bar}, baz_2}
+# Expected: source/{foo, bar, baz_2}, with conflicts on
+# source/bar vs. source/subdir/bar
+
+test_setup_12i2 () {
+ git init 12i2 &&
+ (
+ cd 12i2 &&
+
+ mkdir -p source/subdir &&
+ echo foo >source/subdir/foo &&
+ printf "%d\n" 1 2 3 4 5 6 7 >source/bar &&
+ echo baz >source/baz &&
+ git add source &&
+ git commit -m orig &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git mv source/subdir/foo source/foo &&
+ echo 8 >> source/bar &&
+ git add source/bar &&
+ git commit -m A &&
+
+ git switch B &&
+ git mv source/bar source/subdir/bar &&
+ echo more baz >>source/baz &&
+ git add source/baz &&
+ git commit -m B
+ )
+}
+
+test_expect_success '12i2: Directory rename causes rename-to-self' '
+ test_setup_12i2 &&
+ (
+ cd 12i2 &&
+
+ git checkout A^0 &&
+
test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
test_path_is_missing source/subdir &&
@@ -4771,7 +4854,7 @@ test_expect_success '12i: Directory rename causes rename-to-self' '
git status --porcelain -uno >actual &&
cat >expect <<-\EOF &&
UU source/bar
- M source/baz
+ M source/baz
EOF
test_cmp expect actual
)
@@ -4806,6 +4889,7 @@ test_setup_12j () {
git switch B &&
git mv bar subdir/bar &&
echo more baz >>baz &&
+ git add baz &&
git commit -m B
)
}
@@ -4817,10 +4901,29 @@ test_expect_success '12j: Directory rename to root causes rename-to-self' '
git checkout A^0 &&
- test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
-
- test_path_is_missing subdir &&
- test_path_is_file bar &&
+ # NOTE: A potentially better resolution would be for
+ # bar -> subdir/bar
+ # to use the directory rename to become
+ # bar -> bar
+ # (a rename to self), and thus we end up with bar with
+ # a path conflict (given merge.directoryRenames=conflict).
+ # However, since the relevant renames optimization
+ # prevents us from noticing
+ # bar -> subdir/bar
+ # as a rename and looking at it just as
+ # delete bar
+ # add subdir/bar
+ # the directory rename of subdir/bar -> bar does not look
+ # like a rename-to-self situation but a
+ # rename-on-top-of-other-file situation. We do not want
+ # stage 1 entries from an unrelated file, so we expect an
+ # error about there being a file in the way.
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 >out &&
+ grep "CONFLICT (implicit dir rename).*bar in the way" out &&
+
+ test_path_is_missing bar &&
+ test_path_is_file subdir/bar &&
test_path_is_file baz &&
git ls-files >actual &&
@@ -4829,8 +4932,8 @@ test_expect_success '12j: Directory rename to root causes rename-to-self' '
git status --porcelain -uno >actual &&
cat >expect <<-\EOF &&
- UU bar
- M baz
+ M baz
+ R bar -> subdir/bar
EOF
test_cmp expect actual
)
@@ -4865,6 +4968,7 @@ test_setup_12k () {
git switch B &&
git mv dirA/bar dirB/bar &&
echo more baz >>dirA/baz &&
+ git add dirA/baz &&
git commit -m B
)
}
@@ -4876,10 +4980,29 @@ test_expect_success '12k: Directory rename with sibling causes rename-to-self' '
git checkout A^0 &&
- test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 &&
-
- test_path_is_missing dirB &&
- test_path_is_file dirA/bar &&
+ # NOTE: A potentially better resolution would be for
+ # dirA/bar -> dirB/bar
+ # to use the directory rename (dirB/ -> dirA/) to become
+ # dirA/bar -> dirA/bar
+ # (a rename to self), and thus we end up with bar with
+ # a path conflict (given merge.directoryRenames=conflict).
+ # However, since the relevant renames optimization
+ # prevents us from noticing
+ # dirA/bar -> dirB/bar
+ # as a rename and looking at it just as
+ # delete dirA/bar
+ # add dirB/bar
+ # the directory rename of dirA/bar -> dirB/bar does
+ # not look like a rename-to-self situation but a
+ # rename-on-top-of-other-file situation. We do not want
+ # stage 1 entries from an unrelated file, so we expect an
+ # error about there being a file in the way.
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 >out &&
+ grep "CONFLICT (implicit dir rename).*dirA/bar in the way" out &&
+
+ test_path_is_missing dirA/bar &&
+ test_path_is_file dirB/bar &&
test_path_is_file dirA/baz &&
git ls-files >actual &&
@@ -4888,8 +5011,8 @@ test_expect_success '12k: Directory rename with sibling causes rename-to-self' '
git status --porcelain -uno >actual &&
cat >expect <<-\EOF &&
- UU dirA/bar
- M dirA/baz
+ M dirA/baz
+ R dirA/bar -> dirB/bar
EOF
test_cmp expect actual
)
@@ -5056,6 +5179,25 @@ test_expect_success '12m: Change parent of renamed-dir to symlink on other side'
)
'
+# Testcase 12n, Directory rename transitively makes rename back to self
+#
+# (Since this is a cherry-pick instead of merge, the labels are a bit weird.
+# O, the original commit, is A~1 rather than what branch O points to.)
+#
+# Commit O: tools/hello
+# world
+# Commit A: tools/hello
+# tools/world
+# Commit B: hello
+# In words:
+# A: world -> tools/world
+# B: tools/ -> /, i.e. rename all of tools to toplevel directory
+# delete world
+#
+# Expected:
+# CONFLICT (file location): tools/world vs. world
+#
+
test_setup_12n () {
git init 12n &&
(
@@ -5092,10 +5234,357 @@ test_expect_success '12n: Directory rename transitively makes rename back to sel
git checkout -q B^0 &&
test_must_fail git cherry-pick A^0 >out &&
- grep "CONFLICT (file location).*should perhaps be moved" out
+ test_grep "CONFLICT (file location).*should perhaps be moved" out &&
+
+ # Should have 1 entry for hello, and 2 for world
+ test_stdout_line_count = 3 git ls-files -s &&
+ test_stdout_line_count = 1 git ls-files -s hello &&
+ test_stdout_line_count = 2 git ls-files -s world
+ )
+'
+
+# Testcase 12n2, Directory rename transitively makes rename back to self
+#
+# Commit O: tools/hello
+# world
+# Commit A: tools/hello
+# tools/world
+# Commit B: hello
+# In words:
+# A: world -> tools/world
+# B: tools/ -> /, i.e. rename all of tools to toplevel directory
+# delete world
+#
+# Expected:
+# CONFLICT (file location): tools/world vs. world
+#
+
+test_setup_12n2 () {
+ git init 12n2 &&
+ (
+ cd 12n2 &&
+
+ mkdir tools &&
+ echo hello >tools/hello &&
+ git add tools/hello &&
+ echo world >world &&
+ git add world &&
+ git commit -m "O" &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git mv world tools/world &&
+ git commit -m "Move world into tools/" &&
+
+ git switch B &&
+ git mv tools/hello hello &&
+ git rm world &&
+ git commit -m "Move hello from tools/ to toplevel"
+ )
+}
+
+test_expect_success '12n2: Directory rename transitively makes rename back to self' '
+ test_setup_12n2 &&
+ (
+ cd 12n2 &&
+
+ git checkout -q B^0 &&
+
+ test_might_fail git -c merge.directoryRenames=true merge A^0 >out &&
+
+ # Should have 1 entry for hello, and either 0 or 2 for world
+ #
+ # NOTE: Since merge.directoryRenames=true, there is no path
+ # conflict for world vs. tools/world; it should end up at
+ # world. The fact that world was unmodified on side A, means
+ # there was no content conflict; we should just take the
+ # content from side B -- i.e. delete the file. So merging
+ # could just delete world.
+ #
+ # However, rename-to-self-via-directory-rename is a bit more
+ # challenging. Relax this test to allow world to be treated
+ # as a modify/delete conflict as well, meaning it will have
+ # two higher order stages, that just so happen to match.
+ #
+ test_stdout_line_count = 1 git ls-files -s hello &&
+ test_stdout_line_count = 2 git ls-files -s world &&
+ test_grep "CONFLICT (modify/delete).*world deleted in HEAD" out
)
'
+# Testcase 12o, Directory rename hits other rename source; file still in way on same side
+# Commit O: A/file1_1
+# A/stuff
+# B/file1_2
+# B/stuff
+# C/other
+# Commit A: A/file1_1
+# A/stuff
+# B/stuff
+# C/file1_2
+# C/other
+# Commit B: D/file2_1
+# A/stuff
+# B/file1_2
+# B/stuff
+# A/other
+# In words:
+# A: rename B/file1_2 -> C/file1_2
+# B: rename C/ -> A/
+# rename A/file1_1 -> D/file2_1
+# Rationale:
+# A/stuff is unmodified, it shows up in final output
+# B/stuff is unmodified, it shows up in final output
+# C/other touched on one side (rename to A), so A/other shows up in output
+# A/file1 is renamed to D/file2
+# B/file1 -> C/file1 and even though C/ -> A/, A/file1 is
+# "in the way" so we don't do the directory rename
+# Expected: A/stuff
+# B/stuff
+# A/other
+# D/file2
+# C/file1
+# + CONFLICT (implicit dir rename): A/file1 in way of C/file1
+#
+
+test_setup_12o () {
+ git init 12o &&
+ (
+ cd 12o &&
+
+ mkdir -p A B C &&
+ echo 1 >A/file1 &&
+ echo 2 >B/file1 &&
+ echo other >C/other &&
+ echo Astuff >A/stuff &&
+ echo Bstuff >B/stuff &&
+ git add . &&
+ git commit -m "O" &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git mv B/file1 C/ &&
+ git add . &&
+ git commit -m "A" &&
+
+ git switch B &&
+ mkdir -p D &&
+ git mv A/file1 D/file2 &&
+ git mv C/other A/other &&
+ git add . &&
+ git commit -m "B"
+ )
+}
+
+test_expect_success '12o: Directory rename hits other rename source; file still in way on same side' '
+ test_setup_12o &&
+ (
+ cd 12o &&
+
+ git checkout -q A^0 &&
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 >out &&
+
+ test_stdout_line_count = 5 git ls-files -s &&
+ test_stdout_line_count = 1 git ls-files -s A/other &&
+ test_stdout_line_count = 1 git ls-files -s A/stuff &&
+ test_stdout_line_count = 1 git ls-files -s B/stuff &&
+ test_stdout_line_count = 1 git ls-files -s D/file2 &&
+
+ grep "CONFLICT (implicit dir rename).*Existing file/dir at A/file1 in the way" out &&
+ test_stdout_line_count = 1 git ls-files -s C/file1
+ )
+'
+
+# Testcase 12p, Directory rename hits other rename source; file still in way on other side
+# Commit O: A/file1_1
+# A/stuff
+# B/file1_2
+# B/stuff
+# C/other
+# Commit A: D/file2_1
+# A/stuff
+# B/stuff
+# C/file1_2
+# C/other
+# Commit B: A/file1_1
+# A/stuff
+# B/file1_2
+# B/stuff
+# A/other
+# Short version:
+# A: rename A/file1_1 -> D/file2_1
+# rename B/file1_2 -> C/file1_2
+# B: Rename C/ -> A/
+# Rationale:
+# A/stuff is unmodified, it shows up in final output
+# B/stuff is unmodified, it shows up in final output
+# C/other touched on one side (rename to A), so A/other shows up in output
+# A/file1 is renamed to D/file2
+# B/file1 -> C/file1 and even though C/ -> A/, A/file1 is
+# "in the way" so we don't do the directory rename
+# Expected: A/stuff
+# B/stuff
+# A/other
+# D/file2
+# C/file1
+# + CONFLICT (implicit dir rename): A/file1 in way of C/file1
+#
+
+test_setup_12p () {
+ git init 12p &&
+ (
+ cd 12p &&
+
+ mkdir -p A B C &&
+ echo 1 >A/file1 &&
+ echo 2 >B/file1 &&
+ echo other >C/other &&
+ echo Astuff >A/stuff &&
+ echo Bstuff >B/stuff &&
+ git add . &&
+ git commit -m "O" &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ mkdir -p D &&
+ git mv A/file1 D/file2 &&
+ git mv B/file1 C/ &&
+ git add . &&
+ git commit -m "A" &&
+
+ git switch B &&
+ git mv C/other A/other &&
+ git add . &&
+ git commit -m "B"
+ )
+}
+
+test_expect_success '12p: Directory rename hits other rename source; file still in way on other side' '
+ test_setup_12p &&
+ (
+ cd 12p &&
+
+ git checkout -q A^0 &&
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 >out &&
+
+ test_stdout_line_count = 5 git ls-files -s &&
+ test_stdout_line_count = 1 git ls-files -s A/other &&
+ test_stdout_line_count = 1 git ls-files -s A/stuff &&
+ test_stdout_line_count = 1 git ls-files -s B/stuff &&
+ test_stdout_line_count = 1 git ls-files -s D/file2 &&
+
+ grep "CONFLICT (implicit dir rename).*Existing file/dir at A/file1 in the way" out &&
+ test_stdout_line_count = 1 git ls-files -s C/file1
+ )
+'
+
+# Testcase 12q, Directory rename hits other rename source; file removed though
+# Commit O: A/file1_1
+# A/stuff
+# B/file1_2
+# B/stuff
+# C/other
+# Commit A: A/stuff
+# B/stuff
+# C/file1_2
+# C/other
+# Commit B: D/file2_1
+# A/stuff
+# B/file1_2
+# B/stuff
+# A/other
+# In words:
+# A: delete A/file1_1, rename B/file1_2 -> C/file1_2
+# B: Rename C/ -> A/, rename A/file1_1 -> D/file2_1
+# Rationale:
+# A/stuff is unmodified, it shows up in final output
+# B/stuff is unmodified, it shows up in final output
+# C/other touched on one side (rename to A), so A/other shows up in output
+# A/file1 is rename/delete to D/file2, so two stages for D/file2
+# B/file1 -> C/file1 and even though C/ -> A/, A/file1 as a source was
+# "in the way" (ish) so we don't do the directory rename
+# Expected: A/stuff
+# B/stuff
+# A/other
+# D/file2 (two stages)
+# C/file1
+# + CONFLICT (implicit dir rename): A/file1 in way of C/file1
+# + CONFLICT (rename/delete): D/file2
+#
+
+test_setup_12q () {
+ git init 12q &&
+ (
+ cd 12q &&
+
+ mkdir -p A B C &&
+ echo 1 >A/file1 &&
+ echo 2 >B/file1 &&
+ echo other >C/other &&
+ echo Astuff >A/stuff &&
+ echo Bstuff >B/stuff &&
+ git add . &&
+ git commit -m "O" &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git switch A &&
+ git rm A/file1 &&
+ git mv B/file1 C/ &&
+ git add . &&
+ git commit -m "A" &&
+
+ git switch B &&
+ mkdir -p D &&
+ git mv A/file1 D/file2 &&
+ git mv C/other A/other &&
+ git add . &&
+ git commit -m "B"
+ )
+}
+
+test_expect_success '12q: Directory rename hits other rename source; file removed though' '
+ test_setup_12q &&
+ (
+ cd 12q &&
+
+ git checkout -q A^0 &&
+
+ test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 >out &&
+
+ grep "CONFLICT (rename/delete).*A/file1.*D/file2" out &&
+ grep "CONFLICT (implicit dir rename).*Existing file/dir at A/file1 in the way" out &&
+
+ test_stdout_line_count = 6 git ls-files -s &&
+ test_stdout_line_count = 1 git ls-files -s A/other &&
+ test_stdout_line_count = 1 git ls-files -s A/stuff &&
+ test_stdout_line_count = 1 git ls-files -s B/stuff &&
+ test_stdout_line_count = 2 git ls-files -s D/file2 &&
+
+ # This is a slightly suboptimal resolution; allowing the
+ # rename of C/ -> A/ to affect C/file1 and further rename
+ # it to A/file1 would probably be preferable, but since
+ # A/file1 existed as the source of another rename, allowing
+ # the dir rename of C/file1 -> A/file1 would mean modifying
+ # the code so that renames do not adjust both their source
+ # and target paths in all cases.
+ ! grep "CONFLICT (file location)" out &&
+ test_stdout_line_count = 1 git ls-files -s C/file1
+ )
+'
###########################################################################
# SECTION 13: Checking informational and conflict messages
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index d6a501d453..fd3e7e355e 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -1482,4 +1482,27 @@ test_expect_success '`submodule init` and `init.templateDir`' '
)
'
+test_expect_success 'submodule add fails when name is reused' '
+ git init test-submodule &&
+ (
+ cd test-submodule &&
+ git commit --allow-empty -m init &&
+
+ git init ../child-origin &&
+ git -C ../child-origin commit --allow-empty -m init &&
+
+ git submodule add ../child-origin child &&
+ git commit -m "Add submodule child" &&
+
+ git mv child child_old &&
+ git commit -m "Move child to child_old" &&
+
+ # Now adding a *new* repo at the old name must fail
+ git init ../child2-origin &&
+ git -C ../child2-origin commit --allow-empty -m init &&
+ test_must_fail git submodule add ../child2-origin child 2>err &&
+ test_grep "already used for" err
+ )
+'
+
test_done
diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh
index 9509dc18fd..6fd3b870de 100755
--- a/t/t7413-submodule-is-active.sh
+++ b/t/t7413-submodule-is-active.sh
@@ -124,4 +124,19 @@ test_expect_success 'is-active, submodule.active and submodule add' '
git -C super2 config --get submodule.mod.active
'
+test_expect_success 'submodule add skips redundant active entry' '
+ git init repo &&
+ (
+ cd repo &&
+ git config submodule.active "lib/*" &&
+ git commit --allow-empty -m init &&
+
+ git init ../lib-origin &&
+ git -C ../lib-origin commit --allow-empty -m init &&
+
+ git submodule add ../lib-origin lib/foo &&
+ test_must_fail git config --get submodule.lib/foo.active
+ )
+'
+
test_done
diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh
index 14b5743b96..f512eed278 100755
--- a/t/t7450-bad-git-dotfiles.sh
+++ b/t/t7450-bad-git-dotfiles.sh
@@ -401,7 +401,7 @@ test_expect_success SYMLINKS,!WINDOWS,!MINGW 'submodule must not checkout into d
git -C repo commit -m submodule &&
git -c protocol.file.allow=always clone --recurse-submodules repo bad-clone &&
- ! test -f "$PWD/foo" &&
+ ! test -f "$PWD/bad-clone/sub/foo" &&
test -f $(printf "bad-clone/sub\r/post-checkout")
'
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 39677e859a..1201c85ba6 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -449,7 +449,17 @@ test_expect_success 'custom `gpg.program`' '
test_must_fail env LET_GPG_PROGRAM_FAIL=1 \
git commit -S --allow-empty -m must-fail 2>err &&
- grep zOMG err
+ grep zOMG err &&
+
+ # `gpg.program` starts with `~`, the path should be interpreted to be relative to `$HOME`
+ test_config gpg.program "~/fake-gpg" &&
+ env HOME="$(pwd)" \
+ git commit -S --allow-empty -m signed-commit &&
+
+ # `gpg.program` does not specify an absolute path, it should find a program in `$PATH`
+ test_config gpg.program "fake-gpg" &&
+ env PATH="$PWD:$PATH" \
+ git commit -S --allow-empty -m signed-commit
'
test_done
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 46700dbc40..8f85c69d62 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -48,12 +48,11 @@ test_expect_success 'fast-export | fast-import' '
mkdir new &&
git --git-dir=new/.git init &&
git fast-export --all >actual &&
- (cd new &&
- git fast-import &&
- test $MAIN = $(git rev-parse --verify refs/heads/main) &&
- test $REIN = $(git rev-parse --verify refs/tags/rein) &&
- test $WER = $(git rev-parse --verify refs/heads/wer) &&
- test $MUSS = $(git rev-parse --verify refs/tags/muss)) <actual
+ git -C new fast-import <actual &&
+ test $MAIN = $(git -C new rev-parse --verify refs/heads/main) &&
+ test $REIN = $(git -C new rev-parse --verify refs/tags/rein) &&
+ test $WER = $(git -C new rev-parse --verify refs/heads/wer) &&
+ test $MUSS = $(git -C new rev-parse --verify refs/tags/muss)
'
@@ -87,13 +86,11 @@ test_expect_success 'fast-export --mark-tags ^muss^{commit} muss' '
test_expect_success 'fast-export main~2..main' '
git fast-export main~2..main >actual &&
- sed "s/main/partial/" actual |
- (cd new &&
- git fast-import &&
- test $MAIN != $(git rev-parse --verify refs/heads/partial) &&
- git diff --exit-code main partial &&
- git diff --exit-code main^ partial^ &&
- test_must_fail git rev-parse partial~2)
+ sed "s/main/partial/" actual | git -C new fast-import &&
+ test $MAIN != $(git -C new rev-parse --verify refs/heads/partial) &&
+ git -C new diff --exit-code main partial &&
+ git -C new diff --exit-code main^ partial^ &&
+ test_must_fail git -C new rev-parse partial~2
'
@@ -102,10 +99,8 @@ test_expect_success 'fast-export --reference-excluded-parents main~2..main' '
git fast-export --reference-excluded-parents main~2..main >actual &&
grep commit.refs/heads/main actual >commit-count &&
test_line_count = 2 commit-count &&
- sed "s/main/rewrite/" actual |
- (cd new &&
- git fast-import &&
- test $MAIN = $(git rev-parse --verify refs/heads/rewrite))
+ sed "s/main/rewrite/" actual | git -C new fast-import &&
+ test $MAIN = $(git -C new rev-parse --verify refs/heads/rewrite)
'
test_expect_success 'fast-export --show-original-ids' '
@@ -133,20 +128,19 @@ test_expect_success ICONV 'reencoding iso-8859-7' '
echo rosten >file &&
git commit -s -F "$TEST_DIRECTORY/t9350/simple-iso-8859-7-commit-message.txt" file &&
git fast-export --reencode=yes wer^..wer >iso-8859-7.fi &&
- sed "s/wer/i18n/" iso-8859-7.fi |
- (cd new &&
- git fast-import &&
- # The commit object, if not re-encoded, would be 200 bytes plus hash.
- # Removing the "encoding iso-8859-7\n" header drops 20 bytes.
- # Re-encoding the Pi character from \xF0 (\360) in iso-8859-7
- # to \xCF\x80 (\317\200) in UTF-8 adds a byte. Check for
- # the expected size.
- test $(($(test_oid hexsz) + 181)) -eq "$(git cat-file -s i18n)" &&
- # ...and for the expected translation of bytes.
- git cat-file commit i18n >actual &&
- grep $(printf "\317\200") actual &&
- # Also make sure the commit does not have the "encoding" header
- ! grep ^encoding actual)
+ sed "s/wer/i18n/" iso-8859-7.fi | git -C new fast-import &&
+
+ # The commit object, if not re-encoded, would be 200 bytes plus hash.
+ # Removing the "encoding iso-8859-7\n" header drops 20 bytes.
+ # Re-encoding the Pi character from \xF0 (\360) in iso-8859-7
+ # to \xCF\x80 (\317\200) in UTF-8 adds a byte. Check for
+ # the expected size.
+ test $(($(test_oid hexsz) + 181)) -eq "$(git -C new cat-file -s i18n)" &&
+ # ...and for the expected translation of bytes.
+ git -C new cat-file commit i18n >actual &&
+ grep $(printf "\317\200") actual &&
+ # Also make sure the commit does not have the "encoding" header
+ ! grep ^encoding actual
'
test_expect_success 'aborting on iso-8859-7' '
@@ -165,20 +159,19 @@ test_expect_success 'preserving iso-8859-7' '
echo rosten >file &&
git commit -s -F "$TEST_DIRECTORY/t9350/simple-iso-8859-7-commit-message.txt" file &&
git fast-export --reencode=no wer^..wer >iso-8859-7.fi &&
- sed "s/wer/i18n-no-recoding/" iso-8859-7.fi |
- (cd new &&
- git fast-import &&
- # The commit object, if not re-encoded, is 200 bytes plus hash.
- # Removing the "encoding iso-8859-7\n" header would drops 20
- # bytes. Re-encoding the Pi character from \xF0 (\360) in
- # iso-8859-7 to \xCF\x80 (\317\200) in UTF-8 adds a byte.
- # Check for the expected size...
- test $(($(test_oid hexsz) + 200)) -eq "$(git cat-file -s i18n-no-recoding)" &&
- # ...as well as the expected byte.
- git cat-file commit i18n-no-recoding >actual &&
- grep $(printf "\360") actual &&
- # Also make sure the commit has the "encoding" header
- grep ^encoding actual)
+ sed "s/wer/i18n-no-recoding/" iso-8859-7.fi | git -C new fast-import &&
+
+ # The commit object, if not re-encoded, is 200 bytes plus hash.
+ # Removing the "encoding iso-8859-7\n" header would drops 20
+ # bytes. Re-encoding the Pi character from \xF0 (\360) in
+ # iso-8859-7 to \xCF\x80 (\317\200) in UTF-8 adds a byte.
+ # Check for the expected size...
+ test $(($(test_oid hexsz) + 200)) -eq "$(git -C new cat-file -s i18n-no-recoding)" &&
+ # ...as well as the expected byte.
+ git -C new cat-file commit i18n-no-recoding >actual &&
+ grep $(printf "\360") actual &&
+ # Also make sure the commit has the "encoding" header
+ grep ^encoding actual
'
test_expect_success 'encoding preserved if reencoding fails' '
@@ -188,18 +181,17 @@ test_expect_success 'encoding preserved if reencoding fails' '
echo rosten >file &&
git commit -s -F "$TEST_DIRECTORY/t9350/broken-iso-8859-7-commit-message.txt" file &&
git fast-export --reencode=yes wer^..wer >iso-8859-7.fi &&
- sed "s/wer/i18n-invalid/" iso-8859-7.fi |
- (cd new &&
- git fast-import &&
- git cat-file commit i18n-invalid >actual &&
- # Make sure the commit still has the encoding header
- grep ^encoding actual &&
- # Verify that the commit has the expected size; i.e.
- # that no bytes were re-encoded to a different encoding.
- test $(($(test_oid hexsz) + 212)) -eq "$(git cat-file -s i18n-invalid)" &&
- # ...and check for the original special bytes
- grep $(printf "\360") actual &&
- grep $(printf "\377") actual)
+ sed "s/wer/i18n-invalid/" iso-8859-7.fi | git -C new fast-import &&
+ git -C new cat-file commit i18n-invalid >actual &&
+
+ # Make sure the commit still has the encoding header
+ grep ^encoding actual &&
+ # Verify that the commit has the expected size; i.e.
+ # that no bytes were re-encoded to a different encoding.
+ test $(($(test_oid hexsz) + 212)) -eq "$(git -C new cat-file -s i18n-invalid)" &&
+ # ...and check for the original special bytes
+ grep $(printf "\360") actual &&
+ grep $(printf "\377") actual
'
test_expect_success 'import/export-marks' '
@@ -316,12 +308,9 @@ test_expect_success GPG 'signed-commits=verbatim' '
git fast-export --signed-commits=verbatim --reencode=no commit-signing >output &&
test_grep -E "^gpgsig $GIT_DEFAULT_HASH openpgp" output &&
grep "encoding ISO-8859-1" output &&
- (
- cd new &&
- git fast-import &&
- STRIPPED=$(git rev-parse --verify refs/heads/commit-signing) &&
- test $COMMIT_SIGNING = $STRIPPED
- ) <output
+ git -C new fast-import <output &&
+ STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-signing) &&
+ test $COMMIT_SIGNING = $STRIPPED
'
@@ -331,12 +320,9 @@ test_expect_success GPG 'signed-commits=warn-verbatim' '
test_grep -E "^gpgsig $GIT_DEFAULT_HASH openpgp" output &&
grep "encoding ISO-8859-1" output &&
test -s err &&
- (
- cd new &&
- git fast-import &&
- STRIPPED=$(git rev-parse --verify refs/heads/commit-signing) &&
- test $COMMIT_SIGNING = $STRIPPED
- ) <output
+ git -C new fast-import <output &&
+ STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-signing) &&
+ test $COMMIT_SIGNING = $STRIPPED
'
@@ -345,12 +331,9 @@ test_expect_success GPG 'signed-commits=strip' '
git fast-export --signed-commits=strip --reencode=no commit-signing >output &&
! grep ^gpgsig output &&
grep "^encoding ISO-8859-1" output &&
- sed "s/commit-signing/commit-strip-signing/" output | (
- cd new &&
- git fast-import &&
- STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) &&
- test $COMMIT_SIGNING != $STRIPPED
- )
+ sed "s/commit-signing/commit-strip-signing/" output | git -C new fast-import &&
+ STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-strip-signing) &&
+ test $COMMIT_SIGNING != $STRIPPED
'
@@ -360,12 +343,9 @@ test_expect_success GPG 'signed-commits=warn-strip' '
! grep ^gpgsig output &&
grep "^encoding ISO-8859-1" output &&
test -s err &&
- sed "s/commit-signing/commit-strip-signing/" output | (
- cd new &&
- git fast-import &&
- STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) &&
- test $COMMIT_SIGNING != $STRIPPED
- )
+ sed "s/commit-signing/commit-strip-signing/" output | git -C new fast-import &&
+ STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-strip-signing) &&
+ test $COMMIT_SIGNING != $STRIPPED
'
@@ -386,14 +366,11 @@ test_expect_success GPGSM 'round-trip X.509 signed commit' '
git fast-export --signed-commits=verbatim x509-signing >output &&
test_grep -E "^gpgsig $GIT_DEFAULT_HASH x509" output &&
- (
- cd new &&
- git fast-import &&
- git cat-file commit refs/heads/x509-signing >actual &&
- grep "^gpgsig" actual &&
- IMPORTED=$(git rev-parse refs/heads/x509-signing) &&
- test $X509_COMMIT = $IMPORTED
- ) <output
+ git -C new fast-import <output &&
+ git -C new cat-file commit refs/heads/x509-signing >actual &&
+ grep "^gpgsig" actual &&
+ IMPORTED=$(git -C new rev-parse refs/heads/x509-signing) &&
+ test $X509_COMMIT = $IMPORTED
'
@@ -414,14 +391,11 @@ test_expect_success GPGSSH 'round-trip SSH signed commit' '
git fast-export --signed-commits=verbatim ssh-signing >output &&
test_grep -E "^gpgsig $GIT_DEFAULT_HASH ssh" output &&
- (
- cd new &&
- git fast-import &&
- git cat-file commit refs/heads/ssh-signing >actual &&
- grep "^gpgsig" actual &&
- IMPORTED=$(git rev-parse refs/heads/ssh-signing) &&
- test $SSH_COMMIT = $IMPORTED
- ) <output
+ git -C new fast-import <output &&
+ git -C new cat-file commit refs/heads/ssh-signing >actual &&
+ grep "^gpgsig" actual &&
+ IMPORTED=$(git -C new rev-parse refs/heads/ssh-signing) &&
+ test $SSH_COMMIT = $IMPORTED
'
@@ -461,14 +435,13 @@ test_expect_success 'submodule fast-export | fast-import' '
mkdir new &&
git --git-dir=new/.git init &&
git fast-export --signed-tags=strip --all >actual &&
- (cd new &&
- git fast-import &&
- test "$SUBENT1" = "$(git ls-tree refs/heads/main^ sub)" &&
- test "$SUBENT2" = "$(git ls-tree refs/heads/main sub)" &&
- git checkout main &&
- git submodule init &&
- git submodule update &&
- cmp sub/file ../sub/file) <actual
+ git -C new fast-import <actual &&
+ test "$SUBENT1" = "$(git -C new ls-tree refs/heads/main^ sub)" &&
+ test "$SUBENT2" = "$(git -C new ls-tree refs/heads/main sub)" &&
+ git -C new checkout main &&
+ git -C new submodule init &&
+ git -C new submodule update &&
+ cmp new/sub/file sub/file
'
@@ -510,10 +483,8 @@ test_expect_success 'fast-export -C -C | fast-import' '
git --git-dir=new/.git init &&
git fast-export -C -C --signed-tags=strip --all > output &&
grep "^C file2 file4\$" output &&
- cat output |
- (cd new &&
- git fast-import &&
- test $ENTRY = $(git rev-parse --verify refs/heads/copy))
+ git -C new fast-import <output &&
+ test $ENTRY = $(git -C new rev-parse --verify refs/heads/copy)
'
@@ -986,21 +957,17 @@ test_expect_success GPG 'export and import of doubly signed commit' '
git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
test_grep -E "^gpgsig sha1 openpgp" output &&
test_grep -E "^gpgsig sha256 openpgp" output &&
-
- (
- cd new &&
- git fast-import &&
- git cat-file commit refs/heads/dual-signed >actual &&
- test_grep -E "^gpgsig " actual &&
- test_grep -E "^gpgsig-sha256 " actual &&
- IMPORTED=$(git rev-parse refs/heads/dual-signed) &&
- if test "$GIT_DEFAULT_HASH" = "sha1"
- then
- test $SHA1_B = $IMPORTED
- else
- test $SHA256_B = $IMPORTED
- fi
- ) <output
+ git -C new fast-import <output &&
+ git -C new cat-file commit refs/heads/dual-signed >actual &&
+ test_grep -E "^gpgsig " actual &&
+ test_grep -E "^gpgsig-sha256 " actual &&
+ IMPORTED=$(git -C new rev-parse refs/heads/dual-signed) &&
+ if test "$GIT_DEFAULT_HASH" = "sha1"
+ then
+ test $SHA1_B = $IMPORTED
+ else
+ test $SHA256_B = $IMPORTED
+ fi
'
test_done
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 343b8cd191..6650d33fba 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2596,6 +2596,8 @@ test_expect_success 'double dash "git checkout"' '
--merge Z
--conflict=Z
--patch Z
+ --unified=Z
+ --inter-hunk-context=Z
--ignore-skip-worktree-bits Z
--ignore-other-worktrees Z
--recurse-submodules Z
diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c
index d54e455367..03a3aa8e87 100644
--- a/t/unit-tests/clar/clar.c
+++ b/t/unit-tests/clar/clar.c
@@ -350,7 +350,7 @@ static void
clar_run_suite(const struct clar_suite *suite, const char *filter)
{
const struct clar_func *test = suite->tests;
- size_t i, matchlen;
+ size_t i, matchlen = 0;
struct clar_report *report;
int exact = 0;
diff --git a/t/unit-tests/u-dir.c b/t/unit-tests/u-dir.c
new file mode 100644
index 0000000000..2d0adaa39e
--- /dev/null
+++ b/t/unit-tests/u-dir.c
@@ -0,0 +1,47 @@
+#include "unit-test.h"
+#include "dir.h"
+
+#define TEST_WITHIN_DEPTH(path, depth, max_depth, expect) do { \
+ int actual = within_depth(path, strlen(path), \
+ depth, max_depth); \
+ if (actual != expect) \
+ cl_failf("path '%s' with depth '%d' and max-depth '%d': expected %d, got %d", \
+ path, depth, max_depth, expect, actual); \
+ } while (0)
+
+void test_dir__within_depth(void)
+{
+ /* depth = 0; max_depth = 0 */
+ TEST_WITHIN_DEPTH("", 0, 0, 1);
+ TEST_WITHIN_DEPTH("file", 0, 0, 1);
+ TEST_WITHIN_DEPTH("a", 0, 0, 1);
+ TEST_WITHIN_DEPTH("a/file", 0, 0, 0);
+ TEST_WITHIN_DEPTH("a/b", 0, 0, 0);
+ TEST_WITHIN_DEPTH("a/b/file", 0, 0, 0);
+
+ /* depth = 0; max_depth = 1 */
+ TEST_WITHIN_DEPTH("", 0, 1, 1);
+ TEST_WITHIN_DEPTH("file", 0, 1, 1);
+ TEST_WITHIN_DEPTH("a", 0, 1, 1);
+ TEST_WITHIN_DEPTH("a/file", 0, 1, 1);
+ TEST_WITHIN_DEPTH("a/b", 0, 1, 1);
+ TEST_WITHIN_DEPTH("a/b/file", 0, 1, 0);
+
+ /* depth = 1; max_depth = 1 */
+ TEST_WITHIN_DEPTH("", 1, 1, 1);
+ TEST_WITHIN_DEPTH("file", 1, 1, 1);
+ TEST_WITHIN_DEPTH("a", 1, 1, 1);
+ TEST_WITHIN_DEPTH("a/file", 1, 1, 0);
+ TEST_WITHIN_DEPTH("a/b", 1, 1, 0);
+ TEST_WITHIN_DEPTH("a/b/file", 1, 1, 0);
+
+ /* depth = 1; max_depth = 0 */
+ TEST_WITHIN_DEPTH("", 1, 0, 0);
+ TEST_WITHIN_DEPTH("file", 1, 0, 0);
+ TEST_WITHIN_DEPTH("a", 1, 0, 0);
+ TEST_WITHIN_DEPTH("a/file", 1, 0, 0);
+ TEST_WITHIN_DEPTH("a/b", 1, 0, 0);
+ TEST_WITHIN_DEPTH("a/b/file", 1, 0, 0);
+
+
+}
diff --git a/t/unit-tests/u-string-list.c b/t/unit-tests/u-string-list.c
index d4ba5f9fa5..a2457d7b1e 100644
--- a/t/unit-tests/u-string-list.c
+++ b/t/unit-tests/u-string-list.c
@@ -43,7 +43,7 @@ static void t_string_list_equal(struct string_list *list,
expected_strings->items[i].string);
}
-static void t_string_list_split(const char *data, int delim, int maxsplit, ...)
+static void t_string_list_split(const char *data, const char *delim, int maxsplit, ...)
{
struct string_list expected_strings = STRING_LIST_INIT_DUP;
struct string_list list = STRING_LIST_INIT_DUP;
@@ -63,15 +63,94 @@ static void t_string_list_split(const char *data, int delim, int maxsplit, ...)
string_list_clear(&list, 0);
}
+static void t_string_list_split_f(const char *data, const char *delim,
+ int maxsplit, unsigned flags, ...)
+{
+ struct string_list expected_strings = STRING_LIST_INIT_DUP;
+ struct string_list list = STRING_LIST_INIT_DUP;
+ va_list ap;
+ int len;
+
+ va_start(ap, flags);
+ t_vcreate_string_list_dup(&expected_strings, 0, ap);
+ va_end(ap);
+
+ string_list_clear(&list, 0);
+ len = string_list_split_f(&list, data, delim, maxsplit, flags);
+ cl_assert_equal_i(len, expected_strings.nr);
+ t_string_list_equal(&list, &expected_strings);
+
+ string_list_clear(&expected_strings, 0);
+ string_list_clear(&list, 0);
+}
+
+void test_string_list__split_f(void)
+{
+ t_string_list_split_f("::foo:bar:baz:", ":", -1, 0,
+ "", "", "foo", "bar", "baz", "", NULL);
+ t_string_list_split_f(" foo:bar : baz", ":", -1, STRING_LIST_SPLIT_TRIM,
+ "foo", "bar", "baz", NULL);
+ t_string_list_split_f(" a b c ", " ", 1, STRING_LIST_SPLIT_TRIM,
+ "a", "b c", NULL);
+ t_string_list_split_f("::foo::bar:baz:", ":", -1, STRING_LIST_SPLIT_NONEMPTY,
+ "foo", "bar", "baz", NULL);
+ t_string_list_split_f("foo:baz", ":", -1, STRING_LIST_SPLIT_NONEMPTY,
+ "foo", "baz", NULL);
+ t_string_list_split_f("foo :: : baz", ":", -1,
+ STRING_LIST_SPLIT_NONEMPTY | STRING_LIST_SPLIT_TRIM,
+ "foo", "baz", NULL);
+}
+
+static void t_string_list_split_in_place_f(const char *data_, const char *delim,
+ int maxsplit, unsigned flags, ...)
+{
+ struct string_list expected_strings = STRING_LIST_INIT_DUP;
+ struct string_list list = STRING_LIST_INIT_NODUP;
+ char *data = xstrdup(data_);
+ va_list ap;
+ int len;
+
+ va_start(ap, flags);
+ t_vcreate_string_list_dup(&expected_strings, 0, ap);
+ va_end(ap);
+
+ string_list_clear(&list, 0);
+ len = string_list_split_in_place_f(&list, data, delim, maxsplit, flags);
+ cl_assert_equal_i(len, expected_strings.nr);
+ t_string_list_equal(&list, &expected_strings);
+
+ free(data);
+ string_list_clear(&expected_strings, 0);
+ string_list_clear(&list, 0);
+}
+
+void test_string_list__split_in_place_f(void)
+{
+ t_string_list_split_in_place_f("::foo:bar:baz:", ":", -1, 0,
+ "", "", "foo", "bar", "baz", "", NULL);
+ t_string_list_split_in_place_f(" foo:bar : baz", ":", -1, STRING_LIST_SPLIT_TRIM,
+ "foo", "bar", "baz", NULL);
+ t_string_list_split_in_place_f(" a b c ", " ", 1, STRING_LIST_SPLIT_TRIM,
+ "a", "b c", NULL);
+ t_string_list_split_in_place_f("::foo::bar:baz:", ":", -1,
+ STRING_LIST_SPLIT_NONEMPTY,
+ "foo", "bar", "baz", NULL);
+ t_string_list_split_in_place_f("foo:baz", ":", -1, STRING_LIST_SPLIT_NONEMPTY,
+ "foo", "baz", NULL);
+ t_string_list_split_in_place_f("foo :: : baz", ":", -1,
+ STRING_LIST_SPLIT_NONEMPTY | STRING_LIST_SPLIT_TRIM,
+ "foo", "baz", NULL);
+}
+
void test_string_list__split(void)
{
- t_string_list_split("foo:bar:baz", ':', -1, "foo", "bar", "baz", NULL);
- t_string_list_split("foo:bar:baz", ':', 0, "foo:bar:baz", NULL);
- t_string_list_split("foo:bar:baz", ':', 1, "foo", "bar:baz", NULL);
- t_string_list_split("foo:bar:baz", ':', 2, "foo", "bar", "baz", NULL);
- t_string_list_split("foo:bar:", ':', -1, "foo", "bar", "", NULL);
- t_string_list_split("", ':', -1, "", NULL);
- t_string_list_split(":", ':', -1, "", "", NULL);
+ t_string_list_split("foo:bar:baz", ":", -1, "foo", "bar", "baz", NULL);
+ t_string_list_split("foo:bar:baz", ":", 0, "foo:bar:baz", NULL);
+ t_string_list_split("foo:bar:baz", ":", 1, "foo", "bar:baz", NULL);
+ t_string_list_split("foo:bar:baz", ":", 2, "foo", "bar", "baz", NULL);
+ t_string_list_split("foo:bar:", ":", -1, "foo", "bar", "", NULL);
+ t_string_list_split("", ":", -1, "", NULL);
+ t_string_list_split(":", ":", -1, "", "", NULL);
}
static void t_string_list_split_in_place(const char *data, const char *delim,
diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h
index 85e5d6a948..39a0b72a05 100644
--- a/t/unit-tests/unit-test.h
+++ b/t/unit-tests/unit-test.h
@@ -1,8 +1,13 @@
#include "git-compat-util.h"
#include "clar/clar.h"
-#include "clar-decls.h"
#include "strbuf.h"
+#ifndef GIT_CLAR_DECLS_H
+# include "clar-decls.h"
+#else
+# include GIT_CLAR_DECLS_H
+#endif
+
#define cl_failf(fmt, ...) do { \
char desc[4096]; \
snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \
diff --git a/tmp-objdir.c b/tmp-objdir.c
index ae01eae9c4..9f5a1788cd 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -227,7 +227,7 @@ static int migrate_one(struct tmp_objdir *t,
return -1;
return migrate_paths(t, src, dst, flags);
}
- return finalize_object_file_flags(src->buf, dst->buf, flags);
+ return finalize_object_file_flags(t->repo, src->buf, dst->buf, flags);
}
static int is_loose_object_shard(const char *name)
diff --git a/trace2/tr2_cfg.c b/trace2/tr2_cfg.c
index 22a99a0682..bbcfeda60a 100644
--- a/trace2/tr2_cfg.c
+++ b/trace2/tr2_cfg.c
@@ -8,89 +8,65 @@
#include "trace2/tr2_sysenv.h"
#include "wildmatch.h"
-static struct strbuf **tr2_cfg_patterns;
-static int tr2_cfg_count_patterns;
+static struct string_list tr2_cfg_patterns = STRING_LIST_INIT_DUP;
static int tr2_cfg_loaded;
-static struct strbuf **tr2_cfg_env_vars;
-static int tr2_cfg_env_vars_count;
+static struct string_list tr2_cfg_env_vars = STRING_LIST_INIT_DUP;
static int tr2_cfg_env_vars_loaded;
/*
* Parse a string containing a comma-delimited list of config keys
- * or wildcard patterns into a list of strbufs.
+ * or wildcard patterns into a string list.
*/
-static int tr2_cfg_load_patterns(void)
+static size_t tr2_cfg_load_patterns(void)
{
- struct strbuf **s;
const char *envvar;
if (tr2_cfg_loaded)
- return tr2_cfg_count_patterns;
+ return tr2_cfg_patterns.nr;
tr2_cfg_loaded = 1;
envvar = tr2_sysenv_get(TR2_SYSENV_CFG_PARAM);
if (!envvar || !*envvar)
- return tr2_cfg_count_patterns;
+ return tr2_cfg_patterns.nr;
- tr2_cfg_patterns = strbuf_split_buf(envvar, strlen(envvar), ',', -1);
- for (s = tr2_cfg_patterns; *s; s++) {
- struct strbuf *buf = *s;
-
- if (buf->len && buf->buf[buf->len - 1] == ',')
- strbuf_setlen(buf, buf->len - 1);
- strbuf_trim_trailing_newline(*s);
- strbuf_trim(*s);
- }
-
- tr2_cfg_count_patterns = s - tr2_cfg_patterns;
- return tr2_cfg_count_patterns;
+ string_list_split_f(&tr2_cfg_patterns, envvar, ",", -1,
+ STRING_LIST_SPLIT_TRIM);
+ return tr2_cfg_patterns.nr;
}
void tr2_cfg_free_patterns(void)
{
- if (tr2_cfg_patterns)
- strbuf_list_free(tr2_cfg_patterns);
- tr2_cfg_count_patterns = 0;
+ if (tr2_cfg_patterns.nr)
+ string_list_clear(&tr2_cfg_patterns, 0);
tr2_cfg_loaded = 0;
}
/*
* Parse a string containing a comma-delimited list of environment variable
- * names into a list of strbufs.
+ * names into a string list.
*/
-static int tr2_load_env_vars(void)
+static size_t tr2_load_env_vars(void)
{
- struct strbuf **s;
const char *varlist;
if (tr2_cfg_env_vars_loaded)
- return tr2_cfg_env_vars_count;
+ return tr2_cfg_env_vars.nr;
tr2_cfg_env_vars_loaded = 1;
varlist = tr2_sysenv_get(TR2_SYSENV_ENV_VARS);
if (!varlist || !*varlist)
- return tr2_cfg_env_vars_count;
-
- tr2_cfg_env_vars = strbuf_split_buf(varlist, strlen(varlist), ',', -1);
- for (s = tr2_cfg_env_vars; *s; s++) {
- struct strbuf *buf = *s;
-
- if (buf->len && buf->buf[buf->len - 1] == ',')
- strbuf_setlen(buf, buf->len - 1);
- strbuf_trim_trailing_newline(*s);
- strbuf_trim(*s);
- }
+ return tr2_cfg_env_vars.nr;
- tr2_cfg_env_vars_count = s - tr2_cfg_env_vars;
- return tr2_cfg_env_vars_count;
+ string_list_split_f(&tr2_cfg_env_vars, varlist, ",", -1,
+ STRING_LIST_SPLIT_TRIM);
+ return tr2_cfg_env_vars.nr;
}
void tr2_cfg_free_env_vars(void)
{
- if (tr2_cfg_env_vars)
- strbuf_list_free(tr2_cfg_env_vars);
- tr2_cfg_env_vars_count = 0;
+ if (tr2_cfg_env_vars.nr)
+ string_list_clear(&tr2_cfg_env_vars, 0);
tr2_cfg_env_vars_loaded = 0;
}
@@ -105,12 +81,11 @@ struct tr2_cfg_data {
static int tr2_cfg_cb(const char *key, const char *value,
const struct config_context *ctx, void *d)
{
- struct strbuf **s;
+ struct string_list_item *item;
struct tr2_cfg_data *data = (struct tr2_cfg_data *)d;
- for (s = tr2_cfg_patterns; *s; s++) {
- struct strbuf *buf = *s;
- int wm = wildmatch(buf->buf, key, WM_CASEFOLD);
+ for_each_string_list_item(item, &tr2_cfg_patterns) {
+ int wm = wildmatch(item->string, key, WM_CASEFOLD);
if (wm == WM_MATCH) {
trace2_def_param_fl(data->file, data->line, key, value,
ctx->kvi);
@@ -132,17 +107,16 @@ void tr2_cfg_list_config_fl(const char *file, int line)
void tr2_list_env_vars_fl(const char *file, int line)
{
struct key_value_info kvi = KVI_INIT;
- struct strbuf **s;
+ struct string_list_item *item;
kvi_from_param(&kvi);
if (tr2_load_env_vars() <= 0)
return;
- for (s = tr2_cfg_env_vars; *s; s++) {
- struct strbuf *buf = *s;
- const char *val = getenv(buf->buf);
+ for_each_string_list_item(item, &tr2_cfg_env_vars) {
+ const char *val = getenv(item->string);
if (val && *val)
- trace2_def_param_fl(file, line, buf->buf, val, &kvi);
+ trace2_def_param_fl(file, line, item->string, val, &kvi);
}
}
diff --git a/trailer.c b/trailer.c
index 310cf582dc..911a81ed99 100644
--- a/trailer.c
+++ b/trailer.c
@@ -595,8 +595,8 @@ void trailer_config_init(void)
default_conf_info.where = WHERE_END;
default_conf_info.if_exists = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
default_conf_info.if_missing = MISSING_ADD;
- git_config(git_trailer_default_config, NULL);
- git_config(git_trailer_config, NULL);
+ repo_config(the_repository, git_trailer_default_config, NULL);
+ repo_config(the_repository, git_trailer_config, NULL);
configured = 1;
}
diff --git a/transport.c b/transport.c
index c123ac1e38..6ac8aa402b 100644
--- a/transport.c
+++ b/transport.c
@@ -54,14 +54,14 @@ static int transport_color_config(void)
return 0;
initialized = 1;
- if (!git_config_get_string(key, &value))
+ if (!repo_config_get_string(the_repository, key, &value))
transport_use_color = git_config_colorbool(key, value);
if (!want_color_stderr(transport_use_color))
return 0;
for (size_t i = 0; i < ARRAY_SIZE(keys); i++)
- if (!git_config_get_string(keys[i], &value)) {
+ if (!repo_config_get_string(the_repository, keys[i], &value)) {
if (!value)
return config_error_nonbool(keys[i]);
if (color_parse(value, transport_colors[i]) < 0)
@@ -202,7 +202,7 @@ static int fetch_refs_from_bundle(struct transport *transport,
if (!data->get_refs_from_bundle_called)
get_refs_from_bundle_inner(transport);
- git_config(fetch_fsck_config_cb, &msg_types);
+ repo_config(the_repository, fetch_fsck_config_cb, &msg_types);
opts.fsck_msg_types = msg_types.buf;
ret = unbundle(the_repository, &data->header, data->fd,
@@ -1042,7 +1042,7 @@ static const struct string_list *protocol_allow_list(void)
if (enabled < 0) {
const char *v = getenv("GIT_ALLOW_PROTOCOL");
if (v) {
- string_list_split(&allowed, v, ':', -1);
+ string_list_split(&allowed, v, ":", -1);
string_list_sort(&allowed);
enabled = 1;
} else {
@@ -1078,7 +1078,7 @@ static enum protocol_allow_config get_protocol_config(const char *type)
char *value;
/* first check the per-protocol config */
- if (!git_config_get_string(key, &value)) {
+ if (!repo_config_get_string(the_repository, key, &value)) {
enum protocol_allow_config ret =
parse_protocol_config(key, value);
free(key);
@@ -1088,7 +1088,7 @@ static enum protocol_allow_config get_protocol_config(const char *type)
free(key);
/* if defined, fallback to user-defined default for unknown protocols */
- if (!git_config_get_string("protocol.allow", &value)) {
+ if (!repo_config_get_string(the_repository, "protocol.allow", &value)) {
enum protocol_allow_config ret =
parse_protocol_config("protocol.allow", value);
free(value);
@@ -1602,7 +1602,7 @@ int transport_get_remote_bundle_uri(struct transport *transport)
* Don't request bundle-uri from the server unless configured to
* do so by the transfer.bundleURI=true config option.
*/
- if (git_config_get_bool("transfer.bundleuri", &value) || !value)
+ if (repo_config_get_bool(the_repository, "transfer.bundleuri", &value) || !value)
return 0;
if (!transport->bundles->baseURI)
diff --git a/tree-diff.c b/tree-diff.c
index e00fc2f450..5988148b60 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -13,6 +13,7 @@
#include "tree-walk.h"
#include "environment.h"
#include "repository.h"
+#include "dir.h"
/*
* Some mode bits are also used internally for computations.
@@ -48,6 +49,73 @@
free((x)); \
} while(0)
+/* Returns true if and only if "dir" is a leading directory of "path" */
+static int is_dir_prefix(const char *path, const char *dir, int dirlen)
+{
+ return !strncmp(path, dir, dirlen) &&
+ (!path[dirlen] || path[dirlen] == '/');
+}
+
+static int check_recursion_depth(const struct strbuf *name,
+ const struct pathspec *ps,
+ int max_depth)
+{
+ int i;
+
+ if (!ps->nr)
+ return within_depth(name->buf, name->len, 1, max_depth);
+
+ /*
+ * We look through the pathspecs in reverse-sorted order, because we
+ * want to find the longest match first (e.g., "a/b" is better for
+ * checking depth than "a/b/c").
+ */
+ for (i = ps->nr - 1; i >= 0; i--) {
+ const struct pathspec_item *item = ps->items+i;
+
+ /*
+ * If the name to match is longer than the pathspec, then we
+ * are only interested if the pathspec matches and we are
+ * within the allowed depth.
+ */
+ if (name->len >= item->len) {
+ if (!is_dir_prefix(name->buf, item->match, item->len))
+ continue;
+ return within_depth(name->buf + item->len,
+ name->len - item->len,
+ 1, max_depth);
+ }
+
+ /*
+ * Otherwise, our name is shorter than the pathspec. We need to
+ * check if it is a prefix of the pathspec; if so, we must
+ * always recurse in order to process further (the resulting
+ * paths we find might or might not match our pathspec, but we
+ * cannot know until we recurse).
+ */
+ if (is_dir_prefix(item->match, name->buf, name->len))
+ return 1;
+ }
+ return 0;
+}
+
+static int should_recurse(const struct strbuf *name, struct diff_options *opt)
+{
+ if (!opt->flags.recursive)
+ return 0;
+ if (!opt->max_depth_valid)
+ return 1;
+
+ /*
+ * We catch this during diff_setup_done, but let's double-check
+ * against any internal munging.
+ */
+ if (opt->pathspec.has_wildcard)
+ BUG("wildcard pathspecs are incompatible with max-depth");
+
+ return check_recursion_depth(name, &opt->pathspec, opt->max_depth);
+}
+
static void ll_diff_tree_paths(
struct combine_diff_path ***tail, const struct object_id *oid,
const struct object_id **parents_oid, int nparent,
@@ -170,9 +238,13 @@ static void emit_path(struct combine_diff_path ***tail,
mode = 0;
}
- if (opt->flags.recursive && isdir) {
- recurse = 1;
- emitthis = opt->flags.tree_in_recursive;
+ if (isdir) {
+ strbuf_add(base, path, pathlen);
+ if (should_recurse(base, opt)) {
+ recurse = 1;
+ emitthis = opt->flags.tree_in_recursive;
+ }
+ strbuf_setlen(base, old_baselen);
}
if (emitthis) {
diff --git a/upload-pack.c b/upload-pack.c
index 4f26f6afc7..91fcdcad9b 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -1685,7 +1685,7 @@ static void process_args(struct packet_reader *request,
if (data->uri_protocols.nr)
send_err_and_die(data,
"multiple packfile-uris lines forbidden");
- string_list_split(&data->uri_protocols, p, ',', -1);
+ string_list_split(&data->uri_protocols, p, ",", -1);
continue;
}
diff --git a/usage.c b/usage.c
index 81913236a4..4c245ba0cb 100644
--- a/usage.c
+++ b/usage.c
@@ -192,7 +192,8 @@ static void show_usage_if_asked_helper(const char *err, ...)
void show_usage_if_asked(int ac, const char **av, const char *err)
{
- if (ac == 2 && !strcmp(av[1], "-h"))
+ if (ac == 2 && (!strcmp(av[1], "-h") ||
+ !strcmp(av[1], "--help-all")))
show_usage_if_asked_helper(err);
}
diff --git a/versioncmp.c b/versioncmp.c
index b6eebdb989..3a81b17bc1 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -167,8 +167,8 @@ int versioncmp(const char *s1, const char *s2)
const char *const oldk = "versionsort.prereleasesuffix";
const struct string_list *newl;
const struct string_list *oldl;
- int new = git_config_get_string_multi(newk, &newl);
- int old = git_config_get_string_multi(oldk, &oldl);
+ int new = repo_config_get_string_multi(the_repository, newk, &newl);
+ int old = repo_config_get_string_multi(the_repository, oldk, &oldl);
if (!new && !old)
warning("ignoring %s because %s is set", oldk, newk);
diff --git a/worktree.c b/worktree.c
index c34b9eb74e..a2a5f51f29 100644
--- a/worktree.c
+++ b/worktree.c
@@ -991,9 +991,9 @@ done:
static int move_config_setting(const char *key, const char *value,
const char *from_file, const char *to_file)
{
- if (git_config_set_in_file_gently(to_file, key, NULL, value))
+ if (repo_config_set_in_file_gently(the_repository, to_file, key, NULL, value))
return error(_("unable to set %s in '%s'"), key, to_file);
- if (git_config_set_in_file_gently(from_file, key, NULL, NULL))
+ if (repo_config_set_in_file_gently(the_repository, from_file, key, NULL, NULL))
return error(_("unable to unset %s in '%s'"), key, from_file);
return 0;
}
@@ -1013,7 +1013,7 @@ int init_worktree_config(struct repository *r)
*/
if (r->repository_format_worktree_config)
return 0;
- if ((res = git_config_set_gently("extensions.worktreeConfig", "true")))
+ if ((res = repo_config_set_gently(the_repository, "extensions.worktreeConfig", "true")))
return error(_("failed to set extensions.worktreeConfig setting"));
common_config_file = xstrfmt("%s/config", r->commondir);
@@ -1077,7 +1077,7 @@ void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir,
if (use_relative_paths && !the_repository->repository_format_relative_worktrees) {
if (upgrade_repository_format(1) < 0)
die(_("unable to upgrade repository format to support relative worktrees"));
- if (git_config_set_gently("extensions.relativeWorktrees", "true"))
+ if (repo_config_set_gently(the_repository, "extensions.relativeWorktrees", "true"))
die(_("unable to set extensions.relativeWorktrees setting"));
the_repository->repository_format_relative_worktrees = 1;
}
diff --git a/wt-status.c b/wt-status.c
index 454601afa1..21dabab77d 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -972,7 +972,8 @@ static void wt_longstatus_print_changed(struct wt_status *s)
wt_longstatus_print_trailer(s);
}
-static int stash_count_refs(struct object_id *ooid UNUSED,
+static int stash_count_refs(const char *refname UNUSED,
+ struct object_id *ooid UNUSED,
struct object_id *noid UNUSED,
const char *email UNUSED,
timestamp_t timestamp UNUSED, int tz UNUSED,
@@ -1351,8 +1352,8 @@ static int split_commit_in_progress(struct wt_status *s)
*/
static void abbrev_oid_in_line(struct strbuf *line)
{
- struct strbuf **split;
- int i;
+ struct string_list split = STRING_LIST_INIT_DUP;
+ struct object_id oid;
if (starts_with(line->buf, "exec ") ||
starts_with(line->buf, "x ") ||
@@ -1360,26 +1361,15 @@ static void abbrev_oid_in_line(struct strbuf *line)
starts_with(line->buf, "l "))
return;
- split = strbuf_split_max(line, ' ', 3);
- if (split[0] && split[1]) {
- struct object_id oid;
-
- /*
- * strbuf_split_max left a space. Trim it and re-add
- * it after abbreviation.
- */
- strbuf_trim(split[1]);
- if (!repo_get_oid(the_repository, split[1]->buf, &oid)) {
- strbuf_reset(split[1]);
- strbuf_add_unique_abbrev(split[1], &oid,
- DEFAULT_ABBREV);
- strbuf_addch(split[1], ' ');
- strbuf_reset(line);
- for (i = 0; split[i]; i++)
- strbuf_addbuf(line, split[i]);
- }
+ if ((2 <= string_list_split(&split, line->buf, " ", 2)) &&
+ !repo_get_oid(the_repository, split.items[1].string, &oid)) {
+ strbuf_reset(line);
+ strbuf_addf(line, "%s ", split.items[0].string);
+ strbuf_add_unique_abbrev(line, &oid, DEFAULT_ABBREV);
+ for (size_t i = 2; i < split.nr; i++)
+ strbuf_addf(line, " %s", split.items[i].string);
}
- strbuf_list_free(split);
+ string_list_clear(&split, 0);
}
static int read_rebase_todolist(const char *fname, struct string_list *lines)
@@ -1664,7 +1654,8 @@ struct grab_1st_switch_cbdata {
struct object_id noid;
};
-static int grab_1st_switch(struct object_id *ooid UNUSED,
+static int grab_1st_switch(const char *refname UNUSED,
+ struct object_id *ooid UNUSED,
struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp UNUSED, int tz UNUSED,
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 0e5d38c960..4971f722b3 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -2,6 +2,7 @@
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
+#include "environment.h"
#include "gettext.h"
#include "config.h"
#include "hex.h"
diff --git a/xdiff-interface.h b/xdiff-interface.h
index 1ed430b622..dfc55daddf 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -28,9 +28,9 @@
* from an error internal to xdiff, xdiff itself will see that
* non-zero return and translate it to -1.
*
- * See "diff_grep" in diffcore-pickaxe.c for a trick to work around
- * this, i.e. using the "consume_callback_data" to note the desired
- * early return.
+ * See "diff_grep" in diffcore-pickaxe.c and "quick_consume" in diff.c
+ * for a trick to work around this, i.e. using the "consume_callback_data"
+ * to note the desired early return.
*/
typedef int (*xdiff_emit_line_fn)(void *, char *, unsigned long);
typedef void (*xdiff_emit_hunk_fn)(void *data,