]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'jk/clone-allow-bare-and-o-together'
authorJunio C Hamano <gitster@pobox.com>
Mon, 10 Oct 2022 17:08:39 +0000 (10:08 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 10 Oct 2022 17:08:39 +0000 (10:08 -0700)
"git clone" did not like to see the "--bare" and the "--origin"
options used together without a good reason.

* jk/clone-allow-bare-and-o-together:
  clone: allow "--bare" with "-o"

704 files changed:
.gitignore
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/MyFirstContribution.txt
Documentation/MyFirstObjectWalk.txt
Documentation/RelNotes/2.38.0.txt [new file with mode: 0644]
Documentation/RelNotes/2.39.0.txt [new file with mode: 0644]
Documentation/ReviewingGuidelines.txt [new file with mode: 0644]
Documentation/cmd-list.perl
Documentation/config/core.txt
Documentation/config/diff.txt
Documentation/config/difftool.txt
Documentation/config/format.txt
Documentation/config/grep.txt
Documentation/config/log.txt
Documentation/config/lsrefs.txt
Documentation/config/notes.txt
Documentation/config/pack.txt
Documentation/config/protocol.txt
Documentation/config/push.txt
Documentation/config/rebase.txt
Documentation/config/safe.txt
Documentation/config/sendemail.txt
Documentation/config/transfer.txt
Documentation/config/uploadpack.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-archive.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-bugreport.txt
Documentation/git-bundle.txt
Documentation/git-cat-file.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-column.txt
Documentation/git-commit-graph.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-diagnose.txt [new file with mode: 0644]
Documentation/git-diff.txt
Documentation/git-difftool.txt
Documentation/git-fast-import.txt
Documentation/git-fetch.txt
Documentation/git-format-patch.txt
Documentation/git-fsck.txt
Documentation/git-gc.txt
Documentation/git-grep.txt
Documentation/git-help.txt
Documentation/git-imap-send.txt
Documentation/git-init.txt
Documentation/git-interpret-trailers.txt
Documentation/git-log.txt
Documentation/git-ls-files.txt
Documentation/git-mailinfo.txt
Documentation/git-maintenance.txt
Documentation/git-merge-tree.txt
Documentation/git-merge.txt
Documentation/git-mergetool.txt
Documentation/git-multi-pack-index.txt
Documentation/git-notes.txt
Documentation/git-push.txt
Documentation/git-range-diff.txt
Documentation/git-rebase.txt
Documentation/git-revert.txt
Documentation/git-send-email.txt
Documentation/git-show-branch.txt
Documentation/git-stash.txt
Documentation/git-switch.txt
Documentation/git-update-index.txt
Documentation/git-upload-pack.txt
Documentation/git.txt
Documentation/gitformat-bundle.txt [moved from Documentation/technical/bundle-format.txt with 79% similarity]
Documentation/gitformat-chunk.txt [moved from Documentation/technical/chunk-format.txt with 89% similarity]
Documentation/gitformat-commit-graph.txt [moved from Documentation/technical/commit-graph-format.txt with 87% similarity]
Documentation/gitformat-index.txt [moved from Documentation/technical/index-format.txt with 98% similarity]
Documentation/gitformat-pack.txt [moved from Documentation/technical/pack-format.txt with 72% similarity]
Documentation/gitformat-signature.txt [moved from Documentation/technical/signature-format.txt with 96% similarity]
Documentation/gitprotocol-capabilities.txt [moved from Documentation/technical/protocol-capabilities.txt with 95% similarity]
Documentation/gitprotocol-common.txt [moved from Documentation/technical/protocol-common.txt with 89% similarity]
Documentation/gitprotocol-http.txt [moved from Documentation/technical/http-protocol.txt with 97% similarity]
Documentation/gitprotocol-pack.txt [moved from Documentation/technical/pack-protocol.txt with 98% similarity]
Documentation/gitprotocol-v2.txt [moved from Documentation/technical/protocol-v2.txt with 97% similarity]
Documentation/gitremote-helpers.txt
Documentation/howto/recover-corrupted-object-harder.txt
Documentation/includes/cmd-config-section-all.txt [new file with mode: 0644]
Documentation/includes/cmd-config-section-rest.txt [new file with mode: 0644]
Documentation/lint-man-section-order.perl
Documentation/rerere-options.txt [new file with mode: 0644]
Documentation/rev-list-options.txt
Documentation/scalar.txt [moved from contrib/scalar/scalar.txt with 93% similarity]
Documentation/technical/api-error-handling.txt
Documentation/technical/api-parse-options.txt
Documentation/technical/api-simple-ipc.txt
Documentation/technical/api-trace2.txt
Documentation/technical/bitmap-format.txt
Documentation/technical/bundle-uri.txt [new file with mode: 0644]
Documentation/technical/commit-graph.txt
Documentation/technical/cruft-packs.txt [deleted file]
Documentation/technical/hash-function-transition.txt
Documentation/technical/long-running-process-protocol.txt
Documentation/technical/packfile-uri.txt
Documentation/technical/partial-clone.txt
Documentation/technical/remembering-renames.txt
Documentation/technical/scalar.txt [new file with mode: 0644]
Documentation/user-manual.txt
GIT-VERSION-GEN
INSTALL
Makefile
RelNotes
add-interactive.c
add-patch.c
advice.c
advice.h
archive-tar.c
archive-zip.c
archive.c
archive.h
attr.c
bisect.c
blame.c
block-sha1/sha1.c
bloom.c
branch.c
branch.h
builtin.h
builtin/am.c
builtin/archive.c
builtin/bisect--helper.c
builtin/blame.c
builtin/branch.c
builtin/bugreport.c
builtin/bundle.c
builtin/cat-file.c
builtin/check-ref-format.c
builtin/checkout.c
builtin/clone.c
builtin/commit-graph.c
builtin/config.c
builtin/describe.c
builtin/diagnose.c [new file with mode: 0644]
builtin/difftool.c
builtin/env--helper.c
builtin/fast-export.c
builtin/fast-import.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fsck.c
builtin/fsmonitor--daemon.c
builtin/gc.c
builtin/grep.c
builtin/help.c
builtin/hook.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/merge-file.c
builtin/merge-tree.c
builtin/merge.c
builtin/multi-pack-index.c
builtin/mv.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/range-diff.c
builtin/rebase.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/revert.c
builtin/rm.c
builtin/shortlog.c
builtin/show-branch.c
builtin/show-ref.c
builtin/sparse-checkout.c
builtin/stash.c
builtin/submodule--helper.c
builtin/symbolic-ref.c
builtin/unpack-objects.c
builtin/worktree.c
bulk-checkin.c
bundle-uri.c [new file with mode: 0644]
bundle-uri.h [new file with mode: 0644]
bundle.h
cache-tree.c
cache.h
ci/lib.sh
color.c
command-list.txt
commit-graph.c
commit-graph.h
commit.c
common-main.c
compat/disk.h [new file with mode: 0644]
compat/fsmonitor/fsm-settings-win32.c
compat/terminal.c
config.c
config.h
configure.ac
contrib/buildsystems/CMakeLists.txt
contrib/coccinelle/array.cocci
contrib/coccinelle/tests/free.c [new file with mode: 0644]
contrib/coccinelle/tests/free.res [new file with mode: 0644]
contrib/coccinelle/tests/unused.c [new file with mode: 0644]
contrib/coccinelle/tests/unused.res [new file with mode: 0644]
contrib/coccinelle/unused.cocci [new file with mode: 0644]
contrib/completion/git-prompt.sh
contrib/credential/netrc/t-git-credential-netrc.sh
contrib/scalar/.gitignore [deleted file]
contrib/scalar/Makefile [deleted file]
contrib/scalar/README.md [deleted file]
contrib/scalar/t/Makefile [deleted file]
contrib/subtree/git-subtree.sh
contrib/subtree/t/Makefile
convert.c
delta-islands.c
diagnose.c [new file with mode: 0644]
diagnose.h [new file with mode: 0644]
diff-merges.c
diff-no-index.c
diff.c
dir.c
dir.h
environment.c
fetch-pack.c
fuzz-commit-graph.c [deleted file]
gettext.c
git-compat-util.h
git-instaweb.sh
git-merge-resolve.sh
git-p4.py
git-sh-setup.sh
git-submodule.sh
git.c
gitweb/Makefile
gitweb/gitweb.perl
gpg-interface.c
gpg-interface.h
grep.c
grep.h
hash.h
hashmap.c
help.c
help.h
http-backend.c
http.c
http.h
ident.c
list-objects-filter-options.c
list-objects-filter-options.h
ll-merge.c
log-tree.c
ls-refs.c
merge-ort-wrappers.c
merge-ort.c
merge-ort.h
merge-recursive.c
mergesort.c [deleted file]
mergesort.h
midx.c
midx.h
name-hash.c
negotiator/default.c
negotiator/skipping.c
notes.c
object-file.c
object-name.c
object-store.h
object.c
object.h
oidmap.c
oss-fuzz/.gitignore [new file with mode: 0644]
oss-fuzz/fuzz-commit-graph.c [new file with mode: 0644]
oss-fuzz/fuzz-pack-headers.c [moved from fuzz-pack-headers.c with 100% similarity]
oss-fuzz/fuzz-pack-idx.c [moved from fuzz-pack-idx.c with 100% similarity]
pack-bitmap-write.c
pack-bitmap.c
pack-bitmap.h
pack-revindex.h
packfile.c
pager.c
parse-options.c
parse-options.h
patch-ids.c
pathspec.c
pathspec.h
pkt-line.c
pkt-line.h
po/bg.po
po/ca.po
po/de.po
po/es.po
po/fr.po
po/id.po
po/sv.po
po/tr.po
po/zh_CN.po
po/zh_TW.po
ppc/sha1.c [deleted file]
ppc/sha1.h [deleted file]
ppc/sha1ppc.S [deleted file]
pretty.c
range-diff.c
read-cache.c
rebase-interactive.c
ref-filter.c
reflog.c
refs.c
refs.h
refs/files-backend.c
refs/iterator.c
refs/packed-backend.c
refspec.h
reftable/merged.c
reftable/pq.c
reftable/pq.h
reftable/pq_test.c
reftable/reader.c
remote-curl.c
remote.c
remote.h
replace-object.c
repo-settings.c
repository.h
revision.c
revision.h
scalar.c [moved from contrib/scalar/scalar.c with 65% similarity]
send-pack.c
send-pack.h
sequencer.c
sequencer.h
server-info.c
setup.c
sha256/nettle.h [new file with mode: 0644]
shallow.c
shared.mak
strbuf.c
streaming.c
strmap.c
sub-process.c
submodule-config.c
submodule.c
submodule.h
t/Makefile
t/README
t/annotate-tests.sh
t/chainlint.pl [new file with mode: 0755]
t/chainlint.sed [deleted file]
t/chainlint/blank-line-before-esac.expect [new file with mode: 0644]
t/chainlint/blank-line-before-esac.test [new file with mode: 0644]
t/chainlint/block.expect
t/chainlint/block.test
t/chainlint/chain-break-background.expect [new file with mode: 0644]
t/chainlint/chain-break-background.test [new file with mode: 0644]
t/chainlint/chain-break-continue.expect [new file with mode: 0644]
t/chainlint/chain-break-continue.test [new file with mode: 0644]
t/chainlint/chain-break-false.expect [new file with mode: 0644]
t/chainlint/chain-break-false.test [new file with mode: 0644]
t/chainlint/chain-break-return-exit.expect [new file with mode: 0644]
t/chainlint/chain-break-return-exit.test [new file with mode: 0644]
t/chainlint/chain-break-status.expect [new file with mode: 0644]
t/chainlint/chain-break-status.test [new file with mode: 0644]
t/chainlint/chained-block.expect [new file with mode: 0644]
t/chainlint/chained-block.test [new file with mode: 0644]
t/chainlint/chained-subshell.expect [new file with mode: 0644]
t/chainlint/chained-subshell.test [new file with mode: 0644]
t/chainlint/command-substitution-subsubshell.expect [new file with mode: 0644]
t/chainlint/command-substitution-subsubshell.test [new file with mode: 0644]
t/chainlint/complex-if-in-cuddled-loop.expect
t/chainlint/double-here-doc.expect [new file with mode: 0644]
t/chainlint/double-here-doc.test [new file with mode: 0644]
t/chainlint/dqstring-line-splice.expect [new file with mode: 0644]
t/chainlint/dqstring-line-splice.test [new file with mode: 0644]
t/chainlint/dqstring-no-interpolate.expect [new file with mode: 0644]
t/chainlint/dqstring-no-interpolate.test [new file with mode: 0644]
t/chainlint/empty-here-doc.expect [new file with mode: 0644]
t/chainlint/empty-here-doc.test [new file with mode: 0644]
t/chainlint/exclamation.expect [new file with mode: 0644]
t/chainlint/exclamation.test [new file with mode: 0644]
t/chainlint/for-loop-abbreviated.expect [new file with mode: 0644]
t/chainlint/for-loop-abbreviated.test [new file with mode: 0644]
t/chainlint/for-loop.expect
t/chainlint/function.expect [new file with mode: 0644]
t/chainlint/function.test [new file with mode: 0644]
t/chainlint/here-doc-indent-operator.expect [new file with mode: 0644]
t/chainlint/here-doc-indent-operator.test [new file with mode: 0644]
t/chainlint/here-doc-multi-line-string.expect
t/chainlint/if-condition-split.expect [new file with mode: 0644]
t/chainlint/if-condition-split.test [new file with mode: 0644]
t/chainlint/if-in-loop.expect
t/chainlint/if-in-loop.test
t/chainlint/loop-detect-failure.expect [new file with mode: 0644]
t/chainlint/loop-detect-failure.test [new file with mode: 0644]
t/chainlint/loop-detect-status.expect [new file with mode: 0644]
t/chainlint/loop-detect-status.test [new file with mode: 0644]
t/chainlint/loop-in-if.expect
t/chainlint/loop-upstream-pipe.expect [new file with mode: 0644]
t/chainlint/loop-upstream-pipe.test [new file with mode: 0644]
t/chainlint/multi-line-string.expect
t/chainlint/nested-loop-detect-failure.expect [new file with mode: 0644]
t/chainlint/nested-loop-detect-failure.test [new file with mode: 0644]
t/chainlint/nested-subshell.expect
t/chainlint/one-liner-for-loop.expect [new file with mode: 0644]
t/chainlint/one-liner-for-loop.test [new file with mode: 0644]
t/chainlint/return-loop.expect [new file with mode: 0644]
t/chainlint/return-loop.test [new file with mode: 0644]
t/chainlint/semicolon.expect
t/chainlint/sqstring-in-sqstring.expect [new file with mode: 0644]
t/chainlint/sqstring-in-sqstring.test [new file with mode: 0644]
t/chainlint/t7900-subtree.expect
t/chainlint/token-pasting.expect [new file with mode: 0644]
t/chainlint/token-pasting.test [new file with mode: 0644]
t/chainlint/while-loop.expect
t/check-non-portable-shell.pl
t/helper/test-bloom.c
t/helper/test-config.c
t/helper/test-crontab.c
t/helper/test-delta.c
t/helper/test-dump-cache-tree.c
t/helper/test-fast-rebase.c
t/helper/test-hash.c
t/helper/test-json-writer.c
t/helper/test-mergesort.c
t/helper/test-parse-options.c
t/helper/test-path-utils.c
t/helper/test-ref-store.c
t/helper/test-regex.c
t/helper/test-rot13-filter.c [new file with mode: 0644]
t/helper/test-scrap-cache-tree.c
t/helper/test-serve-v2.c
t/helper/test-submodule-config.c
t/helper/test-submodule.c [new file with mode: 0644]
t/helper/test-tool-utils.h [new file with mode: 0644]
t/helper/test-tool.c
t/helper/test-tool.h
t/helper/test-urlmatch-normalization.c
t/helper/test-userdiff.c
t/lib-bitmap.sh
t/lib-perl.sh [new file with mode: 0644]
t/lib-rebase.sh
t/lib-submodule-update.sh
t/perf/README
t/perf/lib-bitmap.sh
t/perf/p0004-lazy-init-name-hash.sh
t/perf/p0006-read-tree-checkout.sh
t/perf/p0071-sort.sh
t/perf/p2000-sparse-operations.sh
t/perf/p5310-pack-bitmaps.sh
t/perf/p5311-pack-bitmaps-fetch.sh
t/perf/p5312-pack-bitmaps-revs.sh [new file with mode: 0755]
t/perf/p5326-multi-pack-bitmaps.sh
t/perf/p7527-builtin-fsmonitor.sh
t/perf/p9210-scalar.sh [new file with mode: 0755]
t/perf/perf-lib.sh
t/perf/run
t/t0000-basic.sh
t/t0002-gitfile.sh
t/t0003-attributes.sh
t/t0004-unwritable.sh
t/t0008-ignores.sh
t/t0012-help.sh
t/t0015-hash.sh
t/t0019-json-writer.sh
t/t0021-conversion.sh
t/t0021/rot13-filter.pl [deleted file]
t/t0027-auto-crlf.sh
t/t0028-working-tree-encoding.sh
t/t0032-reftable-unittest.sh
t/t0033-safe-directory.sh
t/t0035-safe-bare-repository.sh [new file with mode: 0755]
t/t0040-parse-options.sh
t/t0050-filesystem.sh
t/t0060-path-utils.sh
t/t0071-sort.sh
t/t0090-cache-tree.sh
t/t0091-bugreport.sh
t/t0092-diagnose.sh [new file with mode: 0755]
t/t0095-bloom.sh
t/t0110-urlmatch-normalization.sh
t/t0202-gettext-perl.sh
t/t0203-gettext-setlocale-sanity.sh
t/t0212/parse_events.perl
t/t1006-cat-file.sh
t/t1011-read-tree-sparse-checkout.sh
t/t1020-subdirectory.sh
t/t1051-large-conversion.sh
t/t1060-object-corruption.sh
t/t1090-sparse-checkout-scope.sh
t/t1092-sparse-checkout-compatibility.sh
t/t1301-shared-repo.sh
t/t1304-default-acl.sh
t/t1401-symbolic-ref.sh
t/t1402-check-ref-format.sh
t/t1405-main-ref-store.sh
t/t1407-worktree-ref-store.sh
t/t1418-reflog-exists.sh
t/t1450-fsck.sh
t/t1500-rev-parse.sh
t/t1502-rev-parse-parseopt.sh
t/t1503-rev-parse-verify.sh
t/t1701-racy-split-index.sh
t/t1800-hook.sh
t/t2006-checkout-index-basic.sh
t/t2018-checkout-branch.sh
t/t2020-checkout-detach.sh
t/t2023-checkout-m.sh
t/t2080-parallel-checkout-basics.sh
t/t2082-parallel-checkout-attributes.sh
t/t2205-add-worktree-config.sh
t/t2400-worktree-add.sh
t/t2403-worktree-move.sh
t/t2407-worktree-heads.sh [new file with mode: 0755]
t/t3001-ls-files-others-exclude.sh
t/t3012-ls-files-dedup.sh
t/t3013-ls-files-format.sh [new file with mode: 0755]
t/t3070-wildmatch.sh
t/t3200-branch.sh
t/t3206-range-diff.sh
t/t3301-notes.sh
t/t3304-notes-mixed.sh
t/t3305-notes-fanout.sh
t/t3307-notes-man.sh
t/t3404-rebase-interactive.sh
t/t3426-rebase-submodule.sh
t/t3507-cherry-pick-conflict.sh
t/t3700-add.sh
t/t3701-add-interactive.sh
t/t3702-add-edit.sh
t/t3903-stash.sh
t/t3920-crlf-messages.sh
t/t4013-diff-various.sh
t/t4013/diff.log_--decorate=full_--all
t/t4013/diff.log_--decorate=full_--clear-decorations_--all [new file with mode: 0644]
t/t4013/diff.log_--decorate=full_--decorate-all_--all [new file with mode: 0644]
t/t4013/diff.log_--decorate_--all
t/t4013/diff.log_--decorate_--clear-decorations_--all [new file with mode: 0644]
t/t4013/diff.log_--decorate_--decorate-all_--all [new file with mode: 0644]
t/t4014-format-patch.sh
t/t4017-diff-retval.sh
t/t4020-diff-external.sh
t/t4044-diff-index-unique-abbrev.sh
t/t4051-diff-function-context.sh
t/t4057-diff-combined-paths.sh
t/t4069-remerge-diff.sh
t/t4114-apply-typechange.sh
t/t4140-apply-ita.sh
t/t4202-log.sh
t/t4203-mailmap.sh
t/t4207-log-decoration-colors.sh
t/t4301-merge-tree-write-tree.sh [new file with mode: 0755]
t/t5000-tar-tree.sh
t/t5001-archive-attr.sh
t/t5002-archive-attr-pattern.sh
t/t5003-archive-zip.sh
t/t5303-pack-corruption-resilience.sh
t/t5308-pack-detect-duplicates.sh
t/t5309-pack-delta-cycles.sh
t/t5310-pack-bitmaps.sh
t/t5311-pack-bitmaps-shallow.sh
t/t5314-pack-cycle-detection.sh
t/t5315-pack-objects-compression.sh
t/t5318-commit-graph.sh
t/t5320-delta-islands.sh
t/t5321-pack-large-objects.sh
t/t5326-multi-pack-bitmaps.sh
t/t5327-multi-pack-bitmaps-rev.sh
t/t5329-pack-objects-cruft.sh
t/t5351-unpack-large-objects.sh [new file with mode: 0755]
t/t5402-post-merge-hook.sh
t/t5500-fetch-pack.sh
t/t5503-tagfollow.sh
t/t5505-remote.sh
t/t5516-fetch-push.sh
t/t5520-pull.sh
t/t5524-pull-msg.sh
t/t5541-http-push-smart.sh
t/t5544-pack-objects-hook.sh
t/t5550-http-fetch-dumb.sh
t/t5551-http-fetch-smart.sh
t/t5557-http-get.sh [new file with mode: 0755]
t/t5558-clone-bundle-uri.sh [new file with mode: 0755]
t/t5601-clone.sh
t/t5606-clone-options.sh
t/t5702-protocol-v2.sh
t/t5703-upload-pack-ref-in-want.sh
t/t6001-rev-list-graft.sh
t/t6008-rev-list-submodule.sh
t/t6019-rev-list-ancestry-path.sh
t/t6101-rev-parse-parents.sh
t/t6102-rev-list-unexpected-objects.sh
t/t6115-rev-list-du.sh
t/t6132-pathspec-exclude.sh
t/t6134-pathspec-in-submodule.sh
t/t6400-merge-df.sh
t/t6402-merge-rename.sh
t/t6403-merge-file.sh
t/t6404-recursive-merge.sh
t/t6405-merge-symlinks.sh
t/t6406-merge-attr.sh
t/t6407-merge-binary.sh
t/t6408-merge-up-to-date.sh
t/t6411-merge-filemode.sh
t/t6413-merge-crlf.sh
t/t6416-recursive-corner-cases.sh
t/t6417-merge-ours-theirs.sh
t/t6421-merge-partial-clone.sh
t/t6422-merge-rename-corner-cases.sh
t/t6423-merge-rename-directories.sh
t/t6424-merge-unrelated-index-changes.sh
t/t6425-merge-rename-delete.sh
t/t6426-merge-skip-unneeded-updates.sh
t/t6427-diff3-conflict-markers.sh
t/t6428-merge-conflicts-sparse.sh
t/t6429-merge-sequence-rename-caching.sh
t/t6431-merge-criscross.sh
t/t6435-merge-sparse.sh
t/t6437-submodule-merge.sh
t/t6439-merge-co-error-msgs.sh
t/t7002-mv-sparse-checkout.sh
t/t7003-filter-branch.sh
t/t7007-show.sh
t/t7060-wtstatus.sh
t/t7062-wtstatus-ignorecase.sh
t/t7063-status-untracked-cache.sh
t/t7110-reset-merge.sh
t/t7111-reset-table.sh
t/t7400-submodule-basic.sh
t/t7401-submodule-summary.sh
t/t7402-submodule-rebase.sh
t/t7406-submodule-update.sh
t/t7412-submodule-absorbgitdirs.sh
t/t7413-submodule-is-active.sh
t/t7414-submodule-mistakes.sh
t/t7418-submodule-sparse-gitmodules.sh
t/t7419-submodule-set-branch.sh
t/t7450-bad-git-dotfiles.sh
t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
t/t7506-status-submodule.sh
t/t7507-commit-verbose.sh
t/t7527-builtin-fsmonitor.sh
t/t7607-merge-state.sh [new file with mode: 0755]
t/t7609-mergetool--lib.sh
t/t7701-repack-unpack-unreachable.sh
t/t7810-grep.sh
t/t7812-grep-icase-non-ascii.sh
t/t7814-grep-recurse-submodules.sh
t/t7900-maintenance.sh
t/t8001-annotate.sh
t/t8002-blame.sh
t/t8007-cat-file-textconv.sh
t/t8010-cat-file-filters.sh
t/t8012-blame-colors.sh
t/t9001-send-email.sh
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9104-git-svn-follow-parent.sh
t/t9122-git-svn-author.sh
t/t9132-git-svn-broken-symlink.sh
t/t9133-git-svn-nested-git-repo.sh
t/t9134-git-svn-ignore-paths.sh
t/t9140-git-svn-reset.sh
t/t9147-git-svn-include-paths.sh
t/t9162-git-svn-dcommit-interactive.sh
t/t9210-scalar.sh [moved from contrib/scalar/t/t9099-scalar.sh with 51% similarity]
t/t9211-scalar-clone.sh [new file with mode: 0755]
t/t9301-fast-import-notes.sh
t/t9700-perl-git.sh
t/t9814-git-p4-rename.sh
t/t9815-git-p4-submit-fail.sh
t/t9901-git-web--browse.sh
t/t9903-bash-prompt.sh
t/test-lib-functions.sh
t/test-lib.sh
tempfile.c
tempfile.h
trace2/tr2_tgt_event.c
trace2/tr2_tgt_normal.c
trace2/tr2_tgt_perf.c
trailer.c
transport-helper.c
transport.c
unpack-trees.c
upload-pack.c
walker.c
wrapper.c
wt-status.c
xdiff/xdiff.h
xdiff/xdiffi.c
xdiff/xdiffi.h
xdiff/xhistogram.c
xdiff/xmacros.h
xdiff/xpatience.c
xdiff/xprepare.c
xdiff/xutils.c
xdiff/xutils.h

index a45221576418e77de53f2776912ad62cce00c85b..62720c6135d02fb5f1f533ce79249ebd7b8a3454 100644 (file)
@@ -1,7 +1,4 @@
-/fuzz-commit-graph
 /fuzz_corpora
-/fuzz-pack-headers
-/fuzz-pack-idx
 /GIT-BUILD-OPTIONS
 /GIT-CFLAGS
 /GIT-LDFLAGS
@@ -53,6 +50,7 @@
 /git-cvsimport
 /git-cvsserver
 /git-daemon
+/git-diagnose
 /git-diff
 /git-diff-files
 /git-diff-index
 /git-verify-commit
 /git-verify-pack
 /git-verify-tag
+/git-version
 /git-web--browse
 /git-whatchanged
 /git-worktree
 /git-write-tree
+/scalar
 /git-core-*/?*
+/git.res
 /gitweb/GITWEB-BUILD-OPTIONS
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
 *.hcc
 *.obj
 *.lib
-*.res
 *.sln
 *.sp
 *.suo
index 4c756be517acbfb0e18daf30bf65cb177dacef20..cb7a367ea08f9ab8c4326517d78af7a3ec486f0d 100644 (file)
@@ -162,8 +162,6 @@ For shell scripts specifically (not exhaustive):
 
    - We do not use \{m,n\};
 
-   - We do not use -E;
-
    - We do not use ? or + (which are \{0,1\} and \{1,\}
      respectively in BRE) but that goes without saying as these
      are ERE elements not BRE (note that \? and \+ are not even part
@@ -606,7 +604,7 @@ Writing Documentation:
     avoidance of gendered pronouns.
 
   - When it becomes awkward to stick to this style, prefer "you" when
-    addressing the the hypothetical user, and possibly "we" when
+    addressing the hypothetical user, and possibly "we" when
     discussing how the program might react to the user.  E.g.
 
       You can use this option instead of --xyz, but we might remove
index 4f801f4e4c9470c42ae7933a68970a4984bc54b5..d47acb2e255051fba8cabb6e5f5cb6b55a1b2311 100644 (file)
@@ -21,13 +21,25 @@ MAN1_TXT += $(filter-out \
 MAN1_TXT += git.txt
 MAN1_TXT += gitk.txt
 MAN1_TXT += gitweb.txt
+MAN1_TXT += scalar.txt
 
 # man5 / man7 guides (note: new guides should also be added to command-list.txt)
 MAN5_TXT += gitattributes.txt
+MAN5_TXT += gitformat-bundle.txt
+MAN5_TXT += gitformat-chunk.txt
+MAN5_TXT += gitformat-commit-graph.txt
+MAN5_TXT += gitformat-index.txt
+MAN5_TXT += gitformat-pack.txt
+MAN5_TXT += gitformat-signature.txt
 MAN5_TXT += githooks.txt
 MAN5_TXT += gitignore.txt
 MAN5_TXT += gitmailmap.txt
 MAN5_TXT += gitmodules.txt
+MAN5_TXT += gitprotocol-capabilities.txt
+MAN5_TXT += gitprotocol-common.txt
+MAN5_TXT += gitprotocol-http.txt
+MAN5_TXT += gitprotocol-pack.txt
+MAN5_TXT += gitprotocol-v2.txt
 MAN5_TXT += gitrepository-layout.txt
 MAN5_TXT += gitweb.conf.txt
 
@@ -51,6 +63,7 @@ HOWTO_TXT += $(wildcard howto/*.txt)
 
 DOC_DEP_TXT += $(wildcard *.txt)
 DOC_DEP_TXT += $(wildcard config/*.txt)
+DOC_DEP_TXT += $(wildcard includes/*.txt)
 
 ifdef MAN_FILTER
 MAN_TXT = $(filter $(MAN_FILTER),$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
@@ -90,31 +103,24 @@ SP_ARTICLES += howto/coordinate-embargoed-releases
 API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
 SP_ARTICLES += $(API_DOCS)
 
+TECH_DOCS += ReviewingGuidelines
 TECH_DOCS += MyFirstContribution
 TECH_DOCS += MyFirstObjectWalk
 TECH_DOCS += SubmittingPatches
 TECH_DOCS += ToolsForGit
 TECH_DOCS += technical/bitmap-format
-TECH_DOCS += technical/bundle-format
-TECH_DOCS += technical/cruft-packs
+TECH_DOCS += technical/bundle-uri
 TECH_DOCS += technical/hash-function-transition
-TECH_DOCS += technical/http-protocol
-TECH_DOCS += technical/index-format
 TECH_DOCS += technical/long-running-process-protocol
 TECH_DOCS += technical/multi-pack-index
-TECH_DOCS += technical/pack-format
 TECH_DOCS += technical/pack-heuristics
-TECH_DOCS += technical/pack-protocol
 TECH_DOCS += technical/parallel-checkout
 TECH_DOCS += technical/partial-clone
-TECH_DOCS += technical/protocol-capabilities
-TECH_DOCS += technical/protocol-common
-TECH_DOCS += technical/protocol-v2
 TECH_DOCS += technical/racy-git
 TECH_DOCS += technical/reftable
+TECH_DOCS += technical/scalar
 TECH_DOCS += technical/send-pack-pipeline
 TECH_DOCS += technical/shallow
-TECH_DOCS += technical/signature-format
 TECH_DOCS += technical/trivial-merge
 SP_ARTICLES += $(TECH_DOCS)
 SP_ARTICLES += technical/api-index
@@ -290,6 +296,8 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
        cmds-synchingrepositories.txt \
        cmds-synchelpers.txt \
        cmds-guide.txt \
+       cmds-developerinterfaces.txt \
+       cmds-userinterfaces.txt \
        cmds-purehelpers.txt \
        cmds-foreignscminterface.txt
 
index 1da15d9ad4461578b671c00329805c4ea9b7312a..1a4be8ee0adde5db48e5f53a8fe79dd17036b270 100644 (file)
@@ -1160,7 +1160,7 @@ all named like `v2-000n-my-commit-subject.patch`. `-v2` will also format
 your patches by prefixing them with "[PATCH v2]" instead of "[PATCH]",
 and your range-diff will be prefaced with "Range-diff against v1".
 
-Afer you run this command, `format-patch` will output the patches to the `psuh/`
+After you run this command, `format-patch` will output the patches to the `psuh/`
 directory, alongside the v1 patches. Using a single directory makes it easy to
 refer to the old v1 patches while proofreading the v2 patches, but you will need
 to be careful to send out only the v2 patches. We will use a pattern like
index 8d9e85566e642ecc47620cc4622414d587d3b993..eee513e86f4d645a47afcae4921de89b413fc1be 100644 (file)
@@ -534,7 +534,7 @@ the arguments to `traverse_commit_list()`.
 - `void *show_data`: A context buffer which is passed in turn to `show_commit`
   and `show_object`.
 
-In addition, `traverse_commit_list_filtered()` has an additional paramter:
+In addition, `traverse_commit_list_filtered()` has an additional parameter:
 
 - `struct oidset *omitted`: A linked-list of object IDs which the provided
   filter caused to be omitted.
diff --git a/Documentation/RelNotes/2.38.0.txt b/Documentation/RelNotes/2.38.0.txt
new file mode 100644 (file)
index 0000000..870581f
--- /dev/null
@@ -0,0 +1,404 @@
+Git v2.38 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "git remote show [-n] frotz" now pays attention to negative
+   pathspec.
+
+ * "git push" sometimes performs poorly when reachability bitmaps are
+   used, even in a repository where other operations are helped by
+   bitmaps.  The push.useBitmaps configuration variable is introduced
+   to allow disabling use of reachability bitmaps only for "git push".
+
+ * "git grep -m<max-hits>" is a way to limit the hits shown per file.
+
+ * "git merge-tree" learned a new mode where it takes two commits and
+   computes a tree that would result in the merge commit, if the
+   histories leading to these two commits were to be merged.
+
+ * "git mv A B" in a sparsely populated working tree can be asked to
+   move a path between directories that are "in cone" (i.e. expected
+   to be materialized in the working tree) and "out of cone"
+   (i.e. expected to be hidden).  The handling of such cases has been
+   improved.
+
+ * Earlier, HTTP transport clients learned to tell the server side
+   what locale they are in by sending Accept-Language HTTP header, but
+   this was done only for some requests but not others.
+
+ * Introduce a safe.barerepository configuration variable that
+   allows users to forbid discovery of bare repositories.
+
+ * Various messages that come from the pack-bitmap codepaths have been
+   tweaked.
+
+ * "git rebase -i" learns to update branches whose tip appear in the
+   rebased range with "--update-refs" option.
+
+ * "git ls-files" learns the "--format" option to tweak its output.
+
+ * "git cat-file" learned an option to use the mailmap when showing
+   commit and tag objects.
+
+ * When "git merge" finds that it cannot perform a merge, it should
+   restore the working tree to the state before the command was
+   initiated, but in some corner cases it didn't.
+
+ * Operating modes like "--batch" of "git cat-file" command learned to
+   take NUL-terminated input, instead of one-item-per-line.
+
+ * "git rm" has become more aware of the sparse-index feature.
+
+ * "git rev-list --disk-usage" learned to take an optional value
+   "human" to show the reported value in human-readable format, like
+   "3.40MiB".
+
+ * The "diagnose" feature to create a zip archive for diagnostic
+   material has been lifted from "scalar" and made into a feature of
+   "git bugreport".
+
+ * The namespaces used by "log --decorate" from "refs/" hierarchy by
+   default has been tightened.
+
+ * "git rev-list --ancestry-path=C A..B" is a natural extension of
+   "git rev-list A..B"; instead of choosing a subset of A..B to those
+   that have ancestry relationship with A, it lets a subset with
+   ancestry relationship with C.
+
+ * "scalar" now enables built-in fsmonitor on enlisted repositories,
+   when able.
+
+ * The bash prompt (in contrib/) learned to optionally indicate when
+   the index is unmerged.
+
+ * "git clone" command learned the "--bundle-uri" option to coordinate
+   with hosting sites the use of pre-prepared bundle files.
+
+ * "git range-diff" learned to honor pathspec argument if given.
+
+ * "git format-patch --from=<ident>" can be told to add an in-body
+   "From:" line even for commits that are authored by the given
+   <ident> with "--force-in-body-from" option.
+
+ * The built-in fsmonitor refuses to work on a network mounted
+   repositories; a configuration knob for users to override this has
+   been introduced.
+
+ * The "scalar" addition from Microsoft is now part of the core Git
+   installation.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Collection of what is referenced by objects in promisor packs have
+   been optimized to inspect these objects in the in-pack order.
+
+ * Introduce a helper to see if a branch is already being worked on
+   (hence should not be newly checked out in a working tree), which
+   performs much better than the existing find_shared_symref() to
+   replace many uses of the latter.
+
+ * Teach "git archive" to (optionally and then by default) avoid
+   spawning an external "gzip" process when creating ".tar.gz" (and
+   ".tgz") archives.
+
+ * Allow large objects read from a packstream to be streamed into a
+   loose object file straight, without having to keep it in-core as a
+   whole.
+
+ * Further preparation to turn git-submodule.sh into a builtin
+   continues.
+
+ * Apply Coccinelle rule to turn raw memmove() into MOVE_ARRAY() cpp
+   macro, which would improve maintainability and readability.
+
+ * Teach "make all" to build gitweb as well.
+
+ * Tweak tests so that they still work when the "git init" template
+   did not create .git/info directory.
+
+ * Add Coccinelle rules to detect the pattern of initializing and then
+   finalizing a structure without using it in between at all, which
+   happens after code restructuring and the compilers fail to
+   recognize as an unused variable.
+
+ * The code to convert between GPG trust level strings and internal
+   constants we use to represent them have been cleaned up.
+
+ * Support for libnettle as SHA256 implementation has been added.
+
+ * The way "git multi-pack" uses parse-options API has been improved.
+
+ * A Coccinelle rule (in contrib/) to encourage use of COPY_ARRAY
+   macro has been improved.
+
+ * API tweak to make it easier to run fuzz testing on commit-graph parser.
+
+ * Omit fsync-related trace2 entries when their values are all zero.
+
+ * The codepath to write multi-pack index has been taught to release a
+   large chunk of memory that holds an array of objects in the packs,
+   as soon as it is done with the array, to reduce memory consumption.
+
+ * Add a level of redirection to array allocation API in xdiff part,
+   to make it easier to share with the libgit2 project.
+
+ * "git fetch" client logs the partial clone filter used in the trace2
+   output.
+
+ * The "bundle URI" design gets documented.
+
+ * The common ancestor negotiation exchange during a "git fetch"
+   session now leaves trace log.
+
+ * Test portability improvements.
+   (merge 4d1d843be7 mt/rot13-in-c later to maint).
+
+ * The "subcommand" mode is introduced to parse-options API and update
+   the command line parser of Git commands with subcommands.
+
+ * The pack bitmap file gained a bitmap-lookup table to speed up
+   locating the necessary bitmap for a given commit.
+
+ * The assembly version of SHA-1 implementation for PPC has been
+   removed.
+
+ * The server side that responds to "git fetch" and "git clone"
+   request has been optimized by allowing it to send objects in its
+   object store without recomputing and validating the object names.
+
+ * Annotate function parameters that are not used (but cannot be
+   removed for structural reasons), to prepare us to later compile
+   with -Wunused warning turned on.
+
+ * Share the text used to explain configuration variables used by "git
+   <subcmd>" in "git help <subcmd>" with the text from "git help config".
+
+ * "git mv A B" in a sparsely populated working tree can be asked to
+   move a path from a directory that is "in cone" to another directory
+   that is "out of cone".  Handling of such a case has been improved.
+
+ * The chainlint script for our tests has been revamped.
+
+
+Fixes since v2.37
+-----------------
+
+ * Rewrite of "git add -i" in C that appeared in Git 2.25 didn't
+   correctly record a removed file to the index, which was fixed.
+
+ * Certain diff options are currently ignored when combined-diff is
+   shown; mark them as incompatible with the feature.
+
+ * Adjust technical/bitmap-format to be formatted by AsciiDoc, and
+   add some missing information to the documentation.
+
+ * Fixes for tests when the source directory has unusual characters in
+   its path, e.g. whitespaces, double-quotes, etc.
+
+ * "git mktree --missing" lazily fetched objects that are missing from
+   the local object store, which was totally unnecessary for the purpose
+   of creating the tree object(s) from its input.
+
+ * Give _() markings to fatal/warning/usage: labels that are shown in
+   front of these messages.
+
+ * References to commands-to-be-typed-literally in "git rebase"
+   documentation mark-up have been corrected.
+
+ * In a non-bare repository, the behavior of Git when the
+   core.worktree configuration variable points at a directory that has
+   a repository as its subdirectory, regressed in Git 2.27 days.
+
+ * Recent update to vimdiff layout code has been made more robust
+   against different end-user vim settings.
+
+ * Plug various memory leaks, both in the main code and in test-tool
+   commands.
+
+ * Fixes a long-standing corner case bug around directory renames in
+   the merge-ort strategy.
+
+ * The resolve-undo information in the index was not protected against
+   GC, which has been corrected.
+
+ * A corner case bug where lazily fetching objects from a promisor
+   remote resulted in infinite recursion has been corrected.
+
+ * "git clone" from a repository with some ref whose HEAD is unborn
+   did not set the HEAD in the resulting repository correctly, which
+   has been corrected.
+
+ * An earlier attempt to plug leaks placed a clean-up label to jump to
+   at a bogus place, which as been corrected.
+
+ * Variable quoting fix in the vimdiff driver of "git mergetool"
+
+ * "git shortlog -n" relied on the underlying qsort() to be stable,
+   which shouldn't have.  Fixed.
+
+ * A fix for a regression in test framework.
+
+ * mkstemp() emulation on Windows has been improved.
+
+ * Add missing documentation for "include" and "includeIf" features in
+   "git config" file format, which incidentally teaches the command
+   line completion to include them in its offerings.
+
+ * Avoid "white/black-list" in documentation and code comments.
+
+ * Workaround for a compiler warning against use of die() in
+   osx-keychain (in contrib/).
+
+ * Workaround for a false positive compiler warning.
+
+ * "git p4" working on UTF-16 files on Windows did not implement
+   CRLF-to-LF conversion correctly, which has been corrected.
+
+ * "git p4" did not handle non-ASCII client name well, which has been
+   corrected.
+
+ * "rerere-train" script (in contrib/) used to honor commit.gpgSign
+   while recreating the throw-away merges.
+
+ * "git checkout" miscounted the paths it updated, which has been
+   corrected.
+
+ * Fix for a bug that makes write-tree to fail to write out a
+   non-existent index as a tree, introduced in 2.37.
+
+ * There was a bug in the codepath to upgrade generation information
+   in commit-graph from v1 to v2 format, which has been corrected.
+
+ * Gitweb had legacy URL shortener that is specific to the way
+   projects hosted on kernel.org used to (but no longer) work, which
+   has been removed.
+
+ * Fix build procedure for Windows that uses CMake so that it can pick
+   up the shell interpreter from local installation location.
+
+ * Conditionally allow building Python interpreter on Windows
+
+ * Fix to lstat() emulation on Windows.
+
+ * Older gcc with -Wall complains about the universal zero initializer
+   "struct s = { 0 };" idiom, which makes developers' lives
+   inconvenient (as -Werror is enabled by DEVELOPER=YesPlease).  The
+   build procedure has been tweaked to help these compilers.
+
+ * Plug memory leaks in the failure code path in the "merge-ort" merge
+   strategy backend.
+
+ * "git symbolic-ref symref non..sen..se" is now diagnosed as an error.
+
+ * A follow-up fix to a fix for a regression in 2.36 around hooks.
+
+ * Avoid repeatedly running getconf to ask libc version in the test
+   suite, and instead just as it once per script.
+
+ * Platform-specific code that determines if a directory is OK to use
+   as a repository has been taught to report more details, especially
+   on Windows.
+
+ * "vimdiff3" regression fix.
+
+ * "git fsck" reads mode from tree objects but canonicalizes the mode
+   before passing it to the logic to check object sanity, which has
+   hid broken tree objects from the checking logic.  This has been
+   corrected, but to help existing projects with broken tree objects
+   that they cannot fix retroactively, the severity of anomalies this
+   code detects has been demoted to "info" for now.
+
+ * Fixes to sparse index compatibility work for "reset" and "checkout"
+   commands.
+
+ * An earlier optimization discarded a tree-object buffer that is
+   still in use, which has been corrected.
+
+ * Fix deadlocks between main Git process and subprocess spawned via
+   the pipe_command() API, that can kill "git add -p" that was
+   reimplemented in C recently.
+
+ * The sequencer machinery translated messages left in the reflog by
+   mistake, which has been corrected.
+
+ * xcalloc(), imitating calloc(), takes "number of elements of the
+   array", and "size of a single element", in this order.  A call that
+   does not follow this ordering has been corrected.
+
+ * The preload-index codepath made copies of pathspec to give to
+   multiple threads, which were left leaked.
+
+ * Update the version of Ubuntu used for GitHub Actions CI from 18.04
+   to 22.04.
+
+ * The auto-stashed local changes created by "git merge --autostash"
+   was mixed into a conflicted state left in the working tree, which
+   has been corrected.
+
+ * Multi-pack index got corrupted when preferred pack changed from one
+   pack to another in a certain way, which has been corrected.
+   (merge 99e4d084ff tb/midx-with-changing-preferred-pack-fix later to maint).
+
+ * The clean-up of temporary files created via mks_tempfile_dt() was
+   racy and attempted to unlink() the leading directory when signals
+   are involved, which has been corrected.
+   (merge babe2e0559 rs/tempfile-cleanup-race-fix later to maint).
+
+ * FreeBSD portability fix for "git maintenance" that spawns "crontab"
+   to schedule tasks.
+   (merge ee69e7884e bc/gc-crontab-fix later to maint).
+
+ * Those who use diff-so-fancy as the diff-filter noticed a regression
+   or two in the code that parses the diff output in the built-in
+   version of "add -p", which has been corrected.
+   (merge 0a101676e5 js/add-p-diff-parsing-fix later to maint).
+
+ * Segfault fix-up to an earlier fix to the topic to teach "git reset"
+   and "git checkout" work better in a sparse checkout.
+   (merge 037f8ea6d9 vd/sparse-reset-checkout-fixes later to maint).
+
+ * "git diff --no-index A B" managed its the pathnames of its two
+   input files rather haphazardly, sometimes leaking them.  The
+   command line argument processing has been straightened out to clean
+   it up.
+   (merge 2b43dd0eb5 rs/diff-no-index-cleanup later to maint).
+
+ * "git rev-list --verify-objects" ought to inspect the contents of
+   objects and notice corrupted ones, but it didn't when the commit
+   graph is in use, which has been corrected.
+   (merge b27ccae34b jk/rev-list-verify-objects-fix later to maint).
+
+ * More fixes to "add -p"
+   (merge 64ec8efb83 js/builtin-add-p-portability-fix later to maint).
+
+ * The parser in the script interface to parse-options in "git
+   rev-parse" has been updated to diagnose a bogus input correctly.
+   (merge f20b9c36d0 ow/rev-parse-parseopt-fix later to maint).
+
+ * The code that manages list-object-filter structure, used in partial
+   clones, leaked the instances, which has been plugged.
+   (merge 66eede4a37 jk/plug-list-object-filter-leaks later to maint).
+
+ * Fix another UI regression in the reimplemented "add -p".
+   (merge f6f0ee247f rs/add-p-worktree-mode-prompt-fix later to maint).
+
+ * "git fetch" over protocol v2 sent an incorrect ref prefix request
+   to the server and made "git pull" with configured fetch refspec
+   that does not cover the remote branch to merge with fail, which has
+   been corrected.
+   (merge 49ca2fba39 jk/proto-v2-ref-prefix-fix later to maint).
+
+ * A result from opendir() was leaking in the commit-graph expiration
+   codepath, which has been plugged.
+   (merge 12f1ae5324 ml/commit-graph-expire-dir-leak-fix later to maint).
+
+ * Just like we have coding guidelines, we now have guidelines for
+   reviewers.
+   (merge e01b851923 vd/doc-reviewing-guidelines later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 77b9e85c0f vd/fix-perf-tests later to maint).
+   (merge 0682bc43f5 jk/test-crontab-fixes later to maint).
+   (merge b46dd1726c cc/doc-trailer-whitespace-rules later to maint).
diff --git a/Documentation/RelNotes/2.39.0.txt b/Documentation/RelNotes/2.39.0.txt
new file mode 100644 (file)
index 0000000..3d27b72
--- /dev/null
@@ -0,0 +1,22 @@
+Git v2.39 Release Notes
+=======================
+
+Performance, Internal Implementation, Development Support etc.
+
+ * With a bit of header twiddling, use the native regexp library on
+   macOS instead of the compat/ one.
+
+ * Prepare for GNU [ef]grep that throw warning of their uses.
+
+ * Sources related to fuzz testing have been moved down to their own
+   directory.
+
+
+Fixes since v2.38
+-----------------
+
+ * The codepath that reads from the index v4 had unaligned memory
+   accesses, which has been corrected.
+   (merge 4a6ed30f96 vd/fix-unaligned-read-index-v4 later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
diff --git a/Documentation/ReviewingGuidelines.txt b/Documentation/ReviewingGuidelines.txt
new file mode 100644 (file)
index 0000000..0e323d5
--- /dev/null
@@ -0,0 +1,162 @@
+Reviewing Patches in the Git Project
+====================================
+
+Introduction
+------------
+The Git development community is a widely distributed, diverse, ever-changing
+group of individuals. Asynchronous communication via the Git mailing list poses
+unique challenges when reviewing or discussing patches. This document contains
+some guiding principles and helpful tools you can use to make your reviews both
+more efficient for yourself and more effective for other contributors.
+
+Note that none of the recommendations here are binding or in any way a
+requirement of participation in the Git community. They are provided as a
+resource to supplement your skills as a contributor.
+
+Principles
+----------
+
+Selecting patch(es) to review
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you are looking for a patch series in need of review, start by checking
+latest "What's cooking in git.git" email
+(https://lore.kernel.org/git/xmqqilm1yp3m.fsf@gitster.g/[example]). The "What's
+cooking" emails & replies can be found using the query `s:"What's cooking"` on
+the https://lore.kernel.org/git/[`lore.kernel.org` mailing list archive];
+alternatively, you can find the contents of the "What's cooking" email tracked
+in `whats-cooking.txt` on the `todo` branch of Git. Topics tagged with "Needs
+review" and those in the "[New Topics]" section are typically those that would
+benefit the most from additional review.
+
+Patches can also be searched manually in the mailing list archive using a query
+like `s:"PATCH" -s:"Re:"`. You can browse these results for topics relevant to
+your expertise or interest.
+
+If you've already contributed to Git, you may also be CC'd in another
+contributor's patch series. These are topics where the author feels that your
+attention is warranted. This may be because their patch changes something you
+wrote previously (making you a good judge of whether the new approach does or
+doesn't work), or because you have the expertise to provide an exceptionally
+helpful review. There is no requirement to review these patches but, in the
+spirit of open source collaboration, you should strongly consider doing so.
+
+Reviewing patches
+~~~~~~~~~~~~~~~~~
+While every contributor takes their own approach to reviewing patches, here are
+some general pieces of advice to make your reviews as clear and helpful as
+possible. The advice is broken into two rough categories: high-level reviewing
+guidance, and concrete tips for interacting with patches on the mailing list.
+
+==== High-level guidance
+- Remember to review the content of commit messages for correctness and clarity,
+  in addition to the code change in the patch's diff. The commit message of a
+  patch should accurately and fully explain the code change being made in the
+  diff.
+
+- Reviewing test coverage is an important - but easy to overlook - component of
+  reviews. A patch's changes may be covered by existing tests, or new tests may
+  be introduced to exercise new behavior. Checking out a patch or series locally
+  allows you to manually mutate lines of new & existing tests to verify expected
+  pass/fail behavior. You can use this information to verify proper coverage or
+  to suggest additional tests the author could add.
+
+- When providing a recommendation, be as clear as possible about whether you
+  consider it "blocking" (the code would be broken or otherwise made worse if an
+  issue isn't fixed) or "non-blocking" (the patch could be made better by taking
+  the recommendation, but acceptance of the series does not require it).
+  Non-blocking recommendations can be particularly ambiguous when they are
+  related to - but outside the scope of - a series ("nice-to-have"s), or when
+  they represent only stylistic differences between the author and reviewer.
+
+- When commenting on an issue, try to include suggestions for how the author
+  could fix it. This not only helps the author to understand and fix the issue,
+  it also deepens and improves your understanding of the topic.
+
+- Reviews do not need to exclusively point out problems. Feel free to "think out
+  loud" in your review: describe how you read & understood a complex section of
+  a patch, ask a question about something that confused you, point out something
+  you found exceptionally well-written, etc. In particular, uplifting feedback
+  goes a long way towards encouraging contributors to participate more actively
+  in the Git community.
+
+==== Performing your review
+- Provide your review comments per-patch in a plaintext "Reply-All" email to the
+  relevant patch. Comments should be made inline, immediately below the relevant
+  section(s).
+
+- You may find that the limited context provided in the patch diff is sometimes
+  insufficient for a thorough review. In such cases, you can review patches in
+  your local tree by either applying patches with linkgit:git-am[1] or checking
+  out the associated branch from https://github.com/gitster/git once the series
+  is tracked there.
+
+- Large, complicated patch diffs are sometimes unavoidable, such as when they
+  refactor existing code. If you find such a patch difficult to parse, try
+  reviewing the diff produced with the `--color-moved` and/or
+  `--ignore-space-change` options.
+
+- If a patch is long, you are encouraged to delete parts of it that are
+  unrelated to your review from the email reply. Make sure to leave enough
+  context for readers to understand your comments!
+
+- If you cannot complete a full review of a series all at once, consider letting
+  the author know (on- or off-list) if/when you plan to review the rest of the
+  series.
+
+Completing a review
+~~~~~~~~~~~~~~~~~~~
+Once each patch of a series is reviewed, the author (and/or other contributors)
+may discuss the review(s). This may result in no changes being applied, or the
+author will send a new version of their patch(es).
+
+After a series is rerolled in response to your or others' review, make sure to
+re-review the updates. If you are happy with the state of the patch series,
+explicitly indicate your approval (typically with a reply to the latest
+version's cover letter). Optionally, you can let the author know that they can
+add a "Reviewed-by: <you>" trailer if they resubmit the reviewed patch verbatim
+in a later iteration of the series.
+
+Finally, subsequent "What's cooking" emails may explicitly ask whether a
+reviewed topic is ready for merging to the `next` branch (typically phrased
+"Will merge to \'next\'?"). You can help the maintainer and author by responding
+with a short description of the state of your (and others', if applicable)
+review, including the links to the relevant thread(s).
+
+Terminology
+-----------
+nit: ::
+       Denotes a small issue that should be fixed, such as a typographical error
+       or mis-alignment of conditions in an `if()` statement.
+
+aside: ::
+optional: ::
+non-blocking: ::
+       Indicates to the reader that the following comment should not block the
+       acceptance of the patch or series. These are typically recommendations
+       related to code organization & style, or musings about topics related to
+       the patch in question, but beyond its scope.
+
+s/<before>/<after>/::
+       Shorthand for "you wrote <before>, but I think you meant <after>," usually
+       for misspellings or other typographical errors. The syntax is a reference
+       to "substitute" command commonly found in Unix tools such as `ed`, `sed`,
+       `vim`, and `perl`.
+
+cover letter::
+       The "Patch 0" of a multi-patch series. This email describes the
+       high-level intent and structure of the patch series to readers on the
+       Git mailing list. It is also where the changelog notes and range-diff of
+       subsequent versions are provided by the author.
++
+On single-patch submissions, cover letter content is typically not sent as a
+separate email. Instead, it is inserted between the end of the patch's commit
+message (after the `---`) and the beginning of the diff.
+
+#leftoverbits::
+  Used by either an author or a reviewer to describe features or suggested
+  changes that are out-of-scope of a given patch or series, but are relevant
+  to the topic for the sake of discussion.
+
+See Also
+--------
+link:MyFirstContribution.html[MyFirstContribution]
index af5da45d2878e07ffe4586bfb8c1dc16134f9e95..755a110bc48d7e2b596651ca13664c01192d966c 100755 (executable)
@@ -10,7 +10,7 @@ sub format_one {
        $state = 0;
        open I, '<', "$name.txt" or die "No such file $name.txt";
        while (<I>) {
-               if (/^git[a-z0-9-]*\(([0-9])\)$/) {
+               if (/^(?:git|scalar)[a-z0-9-]*\(([0-9])\)$/) {
                        $mansection = $1;
                        next;
                }
index 88bc799cf36e679088152bce690d3a125c0e0c69..37afbaf5a419d17f22e6598607cc13d121a8020e 100644 (file)
@@ -444,17 +444,32 @@ You probably do not need to adjust this value.
 Common unit suffixes of 'k', 'm', or 'g' are supported.
 
 core.bigFileThreshold::
-       Files larger than this size are stored deflated, without
-       attempting delta compression.  Storing large files without
-       delta compression avoids excessive memory usage, at the
-       slight expense of increased disk usage. Additionally files
-       larger than this size are always treated as binary.
+       The size of files considered "big", which as discussed below
+       changes the behavior of numerous git commands, as well as how
+       such files are stored within the repository. The default is
+       512 MiB. Common unit suffixes of 'k', 'm', or 'g' are
+       supported.
 +
-Default is 512 MiB on all platforms.  This should be reasonable
-for most projects as source code and other text files can still
-be delta compressed, but larger binary media files won't be.
+Files above the configured limit will be:
 +
-Common unit suffixes of 'k', 'm', or 'g' are supported.
+* Stored deflated in packfiles, without attempting delta compression.
++
+The default limit is primarily set with this use-case in mind. With it,
+most projects will have their source code and other text files delta
+compressed, but not larger binary media files.
++
+Storing large files without delta compression avoids excessive memory
+usage, at the slight expense of increased disk usage.
++
+* Will be treated as if they were labeled "binary" (see
+  linkgit:gitattributes[5]). e.g. linkgit:git-log[1] and
+  linkgit:git-diff[1] will not compute diffs for files above this limit.
++
+* Will generally be streamed when written, which avoids excessive
+memory usage, at the cost of some fixed overhead. Commands that make
+use of this include linkgit:git-archive[1],
+linkgit:git-fast-import[1], linkgit:git-index-pack[1],
+linkgit:git-unpack-objects[1] and linkgit:git-fsck[1].
 
 core.excludesFile::
        Specifies the pathname to the file that contains patterns to
index 32f84838ac1fa7cd54eb0d4a12f280ac4ac6fb87..35a7bf86d7774c67dbd129cc29b009aae46c81a9 100644 (file)
@@ -178,21 +178,6 @@ diff.<driver>.cachetextconv::
        Set this option to true to make the diff driver cache the text
        conversion outputs.  See linkgit:gitattributes[5] for details.
 
-diff.tool::
-       Controls which diff tool is used by linkgit:git-difftool[1].
-       This variable overrides the value configured in `merge.tool`.
-       The list below shows the valid built-in values.
-       Any other value is treated as a custom diff tool and requires
-       that a corresponding difftool.<tool>.cmd variable is defined.
-
-diff.guitool::
-       Controls which diff tool is used by linkgit:git-difftool[1] when
-       the -g/--gui flag is specified. This variable overrides the value
-       configured in `merge.guitool`. The list below shows the valid
-       built-in values. Any other value is treated as a custom diff tool
-       and requires that a corresponding difftool.<guitool>.cmd variable
-       is defined.
-
 include::../mergetools-diff.txt[]
 
 diff.indentHeuristic::
index 67625944804f6f93f6a5354056a83d039bac2e8c..a3f821121020c0b6a4c66fd74ad52a974ac07207 100644 (file)
@@ -1,6 +1,17 @@
-difftool.<tool>.path::
-       Override the path for the given tool.  This is useful in case
-       your tool is not in the PATH.
+diff.tool::
+       Controls which diff tool is used by linkgit:git-difftool[1].
+       This variable overrides the value configured in `merge.tool`.
+       The list below shows the valid built-in values.
+       Any other value is treated as a custom diff tool and requires
+       that a corresponding difftool.<tool>.cmd variable is defined.
+
+diff.guitool::
+       Controls which diff tool is used by linkgit:git-difftool[1] when
+       the -g/--gui flag is specified. This variable overrides the value
+       configured in `merge.guitool`. The list below shows the valid
+       built-in values. Any other value is treated as a custom diff tool
+       and requires that a corresponding difftool.<guitool>.cmd variable
+       is defined.
 
 difftool.<tool>.cmd::
        Specify the command to invoke the specified diff tool.
@@ -9,6 +20,17 @@ difftool.<tool>.cmd::
        file containing the contents of the diff pre-image and 'REMOTE'
        is set to the name of the temporary file containing the contents
        of the diff post-image.
++
+See the `--tool=<tool>` option in linkgit:git-difftool[1] for more details.
+
+difftool.<tool>.path::
+       Override the path for the given tool.  This is useful in case
+       your tool is not in the PATH.
+
+difftool.trustExitCode::
+       Exit difftool if the invoked diff tool returns a non-zero exit status.
++
+See the `--trust-exit-code` option in linkgit:git-difftool[1] for more details.
 
 difftool.prompt::
        Prompt before each invocation of the diff tool.
index fdbc06a4d2a837f768a213fd5ffdf28ad5a48315..c7303d8d9f004b5e413c4e5fe0dbb2f0df0c9171 100644 (file)
@@ -15,6 +15,10 @@ format.from::
        different.  If set to a non-boolean value, format-patch uses that
        value instead of your committer identity.  Defaults to false.
 
+format.forceInBodyFrom::
+       Provides the default value for the `--[no-]force-in-body-from`
+       option to format-patch.  Defaults to false.
+
 format.numbered::
        A boolean which can enable or disable sequence numbers in patch
        subjects.  It defaults to "auto" which enables it only if there
index 182edd813a5d3f970922b23e85f1000c32f4a3df..e521f20390ceaeab8701dd424f13962c3a439ffa 100644 (file)
@@ -17,8 +17,11 @@ grep.extendedRegexp::
        other than 'default'.
 
 grep.threads::
-       Number of grep worker threads to use.
-       See `grep.threads` in linkgit:git-grep[1] for more information.
+       Number of grep worker threads to use. If unset (or set to 0), Git will
+       use as many threads as the number of logical cores available.
+
+grep.fullName::
+       If set to true, enable `--full-name` option by default.
 
 grep.fallbackToNoIndex::
        If set to true, fall back to git grep --no-index if git grep
index 456eb07800cb1eef63e9d26f96a1ed35b6e65116..5f96cf87fb96ce7366f11f80b48f9c9bf9fd13f6 100644 (file)
@@ -7,6 +7,10 @@ log.date::
        Set the default date-time mode for the 'log' command.
        Setting a value for log.date is similar to using 'git log''s
        `--date` option.  See linkgit:git-log[1] for details.
++
+If the format is set to "auto:foo" and the pager is in use, format
+"foo" will be the used for the date format. Otherwise "default" will
+be used.
 
 log.decorate::
        Print out the ref names of any commits that are shown by the log
@@ -18,6 +22,11 @@ log.decorate::
        names are shown. This is the same as the `--decorate` option
        of the `git log`.
 
+log.initialDecorationSet::
+       By default, `git log` only shows decorations for certain known ref
+       namespaces. If 'all' is specified, then show all refs as
+       decorations.
+
 log.excludeDecoration::
        Exclude the specified patterns from the log decorations. This is
        similar to the `--decorate-refs-exclude` command-line option, but
@@ -25,9 +34,9 @@ log.excludeDecoration::
        option.
 
 log.diffMerges::
-       Set default diff format to be used for merge commits. See
-       `--diff-merges` in linkgit:git-log[1] for details.
-       Defaults to `separate`.
+       Set diff format to be used when `--diff-merges=on` is
+       specified, see `--diff-merges` in linkgit:git-log[1] for
+       details. Defaults to `separate`.
 
 log.follow::
        If `true`, `git log` will act as if the `--follow` option was used when
index adeda0f24d350aa084cecec0c57570420893223c..3d88fb0badba456ddabac242ee6657b44cbe5768 100644 (file)
@@ -1,7 +1,7 @@
 lsrefs.unborn::
        May be "advertise" (the default), "allow", or "ignore". If "advertise",
        the server will respond to the client sending "unborn" (as described in
-       protocol-v2.txt) and will advertise support for this feature during the
+       linkgit:gitprotocol-v2[5]) and will advertise support for this feature during the
        protocol v2 capability advertisement. "allow" is the same as
        "advertise" except that the server will not advertise support for this
        feature; this is useful for load-balanced servers that cannot be
index aeef56d49ae97dc0df99b1e63f0a842f36f3142e..c7c4811734b5c935c89b52eb3b3ddef58f49689d 100644 (file)
@@ -3,6 +3,9 @@ notes.mergeStrategy::
        conflicts.  Must be one of `manual`, `ours`, `theirs`, `union`, or
        `cat_sort_uniq`.  Defaults to `manual`.  See "NOTES MERGE STRATEGIES"
        section of linkgit:git-notes[1] for more information on each strategy.
++
+This setting can be overridden by passing the `--strategy` option to
+linkgit:git-notes[1].
 
 notes.<name>.mergeStrategy::
        Which merge strategy to choose when doing a notes merge into
@@ -11,28 +14,35 @@ notes.<name>.mergeStrategy::
        linkgit:git-notes[1] for more information on the available strategies.
 
 notes.displayRef::
-       The (fully qualified) refname from which to show notes when
-       showing commit messages.  The value of this variable can be set
-       to a glob, in which case notes from all matching refs will be
-       shown.  You may also specify this configuration variable
-       several times.  A warning will be issued for refs that do not
-       exist, but a glob that does not match any refs is silently
-       ignored.
+       Which ref (or refs, if a glob or specified more than once), in
+       addition to the default set by `core.notesRef` or
+       `GIT_NOTES_REF`, to read notes from when showing commit
+       messages with the 'git log' family of commands.
 +
 This setting can be overridden with the `GIT_NOTES_DISPLAY_REF`
 environment variable, which must be a colon separated list of refs or
 globs.
 +
+A warning will be issued for refs that do not exist,
+but a glob that does not match any refs is silently ignored.
++
+This setting can be disabled by the `--no-notes` option to the 'git
+log' family of commands, or by the `--notes=<ref>` option accepted by
+those commands.
++
 The effective value of "core.notesRef" (possibly overridden by
 GIT_NOTES_REF) is also implicitly added to the list of refs to be
 displayed.
 
 notes.rewrite.<command>::
        When rewriting commits with <command> (currently `amend` or
-       `rebase`) and this variable is set to `true`, Git
-       automatically copies your notes from the original to the
-       rewritten commit.  Defaults to `true`, but see
-       "notes.rewriteRef" below.
+       `rebase`), if this variable is `false`, git will not copy
+       notes from the original to the rewritten commit.  Defaults to
+       `true`.  See also "`notes.rewriteRef`" below.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
+environment variable, which must be a colon separated list of refs or
+globs.
 
 notes.rewriteMode::
        When copying notes during a rewrite (see the
@@ -46,14 +56,13 @@ environment variable.
 
 notes.rewriteRef::
        When copying notes during a rewrite, specifies the (fully
-       qualified) ref whose notes should be copied.  The ref may be a
-       glob, in which case notes in all matching refs will be copied.
-       You may also specify this configuration several times.
+       qualified) ref whose notes should be copied.  May be a glob,
+       in which case notes in all matching refs will be copied.  You
+       may also specify this configuration several times.
 +
 Does not have a default value; you must configure this variable to
 enable note rewriting.  Set it to `refs/notes/commits` to enable
 rewriting for the default commit notes.
 +
-This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
-environment variable, which must be a colon separated list of refs or
-globs.
+Can be overridden with the `GIT_NOTES_REWRITE_REF` environment variable.
+See `notes.rewrite.<command>` above for a further description of its format.
index ad7f73a1eade701492ae7b773cc5bb5dc37e5053..53093d99969cc090e4727a570eb667a6fba445d4 100644 (file)
@@ -164,9 +164,16 @@ When writing a multi-pack reachability bitmap, no new namehashes are
 computed; instead, any namehashes stored in an existing bitmap are
 permuted into their appropriate location when writing a new bitmap.
 
+pack.writeBitmapLookupTable::
+       When true, Git will include a "lookup table" section in the
+       bitmap index (if one is written). This table is used to defer
+       loading individual bitmaps as late as possible. This can be
+       beneficial in repositories that have relatively large bitmap
+       indexes. Defaults to false.
+
 pack.writeReverseIndex::
        When true, git will write a corresponding .rev file (see:
-       link:../technical/pack-format.html[Documentation/technical/pack-format.txt])
+       linkgit:gitformat-pack[5])
        for each new packfile that it writes in all places except for
        linkgit:git-fast-import[1] and in the bulk checkin mechanism.
        Defaults to false.
index 756591d77b080ccfe5be5a26c899b65273cf4866..576038185148d8cce30170b3fe4888b6cf3aa2b6 100644 (file)
@@ -58,6 +58,6 @@ protocol.version::
 * `1` - the original wire protocol with the addition of a version string
   in the initial response from the server.
 
-* `2` - link:technical/protocol-v2.html[wire protocol version 2].
+* `2` - Wire protocol version 2, see linkgit:gitprotocol-v2[5].
 
 --
index e32801e6c91d8145106514021ae200642b7c8366..7386fea225ae4d3215839eb42df28e414ccdf38b 100644 (file)
@@ -137,3 +137,8 @@ push.negotiate::
        server attempt to find commits in common. If "false", Git will
        rely solely on the server's ref advertisement to find commits
        in common.
+
+push.useBitmaps::
+       If set to "false", disable use of bitmaps for "git push" even if
+       `pack.useBitmaps` is "true", without preventing other git operations
+       from using bitmaps. Default is true.
index 8c979cb20f2a57d624efbbcc32d56339531d49de..f19bd0e04079051d6be21ee461d1a98c9a632629 100644 (file)
@@ -21,6 +21,9 @@ rebase.autoStash::
        `--autostash` options of linkgit:git-rebase[1].
        Defaults to false.
 
+rebase.updateRefs::
+       If set to true enable `--update-refs` option by default.
+
 rebase.missingCommitsCheck::
        If set to "warn", git rebase -i will print a warning if some
        commits are removed (e.g. a line was deleted), however the
index fa02f3ccc5490d2c4b72685b8fbb15e4fd3d0668..bde7f31459b98136a31a7eb1d457c5c43fddea54 100644 (file)
@@ -1,3 +1,22 @@
+safe.bareRepository::
+       Specifies which bare repositories Git will work with. The currently
+       supported values are:
++
+* `all`: Git works with all bare repositories. This is the default.
+* `explicit`: Git only works with bare repositories specified via
+  the top-level `--git-dir` command-line option, or the `GIT_DIR`
+  environment variable (see linkgit:git[1]).
++
+If you do not use bare repositories in your workflow, then it may be
+beneficial to set `safe.bareRepository` to `explicit` in your global
+config. This will protect you from attacks that involve cloning a
+repository that contains a bare repository and running a Git command
+within that directory.
++
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents the untrusted repository from tampering with
+this value.
+
 safe.directory::
        These config entries specify Git-tracked directories that are
        considered safe even if they are owned by someone other than the
@@ -12,9 +31,9 @@ via `git config --add`. To reset the list of safe directories (e.g. to
 override any such directories specified in the system config), add a
 `safe.directory` entry with an empty value.
 +
-This config setting is only respected when specified in a system or global
-config, not when it is specified in a repository config, via the command
-line option `-c safe.directory=<path>`, or in environment variables.
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents the untrusted repository from tampering with this
+value.
 +
 The value of this setting is interpolated, i.e. `~/<path>` expands to a
 path relative to the home directory and `%(prefix)/<path>` expands to a
index 50baa5d6bfbe8ad8f60e9f538b0643a13e1c8576..51da7088a844d3f148d78317e792efd485a2c0af 100644 (file)
@@ -18,17 +18,49 @@ sendemail.<identity>.*::
        identity is selected, through either the command-line or
        `sendemail.identity`.
 
+sendemail.multiEdit::
+       If true (default), a single editor instance will be spawned to edit
+       files you have to edit (patches when `--annotate` is used, and the
+       summary when `--compose` is used). If false, files will be edited one
+       after the other, spawning a new editor each time.
+
+sendemail.confirm::
+       Sets the default for whether to confirm before sending. Must be
+       one of 'always', 'never', 'cc', 'compose', or 'auto'. See `--confirm`
+       in the linkgit:git-send-email[1] documentation for the meaning of these
+       values.
+
 sendemail.aliasesFile::
+       To avoid typing long email addresses, point this to one or more
+       email aliases files.  You must also supply `sendemail.aliasFileType`.
+
 sendemail.aliasFileType::
+       Format of the file(s) specified in sendemail.aliasesFile. Must be
+       one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus', or 'sendmail'.
++
+What an alias file in each format looks like can be found in
+the documentation of the email program of the same name. The
+differences and limitations from the standard formats are
+described below:
++
+--
+sendmail;;
+*      Quoted aliases and quoted addresses are not supported: lines that
+       contain a `"` symbol are ignored.
+*      Redirection to a file (`/path/name`) or pipe (`|command`) is not
+       supported.
+*      File inclusion (`:include: /path/name`) is not supported.
+*      Warnings are printed on the standard error output for any
+       explicitly unsupported constructs, and any other lines that are not
+       recognized by the parser.
+--
 sendemail.annotate::
 sendemail.bcc::
 sendemail.cc::
 sendemail.ccCmd::
 sendemail.chainReplyTo::
-sendemail.confirm::
 sendemail.envelopeSender::
 sendemail.from::
-sendemail.multiEdit::
 sendemail.signedoffbycc::
 sendemail.smtpPass::
 sendemail.suppresscc::
@@ -44,7 +76,9 @@ sendemail.thread::
 sendemail.transferEncoding::
 sendemail.validate::
 sendemail.xmailer::
-       See linkgit:git-send-email[1] for description.
+       These configuration variables all provide a default for
+       linkgit:git-send-email[1] command-line options. See its
+       documentation for details.
 
 sendemail.signedoffcc (deprecated)::
        Deprecated alias for `sendemail.signedoffbycc`.
index 7ed917f5fc5f1b2eb67663f7176825bffabf0ef4..264812cca4db9a0a7b70be3eed7703d3439c9f46 100644 (file)
@@ -13,7 +13,7 @@ Note that this is currently limited to detecting credentials in
 You might want to enable this to prevent inadvertent credentials
 exposure, e.g. because:
 +
-* The OS or system where you're running git may not provide way way or
+* The OS or system where you're running git may not provide a way or
   otherwise allow you to configure the permissions of the
   configuration file where the username and/or password are stored.
 * Even if it does, having such data stored "at rest" might expose you
index 32fad5bbe817f2caa6201f0e496a06f4b055144a..16264d82a722ec01d2af662613657715e99b7bf9 100644 (file)
@@ -49,9 +49,9 @@ uploadpack.packObjectsHook::
        `pack-objects` to the hook, and expects a completed packfile on
        stdout.
 +
-Note that this configuration variable is ignored if it is seen in the
-repository-level config (this is a safety measure against fetching from
-untrusted repositories).
+Note that this configuration variable is only respected when it is specified
+in protected configuration (see <<SCOPES>>). This is a safety measure
+against fetching from untrusted repositories.
 
 uploadpack.allowFilter::
        If this option is set, `upload-pack` will support partial
index 9b37f356542d1d8787f0344abf3243996fb89476..a030d33c6e704adaf0b12168cb7ef0d062a1ef19 100644 (file)
@@ -433,6 +433,13 @@ they will make the patch impossible to apply:
 * deleting context or removal lines
 * modifying the contents of context or removal lines
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/add.txt[]
+
 SEE ALSO
 --------
 linkgit:git-status[1]
index 09107fb106703d14c9e695685e93f59e15362fc3..326276e51ce5734675f842771d41290057c53f90 100644 (file)
@@ -112,10 +112,7 @@ default.   You can use `--no-utf8` to override this.
        am.threeWay configuration variable. For more information,
        see am.threeWay in linkgit:git-config[1].
 
---rerere-autoupdate::
---no-rerere-autoupdate::
-       Allow the rerere mechanism to update the index with the
-       result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
 
 --ignore-space-change::
 --ignore-whitespace::
@@ -261,6 +258,13 @@ This command can run `applypatch-msg`, `pre-applypatch`,
 and `post-applypatch` hooks.  See linkgit:githooks[5] for more
 information.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/am.txt[]
+
 SEE ALSO
 --------
 linkgit:git-apply[1].
index b6d77f420682618be63cb27a34e803cfcac8f802..1d478cbe9b5b873566fd9fc34e5d837bd0a4595c 100644 (file)
@@ -263,13 +263,9 @@ has no effect when `--index` or `--cached` is in use.
 CONFIGURATION
 -------------
 
-apply.ignoreWhitespace::
-       Set to 'change' if you want changes in whitespace to be ignored by default.
-       Set to one of: no, none, never, false if you want changes in
-       whitespace to be significant.
-apply.whitespace::
-       When no `--whitespace` flag is given from the command
-       line, this configuration item is used as the default.
+include::includes/cmd-config-section-all.txt[]
+
+include::config/apply.txt[]
 
 SUBMODULES
 ----------
index 56989a2f3493aa80530cb9efc72e74ba8d42eb56..60c040988bb803cbca608b9e58647b75a75ac173 100644 (file)
@@ -34,10 +34,12 @@ OPTIONS
 -------
 
 --format=<fmt>::
-       Format of the resulting archive: 'tar' or 'zip'. If this option
+       Format of the resulting archive. Possible values are `tar`,
+       `zip`, `tar.gz`, `tgz`, and any format defined using the
+       configuration option `tar.<format>.command`. If `--format`
        is not given, and the output file is specified, the format is
-       inferred from the filename if possible (e.g. writing to "foo.zip"
-       makes the output to be in the zip format). Otherwise the output
+       inferred from the filename if possible (e.g. writing to `foo.zip`
+       makes the output to be in the `zip` format). Otherwise the output
        format is `tar`.
 
 -l::
@@ -143,17 +145,16 @@ tar.<format>.command::
        is executed using the shell with the generated tar file on its
        standard input, and should produce the final output on its
        standard output. Any compression-level options will be passed
-       to the command (e.g., "-9"). An output file with the same
-       extension as `<format>` will be use this format if no other
-       format is given.
+       to the command (e.g., `-9`).
 +
-The "tar.gz" and "tgz" formats are defined automatically and default to
-`gzip -cn`. You may override them with custom commands.
+The `tar.gz` and `tgz` formats are defined automatically and use the
+magic command `git archive gzip` by default, which invokes an internal
+implementation of gzip.
 
 tar.<format>.remote::
-       If true, enable `<format>` for use by remote clients via
+       If true, enable the format for use by remote clients via
        linkgit:git-upload-archive[1]. Defaults to false for
-       user-defined formats, but true for the "tar.gz" and "tgz"
+       user-defined formats, but true for the `tar.gz` and `tgz`
        formats.
 
 [[ATTRIBUTES]]
index d7a46cc67441939a9fc80ac7d6ec39eb6b44f752..4400a17330b4204227050b76d380bc84b017628a 100644 (file)
@@ -241,6 +241,12 @@ MAPPING AUTHORS
 
 See linkgit:gitmailmap[5].
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/blame.txt[]
 
 SEE ALSO
 --------
index ae82378349df74745efe26be51903a191fe76c9f..12c5f84e3bef5c83c80edec9850315dd334beffa 100644 (file)
@@ -336,6 +336,10 @@ CONFIGURATION
 `--list` is used or implied. The default is to use a pager.
 See linkgit:git-config[1].
 
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/branch.txt[]
+
 EXAMPLES
 --------
 
index d8817bf3cec3995cc7f3fa4a87c8f8ff3f9db865..eca726e57911af2cc1f0643cafdcf887c20bfa32 100644 (file)
@@ -9,6 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+               [--diagnose[=<mode>]]
 
 DESCRIPTION
 -----------
@@ -31,6 +32,10 @@ The following information is captured automatically:
  - A list of enabled hooks
  - $SHELL
 
+Additional information may be gathered into a separate zip archive using the
+`--diagnose` option, and can be attached alongside the bugreport document to
+provide additional context to readers.
+
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
 is unreadable. In this kind of scenario, it may be helpful to manually gather
@@ -49,6 +54,19 @@ OPTIONS
        named 'git-bugreport-<formatted suffix>'. This should take the form of a
        strftime(3) format string; the current local time will be used.
 
+--no-diagnose::
+--diagnose[=<mode>]::
+       Create a zip archive of supplemental information about the user's
+       machine, Git client, and repository state. The archive is written to the
+       same output directory as the bug report and is named
+       'git-diagnostics-<formatted suffix>'.
++
+Without `mode` specified, the diagnostic archive will contain the default set of
+statistics reported by `git diagnose`. An optional `mode` value may be specified
+to change which information is included in the archive. See
+linkgit:git-diagnose[1] for the list of valid values for `mode` and details
+about their usage.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 7685b570455cadc243929deecc197776326dfeba..18a022b4b40c345040c23e83bed1fd1983bd725e 100644 (file)
@@ -42,7 +42,7 @@ BUNDLE FORMAT
 Bundles are `.pack` files (see linkgit:git-pack-objects[1]) with a
 header indicating what references are contained within the bundle.
 
-Like the the packed archive format itself bundles can either be
+Like the packed archive format itself bundles can either be
 self-contained, or be created using exclusions.
 See the "OBJECT PREREQUISITES" section below.
 
@@ -56,10 +56,8 @@ using "thin packs", bundles created using exclusions are smaller in
 size. That they're "thin" under the hood is merely noted here as a
 curiosity, and as a reference to other documentation.
 
-See link:technical/bundle-format.html[the `bundle-format`
-documentation] for more details and the discussion of "thin pack" in
-link:technical/pack-format.html[the pack format documentation] for
-further details.
+See linkgit:gitformat-bundle[5] for more details and the discussion of
+"thin pack" in linkgit:gitformat-pack[5] for further details.
 
 OPTIONS
 -------
@@ -77,7 +75,7 @@ verify <file>::
        commits exist and are fully linked in the current repository.
        Then, 'git bundle' prints a list of missing commits, if any.
        Finally, information about additional capabilities, such as "object
-       filter", is printed. See "Capabilities" in link:technical/bundle-format.html
+       filter", is printed. See "Capabilities" in linkgit:gitformat-bundle[5]
        for more information. The exit code is zero for success, but will
        be nonzero if the bundle file is invalid.
 
@@ -337,6 +335,11 @@ You can also see what references it offers:
 $ git ls-remote mybundle
 ----------------
 
+FILE FORMAT
+-----------
+
+See linkgit:gitformat-bundle[5].
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 24a811f0ef64b0f411c23a3598e7bc73e6a2e7ee..ec30b5c5743fd64ea9d42f4f451dc6ce0627d80a 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
 'git cat-file' (-t | -s) [--allow-unknown-type] <object>
 'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
             [--buffer] [--follow-symlinks] [--unordered]
-            [--textconv | --filters]
+            [--textconv | --filters] [-z]
 'git cat-file' (--textconv | --filters)
             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
 
@@ -63,6 +63,12 @@ OPTIONS
        or to ask for a "blob" with `<object>` being a tag object that
        points at it.
 
+--[no-]mailmap::
+--[no-]use-mailmap::
+       Use mailmap file to map author, committer and tagger names
+       and email addresses to canonical real names and email addresses.
+       See linkgit:git-shortlog[1].
+
 --textconv::
        Show the content as transformed by a textconv filter. In this case,
        `<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in
@@ -207,6 +213,11 @@ respectively print:
        /etc/passwd
 --
 
+-z::
+       Only meaningful with `--batch`, `--batch-check`, or
+       `--batch-command`; input is NUL-delimited instead of
+       newline-delimited.
+
 
 OUTPUT
 ------
index 9f37e22e13088187c60c49f70878e883e0e092cd..4cb9d555b4b436ae6aef8e14c1729599da0d74e8 100644 (file)
@@ -600,6 +600,13 @@ $ edit frotz
 $ git add frotz
 ------------
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/checkout.txt[]
+
 SEE ALSO
 --------
 linkgit:git-switch[1],
index 78dcc9171fb04da07a5ec0308e3be83d417fefeb..1e8ac9df60274067dcf57d3f9a82ba6f270ea7d9 100644 (file)
@@ -156,10 +156,7 @@ effect to your index in a row.
        Pass the merge strategy-specific option through to the
        merge strategy.  See linkgit:git-merge[1] for details.
 
---rerere-autoupdate::
---no-rerere-autoupdate::
-       Allow the rerere mechanism to update the index with the
-       result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
 
 SEQUENCER SUBCOMMANDS
 ---------------------
index a7f309dff5a327ba14b38b63b931060582c53c28..91742633fa878922d23bc78e1aeec9a638994d38 100644 (file)
@@ -133,6 +133,13 @@ help::
 
   Show brief usage of interactive git-clean.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/clean.txt[]
+
 SEE ALSO
 --------
 linkgit:gitignore[5]
index 632bd1348ea14deb067144f187e7f57c0cf2ae60..d6434d262d6e2945ffe98f397ab8500a53990750 100644 (file)
@@ -323,6 +323,13 @@ or `--mirror` is given)
        for `host.xz:foo/.git`).  Cloning into an existing directory
        is only allowed if the directory is empty.
 
+--bundle-uri=<uri>::
+       Before fetching from the remote, fetch a bundle from the given
+       `<uri>` and unbundle the data into the local repository. The refs
+       in the bundle will be stored under the hidden `refs/bundle/*`
+       namespace. This option is incompatible with `--depth`,
+       `--shallow-since`, and `--shallow-exclude`.
+
 :git-clone: 1
 include::urls.txt[]
 
@@ -363,6 +370,15 @@ $ cd my-linux
 $ git clone --bare -l /home/proj/.git /pub/scm/proj.git
 ------------
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/init.txt[]
+
+include::config/clone.txt[]
+
 
 GIT
 ---
index 6cea9ab4638be5d1cada5e3350ddf41696280112..18431647a2da9fb825330bbb0eebbc25f11c14c6 100644 (file)
@@ -74,6 +74,13 @@ v2.4.3  v2.4.4      v2.4.5      v2.4.6      v2.4.7
 v2.4.8  v2.4.9
 ------------
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/column.txt[]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index e1f48c95b3ca37e67af88e634a44db88dd1ca6a9..36fe56c2c7192906add8bc04d43c1c5cca4aa372 100644 (file)
@@ -142,6 +142,18 @@ $ git show-ref -s | git commit-graph write --stdin-commits
 $ git rev-parse HEAD | git commit-graph write --stdin-commits --append
 ------------------------------------------------
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/commitgraph.txt[]
+
+
+FILE FORMAT
+-----------
+
+see linkgit:gitformat-commit-graph[5].
 
 GIT
 ---
index 6c60bf98f9f73ad9a892337c23c5a7f9b31b3eec..225c6c9f2e5f8f513e1e56ae77bc45d8c2097da4 100644 (file)
@@ -557,6 +557,10 @@ The editor used to edit the commit log message will be chosen from the
 `VISUAL` environment variable, or the `EDITOR` environment variable (in that
 order).  See linkgit:git-var[1] for details.
 
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/commit.txt[]
+
 HOOKS
 -----
 This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`,
index 9376e39aef206ae8d687dcf2066727de746e7c71..7a2bcb2f6cb6f94b677d47de49ae8c6d0b98f2b8 100644 (file)
@@ -297,23 +297,20 @@ The default is to use a pager.
 FILES
 -----
 
-If not set explicitly with `--file`, there are four files where
-'git config' will search for configuration options:
+By default, 'git config' will read configuration options from multiple
+files:
 
 $(prefix)/etc/gitconfig::
        System-wide configuration file.
 
 $XDG_CONFIG_HOME/git/config::
-       Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
-       or empty, `$HOME/.config/git/config` will be used. Any single-valued
-       variable set in this file will be overwritten by whatever is in
-       `~/.gitconfig`.  It is a good idea not to create this file if
-       you sometimes use older versions of Git, as support for this
-       file was added fairly recently.
-
 ~/.gitconfig::
-       User-specific configuration file. Also called "global"
-       configuration file.
+       User-specific configuration files. When the XDG_CONFIG_HOME environment
+       variable is not set or empty, $HOME/.config/ is used as
+       $XDG_CONFIG_HOME.
++
+These are also called "global" configuration files. If both files exist, both
+files are read in the order given above.
 
 $GIT_DIR/config::
        Repository specific configuration file.
@@ -322,28 +319,80 @@ $GIT_DIR/config.worktree::
        This is optional and is only searched when
        `extensions.worktreeConfig` is present in $GIT_DIR/config.
 
-If no further options are given, all reading options will read all of these
-files that are available. If the global or the system-wide configuration
-file are not available they will be ignored. If the repository configuration
-file is not available or readable, 'git config' will exit with a non-zero
-error code. However, in neither case will an error message be issued.
+You may also provide additional configuration parameters when running any
+git command by using the `-c` option. See linkgit:git[1] for details.
+
+Options will be read from all of these files that are available. If the
+global or the system-wide configuration files are missing or unreadable they
+will be ignored. If the repository configuration file is missing or unreadable,
+'git config' will exit with a non-zero error code. An error message is produced
+if the file is unreadable, but not if it is missing.
 
 The files are read in the order given above, with last value found taking
 precedence over values read earlier.  When multiple values are taken then all
 values of a key from all files will be used.
 
-You may override individual configuration parameters when running any git
-command by using the `-c` option. See linkgit:git[1] for details.
-
-All writing options will per default write to the repository specific
+By default, options are only written to the repository specific
 configuration file. Note that this also affects options like `--replace-all`
 and `--unset`. *'git config' will only ever change one file at a time*.
 
-You can override these rules using the `--global`, `--system`,
-`--local`, `--worktree`, and `--file` command-line options; see
-<<OPTIONS>> above.
+You can limit which configuration sources are read from or written to by
+specifying the path of a file with the `--file` option, or by specifying a
+configuration scope with `--system`, `--global`, `--local`, or `--worktree`.
+For more, see <<OPTIONS>> above.
+
+[[SCOPES]]
+SCOPES
+------
+
+Each configuration source falls within a configuration scope. The scopes
+are:
+
+system::
+       $(prefix)/etc/gitconfig
+
+global::
+       $XDG_CONFIG_HOME/git/config
++
+~/.gitconfig
+
+local::
+       $GIT_DIR/config
+
+worktree::
+       $GIT_DIR/config.worktree
+
+command::
+       GIT_CONFIG_{COUNT,KEY,VALUE} environment variables (see <<ENVIRONMENT>>
+       below)
++
+the `-c` option
+
+With the exception of 'command', each scope corresponds to a command line
+option: `--system`, `--global`, `--local`, `--worktree`.
+
+When reading options, specifying a scope will only read options from the
+files within that scope. When writing options, specifying a scope will write
+to the files within that scope (instead of the repository specific
+configuration file). See <<OPTIONS>> above for a complete description.
+
+Most configuration options are respected regardless of the scope it is
+defined in, but some options are only respected in certain scopes. See the
+respective option's documentation for the full details.
+
+Protected configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Protected configuration refers to the 'system', 'global', and 'command' scopes.
+For security reasons, certain options are only respected when they are
+specified in protected configuration, and ignored otherwise.
 
+Git treats these scopes as if they are controlled by the user or a trusted
+administrator. This is because an attacker who controls these scopes can do
+substantial harm without using Git, so it is assumed that the user's environment
+protects these scopes against attackers.
 
+[[ENVIRONMENT]]
 ENVIRONMENT
 -----------
 
diff --git a/Documentation/git-diagnose.txt b/Documentation/git-diagnose.txt
new file mode 100644 (file)
index 0000000..3ec8cc7
--- /dev/null
@@ -0,0 +1,65 @@
+git-diagnose(1)
+================
+
+NAME
+----
+git-diagnose - Generate a zip archive of diagnostic information
+
+SYNOPSIS
+--------
+[verse]
+'git diagnose' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+              [--mode=<mode>]
+
+DESCRIPTION
+-----------
+Collects detailed information about the user's machine, Git client, and
+repository state and packages that information into a zip archive. The
+generated archive can then, for example, be shared with the Git mailing list to
+help debug an issue or serve as a reference for independent debugging.
+
+By default, the following information is captured in the archive:
+
+  * 'git version --build-options'
+  * The path to the repository root
+  * The available disk space on the filesystem
+  * The name and size of each packfile, including those in alternate object
+    stores
+  * The total count of loose objects, as well as counts broken down by
+    `.git/objects` subdirectory
+
+Additional information can be collected by selecting a different diagnostic mode
+using the `--mode` option.
+
+This tool differs from linkgit:git-bugreport[1] in that it collects much more
+detailed information with a greater focus on reporting the size and data shape
+of repository contents.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+       Place the resulting diagnostics archive in `<path>` instead of the
+       current directory.
+
+-s <format>::
+--suffix <format>::
+       Specify an alternate suffix for the diagnostics archive name, to create
+       a file named 'git-diagnostics-<formatted suffix>'. This should take the
+       form of a strftime(3) format string; the current local time will be
+       used.
+
+--mode=(stats|all)::
+       Specify the type of diagnostics that should be collected. The default behavior
+       of 'git diagnose' is equivalent to `--mode=stats`.
++
+The `--mode=all` option collects everything included in `--mode=stats`, as well
+as copies of `.git`, `.git/hooks`, `.git/info`, `.git/logs`, and
+`.git/objects/info` directories. This additional information may be sensitive,
+as it can be used to reconstruct the full contents of the diagnosed repository.
+Users should exercise caution when sharing an archive generated with
+`--mode=all`.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 6236c75c9b826a315e553ead169b7fc3fb183c72..85ae6d6d08a2623a95830041ab076f1526dc6417 100644 (file)
@@ -213,6 +213,13 @@ $ git diff -R                          <2>
     rewrites (very expensive).
 <2> Output diff in reverse.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/diff.txt[]
+
 SEE ALSO
 --------
 diff(1),
index 143b0c49d739aef285aab7b10a0c536257d5f6fc..9d14c3c9f099aab8d225767ef6d308ecee2e6713 100644 (file)
@@ -113,33 +113,14 @@ instead.  `--no-symlinks` is the default on Windows.
 
 See linkgit:git-diff[1] for the full list of supported options.
 
-CONFIG VARIABLES
-----------------
+CONFIGURATION
+-------------
 'git difftool' falls back to 'git mergetool' config variables when the
 difftool equivalents have not been defined.
 
-diff.tool::
-       The default diff tool to use.
+include::includes/cmd-config-section-rest.txt[]
 
-diff.guitool::
-       The default diff tool to use when `--gui` is specified.
-
-difftool.<tool>.path::
-       Override the path for the given tool.  This is useful in case
-       your tool is not in the PATH.
-
-difftool.<tool>.cmd::
-       Specify the command to invoke the specified diff tool.
-+
-See the `--tool=<tool>` option above for more details.
-
-difftool.prompt::
-       Prompt before each invocation of the diff tool.
-
-difftool.trustExitCode::
-       Exit difftool if the invoked diff tool returns a non-zero exit status.
-+
-See the `--trust-exit-code` option above for more details.
+include::config/difftool.txt[]
 
 SEE ALSO
 --------
index 39cfa05b28b0126544b5ed8b89e0fd1b697c3e09..8b5dd6add006d111688fc1193d77ebe6b45422a5 100644 (file)
@@ -1564,6 +1564,13 @@ operator can use this facility to peek at the objects and refs from an
 import in progress, at the cost of some added running time and worse
 compression.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fastimport.txt[]
+
 SEE ALSO
 --------
 linkgit:git-fast-export[1]
index e9d364669af7b9fa2aaf59605dc9e7fa386ca021..63d9569e16444237a7583b8c9dafe232eb1d2e42 100644 (file)
@@ -285,6 +285,13 @@ linkgit:git-gc[1]).
 
 include::transfer-data-leaks.txt[]
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fetch.txt[]
+
 BUGS
 ----
 Using --recurse-submodules can only fetch new commits in submodules that are
index be797d7a28f62f38e2dc38c82141e71b97ea4aae..dfcc7da4c211706570cd1ce7e1fd8552fb8947d9 100644 (file)
@@ -275,6 +275,17 @@ header). Note also that `git send-email` already handles this
 transformation for you, and this option should not be used if you are
 feeding the result to `git send-email`.
 
+--[no-]force-in-body-from::
+       With the e-mail sender specified via the `--from` option, by
+       default, an in-body "From:" to identify the real author of
+       the commit is added at the top of the commit log message if
+       the sender is different from the author.  With this option,
+       the in-body "From:" is added even when the sender and the
+       author have the same name and address, which may help if the
+       mailing list software mangles the sender's identity.
+       Defaults to the value of the `format.forceInBodyFrom`
+       configuration variable.
+
 --add-header=<header>::
        Add an arbitrary header to the email headers.  This is in addition
        to any configured headers, and may be used multiple times.
index 5088783dccb923bac475d4d0a8419d57b27ecfb0..29318ea957ef8fda0aee500d795c6f04fce0cae2 100644 (file)
@@ -107,6 +107,8 @@ care about this output and want to speed it up further.
 CONFIGURATION
 -------------
 
+include::includes/cmd-config-section-all.txt[]
+
 include::config/fsck.txt[]
 
 DISCUSSION
index 0af7540a0c8b1b7b0df703b7b089dcc74e3c3267..a65c9aa62d64112dfd03335af82a680e54d00c58 100644 (file)
@@ -110,8 +110,7 @@ users and their repositories.
 CONFIGURATION
 -------------
 
-The below documentation is the same as what's found in
-linkgit:git-config[1]:
+include::includes/cmd-config-section-all.txt[]
 
 include::config/gc.txt[]
 
index 3d393fbac1bb3323c41ea2b74f6bba8f8ca39c00..dabdbe8471de5d36bf55589aa74a270901ff882e 100644 (file)
@@ -23,6 +23,7 @@ SYNOPSIS
           [--break] [--heading] [-p | --show-function]
           [-A <post-context>] [-B <pre-context>] [-C <context>]
           [-W | --function-context]
+          [(-m | --max-count) <num>]
           [--threads <num>]
           [-f <file>] [-e] <pattern>
           [--and|--or|--not|(|)|-e <pattern>...]
@@ -238,6 +239,14 @@ providing this option will cause it to die.
        `git diff` works out patch hunk headers (see 'Defining a
        custom hunk-header' in linkgit:gitattributes[5]).
 
+-m <num>::
+--max-count <num>::
+       Limit the amount of matches per file. When using the `-v` or
+       `--invert-match` option, the search stops after the specified
+       number of non-matches. A value of -1 will return unlimited
+       results (the default). A value of 0 will exit immediately with
+       a non-zero status.
+
 --threads <num>::
        Number of grep worker threads to use.
        See `grep.threads` in 'CONFIGURATION' for more information.
@@ -334,34 +343,9 @@ performance in this case, it might be desirable to use `--threads=1`.
 CONFIGURATION
 -------------
 
-grep.lineNumber::
-       If set to true, enable `-n` option by default.
-
-grep.column::
-       If set to true, enable the `--column` option by default.
-
-grep.patternType::
-       Set the default matching behavior. Using a value of 'basic', 'extended',
-       'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,
-       `--fixed-strings`, or `--perl-regexp` option accordingly, while the
-       value 'default' will return to the default matching behavior.
-
-grep.extendedRegexp::
-       If set to true, enable `--extended-regexp` option by default. This
-       option is ignored when the `grep.patternType` option is set to a value
-       other than 'default'.
-
-grep.threads::
-       Number of grep worker threads to use. If unset (or set to 0), Git will
-       use as many threads as the number of logical cores available.
-
-grep.fullName::
-       If set to true, enable `--full-name` option by default.
-
-grep.fallbackToNoIndex::
-       If set to true, fall back to git grep --no-index if git grep
-       is executed outside of a git repository.  Defaults to false.
+include::includes/cmd-config-section-all.txt[]
 
+include::config/grep.txt[]
 
 GIT
 ---
index 239c68db457098cae526e4691061c7373b61266a..2b0b5e390dcb94a651ca92ded8c1542a175f7f09 100644 (file)
@@ -9,14 +9,16 @@ SYNOPSIS
 --------
 [verse]
 'git help' [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]
-'git help' [[-i|--info] [-m|--man] [-w|--web]] [<command>|<guide>]
+'git help' [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]
 'git help' [-g|--guides]
 'git help' [-c|--config]
+'git help' [--user-interfaces]
+'git help' [--developer-interfaces]
 
 DESCRIPTION
 -----------
 
-With no options and no '<command>' or '<guide>' given, the synopsis of the 'git'
+With no options and no '<command>' or '<doc>' given, the synopsis of the 'git'
 command and a list of the most commonly used Git commands are printed
 on the standard output.
 
@@ -26,8 +28,8 @@ printed on the standard output.
 If the option `--guides` or `-g` is given, a list of the
 Git concept guides is also printed on the standard output.
 
-If a command, or a guide, is given, a manual page for that command or
-guide is brought up. The 'man' program is used by default for this
+If a command or other documentation is given, the relevant manual page
+will be brought up. The 'man' program is used by default for this
 purpose, but this can be overridden by other options or configuration
 variables.
 
@@ -69,6 +71,23 @@ OPTIONS
 --guides::
        Prints a list of the Git concept guides on the standard output.
 
+--user-interfaces::
+       Prints a list of the repository, command and file interfaces
+       documentation on the standard output.
++
+In-repository file interfaces such as `.git/info/exclude` are
+documented here (see linkgit:gitrepository-layout[5]), as well as
+in-tree configuration such as `.mailmap` (see linkgit:gitmailmap[5]).
++
+This section of the documentation also covers general or widespread
+user-interface conventions (e.g. linkgit:gitcli[7]), and
+pseudo-configuration such as the file-based `.git/hooks/*` interface
+described in linkgit:githooks[5].
+
+--developer-interfaces::
+       Print list of file formats, protocols and other developer
+       interfaces documentation on the standard output.
+
 -i::
 --info::
        Display manual page for the command in the 'info' format. The
index 63cf498ce9f276878ea8a7bd79362a423210d030..f7b185151415b54b08fb21f54062842baf64e636 100644 (file)
@@ -54,6 +54,8 @@ CONFIGURATION
 To use the tool, `imap.folder` and either `imap.tunnel` or `imap.host` must be set
 to appropriate values.
 
+include::includes/cmd-config-section-rest.txt[]
+
 include::config/imap.txt[]
 
 EXAMPLES
index ad921fe782eae542ba5adfaa41e74d674af2dda9..160dea1372cd9ae87f1bad9744e2ae045ed1b5b6 100644 (file)
@@ -169,6 +169,13 @@ $ git commit    <3>
 <2> Add all existing files to the index.
 <3> Record the pristine state as the first commit in the history.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/init.txt[]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 956a01d184f78832ea8ac8d1874ae1cc568dccaa..6d6197cd0a41ec08954e3b19ab1eb355c01dc5ea 100644 (file)
@@ -60,10 +60,12 @@ non-whitespace lines before a line that starts with '---' (followed by a
 space or the end of the line). Such three minus signs start the patch
 part of the message. See also `--no-divider` below.
 
-When reading trailers, there can be whitespaces after the
-token, the separator and the value. There can also be whitespaces
-inside the token and the value. The value may be split over multiple lines with
-each subsequent line starting with whitespace, like the "folding" in RFC 822.
+When reading trailers, there can be no whitespace before or inside the
+token, but any number of regular space and tab characters are allowed
+between the token and the separator. There can be whitespaces before,
+inside or after the value. The value may be split over multiple lines
+with each subsequent line starting with at least one whitespace, like
+the "folding" in RFC 822.
 
 Note that 'trailers' do not follow and are not intended to follow many
 rules for RFC 822 headers. For example they do not follow
index 20e87cecf4917fdbb18c2ffe675a1b2d9e4c3177..2a66cf888074656ce775ad93551603c15fed4ddc 100644 (file)
@@ -45,13 +45,23 @@ OPTIONS
 
 --decorate-refs=<pattern>::
 --decorate-refs-exclude=<pattern>::
-       If no `--decorate-refs` is given, pretend as if all refs were
-       included.  For each candidate, do not use it for decoration if it
+       For each candidate reference, do not use it for decoration if it
        matches any patterns given to `--decorate-refs-exclude` or if it
        doesn't match any of the patterns given to `--decorate-refs`. The
        `log.excludeDecoration` config option allows excluding refs from
        the decorations, but an explicit `--decorate-refs` pattern will
        override a match in `log.excludeDecoration`.
++
+If none of these options or config settings are given, then references are
+used as decoration if they match `HEAD`, `refs/heads/`, `refs/remotes/`,
+`refs/stash/`, or `refs/tags/`.
+
+--clear-decorations::
+       When specified, this option clears all previous `--decorate-refs`
+       or `--decorate-refs-exclude` options and relaxes the default
+       decoration filter to include all references. This option is
+       assumed if the config value `log.initialDecorationSet` is set to
+       `all`.
 
 --source::
        Print out the ref name given on the command line by which each
@@ -199,47 +209,11 @@ i18n.logOutputEncoding::
        Defaults to the value of `i18n.commitEncoding` if set, and UTF-8
        otherwise.
 
-log.date::
-       Default format for human-readable dates.  (Compare the
-       `--date` option.)  Defaults to "default", which means to write
-       dates like `Sat May 8 19:35:34 2010 -0500`.
-+
-If the format is set to "auto:foo" and the pager is in use, format
-"foo" will be the used for the date format. Otherwise "default" will
-be used.
-
-log.follow::
-       If `true`, `git log` will act as if the `--follow` option was used when
-       a single <path> is given.  This has the same limitations as `--follow`,
-       i.e. it cannot be used to follow multiple files and does not work well
-       on non-linear history.
-
-log.showRoot::
-       If `false`, `git log` and related commands will not treat the
-       initial commit as a big creation event.  Any root commits in
-       `git log -p` output would be shown without a diff attached.
-       The default is `true`.
-
-log.showSignature::
-       If `true`, `git log` and related commands will act as if the
-       `--show-signature` option was passed to them.
-
-mailmap.*::
-       See linkgit:git-shortlog[1].
-
-notes.displayRef::
-       Which refs, in addition to the default set by `core.notesRef`
-       or `GIT_NOTES_REF`, to read notes from when showing commit
-       messages with the `log` family of commands.  See
-       linkgit:git-notes[1].
-+
-May be an unabbreviated ref name or a glob and may be specified
-multiple times.  A warning will be issued for refs that do not exist,
-but a glob that does not match any refs is silently ignored.
-+
-This setting can be disabled by the `--no-notes` option,
-overridden by the `GIT_NOTES_DISPLAY_REF` environment variable,
-and overridden by the `--notes=<ref>` option.
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/log.txt[]
+
+include::config/notes.txt[]
 
 GIT
 ---
index 0dabf3f0ddc8d893818b3ce09436c1b5b1c72a33..d7986419c2507a7032961ba5b37ce6c73e5822f9 100644 (file)
@@ -20,7 +20,7 @@ SYNOPSIS
                [--exclude-standard]
                [--error-unmatch] [--with-tree=<tree-ish>]
                [--full-name] [--recurse-submodules]
-               [--abbrev[=<n>]] [--] [<file>...]
+               [--abbrev[=<n>]] [--format=<format>] [--] [<file>...]
 
 DESCRIPTION
 -----------
@@ -192,6 +192,13 @@ followed by the  ("attr/<eolattr>").
        to the contained files. Sparse directories will be shown with a
        trailing slash, such as "x/" for a sparse directory "x".
 
+--format=<format>::
+       A string that interpolates `%(fieldname)` from the result being shown.
+       It also interpolates `%%` to `%`, and `%xx` where `xx` are hex digits
+       interpolates to character with hex code `xx`; for example `%00`
+       interpolates to `\0` (NUL), `%09` to `\t` (TAB) and %0a to `\n` (LF).
+       --format cannot be combined with `-s`, `-o`, `-k`, `-t`, `--resolve-undo`
+       and `--eol`.
 \--::
        Do not interpret any more arguments as options.
 
@@ -223,6 +230,36 @@ quoted as explained for the configuration variable `core.quotePath`
 (see linkgit:git-config[1]).  Using `-z` the filename is output
 verbatim and the line is terminated by a NUL byte.
 
+It is possible to print in a custom format by using the `--format`
+option, which is able to interpolate different fields using
+a `%(fieldname)` notation. For example, if you only care about the
+"objectname" and "path" fields, you can execute with a specific
+"--format" like
+
+       git ls-files --format='%(objectname) %(path)'
+
+FIELD NAMES
+-----------
+The way each path is shown can be customized by using the
+`--format=<format>` option, where the %(fieldname) in the
+<format> string for various aspects of the index entry are
+interpolated.  The following "fieldname" are understood:
+
+objectmode::
+       The mode of the file which is recorded in the index.
+objectname::
+       The name of the file which is recorded in the index.
+stage::
+       The stage of the file which is recorded in the index.
+eolinfo:index::
+eolinfo:worktree::
+       The <eolinfo> (see the description of the `--eol` option) of
+       the contents in the index or in the worktree for the path.
+eolattr::
+       The <eolattr> (see the description of the `--eol` option)
+       that applies to the path.
+path::
+       The pathname of the file which is recorded in the index.
 
 EXCLUDE PATTERNS
 ----------------
index 3fcfd965fdec62613567278dbd7b08b0080778c7..28060283c703a991d4d2aa36b99b867b8d6c8d43 100644 (file)
@@ -115,6 +115,13 @@ If no such configuration option has been set, `warn` will be used.
 <patch>::
        The patch extracted from e-mail.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/mailinfo.txt[]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index e56bad28c6551f0f0a1990f245da4f551df74178..9c630efe19c68ec4b25fee1cf716c5a2073e2f51 100644 (file)
@@ -397,6 +397,13 @@ If you want to customize the background tasks, please rename the tasks
 so future calls to `git maintenance (start|stop)` do not overwrite your
 custom tasks.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/maintenance.txt[]
+
 
 GIT
 ---
index 58731c194229e7e14b4eca27465fd42894d9a710..d6c356740efcaa2ddb7c668f123b4024e3c0f270 100644 (file)
@@ -3,26 +3,237 @@ git-merge-tree(1)
 
 NAME
 ----
-git-merge-tree - Show three-way merge without touching index
+git-merge-tree - Perform merge without touching index or working tree
 
 
 SYNOPSIS
 --------
 [verse]
-'git merge-tree' <base-tree> <branch1> <branch2>
+'git merge-tree' [--write-tree] [<options>] <branch1> <branch2>
+'git merge-tree' [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)
 
+[[NEWMERGE]]
 DESCRIPTION
 -----------
-Reads three tree-ish, and output trivial merge results and
-conflicting stages to the standard output.  This is similar to
-what three-way 'git read-tree -m' does, but instead of storing the
-results in the index, the command outputs the entries to the
-standard output.
-
-This is meant to be used by higher level scripts to compute
-merge results outside of the index, and stuff the results back into the
-index.  For this reason, the output from the command omits
-entries that match the <branch1> tree.
+
+This command has a modern `--write-tree` mode and a deprecated
+`--trivial-merge` mode.  With the exception of the
+<<DEPMERGE,DEPRECATED DESCRIPTION>> section at the end, the rest of
+this documentation describes modern `--write-tree` mode.
+
+Performs a merge, but does not make any new commits and does not read
+from or write to either the working tree or index.
+
+The performed merge will use the same feature as the "real"
+linkgit:git-merge[1], including:
+
+  * three way content merges of individual files
+  * rename detection
+  * proper directory/file conflict handling
+  * recursive ancestor consolidation (i.e. when there is more than one
+    merge base, creating a virtual merge base by merging the merge bases)
+  * etc.
+
+After the merge completes, a new toplevel tree object is created.  See
+`OUTPUT` below for details.
+
+OPTIONS
+-------
+
+-z::
+       Do not quote filenames in the <Conflicted file info> section,
+       and end each filename with a NUL character rather than
+       newline.  Also begin the messages section with a NUL character
+       instead of a newline.  See <<OUTPUT>> below for more information.
+
+--name-only::
+       In the Conflicted file info section, instead of writing a list
+       of (mode, oid, stage, path) tuples to output for conflicted
+       files, just provide a list of filenames with conflicts (and
+       do not list filenames multiple times if they have multiple
+       conflicting stages).
+
+--[no-]messages::
+       Write any informational messages such as "Auto-merging <path>"
+       or CONFLICT notices to the end of stdout.  If unspecified, the
+       default is to include these messages if there are merge
+       conflicts, and to omit them otherwise.
+
+--allow-unrelated-histories::
+       merge-tree will by default error out if the two branches specified
+       share no common history.  This flag can be given to override that
+       check and make the merge proceed anyway.
+
+[[OUTPUT]]
+OUTPUT
+------
+
+For a successful merge, the output from git-merge-tree is simply one
+line:
+
+       <OID of toplevel tree>
+
+Whereas for a conflicted merge, the output is by default of the form:
+
+       <OID of toplevel tree>
+       <Conflicted file info>
+       <Informational messages>
+
+These are discussed individually below.
+
+[[OIDTLT]]
+OID of toplevel tree
+~~~~~~~~~~~~~~~~~~~~
+
+This is a tree object that represents what would be checked out in the
+working tree at the end of `git merge`.  If there were conflicts, then
+files within this tree may have embedded conflict markers.  This section
+is always followed by a newline (or NUL if `-z` is passed).
+
+[[CFI]]
+Conflicted file info
+~~~~~~~~~~~~~~~~~~~~
+
+This is a sequence of lines with the format
+
+       <mode> <object> <stage> <filename>
+
+The filename will be quoted as explained for the configuration
+variable `core.quotePath` (see linkgit:git-config[1]).  However, if
+the `--name-only` option is passed, the mode, object, and stage will
+be omitted.  If `-z` is passed, the "lines" are terminated by a NUL
+character instead of a newline character.
+
+[[IM]]
+Informational messages
+~~~~~~~~~~~~~~~~~~~~~~
+
+This always starts with a blank line (or NUL if `-z` is passed) to
+separate it from the previous sections, and then has free-form
+messages about the merge, such as:
+
+  * "Auto-merging <file>"
+  * "CONFLICT (rename/delete): <oldfile> renamed...but deleted in..."
+  * "Failed to merge submodule <submodule> (<reason>)"
+  * "Warning: cannot merge binary files: <filename>"
+
+Note that these free-form messages will never have a NUL character
+in or between them, even if -z is passed.  It is simply a large block
+of text taking up the remainder of the output.
+
+EXIT STATUS
+-----------
+
+For a successful, non-conflicted merge, the exit status is 0.  When the
+merge has conflicts, the exit status is 1.  If the merge is not able to
+complete (or start) due to some kind of error, the exit status is
+something other than 0 or 1 (and the output is unspecified).
+
+USAGE NOTES
+-----------
+
+This command is intended as low-level plumbing, similar to
+linkgit:git-hash-object[1], linkgit:git-mktree[1],
+linkgit:git-commit-tree[1], linkgit:git-write-tree[1],
+linkgit:git-update-ref[1], and linkgit:git-mktag[1].  Thus, it can be
+used as a part of a series of steps such as:
+
+       NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
+       test $? -eq 0 || die "There were conflicts..."
+       NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
+       git update-ref $BRANCH1 $NEWCOMMIT
+
+Note that when the exit status is non-zero, `NEWTREE` in this sequence
+will contain a lot more output than just a tree.
+
+For conflicts, the output includes the same information that you'd get
+with linkgit:git-merge[1]:
+
+  * what would be written to the working tree (the
+    <<OIDTLT,OID of toplevel tree>>)
+  * the higher order stages that would be written to the index (the
+    <<CFI,Conflicted file info>>)
+  * any messages that would have been printed to stdout (the
+    <<IM,Informational messages>>)
+
+MISTAKES TO AVOID
+-----------------
+
+Do NOT look through the resulting toplevel tree to try to find which
+files conflict; parse the <<CFI,Conflicted file info>> section instead.
+Not only would parsing an entire tree be horrendously slow in large
+repositories, there are numerous types of conflicts not representable by
+conflict markers (modify/delete, mode conflict, binary file changed on
+both sides, file/directory conflicts, various rename conflict
+permutations, etc.)
+
+Do NOT interpret an empty <<CFI,Conflicted file info>> list as a clean
+merge; check the exit status.  A merge can have conflicts without having
+individual files conflict (there are a few types of directory rename
+conflicts that fall into this category, and others might also be added
+in the future).
+
+Do NOT attempt to guess or make the user guess the conflict types from
+the <<CFI,Conflicted file info>> list.  The information there is
+insufficient to do so.  For example: Rename/rename(1to2) conflicts (both
+sides renamed the same file differently) will result in three different
+file having higher order stages (but each only has one higher order
+stage), with no way (short of the <<IM,Informational messages>> section)
+to determine which three files are related.  File/directory conflicts
+also result in a file with exactly one higher order stage.
+Possibly-involved-in-directory-rename conflicts (when
+"merge.directoryRenames" is unset or set to "conflicts") also result in
+a file with exactly one higher order stage.  In all cases, the
+<<IM,Informational messages>> section has the necessary info, though it
+is not designed to be machine parseable.
+
+Do NOT assume that each paths from <<CFI,Conflicted file info>>, and
+the logical conflicts in the <<IM,Informational messages>> have a
+one-to-one mapping, nor that there is a one-to-many mapping, nor a
+many-to-one mapping.  Many-to-many mappings exist, meaning that each
+path can have many logical conflict types in a single merge, and each
+logical conflict type can affect many paths.
+
+Do NOT assume all filenames listed in the <<IM,Informational messages>>
+section had conflicts.  Messages can be included for files that have no
+conflicts, such as "Auto-merging <file>".
+
+AVOID taking the OIDS from the <<CFI,Conflicted file info>> and
+re-merging them to present the conflicts to the user.  This will lose
+information.  Instead, look up the version of the file found within the
+<<OIDTLT,OID of toplevel tree>> and show that instead.  In particular,
+the latter will have conflict markers annotated with the original
+branch/commit being merged and, if renames were involved, the original
+filename.  While you could include the original branch/commit in the
+conflict marker annotations when re-merging, the original filename is
+not available from the <<CFI,Conflicted file info>> and thus you would
+be losing information that might help the user resolve the conflict.
+
+[[DEPMERGE]]
+DEPRECATED DESCRIPTION
+----------------------
+
+Per the <<NEWMERGE,DESCRIPTION>> and unlike the rest of this
+documentation, this section describes the deprecated `--trivial-merge`
+mode.
+
+Other than the optional `--trivial-merge`, this mode accepts no
+options.
+
+This mode reads three tree-ish, and outputs trivial merge results and
+conflicting stages to the standard output in a semi-diff format.
+Since this was designed for higher level scripts to consume and merge
+the results back into the index, it omits entries that match
+<branch1>.  The result of this second form is similar to what
+three-way 'git read-tree -m' does, but instead of storing the results
+in the index, the command outputs the entries to the standard output.
+
+This form not only has limited applicability (a trivial merge cannot
+handle content merges of individual files, rename detection, proper
+directory/file conflict handling, etc.), the output format is also
+difficult to work with, and it will generally be less performant than
+the first form even on successful merges (especially if working in
+large repositories).
 
 GIT
 ---
index 3125473cc1d19140cf54f5286106b86823a9b91f..2d6a1391c89412e66aa1227201bdd89ba2f0f27a 100644 (file)
@@ -90,10 +90,7 @@ invocations. The automated message can include the branch description.
 If `--log` is specified, a shortlog of the commits being merged
 will be appended to the specified message.
 
---rerere-autoupdate::
---no-rerere-autoupdate::
-       Allow the rerere mechanism to update the index with the
-       result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
 
 --overwrite-ignore::
 --no-overwrite-ignore::
@@ -386,13 +383,16 @@ include::merge-strategies.txt[]
 
 CONFIGURATION
 -------------
-include::config/merge.txt[]
 
 branch.<name>.mergeOptions::
        Sets default options for merging into branch <name>. The syntax and
        supported options are the same as those of 'git merge', but option
        values containing whitespace characters are currently not supported.
 
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/merge.txt[]
+
 SEE ALSO
 --------
 linkgit:git-fmt-merge-msg[1], linkgit:git-pull[1],
index f784027bc13724712f902b115abd98bc1c04b43f..c44e205629bf521fbb97c2b49493fcc9b9450932 100644 (file)
@@ -102,6 +102,9 @@ success of the resolution after the custom tool has exited.
 CONFIGURATION
 -------------
 :git-mergetool: 1
+
+include::includes/cmd-config-section-all.txt[]
+
 include::config/mergetool.txt[]
 
 TEMPORARY FILES
index c588fb91af1995c844108cee346512815e39cb3d..a48c3d5ea6301abcdda5df021ac8442ed149f23c 100644 (file)
@@ -128,8 +128,8 @@ $ git multi-pack-index verify
 SEE ALSO
 --------
 See link:technical/multi-pack-index.html[The Multi-Pack-Index Design
-Document] and link:technical/pack-format.html[The Multi-Pack-Index
-Format] for more information on the multi-pack-index feature.
+Document] and linkgit:gitformat-pack[5] for more information on the
+multi-pack-index feature and its file format.
 
 
 GIT
index 0a4200674c40af473d135ccd5df129f28a684864..efbc10f0f598eccd247f13c3e5d1ecf9473a6f78 100644 (file)
@@ -44,7 +44,7 @@ using the `--notes` option. Such notes are added as a patch commentary
 after a three dash separator line.
 
 To change which notes are shown by 'git log', see the
-"notes.displayRef" configuration in linkgit:git-log[1].
+"notes.displayRef" discussion in <<CONFIGURATION>>.
 
 See the "notes.rewrite.<command>" configuration for a way to carry
 notes across commands that rewrite commits.
@@ -307,6 +307,7 @@ with 'git log', so if you use such notes, you'll probably need to write
 some special-purpose tools to do something useful with them.
 
 
+[[CONFIGURATION]]
 CONFIGURATION
 -------------
 
@@ -316,57 +317,9 @@ core.notesRef::
        This setting can be overridden through the environment and
        command line.
 
-notes.mergeStrategy::
-       Which merge strategy to choose by default when resolving notes
-       conflicts.  Must be one of `manual`, `ours`, `theirs`, `union`, or
-       `cat_sort_uniq`.  Defaults to `manual`.  See "NOTES MERGE STRATEGIES"
-       section above for more information on each strategy.
-+
-This setting can be overridden by passing the `--strategy` option.
-
-notes.<name>.mergeStrategy::
-       Which merge strategy to choose when doing a notes merge into
-       refs/notes/<name>.  This overrides the more general
-       "notes.mergeStrategy".  See the "NOTES MERGE STRATEGIES" section above
-       for more information on each available strategy.
-
-notes.displayRef::
-       Which ref (or refs, if a glob or specified more than once), in
-       addition to the default set by `core.notesRef` or
-       `GIT_NOTES_REF`, to read notes from when showing commit
-       messages with the 'git log' family of commands.
-       This setting can be overridden on the command line or by the
-       `GIT_NOTES_DISPLAY_REF` environment variable.
-       See linkgit:git-log[1].
-
-notes.rewrite.<command>::
-       When rewriting commits with <command> (currently `amend` or
-       `rebase`), if this variable is `false`, git will not copy
-       notes from the original to the rewritten commit.  Defaults to
-       `true`.  See also "`notes.rewriteRef`" below.
-+
-This setting can be overridden by the `GIT_NOTES_REWRITE_REF`
-environment variable.
+include::includes/cmd-config-section-rest.txt[]
 
-notes.rewriteMode::
-       When copying notes during a rewrite, what to do if the target
-       commit already has a note.  Must be one of `overwrite`,
-       `concatenate`, `cat_sort_uniq`, or `ignore`.  Defaults to
-       `concatenate`.
-+
-This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
-environment variable.
-
-notes.rewriteRef::
-       When copying notes during a rewrite, specifies the (fully
-       qualified) ref whose notes should be copied.  May be a glob,
-       in which case notes in all matching refs will be copied.  You
-       may also specify this configuration several times.
-+
-Does not have a default value; you must configure this variable to
-enable note rewriting.
-+
-Can be overridden with the `GIT_NOTES_REWRITE_REF` environment variable.
+include::config/notes.txt[]
 
 
 ENVIRONMENT
index 2f25aa3a291b529be87823765e295934f62484e6..def7657ef9cb71b5da3eb36b2b8f439f172651a3 100644 (file)
@@ -692,6 +692,13 @@ a `git gc` command on the origin repository.
 
 include::transfer-data-leaks.txt[]
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/push.txt[]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index fe350d7f4056e280c9740ae9c601f0c7eb2a1119..0b393715d707015a245eb1afe26dfbe044e8fcd6 100644 (file)
@@ -12,6 +12,7 @@ SYNOPSIS
        [--no-dual-color] [--creation-factor=<factor>]
        [--left-only | --right-only]
        ( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
+       [[--] <path>...]
 
 DESCRIPTION
 -----------
@@ -19,6 +20,9 @@ DESCRIPTION
 This command shows the differences between two versions of a patch
 series, or more generally, two commit ranges (ignoring merge commits).
 
+In the presence of `<path>` arguments, these commit ranges are limited
+accordingly.
+
 To that end, it first finds pairs of commits from both commit ranges
 that correspond with each other. Two commits are said to correspond when
 the diff between their patches (i.e. the author information, the commit
index a872ab0fbd1a9a615dd8d370bb5cdd74f7bab918..9cb8931c7ac8e89e1db036446044633cac00bb39 100644 (file)
@@ -376,10 +376,7 @@ See also INCOMPATIBLE OPTIONS below.
 +
 See also INCOMPATIBLE OPTIONS below.
 
---rerere-autoupdate::
---no-rerere-autoupdate::
-       Allow the rerere mechanism to update the index with the
-       result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
 
 -S[<keyid>]::
 --gpg-sign[=<keyid>]::
@@ -612,6 +609,15 @@ provided. Otherwise an explicit `--no-reschedule-failed-exec` at the
 start would be overridden by the presence of
 `rebase.rescheduleFailedExec=true` configuration.
 
+--update-refs::
+--no-update-refs::
+       Automatically force-update any branches that point to commits that
+       are being rebased. Any branches that are checked out in a worktree
+       are not updated in this way.
++
+If the configuration variable `rebase.updateRefs` is set, then this option
+can be used to override and disable this setting.
+
 INCOMPATIBLE OPTIONS
 --------------------
 
@@ -635,6 +641,7 @@ are incompatible with the following options:
  * --empty=
  * --reapply-cherry-picks
  * --edit-todo
+ * --update-refs
  * --root when used in combination with --onto
 
 In addition, the following pairs of options are incompatible:
@@ -1252,6 +1259,8 @@ merge cmake
 CONFIGURATION
 -------------
 
+include::includes/cmd-config-section-all.txt[]
+
 include::config/rebase.txt[]
 include::config/sequencer.txt[]
 
index 8463fe9cf75a3e9aa9cd2dced9907c6c00a87693..5016755efb61ded8351884a978b3febfc35040e6 100644 (file)
@@ -112,10 +112,7 @@ effect to your index in a row.
        Pass the merge strategy-specific option through to the
        merge strategy.  See linkgit:git-merge[1] for details.
 
---rerere-autoupdate::
---no-rerere-autoupdate::
-       Allow the rerere mechanism to update the index with the
-       result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
 
 --reference::
        Instead of starting the body of the log message with "This
@@ -145,6 +142,13 @@ EXAMPLES
        changes. The revert only modifies the working tree and the
        index.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/revert.txt[]
+
 SEE ALSO
 --------
 linkgit:git-cherry-pick[1]
index 41cd8cb42472a71d93f4f2f6379445f453b7be06..3290043053aa6d16f6a0d63f1c9a04e54e349e36 100644 (file)
@@ -456,41 +456,9 @@ Information
 CONFIGURATION
 -------------
 
-sendemail.aliasesFile::
-       To avoid typing long email addresses, point this to one or more
-       email aliases files.  You must also supply `sendemail.aliasFileType`.
+include::includes/cmd-config-section-all.txt[]
 
-sendemail.aliasFileType::
-       Format of the file(s) specified in sendemail.aliasesFile. Must be
-       one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus', or 'sendmail'.
-+
-What an alias file in each format looks like can be found in
-the documentation of the email program of the same name. The
-differences and limitations from the standard formats are
-described below:
-+
---
-sendmail;;
-*      Quoted aliases and quoted addresses are not supported: lines that
-       contain a `"` symbol are ignored.
-*      Redirection to a file (`/path/name`) or pipe (`|command`) is not
-       supported.
-*      File inclusion (`:include: /path/name`) is not supported.
-*      Warnings are printed on the standard error output for any
-       explicitly unsupported constructs, and any other lines that are not
-       recognized by the parser.
---
-
-sendemail.multiEdit::
-       If true (default), a single editor instance will be spawned to edit
-       files you have to edit (patches when `--annotate` is used, and the
-       summary when `--compose` is used). If false, files will be edited one
-       after the other, spawning a new editor each time.
-
-sendemail.confirm::
-       Sets the default for whether to confirm before sending. Must be
-       one of 'always', 'never', 'cc', 'compose', or 'auto'. See `--confirm`
-       in the previous section for the meaning of these values.
+include::config/sendemail.txt[]
 
 EXAMPLES
 --------
index 5cc2fcefbab1bcc80b33192e7ac06a3a5a92efd2..e5ec6b467f9f3f765d31949725ddc0c7c634391f 100644 (file)
@@ -199,6 +199,13 @@ shows 10 reflog entries going back from the tip as of 1 hour ago.
 Without `--list`, the output also shows how these tips are
 topologically related with each other.
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/showbranch.txt[]
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 6e15f47525765ce3da66b793ab519abd1cd90784..c5d70918283836d9a57c1af4710ce69fba78e3f1 100644 (file)
@@ -382,6 +382,13 @@ grep commit | cut -d\  -f3 |
 xargs git log --merges --no-walk --grep=WIP
 ----------------------------------------------------------------
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/stash.txt[]
+
 
 SEE ALSO
 --------
index bbcbdceb459c2828e0eb46110d038137be1f6f92..c60fc9c138b5981ce5727efa4482350e699dbac5 100644 (file)
@@ -265,6 +265,13 @@ always create a new name for it (without switching away):
 $ git switch -c good-surprises
 ------------
 
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/checkout.txt[]
+
 SEE ALSO
 --------
 linkgit:git-checkout[1],
index 5ea2f2c60e45a3c91422fcaa2457c100f450fb71..f4bb9c5daf95c6669210429d7a560565dadc91d5 100644 (file)
@@ -420,7 +420,7 @@ as `switch`, `pull`, `merge`) will avoid writing these files.
 However, these commands will sometimes write these files anyway in
 important cases such as conflicts during a merge or rebase.  Git
 commands will also avoid treating the lack of such files as an
-intentional deletion; for example `git add -u` will not not stage a
+intentional deletion; for example `git add -u` will not stage a
 deletion for these files and `git commit -a` will not make a commit
 deleting them either.
 
index 8f87b23ea86a3dfecb2a736d943a6728b6c9f767..b656b4756752f6d91098b85d2766a80e86ca092a 100644 (file)
@@ -39,10 +39,9 @@ OPTIONS
 --http-backend-info-refs::
        Used by linkgit:git-http-backend[1] to serve up
        `$GIT_URL/info/refs?service=git-upload-pack` requests. See
-       "Smart Clients" in link:technical/http-protocol.html[the HTTP
-       transfer protocols] documentation and "HTTP Transport" in
-       link:technical/protocol-v2.html[the Git Wire Protocol, Version
-       2] documentation. Also understood by
+       "Smart Clients" in linkgit:gitprotocol-http[5] and "HTTP
+       Transport" in the linkgit:gitprotocol-v2[5]
+       documentation. Also understood by
        linkgit:git-receive-pack[1].
 
 <directory>::
index 47a6095ff40f2c3f2f1d8f5684c92dd19b616b83..0c15ef3a8e6a51d3bbab8957f7487022f80bc170 100644 (file)
@@ -339,6 +339,23 @@ The following documentation pages are guides about Git concepts.
 
 include::cmds-guide.txt[]
 
+Repository, command and file interfaces
+---------------------------------------
+
+This documentation discusses repository and command interfaces which
+users are expected to interact with directly. See `--user-formats` in
+linkgit:git-help[1] for more details on the criteria.
+
+include::cmds-userinterfaces.txt[]
+
+File formats, protocols and other developer interfaces
+------------------------------------------------------
+
+This documentation discusses file formats, over-the-wire protocols and
+other git developer interfaces. See `--developer-interfaces` in
+linkgit:git-help[1].
+
+include::cmds-developerinterfaces.txt[]
 
 Configuration Mechanism
 -----------------------
similarity index 79%
rename from Documentation/technical/bundle-format.txt
rename to Documentation/gitformat-bundle.txt
index b9be8644cf5d53161b7190f580be935b28d402a3..00e0a20e6571969ebeabca8da5d9815be65d682b 100644 (file)
@@ -1,11 +1,33 @@
-= Git bundle v2 format
+gitformat-bundle(5)
+===================
 
-The Git bundle format is a format that represents both refs and Git objects.
+NAME
+----
+gitformat-bundle - The bundle file format
+
+
+SYNOPSIS
+--------
+[verse]
+*.bundle
+*.bdl
+
+DESCRIPTION
+-----------
+
+The Git bundle format is a format that represents both refs and Git
+objects. A bundle is a header in a format similar to
+linkgit:git-show-ref[1] followed by a pack in *.pack format.
 
-== Format
+The format is created and read by the linkgit:git-bundle[1] command,
+and supported by e.g. linkgit:git-fetch[1] and linkgit:git-clone[1].
+
+
+FORMAT
+------
 
 We will use ABNF notation to define the Git bundle format. See
-protocol-common.txt for the details.
+linkgit:gitprotocol-common[5] for the details.
 
 A v2 bundle looks like this:
 
@@ -36,7 +58,9 @@ value        = *(%01-09 / %0b-FF)
 pack         = ... ; packfile
 ----
 
-== Semantics
+
+SEMANTICS
+---------
 
 A Git bundle consists of several parts.
 
@@ -62,13 +86,15 @@ In the bundle format, there can be a comment following a prerequisite obj-id.
 This is a comment and it has no specific meaning. The writer of the bundle MAY
 put any string here. The reader of the bundle MUST ignore the comment.
 
-=== Note on the shallow clone and a Git bundle
+Note on the shallow clone and a Git bundle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Note that the prerequisites does not represent a shallow-clone boundary. The
 semantics of the prerequisites and the shallow-clone boundaries are different,
 and the Git bundle v2 format cannot represent a shallow clone repository.
 
-== Capabilities
+CAPABILITIES
+------------
 
 Because there is no opportunity for negotiation, unknown capabilities cause 'git
 bundle' to abort.
@@ -79,3 +105,7 @@ bundle' to abort.
 * `filter` specifies an object filter as in the `--filter` option in
   linkgit:git-rev-list[1]. The resulting pack-file must be marked as a
   `.promisor` pack-file after it is unbundled.
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 89%
rename from Documentation/technical/chunk-format.txt
rename to Documentation/gitformat-chunk.txt
index 593614fcedab47336926c81b3c1708c7358edd01..57202ede273ad266be910045294fd74853dd193c 100644 (file)
@@ -1,12 +1,25 @@
-Chunk-based file formats
-========================
+gitformat-chunk(5)
+==================
+
+NAME
+----
+gitformat-chunk - Chunk-based file formats
+
+SYNOPSIS
+--------
+
+Used by linkgit:gitformat-commit-graph[5] and the "MIDX" format (see
+the pack format documentation in linkgit:gitformat-pack[5]).
+
+DESCRIPTION
+-----------
 
 Some file formats in Git use a common concept of "chunks" to describe
 sections of the file. This allows structured access to a large file by
 scanning a small "table of contents" for the remaining data. This common
 format is used by the `commit-graph` and `multi-pack-index` files. See
-link:technical/pack-format.html[the `multi-pack-index` format] and
-link:technical/commit-graph-format.html[the `commit-graph` format] for
+the `multi-pack-index` format in linkgit:gitformat-pack[5] and
+the `commit-graph` format in linkgit:gitformat-commit-graph[5] for
 how they use the chunks to describe structured data.
 
 A chunk-based file format begins with some header information custom to
@@ -108,9 +121,13 @@ for future formats:
 * *commit-graph:* see `write_commit_graph_file()` and `parse_commit_graph()`
   in `commit-graph.c` for how the chunk-format API is used to write and
   parse the commit-graph file format documented in
-  link:technical/commit-graph-format.html[the commit-graph file format].
+  the commit-graph file format in linkgit:gitformat-commit-graph[5].
 
 * *multi-pack-index:* see `write_midx_internal()` and `load_multi_pack_index()`
   in `midx.c` for how the chunk-format API is used to write and
   parse the multi-pack-index file format documented in
-  link:technical/pack-format.html[the multi-pack-index file format].
+  the multi-pack-index file format section of linkgit:gitformat-pack[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 87%
rename from Documentation/technical/commit-graph-format.txt
rename to Documentation/gitformat-commit-graph.txt
index 484b185ba98bdc00efc147851abdcbe4958ee21f..7324665716d7db7f352354f80c61406629264e95 100644 (file)
@@ -1,5 +1,18 @@
-Git commit graph format
-=======================
+gitformat-commit-graph(5)
+=========================
+
+NAME
+----
+gitformat-commit-graph - Git commit graph format
+
+SYNOPSIS
+--------
+[verse]
+$GIT_DIR/objects/info/commit-graph
+$GIT_DIR/objects/info/commit-graphs/*
+
+DESCRIPTION
+-----------
 
 The Git commit graph stores a list of commit OIDs and some associated
 metadata, including:
@@ -30,7 +43,7 @@ and hash type.
 
 All multi-byte numbers are in network byte order.
 
-HEADER:
+=== HEADER:
 
   4-byte signature:
       The signature is: {'C', 'G', 'P', 'H'}
@@ -52,7 +65,7 @@ HEADER:
       We infer the length (H*B) of the Base Graphs chunk
       from this value.
 
-CHUNK LOOKUP:
+=== CHUNK LOOKUP:
 
   (C + 1) * 12 bytes listing the table of contents for the chunks:
       First 4 bytes describe the chunk id. Value 0 is a terminating label.
@@ -62,23 +75,23 @@ CHUNK LOOKUP:
       ID appears at most once.
 
   The CHUNK LOOKUP matches the table of contents from
-  link:technical/chunk-format.html[the chunk-based file format].
+  the chunk-based file format, see linkgit:gitformat-chunk[5]
 
   The remaining data in the body is described one chunk at a time, and
   these chunks may be given in any order. Chunks are required unless
   otherwise specified.
 
-CHUNK DATA:
+=== CHUNK DATA:
 
-  OID Fanout (ID: {'O', 'I', 'D', 'F'}) (256 * 4 bytes)
+==== OID Fanout (ID: {'O', 'I', 'D', 'F'}) (256 * 4 bytes)
       The ith entry, F[i], stores the number of OIDs with first
       byte at most i. Thus F[255] stores the total
       number of commits (N).
 
-  OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes)
+====  OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes)
       The OIDs for all commits in the graph, sorted in ascending order.
 
-  Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes)
+====  Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes)
     * The first H bytes are for the OID of the root tree.
     * The next 8 bytes are for the positions of the first two parents
       of the ith commit. Stores value 0x70000000 if no parent in that
@@ -93,7 +106,7 @@ CHUNK DATA:
       2 bits of the lowest byte, storing the 33rd and 34th bit of the
       commit time.
 
-  Generation Data (ID: {'G', 'D', 'A', '2' }) (N * 4 bytes) [Optional]
+==== Generation Data (ID: {'G', 'D', 'A', '2' }) (N * 4 bytes) [Optional]
     * This list of 4-byte values store corrected commit date offsets for the
       commits, arranged in the same order as commit data chunk.
     * If the corrected commit date offset cannot be stored within 31 bits,
@@ -104,7 +117,7 @@ CHUNK DATA:
       by compatible versions of Git and in case of split commit-graph chains,
       the topmost layer also has Generation Data chunk.
 
-  Generation Data Overflow (ID: {'G', 'D', 'O', '2' }) [Optional]
+==== Generation Data Overflow (ID: {'G', 'D', 'O', '2' }) [Optional]
     * This list of 8-byte values stores the corrected commit date offsets
       for commits with corrected commit date offsets that cannot be
       stored within 31 bits.
@@ -112,7 +125,7 @@ CHUNK DATA:
       chunk is present and atleast one corrected commit date offset cannot
       be stored within 31 bits.
 
-  Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
+==== Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
       This list of 4-byte values store the second through nth parents for
       all octopus merges. The second parent value in the commit data stores
       an array position within this list along with the most-significant bit
@@ -120,14 +133,14 @@ CHUNK DATA:
       positions for the parents until reaching a value with the most-significant
       bit on. The other bits correspond to the position of the last parent.
 
-  Bloom Filter Index (ID: {'B', 'I', 'D', 'X'}) (N * 4 bytes) [Optional]
+==== Bloom Filter Index (ID: {'B', 'I', 'D', 'X'}) (N * 4 bytes) [Optional]
     * The ith entry, BIDX[i], stores the number of bytes in all Bloom filters
       from commit 0 to commit i (inclusive) in lexicographic order. The Bloom
       filter for the i-th commit spans from BIDX[i-1] to BIDX[i] (plus header
       length), where BIDX[-1] is 0.
     * The BIDX chunk is ignored if the BDAT chunk is not present.
 
-  Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
+==== Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
     * It starts with header consisting of three unsigned 32-bit integers:
       - Version of the hash algorithm being used. We currently only support
        value 1 which corresponds to the 32-bit version of the murmur3 hash
@@ -147,13 +160,13 @@ CHUNK DATA:
       of length one, with either all bits set to zero or one respectively.
     * The BDAT chunk is present if and only if BIDX is present.
 
-  Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
+==== Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
       This list of H-byte hashes describe a set of B commit-graph files that
       form a commit-graph chain. The graph position for the ith commit in this
       file's OID Lookup chunk is equal to i plus the number of commits in all
       base graphs.  If B is non-zero, this chunk must exist.
 
-TRAILER:
+=== TRAILER:
 
        H-byte HASH-checksum of all of the above.
 
@@ -164,3 +177,7 @@ the number '2' in their chunk IDs because a previous version of Git wrote
 possibly erroneous data in these chunks with the IDs "GDAT" and "GDOV". By
 changing the IDs, newer versions of Git will silently ignore those older
 chunks and write the new information without trusting the incorrect data.
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 98%
rename from Documentation/technical/index-format.txt
rename to Documentation/gitformat-index.txt
index f691c20ab0a14dc8ecf18405d54c5572905d1606..015cb21bdc089a30e5403877ca1c61bea2b04e24 100644 (file)
@@ -1,5 +1,19 @@
+gitformat-index(5)
+==================
+
+NAME
+----
+gitformat-index - Git index format
+
+SYNOPSIS
+--------
+[verse]
+$GIT_DIR/index
+
+DESCRIPTION
+-----------
+
 Git index format
-================
 
 == The Git index file has the following format
 
@@ -125,7 +139,7 @@ Git index format
     entry is encoded as if the path name for the previous entry is an
     empty string).  At the beginning of an entry, an integer N in the
     variable width encoding (the same encoding as the offset is encoded
-    for OFS_DELTA pack entries; see pack-format.txt) is stored, followed
+    for OFS_DELTA pack entries; see linkgit:gitformat-pack[5]) is stored, followed
     by a NUL-terminated string S.  Removing N bytes from the end of the
     path name for the previous entry, and replacing it with the string S
     yields the path name for this entry.
@@ -402,3 +416,7 @@ The remaining data of each directory block is grouped by type:
   with signature { 's', 'd', 'i', 'r' }. Like the split-index extension,
   tools should avoid interacting with a sparse index unless they understand
   this extension.
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 72%
rename from Documentation/technical/pack-format.txt
rename to Documentation/gitformat-pack.txt
index b520aa9c45bf6cf9b12d6ef798658c298b1888a2..e06af02f211e7a7a8488d1470d7f76dd58e5989c 100644 (file)
@@ -1,5 +1,30 @@
-Git pack format
-===============
+gitformat-pack(5)
+=================
+
+NAME
+----
+gitformat-pack - Git pack format
+
+
+SYNOPSIS
+--------
+[verse]
+$GIT_DIR/objects/pack/pack-*.{pack,idx}
+$GIT_DIR/objects/pack/pack-*.rev
+$GIT_DIR/objects/pack/pack-*.mtimes
+$GIT_DIR/objects/pack/multi-pack-index
+
+DESCRIPTION
+-----------
+
+The Git pack format is now Git stores most of its primary repository
+data. Over the lietime af a repository loose objects (if any) and
+smaller packs are consolidated into larger pack(s). See
+linkgit:git-gc[1] and linkgit:git-pack-objects[1].
+
+The pack format is also used over-the-wire, see
+e.g. linkgit:gitprotocol-v2[5], as well as being a part of
+other container formats in the case of linkgit:gitformat-bundle[5].
 
 == Checksums and object IDs
 
@@ -356,7 +381,7 @@ CHUNK LOOKUP:
            using the next chunk position if necessary.)
 
        The CHUNK LOOKUP matches the table of contents from
-       link:technical/chunk-format.html[the chunk-based file format].
+       the chunk-based file format, see linkgit:gitformat-chunk[5].
 
        The remaining data in the body is described one chunk at a time, and
        these chunks may be given in any order. Chunks are required unless
@@ -482,3 +507,132 @@ packs arranged in MIDX order (with the preferred pack coming first).
 
 The MIDX's reverse index is stored in the optional 'RIDX' chunk within
 the MIDX itself.
+
+== cruft packs
+
+The cruft packs feature offer an alternative to Git's traditional mechanism of
+removing unreachable objects. This document provides an overview of Git's
+pruning mechanism, and how a cruft pack can be used instead to accomplish the
+same.
+
+=== Background
+
+To remove unreachable objects from your repository, Git offers `git repack -Ad`
+(see linkgit:git-repack[1]). Quoting from the documentation:
+
+----
+[...] unreachable objects in a previous pack become loose, unpacked objects,
+instead of being left in the old pack. [...] loose unreachable objects will be
+pruned according to normal expiry rules with the next 'git gc' invocation.
+----
+
+Unreachable objects aren't removed immediately, since doing so could race with
+an incoming push which may reference an object which is about to be deleted.
+Instead, those unreachable objects are stored as loose objects and stay that way
+until they are older than the expiration window, at which point they are removed
+by linkgit:git-prune[1].
+
+Git must store these unreachable objects loose in order to keep track of their
+per-object mtimes. If these unreachable objects were written into one big pack,
+then either freshening that pack (because an object contained within it was
+re-written) or creating a new pack of unreachable objects would cause the pack's
+mtime to get updated, and the objects within it would never leave the expiration
+window. Instead, objects are stored loose in order to keep track of the
+individual object mtimes and avoid a situation where all cruft objects are
+freshened at once.
+
+This can lead to undesirable situations when a repository contains many
+unreachable objects which have not yet left the grace period. Having large
+directories in the shards of `.git/objects` can lead to decreased performance in
+the repository. But given enough unreachable objects, this can lead to inode
+starvation and degrade the performance of the whole system. Since we
+can never pack those objects, these repositories often take up a large amount of
+disk space, since we can only zlib compress them, but not store them in delta
+chains.
+
+=== Cruft packs
+
+A cruft pack eliminates the need for storing unreachable objects in a loose
+state by including the per-object mtimes in a separate file alongside a single
+pack containing all loose objects.
+
+A cruft pack is written by `git repack --cruft` when generating a new pack.
+linkgit:git-pack-objects[1]'s `--cruft` option. Note that `git repack --cruft`
+is a classic all-into-one repack, meaning that everything in the resulting pack is
+reachable, and everything else is unreachable. Once written, the `--cruft`
+option instructs `git repack` to generate another pack containing only objects
+not packed in the previous step (which equates to packing all unreachable
+objects together). This progresses as follows:
+
+  1. Enumerate every object, marking any object which is (a) not contained in a
+     kept-pack, and (b) whose mtime is within the grace period as a traversal
+     tip.
+
+  2. Perform a reachability traversal based on the tips gathered in the previous
+     step, adding every object along the way to the pack.
+
+  3. Write the pack out, along with a `.mtimes` file that records the per-object
+     timestamps.
+
+This mode is invoked internally by linkgit:git-repack[1] when instructed to
+write a cruft pack. Crucially, the set of in-core kept packs is exactly the set
+of packs which will not be deleted by the repack; in other words, they contain
+all of the repository's reachable objects.
+
+When a repository already has a cruft pack, `git repack --cruft` typically only
+adds objects to it. An exception to this is when `git repack` is given the
+`--cruft-expiration` option, which allows the generated cruft pack to omit
+expired objects instead of waiting for linkgit:git-gc[1] to expire those objects
+later on.
+
+It is linkgit:git-gc[1] that is typically responsible for removing expired
+unreachable objects.
+
+=== Caution for mixed-version environments
+
+Repositories that have cruft packs in them will continue to work with any older
+version of Git. Note, however, that previous versions of Git which do not
+understand the `.mtimes` file will use the cruft pack's mtime as the mtime for
+all of the objects in it. In other words, do not expect older (pre-cruft pack)
+versions of Git to interpret or even read the contents of the `.mtimes` file.
+
+Note that having mixed versions of Git GC-ing the same repository can lead to
+unreachable objects never being completely pruned. This can happen under the
+following circumstances:
+
+  - An older version of Git running GC explodes the contents of an existing
+    cruft pack loose, using the cruft pack's mtime.
+  - A newer version running GC collects those loose objects into a cruft pack,
+    where the .mtime file reflects the loose object's actual mtimes, but the
+    cruft pack mtime is "now".
+
+Repeating this process will lead to unreachable objects not getting pruned as a
+result of repeatedly resetting the objects' mtimes to the present time.
+
+If you are GC-ing repositories in a mixed version environment, consider omitting
+the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
+leaving the `gc.cruftPacks` configuration unset until all writers understand
+cruft packs.
+
+=== Alternatives
+
+Notable alternatives to this design include:
+
+  - The location of the per-object mtime data, and
+  - Storing unreachable objects in multiple cruft packs.
+
+On the location of mtime data, a new auxiliary file tied to the pack was chosen
+to avoid complicating the `.idx` format. If the `.idx` format were ever to gain
+support for optional chunks of data, it may make sense to consolidate the
+`.mtimes` format into the `.idx` itself.
+
+Storing unreachable objects among multiple cruft packs (e.g., creating a new
+cruft pack during each repacking operation including only unreachable objects
+which aren't already stored in an earlier cruft pack) is significantly more
+complicated to construct, and so aren't pursued here. The obvious drawback to
+the current implementation is that the entire cruft pack must be re-written from
+scratch.
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 96%
rename from Documentation/technical/signature-format.txt
rename to Documentation/gitformat-signature.txt
index 166721be6f648cdac8d0fc960e121bafc02cd226..a249869fafaa6b10e52c55c7187efb8d2e212e8e 100644 (file)
@@ -1,7 +1,18 @@
-Git signature format
-====================
+gitformat-signature(5)
+======================
 
-== Overview
+NAME
+----
+gitformat-signature - Git cryptographic signature formats
+
+SYNOPSIS
+--------
+[verse]
+<[tag|commit] object header(s)>
+<over-the-wire protocol>
+
+DESCRIPTION
+-----------
 
 Git uses cryptographic signatures in various places, currently objects (tags,
 commits, mergetags) and transactions (pushes). In every case, the command which
@@ -200,3 +211,7 @@ Date:   Wed Jun 15 09:13:29 2016 +0000
     # gpg:          There is no indication that the signature belongs to the owner.
     # Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA  29A4 6109 2E85 B722 7189
 ----
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 95%
rename from Documentation/technical/protocol-capabilities.txt
rename to Documentation/gitprotocol-capabilities.txt
index 9dfade930dafc471aa3f684b0b5c1dc6feba6e2c..0fb5ea0c1ca7547679d060f8fe2be7d2edf58c86 100644 (file)
@@ -1,8 +1,20 @@
-Git Protocol Capabilities
-=========================
+gitprotocol-capabilities(5)
+===========================
+
+NAME
+----
+gitprotocol-capabilities - Protocol v0 and v1 capabilities
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
 
 NOTE: this document describes capabilities for versions 0 and 1 of the pack
-protocol. For version 2, please refer to the link:protocol-v2.html[protocol-v2]
+protocol. For version 2, please refer to the linkgit:gitprotocol-v2[5]
 doc.
 
 Servers SHOULD support all capabilities defined in this document.
@@ -77,7 +89,7 @@ interleaved with S-R-Q.
 multi_ack_detailed
 ------------------
 This is an extension of multi_ack that permits client to better
-understand the server's in-memory state. See pack-protocol.txt,
+understand the server's in-memory state. See linkgit:gitprotocol-pack[5],
 section "Packfile Negotiation" for more information.
 
 no-done
@@ -281,7 +293,7 @@ a packfile upload and reference update.  If the pushing client requests
 this capability, after unpacking and updating references the server
 will respond with whether the packfile unpacked successfully and if
 each reference was updated successfully.  If any of those were not
-successful, it will send back an error message.  See pack-protocol.txt
+successful, it will send back an error message.  See linkgit:gitprotocol-pack[5]
 for example messages.
 
 report-status-v2
@@ -292,7 +304,7 @@ adding new "option" directives in order to support reference rewritten by
 the "proc-receive" hook.  The "proc-receive" hook may handle a command
 for a pseudo-reference which may create or update a reference with
 different name, new-oid, and old-oid.  While the capability
-'report-status' cannot report for such case.  See pack-protocol.txt
+'report-status' cannot report for such case.  See linkgit:gitprotocol-pack[5]
 for details.
 
 delete-refs
@@ -376,5 +388,9 @@ the server as well.
 Session IDs should be unique to a given process. They must fit within a
 packet-line, and must not contain non-printable or whitespace characters. The
 current implementation uses trace2 session IDs (see
-link:api-trace2.html[api-trace2] for details), but this may change and users of
-the session ID should not rely on this fact.
+link:technical/api-trace2.html[api-trace2] for details), but this may change
+and users of the session ID should not rely on this fact.
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 89%
rename from Documentation/technical/protocol-common.txt
rename to Documentation/gitprotocol-common.txt
index ecedb34bba54ecf8105336d5a98ca349ff35c63c..1486651bd1002f3c121c703caae154caa822fedc 100644 (file)
@@ -1,5 +1,20 @@
-Documentation Common to Pack and Http Protocols
-===============================================
+gitprotocol-common(5)
+=====================
+
+NAME
+----
+gitprotocol-common - Things common to various protocols
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
+
+This document sets defines things common to various over-the-wire
+protocols and file formats used in Git.
 
 ABNF Notation
 -------------
@@ -97,3 +112,7 @@ Examples (as C-style strings):
   "000bfoobar\n"    "foobar\n"
   "0004"            ""
 ----
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 97%
rename from Documentation/technical/http-protocol.txt
rename to Documentation/gitprotocol-http.txt
index cc5126cfedaac2e14e3de48d9cafeb3c58bbb03e..ccc13f0a40758ac5f8268472354998d63331bf92 100644 (file)
@@ -1,5 +1,19 @@
-HTTP transfer protocols
-=======================
+gitprotocol-http(5)
+===================
+
+NAME
+----
+gitprotocol-http - Git HTTP-based protocols
+
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+
+DESCRIPTION
+-----------
 
 Git supports two HTTP based transfer protocols.  A "dumb" protocol
 which requires only a standard HTTP server on the server end of the
@@ -222,7 +236,7 @@ smart server reply:
    S: 0000
 
 The client may send Extra Parameters (see
-Documentation/technical/pack-protocol.txt) as a colon-separated string
+linkgit:gitprotocol-pack[5]) as a colon-separated string
 in the Git-Protocol HTTP header.
 
 Uses the `--http-backend-info-refs` option to
@@ -512,11 +526,18 @@ the id obtained through ref discovery as old_id.
 
 TODO: Document this further.
 
-
-References
+REFERENCES
 ----------
 
 http://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
 http://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
-link:technical/pack-protocol.html
-link:technical/protocol-capabilities.html
+
+SEE ALSO
+--------
+
+linkgit:gitprotocol-pack[5]
+linkgit:gitprotocol-capabilities[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 98%
rename from Documentation/technical/pack-protocol.txt
rename to Documentation/gitprotocol-pack.txt
index e13a2c064d1244fc8926ee4831bc83186e0e514d..dd4108b7a3b95456e0887fc41aed4e381261bd41 100644 (file)
@@ -1,11 +1,23 @@
-Packfile transfer protocols
-===========================
+gitprotocol-pack(5)
+===================
+
+NAME
+----
+gitprotocol-pack - How packs are transferred over-the-wire
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
 
 Git supports transferring data in packfiles over the ssh://, git://, http:// and
 file:// transports.  There exist two sets of protocols, one for pushing
 data from a client to a server and another for fetching data from a
 server to a client.  The three transports (ssh, git, file) use the same
-protocol to transfer data. http is documented in http-protocol.txt.
+protocol to transfer data. http is documented in linkgit:gitprotocol-http[5].
 
 The processes invoked in the canonical Git implementation are 'upload-pack'
 on the server side and 'fetch-pack' on the client side for fetching data;
@@ -18,7 +30,7 @@ pkt-line Format
 ---------------
 
 The descriptions below build on the pkt-line format described in
-protocol-common.txt. When the grammar indicate `PKT-LINE(...)`, unless
+linkgit:gitprotocol-common[5]. When the grammar indicate `PKT-LINE(...)`, unless
 otherwise noted the usual pkt-line LF rules apply: the sender SHOULD
 include a LF, but the receiver MUST NOT complain if it is not present.
 
@@ -60,7 +72,7 @@ Each Extra Parameter takes the form of `<key>=<value>` or `<key>`.
 
 Servers that receive any such Extra Parameters MUST ignore all
 unrecognized keys. Currently, the only Extra Parameter recognized is
-"version" with a value of '1' or '2'.  See protocol-v2.txt for more
+"version" with a value of '1' or '2'.  See linkgit:gitprotocol-v2[5] for more
 information on protocol version 2.
 
 Git Transport
@@ -455,7 +467,7 @@ Now that the client and server have finished negotiation about what
 the minimal amount of data that needs to be sent to the client is, the server
 will construct and send the required data in packfile format.
 
-See pack-format.txt for what the packfile itself actually looks like.
+See linkgit:gitformat-pack[5] for what the packfile itself actually looks like.
 
 If 'side-band' or 'side-band-64k' capabilities have been specified by
 the client, the server will send the packfile data multiplexed.
@@ -707,3 +719,7 @@ An example client/server communication might look like this:
    S: 0018ok refs/heads/debug\n
    S: 002ang refs/heads/master non-fast-forward\n
 ----
+
+GIT
+---
+Part of the linkgit:git[1] suite
similarity index 97%
rename from Documentation/technical/protocol-v2.txt
rename to Documentation/gitprotocol-v2.txt
index 8a877d27e23803686632e223cbc4ba7f4ac0ab79..59bf41cefb9b958f57e6e95201784ec8cec56fb0 100644 (file)
@@ -1,5 +1,17 @@
-Git Wire Protocol, Version 2
-============================
+gitprotocol-v2(5)
+=================
+
+NAME
+----
+gitprotocol-v2 - Git Wire Protocol, Version 2
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
 
 This document presents a specification for a version 2 of Git's wire
 protocol.  Protocol v2 will improve upon v1 in the following ways:
@@ -26,8 +38,7 @@ Packet-Line Framing
 -------------------
 
 All communication is done using packet-line framing, just as in v1.  See
-`Documentation/technical/pack-protocol.txt` and
-`Documentation/technical/protocol-common.txt` for more information.
+linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-common[5] for more information.
 
 In protocol v2 these special packets will have the following semantics:
 
@@ -42,7 +53,7 @@ Initial Client Request
 In general a client can request to speak protocol v2 by sending
 `version=2` through the respective side-channel for the transport being
 used which inevitably sets `GIT_PROTOCOL`.  More information can be
-found in `pack-protocol.txt` and `http-protocol.txt`, as well as the
+found in linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-http[5], as well as the
 `GIT_PROTOCOL` definition in `git.txt`. In all cases the
 response from the server is the capability advertisement.
 
@@ -66,7 +77,7 @@ HTTP Transport
 ~~~~~~~~~~~~~~
 
 When using the http:// or https:// transport a client makes a "smart"
-info/refs request as described in `http-protocol.txt` and requests that
+info/refs request as described in linkgit:gitprotocol-http[5] and requests that
 v2 be used by supplying "version=2" in the `Git-Protocol` header.
 
    C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
@@ -533,8 +544,8 @@ the server as well.
 Session IDs should be unique to a given process. They must fit within a
 packet-line, and must not contain non-printable or whitespace characters. The
 current implementation uses trace2 session IDs (see
-link:api-trace2.html[api-trace2] for details), but this may change and users of
-the session ID should not rely on this fact.
+link:technical/api-trace2.html[api-trace2] for details), but this may change
+and users of the session ID should not rely on this fact.
 
 object-info
 ~~~~~~~~~~~
@@ -566,3 +577,7 @@ and associated requested information, each separated by a single space.
        attr = "size"
 
        obj-info = obj-id SP obj-size
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 6f1e269ae43e00d631feb8798a2a95aef48e8287..ed8da428c98bc96cafdbbcc8543ed0c8479a13a3 100644 (file)
@@ -168,6 +168,9 @@ Supported commands: 'list', 'import'.
        Can guarantee that when a clone is requested, the received
        pack is self contained and is connected.
 
+'get'::
+       Can use the 'get' command to download a file from a given URI.
+
 If a helper advertises 'connect', Git will use it if possible and
 fall back to another capability if the helper requests so when
 connecting (see the 'connect' command under COMMANDS).
@@ -418,6 +421,12 @@ Supported if the helper has the "connect" capability.
 +
 Supported if the helper has the "stateless-connect" capability.
 
+'get' <uri> <path>::
+       Downloads the file from the given `<uri>` to the given `<path>`. If
+       `<path>.temp` exists, then Git assumes that the `.temp` file is a
+       partial download from a previous attempt and will resume the
+       download from that position.
+
 If a fatal error occurs, the program writes the error message to
 stderr and exits. The caller should expect that a suitable error
 message has been printed if the child closes the connection without
index 8994e2559eac0c5746ca898b0bad1946a7b83298..5efb4fe81ff120e50027b836e85c8ee205923821 100644 (file)
@@ -68,7 +68,7 @@ Note that the "object" file isn't fit for feeding straight to zlib; it
 has the git packed object header, which is variable-length. We want to
 strip that off so we can start playing with the zlib data directly. You
 can either work your way through it manually (the format is described in
-link:../technical/pack-format.html[Documentation/technical/pack-format.txt]),
+linkgit:gitformat-pack[5]),
 or you can walk through it in a debugger. I did the latter, creating a
 valid pack like:
 
diff --git a/Documentation/includes/cmd-config-section-all.txt b/Documentation/includes/cmd-config-section-all.txt
new file mode 100644 (file)
index 0000000..296a239
--- /dev/null
@@ -0,0 +1,3 @@
+Everything below this line in this section is selectively included
+from the linkgit:git-config[1] documentation. The content is the same
+as what's found there:
diff --git a/Documentation/includes/cmd-config-section-rest.txt b/Documentation/includes/cmd-config-section-rest.txt
new file mode 100644 (file)
index 0000000..b1e7682
--- /dev/null
@@ -0,0 +1,3 @@
+Everything above this line in this section isn't included from the
+linkgit:git-config[1] documentation. The content that follows is the
+same as what's found there:
index 425377dfeb7fc0856773fd5eaaac7dd3b7b1c999..02408a0062f0c8c380847b32592aae5671ca85de 100755 (executable)
@@ -32,6 +32,9 @@ my %SECTIONS;
                'SEE ALSO' => {
                        order => $order++,
                },
+               'FILE FORMAT' => {
+                       order => $order++,
+               },
                'GIT' => {
                        required => 1,
                        order => $order++,
diff --git a/Documentation/rerere-options.txt b/Documentation/rerere-options.txt
new file mode 100644 (file)
index 0000000..c3321dd
--- /dev/null
@@ -0,0 +1,9 @@
+--rerere-autoupdate::
+--no-rerere-autoupdate::
+       After the rerere mechanism reuses a recorded resolution on
+       the current conflict to update the files in the working
+       tree, allow it to also update the index with the result of
+       resolution.  `--no-rerere-autoupdate` is a good way to
+       double-check what `rerere` did and catch potential
+       mismerges, before committing the result to the index with a
+       separate `git add`.
index 195e74eec633ea913c0934d2b690b674360376d7..1837509566a79a36a5f607837bc13af082d81b86 100644 (file)
@@ -242,6 +242,7 @@ ifdef::git-rev-list[]
        to `/dev/null` as the output does not have to be formatted.
 
 --disk-usage::
+--disk-usage=human::
        Suppress normal output; instead, print the sum of the bytes used
        for on-disk storage by the selected commits or objects. This is
        equivalent to piping the output into `git cat-file
@@ -249,6 +250,8 @@ ifdef::git-rev-list[]
        faster (especially with `--use-bitmap-index`). See the `CAVEATS`
        section in linkgit:git-cat-file[1] for the limitations of what
        "on-disk storage" means.
+       With the optional value `human`, on-disk storage size is shown
+       in human-readable string(e.g. 12.24 Kib, 3.50 Mib).
 endif::git-rev-list[]
 
 --cherry-mark::
@@ -389,12 +392,14 @@ Default mode::
        merges from the resulting history, as there are no selected
        commits contributing to this merge.
 
---ancestry-path::
+--ancestry-path[=<commit>]::
        When given a range of commits to display (e.g. 'commit1..commit2'
-       or 'commit2 {caret}commit1'), only display commits that exist
-       directly on the ancestry chain between the 'commit1' and
-       'commit2', i.e. commits that are both descendants of 'commit1',
-       and ancestors of 'commit2'.
+       or 'commit2 {caret}commit1'), only display commits in that range
+       that are ancestors of <commit>, descendants of <commit>, or
+       <commit> itself.  If no commit is specified, use 'commit1' (the
+       excluded part of the range) as <commit>.  Can be passed multiple
+       times; if so, a commit is included if it is any of the commits
+       given or if it is an ancestor or descendant of one of them.
 
 A more detailed explanation follows.
 
@@ -568,11 +573,10 @@ Note the major differences in `N`, `P`, and `Q` over `--full-history`:
 
 There is another simplification mode available:
 
---ancestry-path::
-       Limit the displayed commits to those directly on the ancestry
-       chain between the ``from'' and ``to'' commits in the given commit
-       range. I.e. only display commits that are ancestor of the ``to''
-       commit and descendants of the ``from'' commit.
+--ancestry-path[=<commit>]::
+       Limit the displayed commits to those which are an ancestor of
+       <commit>, or which are a descendant of <commit>, or are <commit>
+       itself.
 +
 As an example use case, consider the following commit history:
 +
@@ -604,6 +608,29 @@ option does. Applied to the 'D..M' range, it results in:
                               \
                                L--M
 -----------------------------------------------------------------------
++
+We can also use `--ancestry-path=D` instead of `--ancestry-path` which
+means the same thing when applied to the 'D..M' range but is just more
+explicit.
++
+If we instead are interested in a given topic within this range, and all
+commits affected by that topic, we may only want to view the subset of
+`D..M` which contain that topic in their ancestry path.  So, using
+`--ancestry-path=H D..M` for example would result in:
++
+-----------------------------------------------------------------------
+               E
+                \
+                 G---H---I---J
+                              \
+                               L--M
+-----------------------------------------------------------------------
++
+Whereas `--ancestry-path=K D..M` would result in
++
+-----------------------------------------------------------------------
+               K---------------L--M
+-----------------------------------------------------------------------
 
 Before discussing another option, `--show-pulls`, we need to
 create a new example history.
@@ -659,7 +686,7 @@ Here, the merge commits `O` and `P` contribute extra noise, as they did
 not actually contribute a change to `file.txt`. They only merged a topic
 that was based on an older version of `file.txt`. This is a common
 issue in repositories using a workflow where many contributors work in
-parallel and merge their topic branches along a single trunk: manu
+parallel and merge their topic branches along a single trunk: many
 unrelated merges appear in the `--full-history` results.
 
 When using the `--simplify-merges` option, the commits `O` and `P`
similarity index 93%
rename from contrib/scalar/scalar.txt
rename to Documentation/scalar.txt
index c0425e065338fd0c55021de85b50362e8ede9727..f33436c7f65ff9fd46f7ee4fa10975c833a61096 100644 (file)
@@ -3,7 +3,7 @@ scalar(1)
 
 NAME
 ----
-scalar - an opinionated repository management tool
+scalar - A tool for managing large Git repositories
 
 SYNOPSIS
 --------
@@ -20,10 +20,9 @@ scalar delete <enlistment>
 DESCRIPTION
 -----------
 
-Scalar is an opinionated repository management tool. By creating new
-repositories or registering existing repositories with Scalar, your Git
-experience will speed up. Scalar sets advanced Git config settings,
-maintains your repositories in the background, and helps reduce data sent
+Scalar is a repository management tool that optimizes Git for use in large
+repositories. Scalar improves performance by configuring advanced Git settings,
+maintaining repositories in the background, and helping to reduce data sent
 across the network.
 
 An important Scalar concept is the enlistment: this is the top-level directory
@@ -162,6 +161,6 @@ SEE ALSO
 --------
 linkgit:git-clone[1], linkgit:git-maintenance[1].
 
-Scalar
+GIT
 ---
-Associated with the linkgit:git[1] suite
+Part of the linkgit:git[1] suite
index 70bf1d3e522fea62b034fc3f2b380ab6ca6a812c..665c4960b440baef2d5306742cca998836478338 100644 (file)
@@ -46,7 +46,7 @@ parse-options.c.
   returns -1 after reporting the situation to the caller.
 
 These reports will be logged via the trace2 facility. See the "error"
-event in link:api-trace2.txt[trace2 API].
+event in link:api-trace2.html[trace2 API].
 
 Customizable error handlers
 ---------------------------
index acfd5dc1d8b2f6103ddb556956b63f71b83a4d1b..61fa6ee167833a454bfa01b827577feac15b5f1d 100644 (file)
@@ -8,7 +8,8 @@ Basics
 ------
 
 The argument vector `argv[]` may usually contain mandatory or optional
-'non-option arguments', e.g. a filename or a branch, and 'options'.
+'non-option arguments', e.g. a filename or a branch, 'options', and
+'subcommands'.
 Options are optional arguments that start with a dash and
 that allow to change the behavior of a command.
 
@@ -48,6 +49,33 @@ The parse-options API allows:
   option, e.g. `-a -b --option -- --this-is-a-file` indicates that
   `--this-is-a-file` must not be processed as an option.
 
+Subcommands are special in a couple of ways:
+
+* Subcommands only have long form, and they have no double dash prefix, no
+  negated form, and no description, and they don't take any arguments, and
+  can't be abbreviated.
+
+* There must be exactly one subcommand among the arguments, or zero if the
+  command has a default operation mode.
+
+* All arguments following the subcommand are considered to be arguments of
+  the subcommand, and, conversely, arguments meant for the subcommand may
+  not precede the subcommand.
+
+Therefore, if the options array contains at least one subcommand and
+`parse_options()` encounters the first dashless argument, it will either:
+
+* stop and return, if that dashless argument is a known subcommand, setting
+  `value` to the function pointer associated with that subcommand, storing
+  the name of the subcommand in argv[0], and leaving the rest of the
+  arguments unprocessed, or
+
+* stop and return, if it was invoked with the `PARSE_OPT_SUBCOMMAND_OPTIONAL`
+  flag and that dashless argument doesn't match any subcommands, leaving
+  `value` unchanged and the rest of the arguments unprocessed, or
+
+* show error and usage, and abort.
+
 Steps to parse options
 ----------------------
 
@@ -90,8 +118,8 @@ Flags are the bitwise-or of:
        Keep the first argument, which contains the program name.  It's
        removed from argv[] by default.
 
-`PARSE_OPT_KEEP_UNKNOWN`::
-       Keep unknown arguments instead of erroring out.  This doesn't
+`PARSE_OPT_KEEP_UNKNOWN_OPT`::
+       Keep unknown options instead of erroring out.  This doesn't
        work for all combinations of arguments as users might expect
        it to do.  E.g. if the first argument in `--unknown --known`
        takes a value (which we can't know), the second one is
@@ -101,6 +129,8 @@ Flags are the bitwise-or of:
        non-option, not as a value belonging to the unknown option,
        the parser early.  That's why parse_options() errors out if
        both options are set.
+       Note that non-option arguments are always kept, even without
+       this flag.
 
 `PARSE_OPT_NO_INTERNAL_HELP`::
        By default, parse_options() handles `-h`, `--help` and
@@ -108,6 +138,13 @@ Flags are the bitwise-or of:
        turns it off and allows one to add custom handlers for these
        options, or to just leave them unknown.
 
+`PARSE_OPT_SUBCOMMAND_OPTIONAL`::
+       Don't error out when no subcommand is specified.
+
+Note that `PARSE_OPT_STOP_AT_NON_OPTION` is incompatible with subcommands;
+while `PARSE_OPT_KEEP_DASHDASH` and `PARSE_OPT_KEEP_UNKNOWN_OPT` can only be
+used with subcommands when combined with `PARSE_OPT_SUBCOMMAND_OPTIONAL`.
+
 Data Structure
 --------------
 
@@ -236,10 +273,14 @@ There are some macros to easily define options:
 `OPT_CMDMODE(short, long, &int_var, description, enum_val)`::
        Define an "operation mode" option, only one of which in the same
        group of "operating mode" options that share the same `int_var`
-       can be given by the user. `enum_val` is set to `int_var` when the
+       can be given by the user. `int_var` is set to `enum_val` when the
        option is used, but an error is reported if other "operating mode"
        option has already set its value to the same `int_var`.
+       In new commands consider using subcommands instead.
 
+`OPT_SUBCOMMAND(long, &fn_ptr, subcommand_fn)`::
+       Define a subcommand.  `subcommand_fn` is put into `fn_ptr` when
+       this subcommand is used.
 
 The last element of the array must be `OPT_END()`.
 
index d79ad323e675303ceedc6e608f045299b5ed2d8b..d44ada98e7db9ccdd7dd622221ee298af5de5000 100644 (file)
@@ -78,7 +78,7 @@ client and an optional response message from the server.  Both the
 client and server messages are unlimited in length and are terminated
 with a flush packet.
 
-The pkt-line routines (Documentation/technical/protocol-common.txt)
+The pkt-line routines (linkgit:gitprotocol-common[5])
 are used to simplify buffer management during message generation,
 transmission, and reception.  A flush packet is used to mark the end
 of the message.  This allows the sender to incrementally generate and
index 77a150b30ee80247df18d936c2fc03b5be570af0..2afa28bb5aa121489a95800765ae8bf844a3355f 100644 (file)
@@ -717,6 +717,7 @@ The "exec_id" field is a command-unique id and is only useful if the
 {
        "event":"def_param",
        ...
+       "scope":"global",
        "param":"core.abbrev",
        "value":"7"
 }
@@ -1207,6 +1208,45 @@ at offset 508.
 This example also shows that thread names are assigned in a racy manner
 as each thread starts and allocates TLS storage.
 
+Config (def param) Events::
+
+         Dump "interesting" config values to trace2 log.
++
+We can optionally emit configuration events, see
+`trace2.configparams` in linkgit:git-config[1] for how to enable
+it.
++
+----------------
+$ git config --system color.ui never
+$ git config --global color.ui always
+$ git config --local color.ui auto
+$ git config --list --show-scope | grep 'color.ui'
+system  color.ui=never
+global  color.ui=always
+local   color.ui=auto
+----------------
++
+Then, mark the config `color.ui` as "interesting" config with
+`GIT_TRACE2_CONFIG_PARAMS`:
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ export GIT_TRACE2_CONFIG_PARAMS=color.ui
+$ git version
+...
+$ cat ~/log.perf
+d0 | main                     | version      |     |           |           |              | ...
+d0 | main                     | start        |     |  0.001642 |           |              | /usr/local/bin/git version
+d0 | main                     | cmd_name     |     |           |           |              | version (version)
+d0 | main                     | def_param    |     |           |           | scope:system | color.ui:never
+d0 | main                     | def_param    |     |           |           | scope:global | color.ui:always
+d0 | main                     | def_param    |     |           |           | scope:local  | color.ui:auto
+d0 | main                     | data         | r0  |  0.002100 |  0.002100 | fsync        | fsync/writeout-only:0
+d0 | main                     | data         | r0  |  0.002126 |  0.002126 | fsync        | fsync/hardware-flush:0
+d0 | main                     | exit         |     |  0.000470 |           |              | code:0
+d0 | main                     | atexit       |     |  0.000477 |           |              | code:0
+----------------
 == Future Work
 
 === Relationship to the Existing Trace Api (api-trace.txt)
index a85f58f51539cc0cca5313693e96e50858f731a0..c2e652b71a7f698a6843bbf327535b4692538c0f 100644 (file)
@@ -72,6 +72,17 @@ MIDXs, both the bit-cache and rev-cache extensions are required.
            pack/MIDX. The format and meaning of the name-hash is
            described below.
 
+               ** {empty}
+               BITMAP_OPT_LOOKUP_TABLE (0x10): :::
+               If present, the end of the bitmap file contains a table
+               containing a list of `N` <commit_pos, offset, xor_row>
+               triplets. The format and meaning of the table is described
+               below.
++
+NOTE: Unlike the xor_offset used to compress an individual bitmap,
+`xor_row` stores an *absolute* index into the lookup table, not a location
+relative to the current entry.
+
        4-byte entry count (network byte order): ::
            The total count of entries (bitmapped commits) in this bitmap index.
 
@@ -216,3 +227,31 @@ Note that this hashing scheme is tied to the BITMAP_OPT_HASH_CACHE flag.
 If implementations want to choose a different hashing scheme, they are
 free to do so, but MUST allocate a new header flag (because comparing
 hashes made under two different schemes would be pointless).
+
+Commit lookup table
+-------------------
+
+If the BITMAP_OPT_LOOKUP_TABLE flag is set, the last `N * (4 + 8 + 4)`
+bytes (preceding the name-hash cache and trailing hash) of the `.bitmap`
+file contains a lookup table specifying the information needed to get
+the desired bitmap from the entries without parsing previous unnecessary
+bitmaps.
+
+For a `.bitmap` containing `nr_entries` reachability bitmaps, the table
+contains a list of `nr_entries` <commit_pos, offset, xor_row> triplets
+(sorted in the ascending order of `commit_pos`). The content of i'th
+triplet is -
+
+       * {empty}
+       commit_pos (4 byte integer, network byte order): ::
+       It stores the object position of a commit (in the midx or pack
+       index).
+
+       * {empty}
+       offset (8 byte integer, network byte order): ::
+       The offset from which that commit's bitmap can be read.
+
+       * {empty}
+       xor_row (4 byte integer, network byte order): ::
+       The position of the triplet whose bitmap is used to compress
+       this one, or `0xffffffff` if no such bitmap exists.
diff --git a/Documentation/technical/bundle-uri.txt b/Documentation/technical/bundle-uri.txt
new file mode 100644 (file)
index 0000000..18f2ded
--- /dev/null
@@ -0,0 +1,572 @@
+Bundle URIs
+===========
+
+Git bundles are files that store a pack-file along with some extra metadata,
+including a set of refs and a (possibly empty) set of necessary commits. See
+linkgit:git-bundle[1] and linkgit:gitformat-bundle[5] for more information.
+
+Bundle URIs are locations where Git can download one or more bundles in
+order to bootstrap the object database in advance of fetching the remaining
+objects from a remote.
+
+One goal is to speed up clones and fetches for users with poor network
+connectivity to the origin server. Another benefit is to allow heavy users,
+such as CI build farms, to use local resources for the majority of Git data
+and thereby reducing the load on the origin server.
+
+To enable the bundle URI feature, users can specify a bundle URI using
+command-line options or the origin server can advertise one or more URIs
+via a protocol v2 capability.
+
+Design Goals
+------------
+
+The bundle URI standard aims to be flexible enough to satisfy multiple
+workloads. The bundle provider and the Git client have several choices in
+how they create and consume bundle URIs.
+
+* Bundles can have whatever name the server desires. This name could refer
+  to immutable data by using a hash of the bundle contents. However, this
+  means that a new URI will be needed after every update of the content.
+  This might be acceptable if the server is advertising the URI (and the
+  server is aware of new bundles being generated) but would not be
+  ergonomic for users using the command line option.
+
+* The bundles could be organized specifically for bootstrapping full
+  clones, but could also be organized with the intention of bootstrapping
+  incremental fetches. The bundle provider must decide on one of several
+  organization schemes to minimize client downloads during incremental
+  fetches, but the Git client can also choose whether to use bundles for
+  either of these operations.
+
+* The bundle provider can choose to support full clones, partial clones,
+  or both. The client can detect which bundles are appropriate for the
+  repository's partial clone filter, if any.
+
+* The bundle provider can use a single bundle (for clones only), or a
+  list of bundles. When using a list of bundles, the provider can specify
+  whether or not the client needs _all_ of the bundle URIs for a full
+  clone, or if _any_ one of the bundle URIs is sufficient. This allows the
+  bundle provider to use different URIs for different geographies.
+
+* The bundle provider can organize the bundles using heuristics, such as
+  creation tokens, to help the client prevent downloading bundles it does
+  not need. When the bundle provider does not provide these heuristics,
+  the client can use optimizations to minimize how much of the data is
+  downloaded.
+
+* The bundle provider does not need to be associated with the Git server.
+  The client can choose to use the bundle provider without it being
+  advertised by the Git server.
+
+* The client can choose to discover bundle providers that are advertised
+  by the Git server. This could happen during `git clone`, during
+  `git fetch`, both, or neither. The user can choose which combination
+  works best for them.
+
+* The client can choose to configure a bundle provider manually at any
+  time. The client can also choose to specify a bundle provider manually
+  as a command-line option to `git clone`.
+
+Each repository is different and every Git server has different needs.
+Hopefully the bundle URI feature is flexible enough to satisfy all needs.
+If not, then the feature can be extended through its versioning mechanism.
+
+Server requirements
+-------------------
+
+To provide a server-side implementation of bundle servers, no other parts
+of the Git protocol are required. This allows server maintainers to use
+static content solutions such as CDNs in order to serve the bundle files.
+
+At the current scope of the bundle URI feature, all URIs are expected to
+be HTTP(S) URLs where content is downloaded to a local file using a `GET`
+request to that URL. The server could include authentication requirements
+to those requests with the aim of triggering the configured credential
+helper for secure access. (Future extensions could use "file://" URIs or
+SSH URIs.)
+
+Assuming a `200 OK` response from the server, the content at the URL is
+inspected. First, Git attempts to parse the file as a bundle file of
+version 2 or higher. If the file is not a bundle, then the file is parsed
+as a plain-text file using Git's config parser. The key-value pairs in
+that config file are expected to describe a list of bundle URIs. If
+neither of these parse attempts succeed, then Git will report an error to
+the user that the bundle URI provided erroneous data.
+
+Any other data provided by the server is considered erroneous.
+
+Bundle Lists
+------------
+
+The Git server can advertise bundle URIs using a set of `key=value` pairs.
+A bundle URI can also serve a plain-text file in the Git config format
+containing these same `key=value` pairs. In both cases, we consider this
+to be a _bundle list_. The pairs specify information about the bundles
+that the client can use to make decisions for which bundles to download
+and which to ignore.
+
+A few keys focus on properties of the list itself.
+
+bundle.version::
+       (Required) This value provides a version number for the bundle
+       list. If a future Git change enables a feature that needs the Git
+       client to react to a new key in the bundle list file, then this version
+       will increment. The only current version number is 1, and if any other
+       value is specified then Git will fail to use this file.
+
+bundle.mode::
+       (Required) This value has one of two values: `all` and `any`. When `all`
+       is specified, then the client should expect to need all of the listed
+       bundle URIs that match their repository's requirements. When `any` is
+       specified, then the client should expect that any one of the bundle URIs
+       that match their repository's requirements will suffice. Typically, the
+       `any` option is used to list a number of different bundle servers
+       located in different geographies.
+
+bundle.heuristic::
+       If this string-valued key exists, then the bundle list is designed to
+       work well with incremental `git fetch` commands. The heuristic signals
+       that there are additional keys available for each bundle that help
+       determine which subset of bundles the client should download. The only
+       heuristic currently planned is `creationToken`.
+
+The remaining keys include an `<id>` segment which is a server-designated
+name for each available bundle. The `<id>` must contain only alphanumeric
+and `-` characters.
+
+bundle.<id>.uri::
+       (Required) This string value is the URI for downloading bundle `<id>`.
+       If the URI begins with a protocol (`http://` or `https://`) then the URI
+       is absolute. Otherwise, the URI is interpreted as relative to the URI
+       used for the bundle list. If the URI begins with `/`, then that relative
+       path is relative to the domain name used for the bundle list. (This use
+       of relative paths is intended to make it easier to distribute a set of
+       bundles across a large number of servers or CDNs with different domain
+       names.)
+
+bundle.<id>.filter::
+       This string value represents an object filter that should also appear in
+       the header of this bundle. The server uses this value to differentiate
+       different kinds of bundles from which the client can choose those that
+       match their object filters.
+
+bundle.<id>.creationToken::
+       This value is a nonnegative 64-bit integer used for sorting the bundles
+       the list. This is used to download a subset of bundles during a fetch
+       when `bundle.heuristic=creationToken`.
+
+bundle.<id>.location::
+       This string value advertises a real-world location from where the bundle
+       URI is served. This can be used to present the user with an option for
+       which bundle URI to use or simply as an informative indicator of which
+       bundle URI was selected by Git. This is only valuable when
+       `bundle.mode` is `any`.
+
+Here is an example bundle list using the Git config format:
+
+       [bundle]
+               version = 1
+               mode = all
+               heuristic = creationToken
+
+       [bundle "2022-02-09-1644442601-daily"]
+               uri = https://bundles.example.com/git/git/2022-02-09-1644442601-daily.bundle
+               creationToken = 1644442601
+
+       [bundle "2022-02-02-1643842562"]
+               uri = https://bundles.example.com/git/git/2022-02-02-1643842562.bundle
+               creationToken = 1643842562
+
+       [bundle "2022-02-09-1644442631-daily-blobless"]
+               uri = 2022-02-09-1644442631-daily-blobless.bundle
+               creationToken = 1644442631
+               filter = blob:none
+
+       [bundle "2022-02-02-1643842568-blobless"]
+               uri = /git/git/2022-02-02-1643842568-blobless.bundle
+               creationToken = 1643842568
+               filter = blob:none
+
+This example uses `bundle.mode=all` as well as the
+`bundle.<id>.creationToken` heuristic. It also uses the `bundle.<id>.filter`
+options to present two parallel sets of bundles: one for full clones and
+another for blobless partial clones.
+
+Suppose that this bundle list was found at the URI
+`https://bundles.example.com/git/git/` and so the two blobless bundles have
+the following fully-expanded URIs:
+
+* `https://bundles.example.com/git/git/2022-02-09-1644442631-daily-blobless.bundle`
+* `https://bundles.example.com/git/git/2022-02-02-1643842568-blobless.bundle`
+
+Advertising Bundle URIs
+-----------------------
+
+If a user knows a bundle URI for the repository they are cloning, then
+they can specify that URI manually through a command-line option. However,
+a Git host may want to advertise bundle URIs during the clone operation,
+helping users unaware of the feature.
+
+The only thing required for this feature is that the server can advertise
+one or more bundle URIs. This advertisement takes the form of a new
+protocol v2 capability specifically for discovering bundle URIs.
+
+The client could choose an arbitrary bundle URI as an option _or_ select
+the URI with best performance by some exploratory checks. It is up to the
+bundle provider to decide if having multiple URIs is preferable to a
+single URI that is geodistributed through server-side infrastructure.
+
+Cloning with Bundle URIs
+------------------------
+
+The primary need for bundle URIs is to speed up clones. The Git client
+will interact with bundle URIs according to the following flow:
+
+1. The user specifies a bundle URI with the `--bundle-uri` command-line
+   option _or_ the client discovers a bundle list advertised by the
+   Git server.
+
+2. If the downloaded data from a bundle URI is a bundle, then the client
+   inspects the bundle headers to check that the prerequisite commit OIDs
+   are present in the client repository. If some are missing, then the
+   client delays unbundling until other bundles have been unbundled,
+   making those OIDs present. When all required OIDs are present, the
+   client unbundles that data using a refspec. The default refspec is
+   `+refs/heads/*:refs/bundles/*`, but this can be configured. These refs
+   are stored so that later `git fetch` negotiations can communicate the
+   bundled refs as `have`s, reducing the size of the fetch over the Git
+   protocol. To allow pruning refs from this ref namespace, Git may
+   introduce a numbered namespace (such as `refs/bundles/<i>/*`) such that
+   stale bundle refs can be deleted.
+
+3. If the file is instead a bundle list, then the client inspects the
+   `bundle.mode` to see if the list is of the `all` or `any` form.
+
+   a. If `bundle.mode=all`, then the client considers all bundle
+      URIs. The list is reduced based on the `bundle.<id>.filter` options
+      matching the client repository's partial clone filter. Then, all
+      bundle URIs are requested. If the `bundle.<id>.creationToken`
+      heuristic is provided, then the bundles are downloaded in decreasing
+      order by the creation token, stopping when a bundle has all required
+      OIDs. The bundles can then be unbundled in increasing creation token
+      order. The client stores the latest creation token as a heuristic
+      for avoiding future downloads if the bundle list does not advertise
+      bundles with larger creation tokens.
+
+   b. If `bundle.mode=any`, then the client can choose any one of the
+      bundle URIs to inspect. The client can use a variety of ways to
+      choose among these URIs. The client can also fallback to another URI
+      if the initial choice fails to return a result.
+
+Note that during a clone we expect that all bundles will be required, and
+heuristics such as `bundle.<uri>.creationToken` can be used to download
+bundles in chronological order or in parallel.
+
+If a given bundle URI is a bundle list with a `bundle.heuristic`
+value, then the client can choose to store that URI as its chosen bundle
+URI. The client can then navigate directly to that URI during later `git
+fetch` calls.
+
+When downloading bundle URIs, the client can choose to inspect the initial
+content before committing to downloading the entire content. This may
+provide enough information to determine if the URI is a bundle list or
+a bundle. In the case of a bundle, the client may inspect the bundle
+header to determine that all advertised tips are already in the client
+repository and cancel the remaining download.
+
+Fetching with Bundle URIs
+-------------------------
+
+When the client fetches new data, it can decide to fetch from bundle
+servers before fetching from the origin remote. This could be done via a
+command-line option, but it is more likely useful to use a config value
+such as the one specified during the clone.
+
+The fetch operation follows the same procedure to download bundles from a
+bundle list (although we do _not_ want to use parallel downloads here). We
+expect that the process will end when all prerequisite commit OIDs in a
+thin bundle are already in the object database.
+
+When using the `creationToken` heuristic, the client can avoid downloading
+any bundles if their creation tokens are not larger than the stored
+creation token. After fetching new bundles, Git updates this local
+creation token.
+
+If the bundle provider does not provide a heuristic, then the client
+should attempt to inspect the bundle headers before downloading the full
+bundle data in case the bundle tips already exist in the client
+repository.
+
+Error Conditions
+----------------
+
+If the Git client discovers something unexpected while downloading
+information according to a bundle URI or the bundle list found at that
+location, then Git can ignore that data and continue as if it was not
+given a bundle URI. The remote Git server is the ultimate source of truth,
+not the bundle URI.
+
+Here are a few example error conditions:
+
+* The client fails to connect with a server at the given URI or a connection
+  is lost without any chance to recover.
+
+* The client receives a 400-level response (such as `404 Not Found` or
+  `401 Not Authorized`). The client should use the credential helper to
+  find and provide a credential for the URI, but match the semantics of
+  Git's other HTTP protocols in terms of handling specific 400-level
+  errors.
+
+* The server reports any other failure response.
+
+* The client receives data that is not parsable as a bundle or bundle list.
+
+* A bundle includes a filter that does not match expectations.
+
+* The client cannot unbundle the bundles because the prerequisite commit OIDs
+  are not in the object database and there are no more bundles to download.
+
+There are also situations that could be seen as wasteful, but are not
+error conditions:
+
+* The downloaded bundles contain more information than is requested by
+  the clone or fetch request. A primary example is if the user requests
+  a clone with `--single-branch` but downloads bundles that store every
+  reachable commit from all `refs/heads/*` references. This might be
+  initially wasteful, but perhaps these objects will become reachable by
+  a later ref update that the client cares about.
+
+* A bundle download during a `git fetch` contains objects already in the
+  object database. This is probably unavoidable if we are using bundles
+  for fetches, since the client will almost always be slightly ahead of
+  the bundle servers after performing its "catch-up" fetch to the remote
+  server. This extra work is most wasteful when the client is fetching
+  much more frequently than the server is computing bundles, such as if
+  the client is using hourly prefetches with background maintenance, but
+  the server is computing bundles weekly. For this reason, the client
+  should not use bundle URIs for fetch unless the server has explicitly
+  recommended it through a `bundle.heuristic` value.
+
+Example Bundle Provider organization
+------------------------------------
+
+The bundle URI feature is intentionally designed to be flexible to
+different ways a bundle provider wants to organize the object data.
+However, it can be helpful to have a complete organization model described
+here so providers can start from that base.
+
+This example organization is a simplified model of what is used by the
+GVFS Cache Servers (see section near the end of this document) which have
+been beneficial in speeding up clones and fetches for very large
+repositories, although using extra software outside of Git.
+
+The bundle provider deploys servers across multiple geographies. Each
+server manages its own bundle set. The server can track a number of Git
+repositories, but provides a bundle list for each based on a pattern. For
+example, when mirroring a repository at `https://<domain>/<org>/<repo>`
+the bundle server could have its bundle list available at
+`https://<server-url>/<domain>/<org>/<repo>`. The origin Git server can
+list all of these servers under the "any" mode:
+
+       [bundle]
+               version = 1
+               mode = any
+
+       [bundle "eastus"]
+               uri = https://eastus.example.com/<domain>/<org>/<repo>
+
+       [bundle "europe"]
+               uri = https://europe.example.com/<domain>/<org>/<repo>
+
+       [bundle "apac"]
+               uri = https://apac.example.com/<domain>/<org>/<repo>
+
+This "list of lists" is static and only changes if a bundle server is
+added or removed.
+
+Each bundle server manages its own set of bundles. The initial bundle list
+contains only a single bundle, containing all of the objects received from
+cloning the repository from the origin server. The list uses the
+`creationToken` heuristic and a `creationToken` is made for the bundle
+based on the server's timestamp.
+
+The bundle server runs regularly-scheduled updates for the bundle list,
+such as once a day. During this task, the server fetches the latest
+contents from the origin server and generates a bundle containing the
+objects reachable from the latest origin refs, but not contained in a
+previously-computed bundle. This bundle is added to the list, with care
+that the `creationToken` is strictly greater than the previous maximum
+`creationToken`.
+
+When the bundle list grows too large, say more than 30 bundles, then the
+oldest "_N_ minus 30" bundles are combined into a single bundle. This
+bundle's `creationToken` is equal to the maximum `creationToken` among the
+merged bundles.
+
+An example bundle list is provided here, although it only has two daily
+bundles and not a full list of 30:
+
+       [bundle]
+               version = 1
+               mode = all
+               heuristic = creationToken
+
+       [bundle "2022-02-13-1644770820-daily"]
+               uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-09-1644770820-daily.bundle
+               creationToken = 1644770820
+
+       [bundle "2022-02-09-1644442601-daily"]
+               uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-09-1644442601-daily.bundle
+               creationToken = 1644442601
+
+       [bundle "2022-02-02-1643842562"]
+               uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-02-1643842562.bundle
+               creationToken = 1643842562
+
+To avoid storing and serving object data in perpetuity despite becoming
+unreachable in the origin server, this bundle merge can be more careful.
+Instead of taking an absolute union of the old bundles, instead the bundle
+can be created by looking at the newer bundles and ensuring that their
+necessary commits are all available in this merged bundle (or in another
+one of the newer bundles). This allows "expiring" object data that is not
+being used by new commits in this window of time. That data could be
+reintroduced by a later push.
+
+The intention of this data organization has two main goals. First, initial
+clones of the repository become faster by downloading precomputed object
+data from a closer source. Second, `git fetch` commands can be faster,
+especially if the client has not fetched for a few days. However, if a
+client does not fetch for 30 days, then the bundle list organization would
+cause redownloading a large amount of object data.
+
+One way to make this organization more useful to users who fetch frequently
+is to have more frequent bundle creation. For example, bundles could be
+created every hour, and then once a day those "hourly" bundles could be
+merged into a "daily" bundle. The daily bundles are merged into the
+oldest bundle after 30 days.
+
+It is recommended that this bundle strategy is repeated with the `blob:none`
+filter if clients of this repository are expecting to use blobless partial
+clones. This list of blobless bundles stays in the same list as the full
+bundles, but uses the `bundle.<id>.filter` key to separate the two groups.
+For very large repositories, the bundle provider may want to _only_ provide
+blobless bundles.
+
+Implementation Plan
+-------------------
+
+This design document is being submitted on its own as an aspirational
+document, with the goal of implementing all of the mentioned client
+features over the course of several patch series. Here is a potential
+outline for submitting these features:
+
+1. Integrate bundle URIs into `git clone` with a `--bundle-uri` option.
+   This will include a new `git fetch --bundle-uri` mode for use as the
+   implementation underneath `git clone`. The initial version here will
+   expect a single bundle at the given URI.
+
+2. Implement the ability to parse a bundle list from a bundle URI and
+   update the `git fetch --bundle-uri` logic to properly distinguish
+   between `bundle.mode` options. Specifically design the feature so
+   that the config format parsing feeds a list of key-value pairs into the
+   bundle list logic.
+
+3. Create the `bundle-uri` protocol v2 command so Git servers can advertise
+   bundle URIs using the key-value pairs. Plug into the existing key-value
+   input to the bundle list logic. Allow `git clone` to discover these
+   bundle URIs and bootstrap the client repository from the bundle data.
+   (This choice is an opt-in via a config option and a command-line
+   option.)
+
+4. Allow the client to understand the `bundle.flag=forFetch` configuration
+   and the `bundle.<id>.creationToken` heuristic. When `git clone`
+   discovers a bundle URI with `bundle.flag=forFetch`, it configures the
+   client repository to check that bundle URI during later `git fetch <remote>`
+   commands.
+
+5. Allow clients to discover bundle URIs during `git fetch` and configure
+   a bundle URI for later fetches if `bundle.flag=forFetch`.
+
+6. Implement the "inspect headers" heuristic to reduce data downloads when
+   the `bundle.<id>.creationToken` heuristic is not available.
+
+As these features are reviewed, this plan might be updated. We also expect
+that new designs will be discovered and implemented as this feature
+matures and becomes used in real-world scenarios.
+
+Related Work: Packfile URIs
+---------------------------
+
+The Git protocol already has a capability where the Git server can list
+a set of URLs along with the packfile response when serving a client
+request. The client is then expected to download the packfiles at those
+locations in order to have a complete understanding of the response.
+
+This mechanism is used by the Gerrit server (implemented with JGit) and
+has been effective at reducing CPU load and improving user performance for
+clones.
+
+A major downside to this mechanism is that the origin server needs to know
+_exactly_ what is in those packfiles, and the packfiles need to be available
+to the user for some time after the server has responded. This coupling
+between the origin and the packfile data is difficult to manage.
+
+Further, this implementation is extremely hard to make work with fetches.
+
+Related Work: GVFS Cache Servers
+--------------------------------
+
+The GVFS Protocol [2] is a set of HTTP endpoints designed independently of
+the Git project before Git's partial clone was created. One feature of this
+protocol is the idea of a "cache server" which can be colocated with build
+machines or developer offices to transfer Git data without overloading the
+central server.
+
+The endpoint that VFS for Git is famous for is the `GET /gvfs/objects/{oid}`
+endpoint, which allows downloading an object on-demand. This is a critical
+piece of the filesystem virtualization of that product.
+
+However, a more subtle need is the `GET /gvfs/prefetch?lastPackTimestamp=<t>`
+endpoint. Given an optional timestamp, the cache server responds with a list
+of precomputed packfiles containing the commits and trees that were introduced
+in those time intervals.
+
+The cache server computes these "prefetch" packfiles using the following
+strategy:
+
+1. Every hour, an "hourly" pack is generated with a given timestamp.
+2. Nightly, the previous 24 hourly packs are rolled up into a "daily" pack.
+3. Nightly, all prefetch packs more than 30 days old are rolled up into
+   one pack.
+
+When a user runs `gvfs clone` or `scalar clone` against a repo with cache
+servers, the client requests all prefetch packfiles, which is at most
+`24 + 30 + 1` packfiles downloading only commits and trees. The client
+then follows with a request to the origin server for the references, and
+attempts to checkout that tip reference. (There is an extra endpoint that
+helps get all reachable trees from a given commit, in case that commit
+was not already in a prefetch packfile.)
+
+During a `git fetch`, a hook requests the prefetch endpoint using the
+most-recent timestamp from a previously-downloaded prefetch packfile.
+Only the list of packfiles with later timestamps are downloaded. Most
+users fetch hourly, so they get at most one hourly prefetch pack. Users
+whose machines have been off or otherwise have not fetched in over 30 days
+might redownload all prefetch packfiles. This is rare.
+
+It is important to note that the clients always contact the origin server
+for the refs advertisement, so the refs are frequently "ahead" of the
+prefetched pack data. The missing objects are downloaded on-demand using
+the `GET gvfs/objects/{oid}` requests, when needed by a command such as
+`git checkout` or `git log`. Some Git optimizations disable checks that
+would cause these on-demand downloads to be too aggressive.
+
+See Also
+--------
+
+[1] https://lore.kernel.org/git/RFC-cover-00.13-0000000000-20210805T150534Z-avarab@gmail.com/
+    An earlier RFC for a bundle URI feature.
+
+[2] https://github.com/microsoft/VFSForGit/blob/master/Protocol.md
+    The GVFS Protocol
index f05e7bda1a9d66c6c19eec5861384cca86b6690d..90c9760c230555053db461a8cb3d1a3676729cd7 100644 (file)
@@ -40,7 +40,7 @@ Values 1-4 satisfy the requirements of parse_commit_gently().
 
 There are two definitions of generation number:
 1. Corrected committer dates (generation number v2)
-2. Topological levels (generation nummber v1)
+2. Topological levels (generation number v1)
 
 Define "corrected committer date" of a commit recursively as follows:
 
@@ -48,7 +48,7 @@ Define "corrected committer date" of a commit recursively as follows:
     equal to its committer date.
 
  * A commit with at least one parent has corrected committer date equal to
-    the maximum of its commiter date and one more than the largest corrected
+    the maximum of its committer date and one more than the largest corrected
     committer date among its parents.
 
  * As a special case, a root commit with timestamp zero has corrected commit
diff --git a/Documentation/technical/cruft-packs.txt b/Documentation/technical/cruft-packs.txt
deleted file mode 100644 (file)
index d81f3a8..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-= Cruft packs
-
-The cruft packs feature offer an alternative to Git's traditional mechanism of
-removing unreachable objects. This document provides an overview of Git's
-pruning mechanism, and how a cruft pack can be used instead to accomplish the
-same.
-
-== Background
-
-To remove unreachable objects from your repository, Git offers `git repack -Ad`
-(see linkgit:git-repack[1]). Quoting from the documentation:
-
-[quote]
-[...] unreachable objects in a previous pack become loose, unpacked objects,
-instead of being left in the old pack. [...] loose unreachable objects will be
-pruned according to normal expiry rules with the next 'git gc' invocation.
-
-Unreachable objects aren't removed immediately, since doing so could race with
-an incoming push which may reference an object which is about to be deleted.
-Instead, those unreachable objects are stored as loose objects and stay that way
-until they are older than the expiration window, at which point they are removed
-by linkgit:git-prune[1].
-
-Git must store these unreachable objects loose in order to keep track of their
-per-object mtimes. If these unreachable objects were written into one big pack,
-then either freshening that pack (because an object contained within it was
-re-written) or creating a new pack of unreachable objects would cause the pack's
-mtime to get updated, and the objects within it would never leave the expiration
-window. Instead, objects are stored loose in order to keep track of the
-individual object mtimes and avoid a situation where all cruft objects are
-freshened at once.
-
-This can lead to undesirable situations when a repository contains many
-unreachable objects which have not yet left the grace period. Having large
-directories in the shards of `.git/objects` can lead to decreased performance in
-the repository. But given enough unreachable objects, this can lead to inode
-starvation and degrade the performance of the whole system. Since we
-can never pack those objects, these repositories often take up a large amount of
-disk space, since we can only zlib compress them, but not store them in delta
-chains.
-
-== Cruft packs
-
-A cruft pack eliminates the need for storing unreachable objects in a loose
-state by including the per-object mtimes in a separate file alongside a single
-pack containing all loose objects.
-
-A cruft pack is written by `git repack --cruft` when generating a new pack.
-linkgit:git-pack-objects[1]'s `--cruft` option. Note that `git repack --cruft`
-is a classic all-into-one repack, meaning that everything in the resulting pack is
-reachable, and everything else is unreachable. Once written, the `--cruft`
-option instructs `git repack` to generate another pack containing only objects
-not packed in the previous step (which equates to packing all unreachable
-objects together). This progresses as follows:
-
-  1. Enumerate every object, marking any object which is (a) not contained in a
-     kept-pack, and (b) whose mtime is within the grace period as a traversal
-     tip.
-
-  2. Perform a reachability traversal based on the tips gathered in the previous
-     step, adding every object along the way to the pack.
-
-  3. Write the pack out, along with a `.mtimes` file that records the per-object
-     timestamps.
-
-This mode is invoked internally by linkgit:git-repack[1] when instructed to
-write a cruft pack. Crucially, the set of in-core kept packs is exactly the set
-of packs which will not be deleted by the repack; in other words, they contain
-all of the repository's reachable objects.
-
-When a repository already has a cruft pack, `git repack --cruft` typically only
-adds objects to it. An exception to this is when `git repack` is given the
-`--cruft-expiration` option, which allows the generated cruft pack to omit
-expired objects instead of waiting for linkgit:git-gc[1] to expire those objects
-later on.
-
-It is linkgit:git-gc[1] that is typically responsible for removing expired
-unreachable objects.
-
-== Caution for mixed-version environments
-
-Repositories that have cruft packs in them will continue to work with any older
-version of Git. Note, however, that previous versions of Git which do not
-understand the `.mtimes` file will use the cruft pack's mtime as the mtime for
-all of the objects in it. In other words, do not expect older (pre-cruft pack)
-versions of Git to interpret or even read the contents of the `.mtimes` file.
-
-Note that having mixed versions of Git GC-ing the same repository can lead to
-unreachable objects never being completely pruned. This can happen under the
-following circumstances:
-
-  - An older version of Git running GC explodes the contents of an existing
-    cruft pack loose, using the cruft pack's mtime.
-  - A newer version running GC collects those loose objects into a cruft pack,
-    where the .mtime file reflects the loose object's actual mtimes, but the
-    cruft pack mtime is "now".
-
-Repeating this process will lead to unreachable objects not getting pruned as a
-result of repeatedly resetting the objects' mtimes to the present time.
-
-If you are GC-ing repositories in a mixed version environment, consider omitting
-the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
-leaving the `gc.cruftPacks` configuration unset until all writers understand
-cruft packs.
-
-== Alternatives
-
-Notable alternatives to this design include:
-
-  - The location of the per-object mtime data, and
-  - Storing unreachable objects in multiple cruft packs.
-
-On the location of mtime data, a new auxiliary file tied to the pack was chosen
-to avoid complicating the `.idx` format. If the `.idx` format were ever to gain
-support for optional chunks of data, it may make sense to consolidate the
-`.mtimes` format into the `.idx` itself.
-
-Storing unreachable objects among multiple cruft packs (e.g., creating a new
-cruft pack during each repacking operation including only unreachable objects
-which aren't already stored in an earlier cruft pack) is significantly more
-complicated to construct, and so aren't pursued here. The obvious drawback to
-the current implementation is that the entire cruft pack must be re-written from
-scratch.
index 260224b0331c709da9aa4bcfa06ae97146cfffb6..e2ac36dd210bef993e1cca06f37d788c3d4fe262 100644 (file)
@@ -205,7 +205,7 @@ SHA-1 content.
 Object storage
 ~~~~~~~~~~~~~~
 Loose objects use zlib compression and packed objects use the packed
-format described in Documentation/technical/pack-format.txt, just like
+format described in linkgit:gitformat-pack[5], just like
 today. The content that is compressed and stored uses SHA-256 content
 instead of SHA-1 content.
 
index aa0aa9af1c2eb8835e81a5a43a6332df902ceefe..6f33654b4288d4effafed8a78162da9da2bf7f9a 100644 (file)
@@ -3,7 +3,7 @@ Long-running process protocol
 
 This protocol is used when Git needs to communicate with an external
 process throughout the entire life of a single Git command. All
-communication is in pkt-line format (see technical/protocol-common.txt)
+communication is in pkt-line format (see linkgit:gitprotocol-common[5])
 over standard input and standard output.
 
 Handshake
index 1eb525fe760461608442b7a35a40a48e1fddee79..9d453d47651a03dd432c71a71828c1bae2234dfb 100644 (file)
@@ -18,7 +18,7 @@ a `packfile-uris` argument, the server MAY send a `packfile-uris` section
 directly before the `packfile` section (right after `wanted-refs` if it is
 sent) containing URIs of any of the given protocols. The URIs point to
 packfiles that use only features that the client has declared that it supports
-(e.g. ofs-delta and thin-pack). See protocol-v2.txt for the documentation of
+(e.g. ofs-delta and thin-pack). See linkgit:gitprotocol-v2[5] for the documentation of
 this section.
 
 Clients should then download and index all the given URIs (in addition to
index 99f0eb304061adeb6b9d2b487eb1c2c11d07463b..92fcee2bfffff8c42a07f0dd4b87421abd94f2bb 100644 (file)
@@ -79,7 +79,7 @@ Design Details
   upload-pack negotiation.
 +
 This uses the existing capability discovery mechanism.
-See "filter" in Documentation/technical/pack-protocol.txt.
+See "filter" in linkgit:gitprotocol-pack[5].
 
 - Clients pass a "filter-spec" to clone and fetch which is passed to the
   server to request filtering during packfile construction.
index 2fd5cc88e0b808c75344b4e3e7ba80d2e1938c3f..1e34d913901e5922089da9451042ad2dc496b8f0 100644 (file)
@@ -20,7 +20,7 @@ Outline:
   3. Why any rename on MERGE_SIDE1 in any given pick is _almost_ always also
      a rename on MERGE_SIDE1 for the next pick
 
-  4. A detailed description of the the counter-examples to #3.
+  4. A detailed description of the counter-examples to #3.
 
   5. Why the special cases in #4 are still fully reasonable to use to pair
      up files for three-way content merging in the merge machinery, and why
@@ -407,7 +407,7 @@ considered to be "irrelevant".  See for example the following commits:
                no longer relevant", 2021-03-13)
 
 Relevance is always determined by what the _other_ side of history has
-done, in terms of modifing a file that our side renamed, or adding a
+done, in terms of modifying a file that our side renamed, or adding a
 file to a directory which our side renamed.  This means that a path
 that is "irrelevant" when picking the first commit of a series in a
 rebase or cherry-pick, may suddenly become "relevant" when picking the
diff --git a/Documentation/technical/scalar.txt b/Documentation/technical/scalar.txt
new file mode 100644 (file)
index 0000000..921cb10
--- /dev/null
@@ -0,0 +1,66 @@
+Scalar
+======
+
+Scalar is a repository management tool that optimizes Git for use in large
+repositories. It accomplishes this by helping users to take advantage of
+advanced performance features in Git. Unlike most other Git built-in commands,
+Scalar is not executed as a subcommand of 'git'; rather, it is built as a
+separate executable containing its own series of subcommands.
+
+Background
+----------
+
+Scalar was originally designed as an add-on to Git and implemented as a .NET
+Core application. It was created based on the learnings from the VFS for Git
+project (another application aimed at improving the experience of working with
+large repositories). As part of its initial implementation, Scalar relied on
+custom features in the Microsoft fork of Git that have since been integrated
+into core Git:
+
+* partial clone,
+* commit graphs,
+* multi-pack index,
+* sparse checkout (cone mode),
+* scheduled background maintenance,
+* etc
+
+With the requisite Git functionality in place and a desire to bring the benefits
+of Scalar to the larger Git community, the Scalar application itself was ported
+from C# to C and integrated upstream.
+
+Features
+--------
+
+Scalar is comprised of two major pieces of functionality: automatically
+configuring built-in Git performance features and managing repository
+enlistments.
+
+The Git performance features configured by Scalar (see "Background" for
+examples) confer substantial performance benefits to large repositories, but are
+either too experimental to enable for all of Git yet, or only benefit large
+repositories. As new features are introduced, Scalar should be updated
+accordingly to incorporate them. This will prevent the tool from becoming stale
+while also providing a path for more easily bringing features to the appropriate
+users.
+
+Enlistments are how Scalar knows which repositories on a user's system should
+utilize Scalar-configured features. This allows it to update performance
+settings when new ones are added to the tool, as well as centrally manage
+repository maintenance. The enlistment structure - a root directory with a
+`src/` subdirectory containing the cloned repository itself - is designed to
+encourage users to route build outputs outside of the repository to avoid the
+performance-limiting overhead of ignoring those files in Git.
+
+Design
+------
+
+Scalar is implemented in C and interacts with Git via a mix of child process
+invocations of Git and direct usage of `libgit.a`. Internally, it is structured
+much like other built-ins with subcommands (e.g., `git stash`), containing a
+`cmd_<subcommand>()` function for each subcommand, routed through a `cmd_main()`
+function. Most options are unique to each subcommand, with `scalar` respecting
+some "global" `git` options (e.g., `-c` and `-C`).
+
+Because `scalar` is not invoked as a Git subcommand (like `git scalar`), it is
+built and installed as its own executable in the `bin/` directory, alongside
+`git`, `git-gui`, etc.
index 865074bed4eacac0ba3da5edb8f0094dc411227c..dc9c6a663a97e644d865e7d01957bfa2ac77bb5d 100644 (file)
@@ -3133,7 +3133,7 @@ those "loose" objects.
 You can save space and make Git faster by moving these loose objects in
 to a "pack file", which stores a group of objects in an efficient
 compressed format; the details of how pack files are formatted can be
-found in link:technical/pack-format.html[pack format].
+found in linkgit:gitformat-pack[5].
 
 To put the loose objects into a pack, just run git repack:
 
index fb16249620d01d4c948bdbf476dfa606c84b65e4..e3eaeb49264eea1619d10dc6b17b7dbfbd42ec4b 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.37.3
+DEF_VER=v2.38.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 4140a3f5c8b6946ca821c2a876cd4390a1a05f1b..89b15d71df521b2b710b77481e9607c03b78fccc 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -135,8 +135,7 @@ Issues of note:
 
          By default, git uses OpenSSL for SHA1 but it will use its own
          library (inspired by Mozilla's) with either NO_OPENSSL or
-         BLK_SHA1.  Also included is a version optimized for PowerPC
-         (PPC_SHA1).
+         BLK_SHA1.
 
        - "libcurl" library is used for fetching and pushing
          repositories over http:// or https://, as well as by
index 17fdb16dd85afb7a5d2a69755c5cd22dc0d63276..6bfb62cbe941fceaddb9bfc75eb65b9351d67fcf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -155,9 +155,6 @@ include shared.mak
 # Define BLK_SHA1 environment variable to make use of the bundled
 # optimized C SHA1 routine.
 #
-# Define PPC_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for PowerPC.
-#
 # Define DC_SHA1 to unconditionally enable the collision-detecting sha1
 # algorithm. This is slower, but may detect attempted collision attacks.
 # Takes priority over other *_SHA1 knobs.
@@ -182,6 +179,8 @@ include shared.mak
 #
 # Define BLK_SHA256 to use the built-in SHA-256 routines.
 #
+# Define NETTLE_SHA256 to use the SHA-256 routines in libnettle.
+#
 # Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt.
 #
 # Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
@@ -309,6 +308,11 @@ include shared.mak
 # distributions that want to use their packaged versions of Perl
 # modules, instead of the fallbacks shipped with Git.
 #
+# Define NO_GITWEB if you do not want to build or install
+# 'gitweb'. Note that defining NO_PERL currently has the same effect
+# on not installing gitweb, but not on whether it's built in the
+# gitweb/ directory.
+#
 # Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
 # but /usr/bin/python2.7 or /usr/bin/python3 on some platforms).
 #
@@ -544,6 +548,7 @@ gitexecdir = libexec/git-core
 mergetoolsdir = $(gitexecdir)/mergetools
 sharedir = $(prefix)/share
 gitwebdir = $(sharedir)/gitweb
+gitwebstaticdir = $(gitwebdir)/static
 perllibdir = $(sharedir)/perl5
 localedir = $(sharedir)/locale
 template_dir = share/git-core/templates
@@ -562,7 +567,7 @@ localedir_relative = $(patsubst $(prefix)/%,%,$(localedir))
 htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
 perllibdir_relative = $(patsubst $(prefix)/%,%,$(perllibdir))
 
-export prefix bindir sharedir sysconfdir gitwebdir perllibdir localedir
+export prefix bindir sharedir sysconfdir perllibdir localedir
 
 # Set our default programs
 CC = cc
@@ -600,7 +605,9 @@ FUZZ_OBJS =
 FUZZ_PROGRAMS =
 GIT_OBJS =
 LIB_OBJS =
+SCALAR_OBJS =
 OBJECTS =
+OTHER_PROGRAMS =
 PROGRAM_OBJS =
 PROGRAMS =
 EXCLUDED_PROGRAMS =
@@ -681,9 +688,9 @@ SCRIPTS = $(SCRIPT_SH_GEN) \
 
 ETAGS_TARGET = TAGS
 
-FUZZ_OBJS += fuzz-commit-graph.o
-FUZZ_OBJS += fuzz-pack-headers.o
-FUZZ_OBJS += fuzz-pack-idx.o
+FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
 .PHONY: fuzz-objs
 fuzz-objs: $(FUZZ_OBJS)
 
@@ -764,6 +771,7 @@ TEST_BUILTINS_OBJS += test-read-midx.o
 TEST_BUILTINS_OBJS += test-ref-store.o
 TEST_BUILTINS_OBJS += test-reftable.o
 TEST_BUILTINS_OBJS += test-regex.o
+TEST_BUILTINS_OBJS += test-rot13-filter.o
 TEST_BUILTINS_OBJS += test-repository.o
 TEST_BUILTINS_OBJS += test-revision-walking.o
 TEST_BUILTINS_OBJS += test-run-command.o
@@ -777,6 +785,7 @@ TEST_BUILTINS_OBJS += test-strcmp-offset.o
 TEST_BUILTINS_OBJS += test-string-list.o
 TEST_BUILTINS_OBJS += test-submodule-config.o
 TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
+TEST_BUILTINS_OBJS += test-submodule.o
 TEST_BUILTINS_OBJS += test-subprocess.o
 TEST_BUILTINS_OBJS += test-trace2.o
 TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
@@ -809,13 +818,16 @@ BUILT_INS += git-show$X
 BUILT_INS += git-stage$X
 BUILT_INS += git-status$X
 BUILT_INS += git-switch$X
+BUILT_INS += git-version$X
 BUILT_INS += git-whatchanged$X
 
 # what 'all' will build but not install in gitexecdir
-OTHER_PROGRAMS = git$X
+OTHER_PROGRAMS += git$X
+OTHER_PROGRAMS += scalar$X
 
 # what test wrappers are needed and 'install' will install, in bindir
 BINDIR_PROGRAMS_NEED_X += git
+BINDIR_PROGRAMS_NEED_X += scalar
 BINDIR_PROGRAMS_NEED_X += git-receive-pack
 BINDIR_PROGRAMS_NEED_X += git-shell
 BINDIR_PROGRAMS_NEED_X += git-upload-archive
@@ -898,6 +910,7 @@ LIB_OBJS += blob.o
 LIB_OBJS += bloom.o
 LIB_OBJS += branch.o
 LIB_OBJS += bulk-checkin.o
+LIB_OBJS += bundle-uri.o
 LIB_OBJS += bundle.o
 LIB_OBJS += cache-tree.o
 LIB_OBJS += cbtree.o
@@ -925,6 +938,7 @@ LIB_OBJS += ctype.o
 LIB_OBJS += date.o
 LIB_OBJS += decorate.o
 LIB_OBJS += delta-islands.o
+LIB_OBJS += diagnose.o
 LIB_OBJS += diff-delta.o
 LIB_OBJS += diff-merges.o
 LIB_OBJS += diff-lib.o
@@ -985,7 +999,6 @@ LIB_OBJS += merge-ort.o
 LIB_OBJS += merge-ort-wrappers.o
 LIB_OBJS += merge-recursive.o
 LIB_OBJS += merge.o
-LIB_OBJS += mergesort.o
 LIB_OBJS += midx.o
 LIB_OBJS += name-hash.o
 LIB_OBJS += negotiator/default.o
@@ -1146,6 +1159,7 @@ BUILTIN_OBJS += builtin/credential-cache.o
 BUILTIN_OBJS += builtin/credential-store.o
 BUILTIN_OBJS += builtin/credential.o
 BUILTIN_OBJS += builtin/describe.o
+BUILTIN_OBJS += builtin/diagnose.o
 BUILTIN_OBJS += builtin/diff-files.o
 BUILTIN_OBJS += builtin/diff-index.o
 BUILTIN_OBJS += builtin/diff-tree.o
@@ -1287,7 +1301,7 @@ SANITIZE_ADDRESS =
 # For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
 # usually result in less CPU usage at the cost of higher peak memory.
 # Setting it to 0 will feed all files in a single spatch invocation.
-SPATCH_FLAGS = --all-includes --patch .
+SPATCH_FLAGS = --all-includes
 SPATCH_BATCH_SIZE = 1
 
 include config.mak.uname
@@ -1428,7 +1442,6 @@ ifeq ($(uname_S),Darwin)
                APPLE_COMMON_CRYPTO = YesPlease
                COMPAT_CFLAGS += -DAPPLE_COMMON_CRYPTO
        endif
-       NO_REGEX = YesPlease
        PTHREAD_LIBS =
 endif
 
@@ -1792,6 +1805,10 @@ ifdef APPLE_COMMON_CRYPTO
        SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L
 endif
 
+ifdef PPC_SHA1
+$(error the PPC_SHA1 flag has been removed along with the PowerPC-specific SHA-1 implementation.)
+endif
+
 ifdef OPENSSL_SHA1
        EXTLIBS += $(LIB_4_CRYPTO)
        BASIC_CFLAGS += -DSHA1_OPENSSL
@@ -1800,10 +1817,6 @@ ifdef BLK_SHA1
        LIB_OBJS += block-sha1/sha1.o
        BASIC_CFLAGS += -DSHA1_BLK
 else
-ifdef PPC_SHA1
-       LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
-       BASIC_CFLAGS += -DSHA1_PPC
-else
 ifdef APPLE_COMMON_CRYPTO
        COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
        BASIC_CFLAGS += -DSHA1_APPLE
@@ -1837,12 +1850,15 @@ endif
 endif
 endif
 endif
-endif
 
 ifdef OPENSSL_SHA256
        EXTLIBS += $(LIB_4_CRYPTO)
        BASIC_CFLAGS += -DSHA256_OPENSSL
 else
+ifdef NETTLE_SHA256
+       BASIC_CFLAGS += -DSHA256_NETTLE
+       EXTLIBS += -lnettle
+else
 ifdef GCRYPT_SHA256
        BASIC_CFLAGS += -DSHA256_GCRYPT
        EXTLIBS += -lgcrypt
@@ -1851,6 +1867,7 @@ else
        BASIC_CFLAGS += -DSHA256_BLK
 endif
 endif
+endif
 
 ifdef SHA1_MAX_BLOCK_SIZE
        LIB_OBJS += compat/sha1-chunked.o
@@ -2090,6 +2107,7 @@ htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
 prefix_SQ = $(subst ','\'',$(prefix))
 perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative))
 gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
+gitwebstaticdir_SQ = $(subst ','\'',$(gitwebstaticdir))
 
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH))
@@ -2206,7 +2224,7 @@ profile-fast: profile-clean
 
 all:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
 ifneq (,$X)
-       $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
+       $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) $(OTHER_PROGRAMS))), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
 endif
 
 all::
@@ -2418,10 +2436,6 @@ GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
 perllibdir:
        @echo '$(perllibdir_SQ)'
 
-.PHONY: gitweb
-gitweb:
-       $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
-
 git-instaweb: git-instaweb.sh GIT-SCRIPT-DEFINES
        $(QUIET_GEN)$(cmd_munge_script) && \
        chmod +x $@+ && \
@@ -2533,7 +2547,12 @@ GIT_OBJS += git.o
 .PHONY: git-objs
 git-objs: $(GIT_OBJS)
 
+SCALAR_OBJS += scalar.o
+.PHONY: scalar-objs
+scalar-objs: $(SCALAR_OBJS)
+
 OBJECTS += $(GIT_OBJS)
+OBJECTS += $(SCALAR_OBJS)
 OBJECTS += $(PROGRAM_OBJS)
 OBJECTS += $(TEST_OBJS)
 OBJECTS += $(XDIFF_OBJS)
@@ -2544,10 +2563,6 @@ ifndef NO_CURL
        OBJECTS += http.o http-walker.o remote-curl.o
 endif
 
-SCALAR_SOURCES := contrib/scalar/scalar.c
-SCALAR_OBJECTS := $(SCALAR_SOURCES:c=o)
-OBJECTS += $(SCALAR_OBJECTS)
-
 .PHONY: objects
 objects: $(OBJECTS)
 
@@ -2582,13 +2597,7 @@ missing_compdb_dir =
 compdb_args =
 endif
 
-ASM_SRC := $(wildcard $(OBJECTS:o=S))
-ASM_OBJ := $(ASM_SRC:S=o)
-C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
-
-$(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
-       $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
-$(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
+$(OBJECTS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
        $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 
 %.s: %.c GIT-CFLAGS FORCE
@@ -2679,7 +2688,7 @@ $(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
-contrib/scalar/scalar$X: $(SCALAR_OBJECTS) GIT-LDFLAGS $(GITLIBS)
+scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
                $(filter %.o,$^) $(LIBS)
 
@@ -2735,8 +2744,7 @@ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
 XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \
        --keyword=__ --keyword=N__ --keyword="__n:1,2"
 MSGMERGE_FLAGS = --add-location --backup=off --update
-LOCALIZED_C = $(sort $(FOUND_C_SOURCES) $(FOUND_H_SOURCES) $(SCALAR_SOURCES) \
-               $(GENERATED_H))
+LOCALIZED_C = $(sort $(FOUND_C_SOURCES) $(FOUND_H_SOURCES) $(GENERATED_H))
 LOCALIZED_SH = $(sort $(SCRIPT_SH) git-sh-setup.sh)
 LOCALIZED_PERL = $(sort $(SCRIPT_PERL))
 
@@ -2971,6 +2979,7 @@ GIT-BUILD-OPTIONS: FORCE
        @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
        @echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+
        @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+
+       @echo NO_REGEX=\''$(subst ','\'',$(subst ','\'',$(NO_REGEX)))'\' >>$@+
        @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
        @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
        @echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+
@@ -3050,7 +3059,7 @@ bin-wrappers/%: wrap-for-bin.sh
        $(call mkdir_p_parent_template)
        $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
             -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
-            -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%$(X),$(@F))$(patsubst git%,$(X),$(filter $(@F),$(BINDIR_PROGRAMS_NEED_X)))|' < $< > $@ && \
+            -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \
        chmod +x $@
 
 # GNU make supports exporting all variables by "export" without parameters.
@@ -3080,7 +3089,7 @@ t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB)
 check-sha1:: t/helper/test-tool$X
        t/helper/test-sha1.sh
 
-SP_OBJ = $(patsubst %.o,%.sp,$(C_OBJ))
+SP_OBJ = $(patsubst %.o,%.sp,$(OBJECTS))
 
 $(SP_OBJ): %.sp: %.c %.o
        $(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
@@ -3092,6 +3101,9 @@ $(SP_OBJ): %.sp: %.c %.o
 sparse: $(SP_OBJ)
 
 EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
+ifndef NETTLE_SHA256
+       EXCEPT_HDRS += sha256/nettle.h
+endif
 ifndef GCRYPT_SHA256
        EXCEPT_HDRS += sha256/gcrypt.h
 endif
@@ -3124,6 +3136,8 @@ check: $(GENERATED_H)
                exit 1; \
        fi
 
+COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)
+
 %.cocci.patch: %.cocci $(COCCI_SOURCES)
        $(QUIET_SPATCH) \
        if test $(SPATCH_BATCH_SIZE) = 0; then \
@@ -3132,7 +3146,8 @@ check: $(GENERATED_H)
                limit='-n $(SPATCH_BATCH_SIZE)'; \
        fi; \
        if ! echo $(COCCI_SOURCES) | xargs $$limit \
-               $(SPATCH) --sp-file $< $(SPATCH_FLAGS) \
+               $(SPATCH) $(SPATCH_FLAGS) \
+               --sp-file $< --patch . \
                >$@+ 2>$@.log; \
        then \
                cat $@.log; \
@@ -3143,13 +3158,43 @@ check: $(GENERATED_H)
        then \
                echo '    ' SPATCH result: $@; \
        fi
+
+COCCI_TEST_RES_GEN = $(addprefix .build/,$(COCCI_TEST_RES))
+$(COCCI_TEST_RES_GEN): .build/%.res : %.c
+$(COCCI_TEST_RES_GEN): .build/%.res : %.res
+$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci
+       $(call mkdir_p_parent_template)
+       $(QUIET_SPATCH_T)$(SPATCH) $(SPATCH_FLAGS) \
+               --very-quiet --no-show-diff \
+               --sp-file $< -o $@ \
+               $(@:.build/%.res=%.c) && \
+       cmp $(@:.build/%=%) $@ || \
+       git -P diff --no-index $(@:.build/%=%) $@ 2>/dev/null; \
+
+.PHONY: coccicheck-test
+coccicheck-test: $(COCCI_TEST_RES_GEN)
+
+coccicheck: coccicheck-test
 coccicheck: $(addsuffix .patch,$(filter-out %.pending.cocci,$(wildcard contrib/coccinelle/*.cocci)))
 
 # See contrib/coccinelle/README
+coccicheck-pending: coccicheck-test
 coccicheck-pending: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.pending.cocci))
 
 .PHONY: coccicheck coccicheck-pending
 
+# "Sub"-Makefiles, not really because they can't be run stand-alone,
+# only there to contain directory-specific rules and variables
+## gitweb/Makefile inclusion:
+MAK_DIR_GITWEB = gitweb/
+include gitweb/Makefile
+
+.PHONY: gitweb
+gitweb: $(MAK_DIR_GITWEB_ALL)
+ifndef NO_GITWEB
+all:: gitweb
+endif
+
 ### Installation rules
 
 ifneq ($(filter /%,$(firstword $(template_dir))),)
@@ -3222,21 +3267,20 @@ ifndef NO_PERL
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perllibdir_SQ)'
        (cd perl/build/lib && $(TAR) cf - .) | \
        (cd '$(DESTDIR_SQ)$(perllibdir_SQ)' && umask 022 && $(TAR) xof -)
-       $(MAKE) -C gitweb install
 endif
 ifndef NO_TCLTK
        $(MAKE) -C gitk-git install
        $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
 endif
 ifneq (,$X)
-       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
+       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) $(OTHER_PROGRAMS))), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
 endif
 
        bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
        execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
        destdir_from_execdir_SQ=$$(echo '$(gitexecdir_relative_SQ)' | sed -e 's|[^/][^/]*|..|g') && \
        { test "$$bindir/" = "$$execdir/" || \
-         for p in git$X $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \
+         for p in $(OTHER_PROGRAMS) $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \
                $(RM) "$$execdir/$$p" && \
                test -n "$(INSTALL_SYMLINKS)" && \
                ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/$$p" "$$execdir/$$p" || \
@@ -3277,10 +3321,8 @@ endif
                  cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; } \
        done
 
-.PHONY: install-gitweb install-doc install-man install-man-perl install-html install-info install-pdf
+.PHONY: install-doc install-man install-man-perl install-html install-info install-pdf
 .PHONY: quick-install-doc quick-install-man quick-install-html
-install-gitweb:
-       $(MAKE) -C gitweb install
 
 install-doc: install-man-perl
        $(MAKE) -C Documentation install
@@ -3404,15 +3446,16 @@ profile-clean:
        $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
 
 cocciclean:
+       $(RM) -r .build/contrib/coccinelle
        $(RM) contrib/coccinelle/*.cocci.patch*
 
 clean: profile-clean coverage-clean cocciclean
        $(RM) -r .build
        $(RM) po/git.pot po/git-core.pot
-       $(RM) *.res
+       $(RM) git.res
        $(RM) $(OBJECTS)
        $(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
-       $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
+       $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
        $(RM) $(TEST_PROGRAMS)
        $(RM) $(FUZZ_PROGRAMS)
        $(RM) $(SP_OBJ)
@@ -3426,7 +3469,6 @@ clean: profile-clean coverage-clean cocciclean
        $(MAKE) -C Documentation/ clean
        $(RM) Documentation/GIT-EXCLUDED-PROGRAMS
 ifndef NO_PERL
-       $(MAKE) -C gitweb clean
        $(RM) -r perl/build/
 endif
        $(MAKE) -C templates/ clean
@@ -3464,6 +3506,7 @@ ALL_COMMANDS += git-citool
 ALL_COMMANDS += git-gui
 ALL_COMMANDS += gitk
 ALL_COMMANDS += gitweb
+ALL_COMMANDS += scalar
 
 .PHONY: check-docs
 check-docs::
@@ -3490,6 +3533,7 @@ check-docs::
                sed -e '1,/^### command list/d' \
                    -e '/^#/d' \
                    -e '/guide$$/d' \
+                   -e '/interfaces$$/d' \
                    -e 's/[     ].*//' \
                    -e 's/^/listed /' command-list.txt; \
                $(MAKE) -C Documentation print-man1 | \
index fcb45c8c048c710aacd5527ae8904398e9e2b2fe..758368388a4641dd46cf221bea607f885d487e84 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.37.4.txt
\ No newline at end of file
+Documentation/RelNotes/2.39.0.txt
\ No newline at end of file
index 22fcd3412ca5d8b343190cd3ae07148d83fd55e3..f071b2a1b4f2ee8bf1959706d1778c3697d81ba7 100644 (file)
@@ -430,7 +430,7 @@ struct pathname_entry {
        struct file_item *item;
 };
 
-static int pathname_entry_cmp(const void *unused_cmp_data,
+static int pathname_entry_cmp(const void *cmp_data UNUSED,
                              const struct hashmap_entry *he1,
                              const struct hashmap_entry *he2,
                              const void *name)
index 509ca04456bd390eb757f9c04a9d35a3285e313f..33ecd8398a12707836cd89975226179413fa9574 100644 (file)
@@ -191,10 +191,10 @@ static struct patch_mode patch_mode_worktree_head = {
        .apply_check_args = { "-R", NULL },
        .is_reverse = 1,
        .prompt_mode = {
-               N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
-               N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
-               N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
-               N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
+               N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
+               N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+               N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
+               N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
        },
        .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
                             "will immediately be marked for discarding."),
@@ -213,10 +213,10 @@ static struct patch_mode patch_mode_worktree_nothead = {
        .apply_args = { NULL },
        .apply_check_args = { NULL },
        .prompt_mode = {
-               N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
-               N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
-               N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
-               N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
+               N_("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
+               N_("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
+               N_("Apply addition to worktree [y,n,q,a,d%s,?]? "),
+               N_("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
        },
        .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
                             "will immediately be marked for applying."),
@@ -238,6 +238,7 @@ struct hunk_header {
         * include the newline.
         */
        size_t extra_start, extra_end, colored_extra_start, colored_extra_end;
+       unsigned suppress_colored_line_range:1;
 };
 
 struct hunk {
@@ -358,15 +359,14 @@ static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk)
        if (!eol)
                eol = s->colored.buf + s->colored.len;
        p = memmem(line, eol - line, "@@ -", 4);
-       if (!p)
-               return error(_("could not parse colored hunk header '%.*s'"),
-                            (int)(eol - line), line);
-       p = memmem(p + 4, eol - p - 4, " @@", 3);
-       if (!p)
-               return error(_("could not parse colored hunk header '%.*s'"),
-                            (int)(eol - line), line);
+       if (p && (p = memmem(p + 4, eol - p - 4, " @@", 3))) {
+               header->colored_extra_start = p + 3 - s->colored.buf;
+       } else {
+               /* could not parse colored hunk header, leave as-is */
+               header->colored_extra_start = hunk->colored_start;
+               header->suppress_colored_line_range = 1;
+       }
        hunk->colored_start = eol - s->colored.buf + (*eol == '\n');
-       header->colored_extra_start = p + 3 - s->colored.buf;
        header->colored_extra_end = hunk->colored_start;
 
        return 0;
@@ -419,7 +419,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
        }
        color_arg_index = args.nr;
        /* Use `--no-color` explicitly, just in case `diff.color = always`. */
-       strvec_pushl(&args, "--no-color", "-p", "--", NULL);
+       strvec_pushl(&args, "--no-color", "--ignore-submodules=dirty", "-p",
+                    "--", NULL);
        for (i = 0; i < ps->nr; i++)
                strvec_push(&args, ps->items[i].original);
 
@@ -592,7 +593,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                        if (colored_eol)
                                colored_p = colored_eol + 1;
                        else if (p != pend)
-                               /* colored shorter than non-colored? */
+                               /* non-colored has more lines? */
+                               goto mismatched_output;
+                       else if (colored_p == colored_pend)
+                               /* last line has no matching colored one? */
                                goto mismatched_output;
                        else
                                colored_p = colored_pend;
@@ -656,6 +660,15 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
                if (!colored) {
                        p = s->plain.buf + header->extra_start;
                        len = header->extra_end - header->extra_start;
+               } else if (header->suppress_colored_line_range) {
+                       strbuf_add(out,
+                                  s->colored.buf + header->colored_extra_start,
+                                  header->colored_extra_end -
+                                  header->colored_extra_start);
+
+                       strbuf_add(out, s->colored.buf + hunk->colored_start,
+                                  hunk->colored_end - hunk->colored_start);
+                       return;
                } else {
                        strbuf_addstr(out, s->s.fraginfo_color);
                        p = s->colored.buf + header->colored_extra_start;
@@ -1547,7 +1560,7 @@ soft_increment:
                        strbuf_remove(&s->answer, 0, 1);
                        strbuf_trim(&s->answer);
                        i = hunk_index - DISPLAY_HUNKS_LINES / 2;
-                       if (i < file_diff->mode_change)
+                       if (i < (int)file_diff->mode_change)
                                i = file_diff->mode_change;
                        while (s->answer.len == 0) {
                                i = display_hunks(s, file_diff, i);
index 6fda9edbc2474fe15c128014b99660034d269177..fd189689437c7512e549482fe696f7a2d2400cd2 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -261,3 +261,22 @@ void detach_advice(const char *new_name)
 
        fprintf(stderr, fmt, new_name);
 }
+
+void advise_on_moving_dirty_path(struct string_list *pathspec_list)
+{
+       struct string_list_item *item;
+
+       if (!pathspec_list->nr)
+               return;
+
+       fprintf(stderr, _("The following paths have been moved outside the\n"
+                         "sparse-checkout definition but are not sparse due to local\n"
+                         "modifications.\n"));
+       for_each_string_list_item(item, pathspec_list)
+               fprintf(stderr, "%s\n", item->string);
+
+       advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
+                         _("To correct the sparsity of these paths, do the following:\n"
+                           "* Use \"git add --sparse <paths>\" to update the index\n"
+                           "* Use \"git sparse-checkout reapply\" to apply the sparsity rules"));
+}
index 7ddc6cbc1ac8d7d9d15c9761187b87b5c00e4107..07e0f76833e78070a26ec288db929ec966024d7e 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -74,5 +74,6 @@ void NORETURN die_conclude_merge(void);
 void NORETURN die_ff_impossible(void);
 void advise_on_updating_sparse_paths(struct string_list *pathspec_list);
 void detach_advice(const char *new_name);
+void advise_on_moving_dirty_path(struct string_list *pathspec_list);
 
 #endif /* ADVICE_H */
index 042feb66d287329c43cd7b4f94d03339f6c144a3..3e4822b68409b85d36436bd42da862991274cd81 100644 (file)
@@ -38,11 +38,18 @@ static int write_tar_filter_archive(const struct archiver *ar,
 #define USTAR_MAX_MTIME 077777777777ULL
 #endif
 
+static void tar_write_block(const void *buf)
+{
+       write_or_die(1, buf, BLOCKSIZE);
+}
+
+static void (*write_block)(const void *) = tar_write_block;
+
 /* writes out the whole block, but only if it is full */
 static void write_if_needed(void)
 {
        if (offset == BLOCKSIZE) {
-               write_or_die(1, block, BLOCKSIZE);
+               write_block(block);
                offset = 0;
        }
 }
@@ -66,7 +73,7 @@ static void do_write_blocked(const void *data, unsigned long size)
                write_if_needed();
        }
        while (size >= BLOCKSIZE) {
-               write_or_die(1, buf, BLOCKSIZE);
+               write_block(buf);
                size -= BLOCKSIZE;
                buf += BLOCKSIZE;
        }
@@ -101,10 +108,10 @@ static void write_trailer(void)
 {
        int tail = BLOCKSIZE - offset;
        memset(block + offset, 0, tail);
-       write_or_die(1, block, BLOCKSIZE);
+       write_block(block);
        if (tail < 2 * RECORDSIZE) {
                memset(block, 0, offset);
-               write_or_die(1, block, BLOCKSIZE);
+               write_block(block);
        }
 }
 
@@ -359,7 +366,8 @@ static struct archiver *find_tar_filter(const char *name, size_t len)
        return NULL;
 }
 
-static int tar_filter_config(const char *var, const char *value, void *data)
+static int tar_filter_config(const char *var, const char *value,
+                            void *data UNUSED)
 {
        struct archiver *ar;
        const char *name;
@@ -383,8 +391,8 @@ static int tar_filter_config(const char *var, const char *value, void *data)
        if (!strcmp(type, "command")) {
                if (!value)
                        return config_error_nonbool(var);
-               free(ar->data);
-               ar->data = xstrdup(value);
+               free(ar->filter_command);
+               ar->filter_command = xstrdup(value);
                return 0;
        }
        if (!strcmp(type, "remote")) {
@@ -413,7 +421,7 @@ static int git_tar_config(const char *var, const char *value, void *cb)
        return tar_filter_config(var, value, cb);
 }
 
-static int write_tar_archive(const struct archiver *ar,
+static int write_tar_archive(const struct archiver *ar UNUSED,
                             struct archiver_args *args)
 {
        int err = 0;
@@ -425,17 +433,65 @@ static int write_tar_archive(const struct archiver *ar,
        return err;
 }
 
+static git_zstream gzstream;
+static unsigned char outbuf[16384];
+
+static void tgz_deflate(int flush)
+{
+       while (gzstream.avail_in || flush == Z_FINISH) {
+               int status = git_deflate(&gzstream, flush);
+               if (!gzstream.avail_out || status == Z_STREAM_END) {
+                       write_or_die(1, outbuf, gzstream.next_out - outbuf);
+                       gzstream.next_out = outbuf;
+                       gzstream.avail_out = sizeof(outbuf);
+                       if (status == Z_STREAM_END)
+                               break;
+               }
+               if (status != Z_OK && status != Z_BUF_ERROR)
+                       die(_("deflate error (%d)"), status);
+       }
+}
+
+static void tgz_write_block(const void *data)
+{
+       gzstream.next_in = (void *)data;
+       gzstream.avail_in = BLOCKSIZE;
+       tgz_deflate(Z_NO_FLUSH);
+}
+
+static const char internal_gzip_command[] = "git archive gzip";
+
 static int write_tar_filter_archive(const struct archiver *ar,
                                    struct archiver_args *args)
 {
+#if ZLIB_VERNUM >= 0x1221
+       struct gz_header_s gzhead = { .os = 3 }; /* Unix, for reproducibility */
+#endif
        struct strbuf cmd = STRBUF_INIT;
        struct child_process filter = CHILD_PROCESS_INIT;
        int r;
 
-       if (!ar->data)
+       if (!ar->filter_command)
                BUG("tar-filter archiver called with no filter defined");
 
-       strbuf_addstr(&cmd, ar->data);
+       if (!strcmp(ar->filter_command, internal_gzip_command)) {
+               write_block = tgz_write_block;
+               git_deflate_init_gzip(&gzstream, args->compression_level);
+#if ZLIB_VERNUM >= 0x1221
+               if (deflateSetHeader(&gzstream.z, &gzhead) != Z_OK)
+                       BUG("deflateSetHeader() called too late");
+#endif
+               gzstream.next_out = outbuf;
+               gzstream.avail_out = sizeof(outbuf);
+
+               r = write_tar_archive(ar, args);
+
+               tgz_deflate(Z_FINISH);
+               git_deflate_end(&gzstream);
+               return r;
+       }
+
+       strbuf_addstr(&cmd, ar->filter_command);
        if (args->compression_level >= 0)
                strbuf_addf(&cmd, " -%d", args->compression_level);
 
@@ -471,14 +527,14 @@ void init_tar_archiver(void)
        int i;
        register_archiver(&tar_archiver);
 
-       tar_filter_config("tar.tgz.command", "gzip -cn", NULL);
+       tar_filter_config("tar.tgz.command", internal_gzip_command, NULL);
        tar_filter_config("tar.tgz.remote", "true", NULL);
-       tar_filter_config("tar.tar.gz.command", "gzip -cn", 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);
        for (i = 0; i < nr_tar_filters; i++) {
                /* omit any filters that never had a command configured */
-               if (tar_filters[i]->data)
+               if (tar_filters[i]->filter_command)
                        register_archiver(tar_filters[i]);
        }
 }
index 9fe43d740d83f99111c31ef64207cf908765c17e..0456f1ebf15c839639f4759c329cb957b0a64feb 100644 (file)
@@ -612,12 +612,13 @@ static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)
        *dos_time = tm.tm_sec / 2 + tm.tm_min * 32 + tm.tm_hour * 2048;
 }
 
-static int archive_zip_config(const char *var, const char *value, void *data)
+static int archive_zip_config(const char *var, const char *value,
+                             void *data UNUSED)
 {
        return userdiff_config(var, value);
 }
 
-static int write_zip_archive(const struct archiver *ar,
+static int write_zip_archive(const struct archiver *ar UNUSED,
                             struct archiver_args *args)
 {
        int err;
index d5109abb894200f9b37b3631286a529437463816..61a79e4a2270dfc0e738ee97dd5cb5a9054ba79f 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -382,7 +382,8 @@ struct path_exists_context {
        struct archiver_args *args;
 };
 
-static int reject_entry(const struct object_id *oid, struct strbuf *base,
+static int reject_entry(const struct object_id *oid UNUSED,
+                       struct strbuf *base,
                        const char *filename, unsigned mode,
                        void *context)
 {
index 49fab71aaf649e1d5576f359eec8dcc0c096bf22..08bed3ed3af6b062f3ff2791613c64b86d42ec00 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -43,7 +43,7 @@ struct archiver {
        const char *name;
        int (*write_archive)(const struct archiver *, struct archiver_args *);
        unsigned flags;
-       void *data;
+       char *filter_command;
 };
 void register_archiver(struct archiver *);
 
diff --git a/attr.c b/attr.c
index 21e4ad25ada625885ebcc524facf6a9ce816d39e..8250b0695321a804be3d06777570702aee1e5f2e 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -61,10 +61,10 @@ struct attr_hash_entry {
 };
 
 /* attr_hashmap comparison function */
-static int attr_hash_entry_cmp(const void *unused_cmp_data,
+static int attr_hash_entry_cmp(const void *cmp_data UNUSED,
                               const struct hashmap_entry *eptr,
                               const struct hashmap_entry *entry_or_key,
-                              const void *unused_keydata)
+                              const void *keydata UNUSED)
 {
        const struct attr_hash_entry *a, *b;
 
@@ -1023,7 +1023,7 @@ static int path_matches(const char *pathname, int pathlen,
        }
        return match_pathname(pathname, pathlen - isdir,
                              base, baselen,
-                             pattern, prefix, pat->patternlen, pat->flags);
+                             pattern, prefix, pat->patternlen);
 }
 
 static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
index b63669cc9d768fd1de2cbc06e20e942f77ffcda7..fd581b85a72cc6d1f9b447893f9a3b345a8ce9da 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -441,7 +441,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
 }
 
 static int register_ref(const char *refname, const struct object_id *oid,
-                       int flags, void *cb_data)
+                       int flags UNUSED, void *cb_data UNUSED)
 {
        struct strbuf good_prefix = STRBUF_INIT;
        strbuf_addstr(&good_prefix, term_good);
@@ -648,11 +648,14 @@ static struct commit_list *managed_skipped(struct commit_list *list,
 }
 
 static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
+                            struct strvec *rev_argv,
                             const char *prefix,
                             const char *bad_format, const char *good_format,
                             int read_paths)
 {
-       struct strvec rev_argv = STRVEC_INIT;
+       struct setup_revision_opt opt = {
+               .free_removed_argv_elements = 1,
+       };
        int i;
 
        repo_init_revisions(r, revs, prefix);
@@ -660,17 +663,16 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
        revs->commit_format = CMIT_FMT_UNSPECIFIED;
 
        /* rev_argv.argv[0] will be ignored by setup_revisions */
-       strvec_push(&rev_argv, "bisect_rev_setup");
-       strvec_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid));
+       strvec_push(rev_argv, "bisect_rev_setup");
+       strvec_pushf(rev_argv, bad_format, oid_to_hex(current_bad_oid));
        for (i = 0; i < good_revs.nr; i++)
-               strvec_pushf(&rev_argv, good_format,
+               strvec_pushf(rev_argv, good_format,
                             oid_to_hex(good_revs.oid + i));
-       strvec_push(&rev_argv, "--");
+       strvec_push(rev_argv, "--");
        if (read_paths)
-               read_bisect_paths(&rev_argv);
+               read_bisect_paths(rev_argv);
 
-       setup_revisions(rev_argv.nr, rev_argv.v, revs, NULL);
-       /* XXX leak rev_argv, as "revs" may still be pointing to it */
+       setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt);
 }
 
 static void bisect_common(struct rev_info *revs)
@@ -873,10 +875,11 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int
 static int check_ancestors(struct repository *r, int rev_nr,
                           struct commit **rev, const char *prefix)
 {
+       struct strvec rev_argv = STRVEC_INIT;
        struct rev_info revs;
        int res;
 
-       bisect_rev_setup(r, &revs, prefix, "^%s", "%s", 0);
+       bisect_rev_setup(r, &revs, &rev_argv, prefix, "^%s", "%s", 0);
 
        bisect_common(&revs);
        res = (revs.commits != NULL);
@@ -885,6 +888,7 @@ static int check_ancestors(struct repository *r, int rev_nr,
        clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS);
 
        release_revisions(&revs);
+       strvec_clear(&rev_argv);
        return res;
 }
 
@@ -1010,6 +1014,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
  */
 enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 {
+       struct strvec rev_argv = STRVEC_INIT;
        struct rev_info revs = REV_INFO_INIT;
        struct commit_list *tried;
        int reaches = 0, all = 0, nr, steps;
@@ -1037,7 +1042,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
        if (res)
                goto cleanup;
 
-       bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
+       bisect_rev_setup(r, &revs, &rev_argv, prefix, "%s", "^%s", 1);
 
        revs.first_parent_only = !!(bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY);
        revs.limited = 1;
@@ -1054,7 +1059,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
                 */
                res = error_if_skipped_commits(tried, NULL);
                if (res < 0)
-                       return res;
+                       goto cleanup;
                printf(_("%s was both %s and %s\n"),
                       oid_to_hex(current_bad_oid),
                       term_good,
@@ -1112,6 +1117,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
        res = bisect_checkout(bisect_rev, no_checkout);
 cleanup:
        release_revisions(&revs);
+       strvec_clear(&rev_argv);
        return res;
 }
 
@@ -1154,8 +1160,9 @@ int estimate_bisect_steps(int all)
        return (e < 3 * x) ? n : n - 1;
 }
 
-static int mark_for_removal(const char *refname, const struct object_id *oid,
-                           int flag, void *cb_data)
+static int mark_for_removal(const char *refname,
+                           const struct object_id *oid UNUSED,
+                           int flag UNUSED, void *cb_data)
 {
        struct string_list *refs = cb_data;
        char *ref = xstrfmt("refs/bisect%s", refname);
diff --git a/blame.c b/blame.c
index da1052ac94bb47282fb6191e457dda6597c3e8fc..8bfeaa1c63aedc151b1125e98f52229842d48b19 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -1098,30 +1098,22 @@ static struct blame_entry *blame_merge(struct blame_entry *list1,
        }
 }
 
-static void *get_next_blame(const void *p)
-{
-       return ((struct blame_entry *)p)->next;
-}
-
-static void set_next_blame(void *p1, void *p2)
-{
-       ((struct blame_entry *)p1)->next = p2;
-}
+DEFINE_LIST_SORT(static, sort_blame_entries, struct blame_entry, next);
 
 /*
  * Final image line numbers are all different, so we don't need a
  * three-way comparison here.
  */
 
-static int compare_blame_final(const void *p1, const void *p2)
+static int compare_blame_final(const struct blame_entry *e1,
+                              const struct blame_entry *e2)
 {
-       return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno
-               ? 1 : -1;
+       return e1->lno > e2->lno ? 1 : -1;
 }
 
-static int compare_blame_suspect(const void *p1, const void *p2)
+static int compare_blame_suspect(const struct blame_entry *s1,
+                                const struct blame_entry *s2)
 {
-       const struct blame_entry *s1 = p1, *s2 = p2;
        /*
         * to allow for collating suspects, we sort according to the
         * respective pointer value as the primary sorting criterion.
@@ -1138,8 +1130,7 @@ static int compare_blame_suspect(const void *p1, const void *p2)
 
 void blame_sort_final(struct blame_scoreboard *sb)
 {
-       sb->ent = llist_mergesort(sb->ent, get_next_blame, set_next_blame,
-                                 compare_blame_final);
+       sort_blame_entries(&sb->ent, compare_blame_final);
 }
 
 static int compare_commits_by_reverse_commit_date(const void *a,
@@ -1964,9 +1955,7 @@ static void pass_blame_to_parent(struct blame_scoreboard *sb,
                    parent, target, 0);
        *d.dstq = NULL;
        if (ignore_diffs)
-               newdest = llist_mergesort(newdest, get_next_blame,
-                                         set_next_blame,
-                                         compare_blame_suspect);
+               sort_blame_entries(&newdest, compare_blame_suspect);
        queue_blames(sb, parent, newdest);
 
        return;
@@ -2383,8 +2372,7 @@ static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reve
  */
 static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
 {
-       blamed = llist_mergesort(blamed, get_next_blame, set_next_blame,
-                                compare_blame_suspect);
+       sort_blame_entries(&blamed, compare_blame_suspect);
        while (blamed)
        {
                struct blame_origin *porigin = blamed->suspect;
index 5974cd7dd3cc128a7d0f7fd9a5f5c7c9c972de15..80cebd27564f5aeace14bd3963f0a2f981fad330 100644 (file)
  * try to do the silly "optimize away loads" part because it won't
  * see what the value will be).
  *
- * Ben Herrenschmidt reports that on PPC, the C version comes close
- * to the optimized asm with this (ie on PPC you don't want that
- * 'volatile', since there are lots of registers).
- *
  * On ARM we get the best code generation by forcing a full memory barrier
  * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
  * the stack frame size simply explode and performance goes down the drain.
diff --git a/bloom.c b/bloom.c
index 816f063dca58bda64cd0ff452c9ae917d3c681a9..d0730525da51f783e0f72f502a62db4407bd7ad9 100644 (file)
--- a/bloom.c
+++ b/bloom.c
@@ -163,10 +163,10 @@ void init_bloom_filters(void)
        init_bloom_filter_slab(&bloom_filters);
 }
 
-static int pathmap_cmp(const void *hashmap_cmp_fn_data,
+static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED,
                       const struct hashmap_entry *eptr,
                       const struct hashmap_entry *entry_or_key,
-                      const void *keydata)
+                      const void *keydata UNUSED)
 {
        const struct pathmap_hash_entry *e1, *e2;
 
index 4c8523c66ad07f956fc7ff8a81339d069dd586c8..d182756827fe5128292798b707a52aed25e7aa48 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -10,6 +10,7 @@
 #include "worktree.h"
 #include "submodule-config.h"
 #include "run-command.h"
+#include "strmap.h"
 
 struct tracking {
        struct refspec_item spec;
@@ -369,6 +370,83 @@ int validate_branchname(const char *name, struct strbuf *ref)
        return ref_exists(ref->buf);
 }
 
+static int initialized_checked_out_branches;
+static struct strmap current_checked_out_branches = STRMAP_INIT;
+
+static void prepare_checked_out_branches(void)
+{
+       int i = 0;
+       struct worktree **worktrees;
+
+       if (initialized_checked_out_branches)
+               return;
+       initialized_checked_out_branches = 1;
+
+       worktrees = get_worktrees();
+
+       while (worktrees[i]) {
+               char *old;
+               struct wt_status_state state = { 0 };
+               struct worktree *wt = worktrees[i++];
+               struct string_list update_refs = STRING_LIST_INIT_DUP;
+
+               if (wt->is_bare)
+                       continue;
+
+               if (wt->head_ref) {
+                       old = strmap_put(&current_checked_out_branches,
+                                        wt->head_ref,
+                                        xstrdup(wt->path));
+                       free(old);
+               }
+
+               if (wt_status_check_rebase(wt, &state) &&
+                   (state.rebase_in_progress || state.rebase_interactive_in_progress) &&
+                   state.branch) {
+                       struct strbuf ref = STRBUF_INIT;
+                       strbuf_addf(&ref, "refs/heads/%s", state.branch);
+                       old = strmap_put(&current_checked_out_branches,
+                                        ref.buf,
+                                        xstrdup(wt->path));
+                       free(old);
+                       strbuf_release(&ref);
+               }
+               wt_status_state_free_buffers(&state);
+
+               if (wt_status_check_bisect(wt, &state) &&
+                   state.branch) {
+                       struct strbuf ref = STRBUF_INIT;
+                       strbuf_addf(&ref, "refs/heads/%s", state.branch);
+                       old = strmap_put(&current_checked_out_branches,
+                                        ref.buf,
+                                        xstrdup(wt->path));
+                       free(old);
+                       strbuf_release(&ref);
+               }
+               wt_status_state_free_buffers(&state);
+
+               if (!sequencer_get_update_refs_state(get_worktree_git_dir(wt),
+                                                    &update_refs)) {
+                       struct string_list_item *item;
+                       for_each_string_list_item(item, &update_refs) {
+                               old = strmap_put(&current_checked_out_branches,
+                                                item->string,
+                                                xstrdup(wt->path));
+                               free(old);
+                       }
+                       string_list_clear(&update_refs, 1);
+               }
+       }
+
+       free_worktrees(worktrees);
+}
+
+const char *branch_checked_out(const char *refname)
+{
+       prepare_checked_out_branches();
+       return strmap_get(&current_checked_out_branches, refname);
+}
+
 /*
  * Check if a branch 'name' can be created as a new branch; die otherwise.
  * 'force' can be used when it is OK for the named branch already exists.
@@ -377,9 +455,7 @@ int validate_branchname(const char *name, struct strbuf *ref)
  */
 int validate_new_branchname(const char *name, struct strbuf *ref, int force)
 {
-       struct worktree **worktrees;
-       const struct worktree *wt;
-
+       const char *path;
        if (!validate_branchname(name, ref))
                return 0;
 
@@ -387,13 +463,10 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)
                die(_("a branch named '%s' already exists"),
                    ref->buf + strlen("refs/heads/"));
 
-       worktrees = get_worktrees();
-       wt = find_shared_symref(worktrees, "HEAD", ref->buf);
-       if (wt && !wt->is_bare)
+       if ((path = branch_checked_out(ref->buf)))
                die(_("cannot force update the branch '%s' "
                      "checked out at '%s'"),
-                   ref->buf + strlen("refs/heads/"), wt->path);
-       free_worktrees(worktrees);
+                   ref->buf + strlen("refs/heads/"), path);
 
        return 1;
 }
index 560b6b96a8f307baac31ea699321e17ed2c22dbe..ef56103c050fa09d6087e2bade7f24240d79ae04 100644 (file)
--- a/branch.h
+++ b/branch.h
@@ -101,6 +101,13 @@ void create_branches_recursively(struct repository *r, const char *name,
                                 const char *tracking_name, int force,
                                 int reflog, int quiet, enum branch_track track,
                                 int dry_run);
+
+/*
+ * If the branch at 'refname' is currently checked out in a worktree,
+ * then return the path to that worktree.
+ */
+const char *branch_checked_out(const char *refname);
+
 /*
  * Check if 'name' can be a valid name for a branch; die otherwise.
  * Return 1 if the named branch already exists; return 0 otherwise.
index 40e9ecc8485324a40e142d5cbc9345a22e45f333..8901a34d6bf424680b9d13a1bdf332bedb4d8e20 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -144,6 +144,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix);
 int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
 int cmd_credential_store(int argc, const char **argv, const char *prefix);
 int cmd_describe(int argc, const char **argv, const char *prefix);
+int cmd_diagnose(int argc, const char **argv, const char *prefix);
 int cmd_diff_files(int argc, const char **argv, const char *prefix);
 int cmd_diff_index(int argc, const char **argv, const char *prefix);
 int cmd_diff(int argc, const char **argv, const char *prefix);
index 93bec62afa993cb236ce09c13b38932ee396f250..39fea24833078be76d76d974e5b601715ed51aea 100644 (file)
@@ -2301,7 +2301,7 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
        return 0;
 }
 
-static int git_am_config(const char *k, const char *v, void *cb)
+static int git_am_config(const char *k, const char *v, void *cb UNUSED)
 {
        int status;
 
index 7176b041b6d85b5760c91f94fcdde551a38d147f..f094390ee01f810e7035f2efc2be75deedc3befa 100644 (file)
@@ -75,7 +75,7 @@ static int run_remote_archiver(int argc, const char **argv,
 
 #define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH |         \
                             PARSE_OPT_KEEP_ARGV0 |     \
-                            PARSE_OPT_KEEP_UNKNOWN |   \
+                            PARSE_OPT_KEEP_UNKNOWN_OPT |       \
                             PARSE_OPT_NO_INTERNAL_HELP )
 
 int cmd_archive(int argc, const char **argv, const char *prefix)
index 8a052c7111f97f02690a31e98ef4102961796800..501245fac9521717d4ca83341ab5528686fb5777 100644 (file)
@@ -329,8 +329,9 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
        return 0;
 }
 
-static int inc_nr(const char *refname, const struct object_id *oid,
-                 int flag, void *cb_data)
+static int inc_nr(const char *refname UNUSED,
+                 const struct object_id *oid UNUSED,
+                 int flag UNUSED, void *cb_data)
 {
        unsigned int *nr = (unsigned int *)cb_data;
        (*nr)++;
@@ -518,7 +519,7 @@ finish:
 }
 
 static int add_bisect_ref(const char *refname, const struct object_id *oid,
-                         int flags, void *cb)
+                         int flags UNUSED, void *cb)
 {
        struct add_bisect_ref_data *data = cb;
 
@@ -1134,8 +1135,9 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a
        return res;
 }
 
-static int get_first_good(const char *refname, const struct object_id *oid,
-                         int flag, void *cb_data)
+static int get_first_good(const char *refname UNUSED,
+                         const struct object_id *oid,
+                         int flag UNUSED, void *cb_data)
 {
        oidcpy(cb_data, oid);
        return 1;
@@ -1324,7 +1326,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 
        argc = parse_options(argc, argv, prefix, options,
                             git_bisect_helper_usage,
-                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        if (!cmdmode)
                usage_with_options(git_bisect_helper_usage, options);
index 02e39420b62babb5124708f3305985ebe6e316a9..a9fe8cf7a68bf31547b7482a40eb269f6ea0c30f 100644 (file)
@@ -920,6 +920,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        break;
                case PARSE_OPT_HELP:
                case PARSE_OPT_ERROR:
+               case PARSE_OPT_SUBCOMMAND:
                        exit(129);
                case PARSE_OPT_COMPLETE:
                        exit(0);
index 5d00d0b8d327c5cc048ac0baf997e3670d5ff3df..55cd9a6e9984fc66334a7e78bd65294c628e34fb 100644 (file)
@@ -204,7 +204,6 @@ static void delete_branch_config(const char *branchname)
 static int delete_branches(int argc, const char **argv, int force, int kinds,
                           int quiet)
 {
-       struct worktree **worktrees;
        struct commit *head_rev = NULL;
        struct object_id oid;
        char *name = NULL;
@@ -242,8 +241,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        die(_("Couldn't look up commit object for HEAD"));
        }
 
-       worktrees = get_worktrees();
-
        for (i = 0; i < argc; i++, strbuf_reset(&bname)) {
                char *target = NULL;
                int flags = 0;
@@ -253,12 +250,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                name = mkpathdup(fmt, bname.buf);
 
                if (kinds == FILTER_REFS_BRANCHES) {
-                       const struct worktree *wt =
-                               find_shared_symref(worktrees, "HEAD", name);
-                       if (wt) {
+                       const char *path;
+                       if ((path = branch_checked_out(name))) {
                                error(_("Cannot delete branch '%s' "
                                        "checked out at '%s'"),
-                                     bname.buf, wt->path);
+                                     bname.buf, path);
                                ret = 1;
                                continue;
                        }
@@ -315,7 +311,6 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
 
        free(name);
        strbuf_release(&bname);
-       free_worktrees(worktrees);
 
        return ret;
 }
index 9de32bc96e7a6f2171473b8d20f5cde3834e5c42..530895be55fe6d9627c5d954f4c235d22769051e 100644 (file)
@@ -5,6 +5,7 @@
 #include "compat/compiler.h"
 #include "hook.h"
 #include "hook-list.h"
+#include "diagnose.h"
 
 
 static void get_system_info(struct strbuf *sys_info)
@@ -59,7 +60,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
 }
 
 static const char * const bugreport_usage[] = {
-       N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
+       N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--diagnose[=<mode>]"),
        NULL
 };
 
@@ -98,16 +99,21 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
        int report = -1;
        time_t now = time(NULL);
        struct tm tm;
+       enum diagnose_mode diagnose = DIAGNOSE_NONE;
        char *option_output = NULL;
        char *option_suffix = "%Y-%m-%d-%H%M";
        const char *user_relative_path = NULL;
        char *prefixed_filename;
+       size_t output_path_len;
 
        const struct option bugreport_options[] = {
+               OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
+                              N_("create an additional zip archive of detailed diagnostics (default 'stats')"),
+                              PARSE_OPT_OPTARG, option_parse_diagnose),
                OPT_STRING('o', "output-directory", &option_output, N_("path"),
-                          N_("specify a destination for the bugreport file")),
+                          N_("specify a destination for the bugreport file(s)")),
                OPT_STRING('s', "suffix", &option_suffix, N_("format"),
-                          N_("specify a strftime format suffix for the filename")),
+                          N_("specify a strftime format suffix for the filename(s)")),
                OPT_END()
        };
 
@@ -119,6 +125,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
                                            option_output ? option_output : "");
        strbuf_addstr(&report_path, prefixed_filename);
        strbuf_complete(&report_path, '/');
+       output_path_len = report_path.len;
 
        strbuf_addstr(&report_path, "git-bugreport-");
        strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
@@ -133,6 +140,20 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
                    report_path.buf);
        }
 
+       /* Prepare diagnostics, if requested */
+       if (diagnose != DIAGNOSE_NONE) {
+               struct strbuf zip_path = STRBUF_INIT;
+               strbuf_add(&zip_path, report_path.buf, output_path_len);
+               strbuf_addstr(&zip_path, "git-diagnostics-");
+               strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+               strbuf_addstr(&zip_path, ".zip");
+
+               if (create_diagnostics_archive(&zip_path, diagnose))
+                       die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
+
+               strbuf_release(&zip_path);
+       }
+
        /* Prepare the report contents */
        get_bug_template(&buffer);
 
index 2adad545a2e972221869703658e98be0c514d005..e80efce3a420a0371bd984102105b8a51af34df1 100644 (file)
@@ -195,30 +195,19 @@ cleanup:
 
 int cmd_bundle(int argc, const char **argv, const char *prefix)
 {
+       parse_opt_subcommand_fn *fn = NULL;
        struct option options[] = {
+               OPT_SUBCOMMAND("create", &fn, cmd_bundle_create),
+               OPT_SUBCOMMAND("verify", &fn, cmd_bundle_verify),
+               OPT_SUBCOMMAND("list-heads", &fn, cmd_bundle_list_heads),
+               OPT_SUBCOMMAND("unbundle", &fn, cmd_bundle_unbundle),
                OPT_END()
        };
-       int result;
 
        argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
-               PARSE_OPT_STOP_AT_NON_OPTION);
+                            0);
 
        packet_trace_identity("bundle");
 
-       if (argc < 2)
-               usage_with_options(builtin_bundle_usage, options);
-
-       else if (!strcmp(argv[0], "create"))
-               result = cmd_bundle_create(argc, argv, prefix);
-       else if (!strcmp(argv[0], "verify"))
-               result = cmd_bundle_verify(argc, argv, prefix);
-       else if (!strcmp(argv[0], "list-heads"))
-               result = cmd_bundle_list_heads(argc, argv, prefix);
-       else if (!strcmp(argv[0], "unbundle"))
-               result = cmd_bundle_unbundle(argc, argv, prefix);
-       else {
-               error(_("Unknown subcommand: %s"), argv[0]);
-               usage_with_options(builtin_bundle_usage, options);
-       }
-       return result ? 1 : 0;
+       return !!fn(argc, argv, prefix);
 }
index 50cf38999d10125428e4c558383582af4f191b95..989eee0bb4c7d924b97b3aac6b43443f7c34ab67 100644 (file)
@@ -16,6 +16,7 @@
 #include "packfile.h"
 #include "object-store.h"
 #include "promisor-remote.h"
+#include "mailmap.h"
 
 enum batch_mode {
        BATCH_MODE_CONTENTS,
@@ -31,11 +32,28 @@ struct batch_options {
        int all_objects;
        int unordered;
        int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
+       int nul_terminated;
        const char *format;
 };
 
 static const char *force_path;
 
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
+static int use_mailmap;
+
+static char *replace_idents_using_mailmap(char *, size_t *);
+
+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
+{
+       struct strbuf sb = STRBUF_INIT;
+       const char *headers[] = { "author ", "committer ", "tagger ", NULL };
+
+       strbuf_attach(&sb, object_buf, *size, *size + 1);
+       apply_mailmap_to_header(&sb, headers, &mailmap);
+       *size = sb.len;
+       return strbuf_detach(&sb, NULL);
+}
+
 static int filter_object(const char *path, unsigned mode,
                         const struct object_id *oid,
                         char **buf, unsigned long *size)
@@ -71,6 +89,7 @@ static int stream_blob(const struct object_id *oid)
 static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        int unknown_type)
 {
+       int ret;
        struct object_id oid;
        enum object_type type;
        char *buf;
@@ -106,7 +125,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                if (sb.len) {
                        printf("%s\n", sb.buf);
                        strbuf_release(&sb);
-                       return 0;
+                       ret = 0;
+                       goto cleanup;
                }
                break;
 
@@ -115,7 +135,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
                        die("git cat-file: could not get object info");
                printf("%"PRIuMAX"\n", (uintmax_t)size);
-               return 0;
+               ret = 0;
+               goto cleanup;
 
        case 'e':
                return !has_object_file(&oid);
@@ -123,8 +144,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
        case 'w':
 
                if (filter_object(path, obj_context.mode,
-                                 &oid, &buf, &size))
-                       return -1;
+                                 &oid, &buf, &size)) {
+                       ret = -1;
+                       goto cleanup;
+               }
                break;
 
        case 'c':
@@ -143,15 +166,24 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        const char *ls_args[3] = { NULL };
                        ls_args[0] =  "ls-tree";
                        ls_args[1] =  obj_name;
-                       return cmd_ls_tree(2, ls_args, NULL);
+                       ret = cmd_ls_tree(2, ls_args, NULL);
+                       goto cleanup;
                }
 
-               if (type == OBJ_BLOB)
-                       return stream_blob(&oid);
+               if (type == OBJ_BLOB) {
+                       ret = stream_blob(&oid);
+                       goto cleanup;
+               }
                buf = read_object_file(&oid, &type, &size);
                if (!buf)
                        die("Cannot read object %s", obj_name);
 
+               if (use_mailmap) {
+                       size_t s = size;
+                       buf = replace_idents_using_mailmap(buf, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
+
                /* otherwise just spit out the data */
                break;
 
@@ -172,8 +204,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        } else
                                oidcpy(&blob_oid, &oid);
 
-                       if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
-                               return stream_blob(&blob_oid);
+                       if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) {
+                               ret = stream_blob(&blob_oid);
+                               goto cleanup;
+                       }
                        /*
                         * we attempted to dereference a tag to a blob
                         * and failed; there may be new dereference
@@ -183,6 +217,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                }
                buf = read_object_with_reference(the_repository, &oid,
                                                 exp_type_id, &size, NULL);
+
+               if (use_mailmap) {
+                       size_t s = size;
+                       buf = replace_idents_using_mailmap(buf, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
                break;
        }
        default:
@@ -193,9 +233,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                die("git cat-file %s: bad file", obj_name);
 
        write_or_die(1, buf, size);
+       ret = 0;
+cleanup:
        free(buf);
        free(obj_context.path);
-       return 0;
+       return ret;
 }
 
 struct expand_data {
@@ -348,11 +390,18 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
                void *contents;
 
                contents = read_object_file(oid, &type, &size);
+
+               if (use_mailmap) {
+                       size_t s = size;
+                       contents = replace_idents_using_mailmap(contents, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
+
                if (!contents)
                        die("object %s disappeared", oid_to_hex(oid));
                if (type != data->type)
                        die("object %s changed type!?", oid_to_hex(oid));
-               if (data->info.sizep && size != data->size)
+               if (data->info.sizep && size != data->size && !use_mailmap)
                        die("object %s changed size!?", oid_to_hex(oid));
 
                batch_write(opt, contents, size);
@@ -602,12 +651,20 @@ static void batch_objects_command(struct batch_options *opt,
        struct queued_cmd *queued_cmd = NULL;
        size_t alloc = 0, nr = 0;
 
-       while (!strbuf_getline(&input, stdin)) {
-               int i;
+       while (1) {
+               int i, ret;
                const struct parse_cmd *cmd = NULL;
                const char *p = NULL, *cmd_end;
                struct queued_cmd call = {0};
 
+               if (opt->nul_terminated)
+                       ret = strbuf_getline_nul(&input, stdin);
+               else
+                       ret = strbuf_getline(&input, stdin);
+
+               if (ret)
+                       break;
+
                if (!input.len)
                        die(_("empty command in input"));
                if (isspace(*input.buf))
@@ -655,6 +712,7 @@ static void batch_objects_command(struct batch_options *opt,
                free_cmds(queued_cmd, &nr);
        }
 
+       free_cmds(queued_cmd, &nr);
        free(queued_cmd);
        strbuf_release(&input);
 }
@@ -750,7 +808,16 @@ static int batch_objects(struct batch_options *opt)
                goto cleanup;
        }
 
-       while (strbuf_getline(&input, stdin) != EOF) {
+       while (1) {
+               int ret;
+               if (opt->nul_terminated)
+                       ret = strbuf_getline_nul(&input, stdin);
+               else
+                       ret = strbuf_getline(&input, stdin);
+
+               if (ret == EOF)
+                       break;
+
                if (data.split_on_whitespace) {
                        /*
                         * Split at first whitespace, tying off the beginning
@@ -843,6 +910,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'),
                OPT_BOOL(0, "allow-unknown-type", &unknown_type,
                          N_("allow -s and -t to work with broken/corrupt objects")),
+               OPT_BOOL(0, "use-mailmap", &use_mailmap, N_("use mail map file")),
+               OPT_ALIAS(0, "mailmap", "use-mailmap"),
                /* Batch mode */
                OPT_GROUP(N_("Batch objects requested on stdin (or --batch-all-objects)")),
                OPT_CALLBACK_F(0, "batch", &batch, N_("format"),
@@ -853,6 +922,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                        N_("like --batch, but don't emit <contents>"),
                        PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
                        batch_option_callback),
+               OPT_BOOL('z', NULL, &batch.nul_terminated, N_("stdin is NUL-terminated")),
                OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
                        N_("read commands from stdin"),
                        PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
@@ -885,6 +955,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        opt_cw = (opt == 'c' || opt == 'w');
        opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
 
+       if (use_mailmap)
+               read_mailmap(&mailmap);
+
        /* --batch-all-objects? */
        if (opt == 'b')
                batch.all_objects = 1;
@@ -908,6 +981,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        else if (batch.all_objects)
                usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
                               "--batch-all-objects");
+       else if (batch.nul_terminated)
+               usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+                              "-z");
 
        /* Batch defaults */
        if (batch.buffer_output < 0)
index bc67d3f0a83d35b2fc6d81f28c6908075564644a..fd0e5f86832a0ed4d9c08512291c836938f2bec2 100644 (file)
@@ -57,6 +57,8 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
        int normalize = 0;
        int flags = 0;
        const char *refname;
+       char *to_free = NULL;
+       int ret = 1;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(builtin_check_ref_format_usage);
@@ -81,11 +83,14 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
 
        refname = argv[i];
        if (normalize)
-               refname = collapse_slashes(refname);
+               refname = to_free = collapse_slashes(refname);
        if (check_refname_format(refname, flags))
-               return 1;
+               goto cleanup;
        if (normalize)
                printf("%s\n", refname);
 
-       return 0;
+       ret = 0;
+cleanup:
+       free(to_free);
+       return ret;
 }
index cdd96cd9c6f623fa87b85299eeef6debe6ab04f9..2a132392fbe7478c808b01d06039112fc321a55e 100644 (file)
@@ -125,7 +125,7 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
 }
 
 static int update_some(const struct object_id *oid, struct strbuf *base,
-               const char *pathname, unsigned mode, void *context)
+                      const char *pathname, unsigned mode, void *context UNUSED)
 {
        int len;
        struct cache_entry *ce;
@@ -711,6 +711,26 @@ static void setup_branch_path(struct branch_info *branch)
        branch->path = strbuf_detach(&buf, NULL);
 }
 
+static void init_topts(struct unpack_trees_options *topts, int merge,
+                      int show_progress, int overwrite_ignore,
+                      struct commit *old_commit)
+{
+       memset(topts, 0, sizeof(*topts));
+       topts->head_idx = -1;
+       topts->src_index = &the_index;
+       topts->dst_index = &the_index;
+
+       setup_unpack_trees_porcelain(topts, "checkout");
+
+       topts->initial_checkout = is_cache_unborn();
+       topts->update = 1;
+       topts->merge = 1;
+       topts->quiet = merge && old_commit;
+       topts->verbose_update = show_progress;
+       topts->fn = twoway_merge;
+       topts->preserve_ignored = !overwrite_ignore;
+}
+
 static int merge_working_tree(const struct checkout_opts *opts,
                              struct branch_info *old_branch_info,
                              struct branch_info *new_branch_info,
@@ -741,13 +761,6 @@ static int merge_working_tree(const struct checkout_opts *opts,
                struct unpack_trees_options topts;
                const struct object_id *old_commit_oid;
 
-               memset(&topts, 0, sizeof(topts));
-               topts.head_idx = -1;
-               topts.src_index = &the_index;
-               topts.dst_index = &the_index;
-
-               setup_unpack_trees_porcelain(&topts, "checkout");
-
                refresh_cache(REFRESH_QUIET);
 
                if (unmerged_cache()) {
@@ -756,17 +769,12 @@ static int merge_working_tree(const struct checkout_opts *opts,
                }
 
                /* 2-way merge to the new branch */
-               topts.initial_checkout = is_cache_unborn();
-               topts.update = 1;
-               topts.merge = 1;
-               topts.quiet = opts->merge && old_branch_info->commit;
-               topts.verbose_update = opts->show_progress;
-               topts.fn = twoway_merge;
+               init_topts(&topts, opts->merge, opts->show_progress,
+                          opts->overwrite_ignore, old_branch_info->commit);
                init_checkout_metadata(&topts.meta, new_branch_info->refname,
                                       new_branch_info->commit ?
                                       &new_branch_info->commit->object.oid :
                                       &new_branch_info->oid, NULL);
-               topts.preserve_ignored = !opts->overwrite_ignore;
 
                old_commit_oid = old_branch_info->commit ?
                        &old_branch_info->commit->object.oid :
@@ -982,7 +990,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
 
 static int add_pending_uninteresting_ref(const char *refname,
                                         const struct object_id *oid,
-                                        int flags, void *cb_data)
+                                        int flags UNUSED, void *cb_data)
 {
        add_pending_oid(cb_data, refname, oid, UNINTERESTING);
        return 0;
index f5f902cce194ee01b889a1cb57fd03fd19ebebf1..ed8d44bb6ab72857508824958f6857ca4b0cff64 100644 (file)
@@ -34,6 +34,7 @@
 #include "list-objects-filter-options.h"
 #include "hook.h"
 #include "bundle.h"
+#include "bundle-uri.h"
 
 /*
  * Overall FIXMEs:
@@ -72,11 +73,12 @@ static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
 static int option_dissociate;
 static int max_jobs = -1;
 static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
-static struct list_objects_filter_options filter_options;
+static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
 static int option_filter_submodules = -1;    /* unspecified */
 static int config_filter_submodules = -1;    /* unspecified */
 static struct string_list server_options = STRING_LIST_INIT_NODUP;
 static int option_remote_submodules;
+static const char *bundle_uri;
 
 static int recurse_submodules_cb(const struct option *opt,
                                 const char *arg, int unset)
@@ -160,6 +162,8 @@ static struct option builtin_clone_options[] = {
                    N_("any cloned submodules will use their remote-tracking branch")),
        OPT_BOOL(0, "sparse", &option_sparse_checkout,
                    N_("initialize sparse-checkout file to include only files at root")),
+       OPT_STRING(0, "bundle-uri", &bundle_uri,
+                  N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
        OPT_END()
 };
 
@@ -494,6 +498,7 @@ static struct ref *wanted_peer_refs(const struct ref *refs,
                        /* if --branch=tag, pull the requested tag explicitly */
                        get_fetch_map(remote_head, tag_refspec, &tail, 0);
                }
+               free_refs(remote_head);
        } else {
                int i;
                for (i = 0; i < refspec->nr; i++)
@@ -929,6 +934,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                option_no_checkout = 1;
        }
 
+       if (bundle_uri && deepen)
+               die(_("--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-exclude"));
+
        repo_name = argv[0];
 
        path = get_repo_path(repo_name, &is_bundle);
@@ -1228,6 +1236,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (transport->smart_options && !deepen && !filter_options.choice)
                transport->smart_options->check_self_contained_and_connected = 1;
 
+       /*
+        * Before fetching from the remote, download and install bundle
+        * data from the --bundle-uri option.
+        */
+       if (bundle_uri) {
+               /* At this point, we need the_repository to match the cloned repo. */
+               if (repo_init(the_repository, git_dir, work_tree))
+                       warning(_("failed to initialize the repo, skipping bundle URI"));
+               else if (fetch_bundle_uri(the_repository, bundle_uri))
+                       warning(_("failed to fetch objects from bundle URI '%s'"),
+                               bundle_uri);
+       }
 
        strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
        refspec_ref_prefixes(&remote->fetch,
index 51c4040ea6c879bda3631343643f3a52063a1bdc..51557fe786e6d1674ad5ffff87d55e7155a0c4b9 100644 (file)
@@ -58,7 +58,7 @@ static struct option *add_common_options(struct option *to)
        return parse_options_concat(common_opts, to);
 }
 
-static int graph_verify(int argc, const char **argv)
+static int graph_verify(int argc, const char **argv, const char *prefix)
 {
        struct commit_graph *graph = NULL;
        struct object_directory *odb = NULL;
@@ -80,7 +80,7 @@ static int graph_verify(int argc, const char **argv)
        trace2_cmd_mode("verify");
 
        opts.progress = isatty(2);
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             options,
                             builtin_commit_graph_verify_usage, 0);
        if (argc)
@@ -179,7 +179,7 @@ static int write_option_max_new_filters(const struct option *opt,
 }
 
 static int git_commit_graph_write_config(const char *var, const char *value,
-                                        void *cb)
+                                        void *cb UNUSED)
 {
        if (!strcmp(var, "commitgraph.maxnewfilters"))
                write_opts.max_new_filters = git_config_int(var, value);
@@ -190,7 +190,7 @@ static int git_commit_graph_write_config(const char *var, const char *value,
        return 0;
 }
 
-static int graph_write(int argc, const char **argv)
+static int graph_write(int argc, const char **argv, const char *prefix)
 {
        struct string_list pack_indexes = STRING_LIST_INIT_DUP;
        struct strbuf buf = STRBUF_INIT;
@@ -241,7 +241,7 @@ static int graph_write(int argc, const char **argv)
 
        git_config(git_commit_graph_write_config, &opts);
 
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             options,
                             builtin_commit_graph_write_usage, 0);
        if (argc)
@@ -307,26 +307,22 @@ cleanup:
 
 int cmd_commit_graph(int argc, const char **argv, const char *prefix)
 {
-       struct option *builtin_commit_graph_options = common_opts;
+       parse_opt_subcommand_fn *fn = NULL;
+       struct option builtin_commit_graph_options[] = {
+               OPT_SUBCOMMAND("verify", &fn, graph_verify),
+               OPT_SUBCOMMAND("write", &fn, graph_write),
+               OPT_END(),
+       };
+       struct option *options = parse_options_concat(builtin_commit_graph_options, common_opts);
 
        git_config(git_default_config, NULL);
-       argc = parse_options(argc, argv, prefix,
-                            builtin_commit_graph_options,
-                            builtin_commit_graph_usage,
-                            PARSE_OPT_STOP_AT_NON_OPTION);
-       if (!argc)
-               goto usage;
 
        read_replace_refs = 0;
        save_commit_buffer = 0;
 
-       if (!strcmp(argv[0], "verify"))
-               return graph_verify(argc, argv);
-       else if (argc && !strcmp(argv[0], "write"))
-               return graph_write(argc, argv);
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_commit_graph_usage, 0);
+       FREE_AND_NULL(options);
 
-       error(_("unrecognized subcommand: %s"), argv[0]);
-usage:
-       usage_with_options(builtin_commit_graph_usage,
-                          builtin_commit_graph_options);
+       return fn(argc, argv, prefix);
 }
index e7b88a9c08dc17055dd201eb5f985a77b6150604..753e5fac297e08763317adcab2fefe386ea68421 100644 (file)
@@ -207,7 +207,8 @@ static void show_config_scope(struct strbuf *buf)
        strbuf_addch(buf, term);
 }
 
-static int show_all_config(const char *key_, const char *value_, void *cb)
+static int show_all_config(const char *key_, const char *value_,
+                          void *cb UNUSED)
 {
        if (show_origin || show_scope) {
                struct strbuf buf = STRBUF_INIT;
@@ -458,7 +459,8 @@ static const char *get_color_slot;
 static const char *get_colorbool_slot;
 static char parsed_color[COLOR_MAXLEN];
 
-static int git_get_color_config(const char *var, const char *value, void *cb)
+static int git_get_color_config(const char *var, const char *value,
+                               void *cb UNUSED)
 {
        if (!strcmp(var, get_color_slot)) {
                if (!value)
@@ -490,7 +492,7 @@ static int get_colorbool_found;
 static int get_diff_color_found;
 static int get_color_ui_found;
 static int git_get_colorbool_config(const char *var, const char *value,
-               void *cb)
+                                   void *data UNUSED)
 {
        if (!strcmp(var, get_colorbool_slot))
                get_colorbool_found = git_config_colorbool(var, value);
index a76f1a1a7a7004cc95f392024cc1a27d54c870df..e17c4b4c69b0feb7b9c8a897ca6120e46e502251 100644 (file)
@@ -63,7 +63,7 @@ static const char *prio_names[] = {
        N_("head"), N_("lightweight"), N_("annotated"),
 };
 
-static int commit_name_neq(const void *unused_cmp_data,
+static int commit_name_neq(const void *cmp_data UNUSED,
                           const struct hashmap_entry *eptr,
                           const struct hashmap_entry *entry_or_key,
                           const void *peeled)
@@ -140,7 +140,8 @@ static void add_to_known_names(const char *path,
        }
 }
 
-static int get_name(const char *path, const struct object_id *oid, int flag, void *cb_data)
+static int get_name(const char *path, const struct object_id *oid,
+                   int flag UNUSED, void *cb_data UNUSED)
 {
        int is_tag = 0;
        struct object_id peeled;
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
new file mode 100644 (file)
index 0000000..576e0e8
--- /dev/null
@@ -0,0 +1,61 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "diagnose.h"
+
+static const char * const diagnose_usage[] = {
+       N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--mode=<mode>]"),
+       NULL
+};
+
+int cmd_diagnose(int argc, const char **argv, const char *prefix)
+{
+       struct strbuf zip_path = STRBUF_INIT;
+       time_t now = time(NULL);
+       struct tm tm;
+       enum diagnose_mode mode = DIAGNOSE_STATS;
+       char *option_output = NULL;
+       char *option_suffix = "%Y-%m-%d-%H%M";
+       char *prefixed_filename;
+
+       const struct option diagnose_options[] = {
+               OPT_STRING('o', "output-directory", &option_output, N_("path"),
+                          N_("specify a destination for the diagnostics archive")),
+               OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+                          N_("specify a strftime format suffix for the filename")),
+               OPT_CALLBACK_F(0, "mode", &mode, "(stats|all)",
+                              N_("specify the content of the diagnostic archive"),
+                              PARSE_OPT_NONEG, option_parse_diagnose),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, diagnose_options,
+                            diagnose_usage, 0);
+
+       /* Prepare the path to put the result */
+       prefixed_filename = prefix_filename(prefix,
+                                           option_output ? option_output : "");
+       strbuf_addstr(&zip_path, prefixed_filename);
+       strbuf_complete(&zip_path, '/');
+
+       strbuf_addstr(&zip_path, "git-diagnostics-");
+       strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+       strbuf_addstr(&zip_path, ".zip");
+
+       switch (safe_create_leading_directories(zip_path.buf)) {
+       case SCLD_OK:
+       case SCLD_EXISTS:
+               break;
+       default:
+               die_errno(_("could not create leading directories for '%s'"),
+                         zip_path.buf);
+       }
+
+       /* Prepare diagnostics */
+       if (create_diagnostics_archive(&zip_path, mode))
+               die_errno(_("unable to create diagnostics archive %s"),
+                         zip_path.buf);
+
+       free(prefixed_filename);
+       strbuf_release(&zip_path);
+       return 0;
+}
index b3c509b8de305db3ba5b393618024087e387dc46..4b10ad1a36908fe8067daa1e66a000c8c8e85718 100644 (file)
@@ -125,10 +125,10 @@ struct working_tree_entry {
        char path[FLEX_ARRAY];
 };
 
-static int working_tree_entry_cmp(const void *unused_cmp_data,
+static int working_tree_entry_cmp(const void *cmp_data UNUSED,
                                  const struct hashmap_entry *eptr,
                                  const struct hashmap_entry *entry_or_key,
-                                 const void *unused_keydata)
+                                 const void *keydata UNUSED)
 {
        const struct working_tree_entry *a, *b;
 
@@ -148,10 +148,10 @@ struct pair_entry {
        const char path[FLEX_ARRAY];
 };
 
-static int pair_cmp(const void *unused_cmp_data,
+static int pair_cmp(const void *cmp_data UNUSED,
                    const struct hashmap_entry *eptr,
                    const struct hashmap_entry *entry_or_key,
-                   const void *unused_keydata)
+                   const void *keydata UNUSED)
 {
        const struct pair_entry *a, *b;
 
@@ -184,7 +184,7 @@ struct path_entry {
        char path[FLEX_ARRAY];
 };
 
-static int path_entry_cmp(const void *unused_cmp_data,
+static int path_entry_cmp(const void *cmp_data UNUSED,
                          const struct hashmap_entry *eptr,
                          const struct hashmap_entry *entry_or_key,
                          const void *key)
@@ -716,7 +716,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
        symlinks = has_symlinks;
 
        argc = parse_options(argc, argv, prefix, builtin_difftool_options,
-                            builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
+                            builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN_OPT |
                             PARSE_OPT_KEEP_DASHDASH);
 
        if (tool_help)
index 27349098b074f9c3118114ee16f3653f3d61baa2..ea04c166364fe5776cd196950c3ee44a866076d7 100644 (file)
@@ -50,7 +50,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
        };
 
        argc = parse_options(argc, argv, prefix, opts, env__helper_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
        if (env_default && !*env_default)
                usage_with_options(env__helper_usage, opts);
        if (!cmdmode)
index e1748fb98be5b970a8d31bf43f3f708d6a60c3d9..3b3314e7b2a3343b78d14ee3bc9d4a92fb578fd6 100644 (file)
@@ -119,7 +119,7 @@ struct anonymized_entry_key {
        size_t orig_len;
 };
 
-static int anonymized_entry_cmp(const void *unused_cmp_data,
+static int anonymized_entry_cmp(const void *cmp_data UNUSED,
                                const struct hashmap_entry *eptr,
                                const struct hashmap_entry *entry_or_key,
                                const void *keydata)
@@ -1221,7 +1221,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        revs.sources = &revision_sources;
        revs.rewrite_parents = 1;
        argc = parse_options(argc, argv, prefix, options, fast_export_usage,
-                       PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
+                       PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
        argc = setup_revisions(argc, argv, &revs, NULL);
        if (argc > 1)
                usage_with_options (fast_export_usage, options);
index 14113cfd82b78034cb7bbb4d0ff843f20d5ae498..7134683ab93f96d4c213d478fc7fadc8a17856c0 100644 (file)
@@ -46,7 +46,7 @@ struct object_entry {
                depth : DEPTH_BITS;
 };
 
-static int object_entry_hashcmp(const void *map_data,
+static int object_entry_hashcmp(const void *map_data UNUSED,
                                const struct hashmap_entry *eptr,
                                const struct hashmap_entry *entry_or_key,
                                const void *keydata)
index f045bbbe946dcbf96eff8849317c499595de295f..afe679368deec2a0288de1606259b73847ce434b 100644 (file)
@@ -62,6 +62,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        packet_trace_identity("fetch-pack");
 
        memset(&args, 0, sizeof(args));
+       list_objects_filter_init(&args.filter_options);
        args.uploadpack = "git-upload-pack";
 
        for (i = 1; i < argc && *argv[i] == '-'; i++) {
index ac29c2b1ae34df79f8a2bd62318dc714a1f37e24..a0fca93bb6a63e441e3921832f7c7d9a7bd3dd78 100644 (file)
@@ -80,7 +80,7 @@ static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
 static int shown_url = 0;
 static struct refspec refmap = REFSPEC_INIT_FETCH;
-static struct list_objects_filter_options filter_options;
+static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
 static struct string_list server_options = STRING_LIST_INIT_DUP;
 static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
 static int fetch_write_commit_graph = -1;
@@ -301,7 +301,7 @@ struct refname_hash_entry {
        char refname[FLEX_ARRAY];
 };
 
-static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data,
+static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data UNUSED,
                                  const struct hashmap_entry *eptr,
                                  const struct hashmap_entry *entry_or_key,
                                  const void *keydata)
@@ -329,7 +329,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
 
 static int add_one_refname(const char *refname,
                           const struct object_id *oid,
-                          int flag, void *cbdata)
+                          int flag UNUSED, void *cbdata)
 {
        struct hashmap *refname_map = cbdata;
 
@@ -490,7 +490,9 @@ static void filter_prefetch_refspec(struct refspec *rs)
                        continue;
                if (!rs->items[i].dst ||
                    (rs->items[i].src &&
-                    !strncmp(rs->items[i].src, "refs/tags/", 10))) {
+                    !strncmp(rs->items[i].src,
+                             ref_namespace[NAMESPACE_TAGS].ref,
+                             strlen(ref_namespace[NAMESPACE_TAGS].ref)))) {
                        int j;
 
                        free(rs->items[i].src);
@@ -506,7 +508,7 @@ static void filter_prefetch_refspec(struct refspec *rs)
                }
 
                old_dst = rs->items[i].dst;
-               strbuf_addstr(&new_dst, "refs/prefetch/");
+               strbuf_addstr(&new_dst, ref_namespace[NAMESPACE_PREFETCH].ref);
 
                /*
                 * If old_dst starts with "refs/", then place
@@ -881,11 +883,9 @@ static void format_display(struct strbuf *display, char code,
 static int update_local_ref(struct ref *ref,
                            struct ref_transaction *transaction,
                            const char *remote, const struct ref *remote_ref,
-                           struct strbuf *display, int summary_width,
-                           struct worktree **worktrees)
+                           struct strbuf *display, int summary_width)
 {
        struct commit *current = NULL, *updated;
-       const struct worktree *wt;
        const char *pretty_ref = prettify_refname(ref->name);
        int fast_forward = 0;
 
@@ -900,16 +900,14 @@ static int update_local_ref(struct ref *ref,
        }
 
        if (!update_head_ok &&
-           (wt = find_shared_symref(worktrees, "HEAD", ref->name)) &&
-           !wt->is_bare && !is_null_oid(&ref->old_oid)) {
+           !is_null_oid(&ref->old_oid) &&
+           branch_checked_out(ref->name)) {
                /*
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
                format_display(display, '!', _("[rejected]"),
-                              wt->is_current ?
-                                      _("can't fetch in current branch") :
-                                      _("checked out in another worktree"),
+                              _("can't fetch into checked-out branch"),
                               remote, pretty_ref, summary_width);
                return 1;
        }
@@ -1110,10 +1108,10 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
 static int store_updated_refs(const char *raw_url, const char *remote_name,
                              int connectivity_checked,
                              struct ref_transaction *transaction, struct ref *ref_map,
-                             struct fetch_head *fetch_head, struct worktree **worktrees)
+                             struct fetch_head *fetch_head)
 {
        int url_len, i, rc = 0;
-       struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
+       struct strbuf note = STRBUF_INIT;
        const char *what, *kind;
        struct ref *rm;
        char *url;
@@ -1240,8 +1238,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                        strbuf_reset(&note);
                        if (ref) {
                                rc |= update_local_ref(ref, transaction, what,
-                                                      rm, &note, summary_width,
-                                                      worktrees);
+                                                      rm, &note, summary_width);
                                free(ref);
                        } else if (write_fetch_head || dry_run) {
                                /*
@@ -1281,7 +1278,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
 
  abort:
        strbuf_release(&note);
-       strbuf_release(&err);
        free(url);
        return rc;
 }
@@ -1332,8 +1328,7 @@ static int check_exist_and_connected(struct ref *ref_map)
 static int fetch_and_consume_refs(struct transport *transport,
                                  struct ref_transaction *transaction,
                                  struct ref *ref_map,
-                                 struct fetch_head *fetch_head,
-                                 struct worktree **worktrees)
+                                 struct fetch_head *fetch_head)
 {
        int connectivity_checked = 1;
        int ret;
@@ -1356,7 +1351,7 @@ static int fetch_and_consume_refs(struct transport *transport,
        trace2_region_enter("fetch", "consume_refs", the_repository);
        ret = store_updated_refs(transport->url, transport->remote->name,
                                 connectivity_checked, transaction, ref_map,
-                                fetch_head, worktrees);
+                                fetch_head);
        trace2_region_leave("fetch", "consume_refs", the_repository);
 
 out:
@@ -1434,19 +1429,16 @@ cleanup:
        return result;
 }
 
-static void check_not_current_branch(struct ref *ref_map,
-                                    struct worktree **worktrees)
+static void check_not_current_branch(struct ref *ref_map)
 {
-       const struct worktree *wt;
+       const char *path;
        for (; ref_map; ref_map = ref_map->next)
                if (ref_map->peer_ref &&
                    starts_with(ref_map->peer_ref->name, "refs/heads/") &&
-                   (wt = find_shared_symref(worktrees, "HEAD",
-                                            ref_map->peer_ref->name)) &&
-                   !wt->is_bare)
+                   (path = branch_checked_out(ref_map->peer_ref->name)))
                        die(_("refusing to fetch into branch '%s' "
                              "checked out at '%s'"),
-                           ref_map->peer_ref->name, wt->path);
+                           ref_map->peer_ref->name, path);
 }
 
 static int truncate_fetch_head(void)
@@ -1472,8 +1464,9 @@ static void set_option(struct transport *transport, const char *name, const char
 }
 
 
-static int add_oid(const char *refname, const struct object_id *oid, int flags,
-                  void *cb_data)
+static int add_oid(const char *refname UNUSED,
+                  const struct object_id *oid,
+                  int flags UNUSED, void *cb_data)
 {
        struct oid_array *oids = cb_data;
 
@@ -1549,8 +1542,7 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
 static int backfill_tags(struct transport *transport,
                         struct ref_transaction *transaction,
                         struct ref *ref_map,
-                        struct fetch_head *fetch_head,
-                        struct worktree **worktrees)
+                        struct fetch_head *fetch_head)
 {
        int retcode, cannot_reuse;
 
@@ -1571,7 +1563,7 @@ static int backfill_tags(struct transport *transport,
        transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
        transport_set_option(transport, TRANS_OPT_DEPTH, "0");
        transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
-       retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head, worktrees);
+       retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head);
 
        if (gsecondary) {
                transport_disconnect(gsecondary);
@@ -1592,7 +1584,6 @@ static int do_fetch(struct transport *transport,
        struct transport_ls_refs_options transport_ls_refs_options =
                TRANSPORT_LS_REFS_OPTIONS_INIT;
        int must_list_refs = 1;
-       struct worktree **worktrees = get_worktrees();
        struct fetch_head fetch_head = { 0 };
        struct strbuf err = STRBUF_INIT;
 
@@ -1626,9 +1617,21 @@ static int do_fetch(struct transport *transport,
                                break;
                        }
                }
-       } else if (transport->remote && transport->remote->fetch.nr)
-               refspec_ref_prefixes(&transport->remote->fetch,
-                                    &transport_ls_refs_options.ref_prefixes);
+       } else {
+               struct branch *branch = branch_get(NULL);
+
+               if (transport->remote->fetch.nr)
+                       refspec_ref_prefixes(&transport->remote->fetch,
+                                            &transport_ls_refs_options.ref_prefixes);
+               if (branch_has_merge_config(branch) &&
+                   !strcmp(branch->remote_name, transport->remote->name)) {
+                       int i;
+                       for (i = 0; i < branch->merge_nr; i++) {
+                               strvec_push(&transport_ls_refs_options.ref_prefixes,
+                                           branch->merge[i]->src);
+                       }
+               }
+       }
 
        if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
                must_list_refs = 1;
@@ -1650,7 +1653,7 @@ static int do_fetch(struct transport *transport,
        ref_map = get_ref_map(transport->remote, remote_refs, rs,
                              tags, &autotags);
        if (!update_head_ok)
-               check_not_current_branch(ref_map, worktrees);
+               check_not_current_branch(ref_map);
 
        retcode = open_fetch_head(&fetch_head);
        if (retcode)
@@ -1683,7 +1686,7 @@ static int do_fetch(struct transport *transport,
                        retcode = 1;
        }
 
-       if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head, worktrees)) {
+       if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head)) {
                retcode = 1;
                goto cleanup;
        }
@@ -1706,7 +1709,7 @@ static int do_fetch(struct transport *transport,
                         * the transaction and don't commit anything.
                         */
                        if (backfill_tags(transport, transaction, tags_ref_map,
-                                         &fetch_head, worktrees))
+                                         &fetch_head))
                                retcode = 1;
                }
 
@@ -1791,7 +1794,6 @@ cleanup:
        close_fetch_head(&fetch_head);
        strbuf_release(&err);
        free_refs(ref_map);
-       free_worktrees(worktrees);
        return retcode;
 }
 
index 6c73092f10dedd64a53090847c16b65232bc0c86..41acbc229e468f68092a5b6e3f2df95ece62fd7c 100644 (file)
@@ -228,6 +228,8 @@ static void mark_unreachable_referents(const struct object_id *oid)
 
        options.walk = mark_used;
        fsck_walk(obj, NULL, &options);
+       if (obj->type == OBJ_TREE)
+               free_tree_buffer((struct tree *)obj);
 }
 
 static int mark_loose_unreachable_referents(const struct object_id *oid,
@@ -437,9 +439,6 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 out:
        if (obj->type == OBJ_TREE)
                free_tree_buffer((struct tree *)obj);
-       if (obj->type == OBJ_COMMIT)
-               free_commit_buffer(the_repository->parsed_objects,
-                                  (struct commit *)obj);
        return err;
 }
 
@@ -488,8 +487,9 @@ 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,
-               const char *email, timestamp_t timestamp, int tz,
-               const char *message, void *cb_data)
+                                 const char *email UNUSED,
+                                 timestamp_t timestamp, int tz UNUSED,
+                                 const char *message UNUSED, void *cb_data)
 {
        const char *refname = cb_data;
 
@@ -502,8 +502,9 @@ static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid
        return 0;
 }
 
-static int fsck_handle_reflog(const char *logname, const struct object_id *oid,
-                             int flag, void *cb_data)
+static int fsck_handle_reflog(const char *logname,
+                             const struct object_id *oid UNUSED,
+                             int flag UNUSED, void *cb_data)
 {
        struct strbuf refname = STRBUF_INIT;
 
@@ -514,7 +515,7 @@ static int fsck_handle_reflog(const char *logname, const struct object_id *oid,
 }
 
 static int fsck_handle_ref(const char *refname, const struct object_id *oid,
-                          int flag, void *cb_data)
+                          int flag UNUSED, void *cb_data UNUSED)
 {
        struct object *obj;
 
@@ -851,6 +852,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 
        errors_found = 0;
        read_replace_refs = 0;
+       save_commit_buffer = 0;
 
        argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
 
index 2c109cf8b377712a1bb2849ee83724d9c3473656..c69da93ecebe54b8af93a51452c9796eda15b377 100644 (file)
@@ -13,8 +13,8 @@
 static const char * const builtin_fsmonitor__daemon_usage[] = {
        N_("git fsmonitor--daemon start [<options>]"),
        N_("git fsmonitor--daemon run [<options>]"),
-       N_("git fsmonitor--daemon stop"),
-       N_("git fsmonitor--daemon status"),
+       "git fsmonitor--daemon stop",
+       "git fsmonitor--daemon status",
        NULL
 };
 
index 021e9256ae23561007b1178b3de99341f6c72357..2753bd15a5e85f584a0e73943828ce8cd1d0fe5c 100644 (file)
@@ -168,9 +168,15 @@ struct maintenance_run_opts;
 static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
 {
        struct strvec pack_refs_cmd = STRVEC_INIT;
+       int ret;
+
        strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
 
-       return run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
+       ret = run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
+
+       strvec_clear(&pack_refs_cmd);
+
+       return ret;
 }
 
 static int too_many_loose_objects(void)
@@ -776,8 +782,9 @@ struct cg_auto_data {
        int limit;
 };
 
-static int dfs_on_ref(const char *refname,
-                     const struct object_id *oid, int flags,
+static int dfs_on_ref(const char *refname UNUSED,
+                     const struct object_id *oid,
+                     int flags UNUSED,
                      void *cb_data)
 {
        struct cg_auto_data *data = (struct cg_auto_data *)cb_data;
@@ -904,12 +911,6 @@ static int fetch_remote(struct remote *remote, void *cbdata)
 
 static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
 {
-       git_config_set_multivar_gently("log.excludedecoration",
-                                       "refs/prefetch/",
-                                       "refs/prefetch/",
-                                       CONFIG_FLAGS_FIXED_VALUE |
-                                       CONFIG_FLAGS_MULTI_REPLACE);
-
        if (for_each_remote(fetch_remote, opts)) {
                error(_("failed to prefetch remotes"));
                return 1;
@@ -1459,14 +1460,28 @@ static char *get_maintpath(void)
        return strbuf_detach(&sb, NULL);
 }
 
-static int maintenance_register(void)
+static char const * const builtin_maintenance_register_usage[] = {
+       "git maintenance register",
+       NULL
+};
+
+static int maintenance_register(int argc, const char **argv, const char *prefix)
 {
+       struct option options[] = {
+               OPT_END(),
+       };
        int rc;
        char *config_value;
        struct child_process config_set = CHILD_PROCESS_INIT;
        struct child_process config_get = CHILD_PROCESS_INIT;
        char *maintpath = get_maintpath();
 
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_maintenance_register_usage, 0);
+       if (argc)
+               usage_with_options(builtin_maintenance_register_usage,
+                                  options);
+
        /* Disable foreground maintenance */
        git_config_set("maintenance.auto", "false");
 
@@ -1503,12 +1518,26 @@ done:
        return rc;
 }
 
-static int maintenance_unregister(void)
+static char const * const builtin_maintenance_unregister_usage[] = {
+       "git maintenance unregister",
+       NULL
+};
+
+static int maintenance_unregister(int argc, const char **argv, const char *prefix)
 {
+       struct option options[] = {
+               OPT_END(),
+       };
        int rc;
        struct child_process config_unset = CHILD_PROCESS_INIT;
        char *maintpath = get_maintpath();
 
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_maintenance_unregister_usage, 0);
+       if (argc)
+               usage_with_options(builtin_maintenance_unregister_usage,
+                                  options);
+
        config_unset.git_cmd = 1;
        strvec_pushl(&config_unset.args, "config", "--global", "--unset",
                     "--fixed-value", "maintenance.repo", maintpath, NULL);
@@ -2059,6 +2088,7 @@ static int crontab_update_schedule(int run_maintenance, int fd)
        struct child_process crontab_edit = CHILD_PROCESS_INIT;
        FILE *cron_list, *cron_in;
        struct strbuf line = STRBUF_INIT;
+       struct tempfile *tmpedit = NULL;
 
        get_schedule_cmd(&cmd, NULL);
        strvec_split(&crontab_list.args, cmd);
@@ -2073,6 +2103,17 @@ static int crontab_update_schedule(int run_maintenance, int fd)
        /* Ignore exit code, as an empty crontab will return error. */
        finish_command(&crontab_list);
 
+       tmpedit = mks_tempfile_t(".git_cron_edit_tmpXXXXXX");
+       if (!tmpedit) {
+               result = error(_("failed to create crontab temporary file"));
+               goto out;
+       }
+       cron_in = fdopen_tempfile(tmpedit, "w");
+       if (!cron_in) {
+               result = error(_("failed to open temporary file"));
+               goto out;
+       }
+
        /*
         * Read from the .lock file, filtering out the old
         * schedule while appending the new schedule.
@@ -2080,19 +2121,6 @@ static int crontab_update_schedule(int run_maintenance, int fd)
        cron_list = fdopen(fd, "r");
        rewind(cron_list);
 
-       strvec_split(&crontab_edit.args, cmd);
-       crontab_edit.in = -1;
-       crontab_edit.git_cmd = 0;
-
-       if (start_command(&crontab_edit))
-               return error(_("failed to run 'crontab'; your system might not support 'cron'"));
-
-       cron_in = fdopen(crontab_edit.in, "w");
-       if (!cron_in) {
-               result = error(_("failed to open stdin of 'crontab'"));
-               goto done_editing;
-       }
-
        while (!strbuf_getline_lf(&line, cron_list)) {
                if (!in_old_region && !strcmp(line.buf, BEGIN_LINE))
                        in_old_region = 1;
@@ -2126,14 +2154,22 @@ static int crontab_update_schedule(int run_maintenance, int fd)
        }
 
        fflush(cron_in);
-       fclose(cron_in);
-       close(crontab_edit.in);
 
-done_editing:
+       strvec_split(&crontab_edit.args, cmd);
+       strvec_push(&crontab_edit.args, get_tempfile_path(tmpedit));
+       crontab_edit.git_cmd = 0;
+
+       if (start_command(&crontab_edit)) {
+               result = error(_("failed to run 'crontab'; your system might not support 'cron'"));
+               goto out;
+       }
+
        if (finish_command(&crontab_edit))
                result = error(_("'crontab' died"));
        else
                fclose(cron_list);
+out:
+       delete_tempfile(&tmpedit);
        return result;
 }
 
@@ -2490,6 +2526,7 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
                        PARSE_OPT_NONEG, maintenance_opt_scheduler),
                OPT_END()
        };
+       const char *register_args[] = { "register", NULL };
 
        argc = parse_options(argc, argv, prefix, options,
                             builtin_maintenance_start_usage, 0);
@@ -2499,34 +2536,46 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
        opts.scheduler = resolve_scheduler(opts.scheduler);
        validate_scheduler(opts.scheduler);
 
-       if (maintenance_register())
+       if (maintenance_register(ARRAY_SIZE(register_args)-1, register_args, NULL))
                warning(_("failed to add repo to global config"));
        return update_background_schedule(&opts, 1);
 }
 
-static int maintenance_stop(void)
+static const char *const builtin_maintenance_stop_usage[] = {
+       "git maintenance stop",
+       NULL
+};
+
+static int maintenance_stop(int argc, const char **argv, const char *prefix)
 {
+       struct option options[] = {
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_maintenance_stop_usage, 0);
+       if (argc)
+               usage_with_options(builtin_maintenance_stop_usage, options);
        return update_background_schedule(NULL, 0);
 }
 
-static const char builtin_maintenance_usage[] =        N_("git maintenance <subcommand> [<options>]");
+static const char * const builtin_maintenance_usage[] = {
+       N_("git maintenance <subcommand> [<options>]"),
+       NULL,
+};
 
 int cmd_maintenance(int argc, const char **argv, const char *prefix)
 {
-       if (argc < 2 ||
-           (argc == 2 && !strcmp(argv[1], "-h")))
-               usage(builtin_maintenance_usage);
-
-       if (!strcmp(argv[1], "run"))
-               return maintenance_run(argc - 1, argv + 1, prefix);
-       if (!strcmp(argv[1], "start"))
-               return maintenance_start(argc - 1, argv + 1, prefix);
-       if (!strcmp(argv[1], "stop"))
-               return maintenance_stop();
-       if (!strcmp(argv[1], "register"))
-               return maintenance_register();
-       if (!strcmp(argv[1], "unregister"))
-               return maintenance_unregister();
-
-       die(_("invalid subcommand: %s"), argv[1]);
+       parse_opt_subcommand_fn *fn = NULL;
+       struct option builtin_maintenance_options[] = {
+               OPT_SUBCOMMAND("run", &fn, maintenance_run),
+               OPT_SUBCOMMAND("start", &fn, maintenance_start),
+               OPT_SUBCOMMAND("stop", &fn, maintenance_stop),
+               OPT_SUBCOMMAND("register", &fn, maintenance_register),
+               OPT_SUBCOMMAND("unregister", &fn, maintenance_unregister),
+               OPT_END(),
+       };
+
+       argc = parse_options(argc, argv, prefix, builtin_maintenance_options,
+                            builtin_maintenance_usage, 0);
+       return fn(argc, argv, prefix);
 }
index bcb07ea7f75ba35079d0093248df0647292665a1..e6bcdf860cc96af2e70975eea2f66ac8ec8606eb 100644 (file)
@@ -961,6 +961,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored,
                           N_("allow calling of grep(1) (ignored by this build)"),
                           PARSE_OPT_NOCOMPLETE),
+               OPT_INTEGER('m', "max-count", &opt.max_count,
+                       N_("maximum number of results per file")),
                OPT_END()
        };
        grep_prefix = prefix;
@@ -1101,6 +1103,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (recurse_submodules && untracked)
                die(_("--untracked not supported with --recurse-submodules"));
 
+       /*
+        * Optimize out the case where the amount of matches is limited to zero.
+        * We do this to keep results consistent with GNU grep(1).
+        */
+       if (opt.max_count == 0)
+               return 1;
+
        if (show_in_pager) {
                if (num_threads > 1)
                        warning(_("invalid option combination, ignoring --threads"));
index 222f994f863cba4226e867bf0f1022e9d551e308..6f2796f211e24c47c2efd3b1dfe52d8b8b757865 100644 (file)
@@ -43,6 +43,8 @@ static enum help_action {
        HELP_ACTION_ALL = 1,
        HELP_ACTION_GUIDES,
        HELP_ACTION_CONFIG,
+       HELP_ACTION_USER_INTERFACES,
+       HELP_ACTION_DEVELOPER_INTERFACES,
        HELP_ACTION_CONFIG_FOR_COMPLETION,
        HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
 } cmd_mode;
@@ -69,6 +71,12 @@ static struct option builtin_help_options[] = {
 
        OPT_CMDMODE('g', "guides", &cmd_mode, N_("print list of useful guides"),
                    HELP_ACTION_GUIDES),
+       OPT_CMDMODE(0, "user-interfaces", &cmd_mode,
+                   N_("print list of user-facing repository, command and file interfaces"),
+                   HELP_ACTION_USER_INTERFACES),
+       OPT_CMDMODE(0, "developer-interfaces", &cmd_mode,
+                   N_("print list of file formats, protocols and other developer interfaces"),
+                   HELP_ACTION_DEVELOPER_INTERFACES),
        OPT_CMDMODE('c', "config", &cmd_mode, N_("print all configuration variable names"),
                    HELP_ACTION_CONFIG),
        OPT_CMDMODE_F(0, "config-for-completion", &cmd_mode, "",
@@ -81,9 +89,11 @@ static struct option builtin_help_options[] = {
 
 static const char * const builtin_help_usage[] = {
        "git help [-a|--all] [--[no-]verbose]] [--[no-]external-commands] [--[no-]aliases]",
-       N_("git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"),
+       N_("git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"),
        "git help [-g|--guides]",
        "git help [-c|--config]",
+       "git help [--user-interfaces]",
+       "git help [--developer-interfaces]",
        NULL
 };
 
@@ -430,6 +440,8 @@ static const char *cmd_to_page(const char *git_cmd)
                return git_cmd;
        else if (is_git_command(git_cmd))
                return xstrfmt("git-%s", git_cmd);
+       else if (!strcmp("scalar", git_cmd))
+               return xstrdup(git_cmd);
        else
                return xstrfmt("git%s", git_cmd);
 }
@@ -654,6 +666,14 @@ int cmd_help(int argc, const char **argv, const char *prefix)
                opt_mode_usage(argc, "--config-for-completion", help_format);
                list_config_help(SHOW_CONFIG_VARS);
                return 0;
+       case HELP_ACTION_USER_INTERFACES:
+               opt_mode_usage(argc, "--user-interfaces", help_format);
+               list_user_interfaces_help();
+               return 0;
+       case HELP_ACTION_DEVELOPER_INTERFACES:
+               opt_mode_usage(argc, "--developer-interfaces", help_format);
+               list_developer_interfaces_help();
+               return 0;
        case HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION:
                opt_mode_usage(argc, "--config-sections-for-completion",
                               help_format);
index 54e5c6ec933f4c032fa03d514d8f7e93e29883e5..b6530d189ad08dc76367fca61cc8eae95be13ffd 100644 (file)
@@ -67,18 +67,14 @@ usage:
 
 int cmd_hook(int argc, const char **argv, const char *prefix)
 {
+       parse_opt_subcommand_fn *fn = NULL;
        struct option builtin_hook_options[] = {
+               OPT_SUBCOMMAND("run", &fn, run),
                OPT_END(),
        };
 
        argc = parse_options(argc, argv, NULL, builtin_hook_options,
-                            builtin_hook_usage, PARSE_OPT_STOP_AT_NON_OPTION);
-       if (!argc)
-               goto usage;
+                            builtin_hook_usage, 0);
 
-       if (!strcmp(argv[0], "run"))
-               return run(argc, argv, prefix);
-
-usage:
-       usage_with_options(builtin_hook_usage, builtin_hook_options);
+       return fn(argc, argv, prefix);
 }
index 88a5e98875adb0398b2855460bddd5fa43e073ec..ee19dc5d450c57df89a864767a2b4f17d933781d 100644 (file)
@@ -52,6 +52,7 @@ static int default_encode_email_headers = 1;
 static int decoration_style;
 static int decoration_given;
 static int use_mailmap_config = 1;
+static unsigned int force_in_body_from;
 static const char *fmt_patch_subject_prefix = "PATCH";
 static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
 static const char *fmt_pretty;
@@ -101,6 +102,20 @@ static int parse_decoration_style(const char *value)
        return -1;
 }
 
+static int use_default_decoration_filter = 1;
+static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
+static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
+static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
+
+static int clear_decorations_callback(const struct option *opt,
+                                           const char *arg, int unset)
+{
+       string_list_clear(&decorate_refs_include, 0);
+       string_list_clear(&decorate_refs_exclude, 0);
+       use_default_decoration_filter = 0;
+       return 0;
+}
+
 static int decorate_callback(const struct option *opt, const char *arg, int unset)
 {
        if (unset)
@@ -162,18 +177,61 @@ static void cmd_log_init_defaults(struct rev_info *rev)
                parse_date_format(default_date_mode, &rev->date_mode);
 }
 
+static void set_default_decoration_filter(struct decoration_filter *decoration_filter)
+{
+       int i;
+       char *value = NULL;
+       struct string_list *include = decoration_filter->include_ref_pattern;
+       const struct string_list *config_exclude =
+                       git_config_get_value_multi("log.excludeDecoration");
+
+       if (config_exclude) {
+               struct string_list_item *item;
+               for_each_string_list_item(item, config_exclude)
+                       string_list_append(decoration_filter->exclude_ref_config_pattern,
+                                          item->string);
+       }
+
+       /*
+        * By default, decorate_all is disabled. Enable it if
+        * log.initialDecorationSet=all. Don't ever disable it by config,
+        * since the command-line takes precedent.
+        */
+       if (use_default_decoration_filter &&
+           !git_config_get_string("log.initialdecorationset", &value) &&
+           !strcmp("all", value))
+               use_default_decoration_filter = 0;
+       free(value);
+
+       if (!use_default_decoration_filter ||
+           decoration_filter->exclude_ref_pattern->nr ||
+           decoration_filter->include_ref_pattern->nr ||
+           decoration_filter->exclude_ref_config_pattern->nr)
+               return;
+
+       /*
+        * No command-line or config options were given, so
+        * populate with sensible defaults.
+        */
+       for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
+               if (!ref_namespace[i].decoration)
+                       continue;
+
+               string_list_append(include, ref_namespace[i].ref);
+       }
+}
+
 static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                         struct rev_info *rev, struct setup_revision_opt *opt)
 {
        struct userformat_want w;
        int quiet = 0, source = 0, mailmap;
        static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
-       static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
-       static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
-       static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
-       struct decoration_filter decoration_filter = {&decorate_refs_include,
-                                                     &decorate_refs_exclude,
-                                                     &decorate_refs_exclude_config};
+       struct decoration_filter decoration_filter = {
+               .exclude_ref_pattern = &decorate_refs_exclude,
+               .include_ref_pattern = &decorate_refs_include,
+               .exclude_ref_config_pattern = &decorate_refs_exclude_config,
+       };
        static struct revision_sources revision_sources;
 
        const struct option builtin_log_options[] = {
@@ -181,6 +239,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                OPT_BOOL(0, "source", &source, N_("show source")),
                OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")),
                OPT_ALIAS(0, "mailmap", "use-mailmap"),
+               OPT_CALLBACK_F(0, "clear-decorations", NULL, NULL,
+                              N_("clear all previously-defined decoration filters"),
+                              PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+                              clear_decorations_callback),
                OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
                                N_("pattern"), N_("only decorate refs that match <pattern>")),
                OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
@@ -199,7 +261,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        mailmap = use_mailmap_config;
        argc = parse_options(argc, argv, prefix,
                             builtin_log_options, builtin_log_usage,
-                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
+                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
                             PARSE_OPT_KEEP_DASHDASH);
 
        if (quiet)
@@ -265,16 +327,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        }
 
        if (decoration_style || rev->simplify_by_decoration) {
-               const struct string_list *config_exclude =
-                       repo_config_get_value_multi(the_repository,
-                                                   "log.excludeDecoration");
-
-               if (config_exclude) {
-                       struct string_list_item *item;
-                       for_each_string_list_item(item, config_exclude)
-                               string_list_append(&decorate_refs_exclude_config,
-                                                  item->string);
-               }
+               set_default_decoration_filter(&decoration_filter);
 
                if (decoration_style)
                        rev->show_decorations = 1;
@@ -645,9 +698,10 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
        return 0;
 }
 
-static int show_tree_object(const struct object_id *oid,
-               struct strbuf *base,
-               const char *pathname, unsigned mode, void *context)
+static int show_tree_object(const struct object_id *oid UNUSED,
+                           struct strbuf *base UNUSED,
+                           const char *pathname, unsigned mode,
+                           void *context)
 {
        FILE *file = context;
        fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
@@ -668,10 +722,10 @@ static void show_setup_revisions_tweak(struct rev_info *rev,
 int cmd_show(int argc, const char **argv, const char *prefix)
 {
        struct rev_info rev;
-       struct object_array_entry *objects;
+       unsigned int i;
        struct setup_revision_opt opt;
        struct pathspec match_all;
-       int i, count, ret = 0;
+       int ret = 0;
 
        init_log_defaults();
        git_config(git_log_config, NULL);
@@ -698,12 +752,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
        if (!rev.no_walk)
                return cmd_log_deinit(cmd_log_walk(&rev), &rev);
 
-       count = rev.pending.nr;
-       objects = rev.pending.objects;
        rev.diffopt.no_free = 1;
-       for (i = 0; i < count && !ret; i++) {
-               struct object *o = objects[i].item;
-               const char *name = objects[i].name;
+       for (i = 0; i < rev.pending.nr && !ret; i++) {
+               struct object *o = rev.pending.objects[i].item;
+               const char *name = rev.pending.objects[i].name;
                switch (o->type) {
                case OBJ_BLOB:
                        ret = show_blob_object(&o->oid, &rev, name);
@@ -726,7 +778,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                        if (!o)
                                ret = error(_("could not read object %s"),
                                            oid_to_hex(oid));
-                       objects[i].item = o;
+                       rev.pending.objects[i].item = o;
                        i--;
                        break;
                }
@@ -743,11 +795,24 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                        rev.shown_one = 1;
                        break;
                case OBJ_COMMIT:
-                       rev.pending.nr = rev.pending.alloc = 0;
-                       rev.pending.objects = NULL;
+               {
+                       struct object_array old;
+                       struct object_array blank = OBJECT_ARRAY_INIT;
+
+                       memcpy(&old, &rev.pending, sizeof(old));
+                       memcpy(&rev.pending, &blank, sizeof(rev.pending));
+
                        add_object_array(o, name, &rev.pending);
                        ret = cmd_log_walk_no_free(&rev);
+
+                       /*
+                        * No need for
+                        * object_array_clear(&pending). It was
+                        * cleared already in prepare_revision_walk()
+                        */
+                       memcpy(&rev.pending, &old, sizeof(rev.pending));
                        break;
+               }
                default:
                        ret = error(_("unknown type: %d"), o->type);
                }
@@ -995,6 +1060,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
                        from = NULL;
                return 0;
        }
+       if (!strcmp(var, "format.forceinbodyfrom")) {
+               force_in_body_from = git_config_bool(var, value);
+               return 0;
+       }
        if (!strcmp(var, "format.notes")) {
                int b = git_parse_maybe_bool(value);
                if (b < 0)
@@ -1886,6 +1955,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                           N_("show changes against <refspec> in cover letter or single patch")),
                OPT_INTEGER(0, "creation-factor", &creation_factor,
                            N_("percentage by which creation is weighted")),
+               OPT_BOOL(0, "force-in-body-from", &force_in_body_from,
+                        N_("show in-body From: even if identical to the e-mail header")),
                OPT_END()
        };
 
@@ -1926,9 +1997,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
         */
        argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
                             builtin_format_patch_usage,
-                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
+                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
                             PARSE_OPT_KEEP_DASHDASH);
 
+       rev.force_in_body_from = force_in_body_from;
+
        /* Make sure "0000-$sub.patch" gives non-negative length for $sub */
        if (fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
                fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
index e791b65e7e9afb2b9f51fee4af9a0f1c978b9536..4cf8a2364835c9fc1ae39b8d52fd09a8aeeb368e 100644 (file)
@@ -11,6 +11,7 @@
 #include "quote.h"
 #include "dir.h"
 #include "builtin.h"
+#include "strbuf.h"
 #include "tree.h"
 #include "cache-tree.h"
 #include "parse-options.h"
@@ -48,6 +49,7 @@ static char *ps_matched;
 static const char *with_tree;
 static int exc_given;
 static int exclude_args;
+static const char *format;
 
 static const char *tag_cached = "";
 static const char *tag_unmerged = "";
@@ -85,6 +87,16 @@ static void write_name(const char *name)
                                   stdout, line_terminator);
 }
 
+static void write_name_to_buf(struct strbuf *sb, const char *name)
+{
+       const char *rel = relative_path(name, prefix_len ? prefix : NULL, sb);
+
+       if (line_terminator)
+               quote_c_style(rel, sb, NULL, 0);
+       else
+               strbuf_addstr(sb, rel);
+}
+
 static const char *get_tag(const struct cache_entry *ce, const char *tag)
 {
        static char alttag[4];
@@ -222,6 +234,73 @@ static void show_submodule(struct repository *superproject,
        repo_clear(&subrepo);
 }
 
+struct show_index_data {
+       const char *pathname;
+       struct index_state *istate;
+       const struct cache_entry *ce;
+};
+
+static size_t expand_show_index(struct strbuf *sb, const char *start,
+                               void *context)
+{
+       struct show_index_data *data = context;
+       const char *end;
+       const char *p;
+       size_t len = strbuf_expand_literal_cb(sb, start, NULL);
+       struct stat st;
+
+       if (len)
+               return len;
+       if (*start != '(')
+               die(_("bad ls-files format: element '%s' "
+                     "does not start with '('"), start);
+
+       end = strchr(start + 1, ')');
+       if (!end)
+               die(_("bad ls-files format: element '%s' "
+                     "does not end in ')'"), start);
+
+       len = end - start + 1;
+       if (skip_prefix(start, "(objectmode)", &p))
+               strbuf_addf(sb, "%06o", data->ce->ce_mode);
+       else if (skip_prefix(start, "(objectname)", &p))
+               strbuf_add_unique_abbrev(sb, &data->ce->oid, abbrev);
+       else if (skip_prefix(start, "(stage)", &p))
+               strbuf_addf(sb, "%d", ce_stage(data->ce));
+       else if (skip_prefix(start, "(eolinfo:index)", &p))
+               strbuf_addstr(sb, S_ISREG(data->ce->ce_mode) ?
+                             get_cached_convert_stats_ascii(data->istate,
+                             data->ce->name) : "");
+       else if (skip_prefix(start, "(eolinfo:worktree)", &p))
+               strbuf_addstr(sb, !lstat(data->pathname, &st) &&
+                             S_ISREG(st.st_mode) ?
+                             get_wt_convert_stats_ascii(data->pathname) : "");
+       else if (skip_prefix(start, "(eolattr)", &p))
+               strbuf_addstr(sb, get_convert_attr_ascii(data->istate,
+                             data->pathname));
+       else if (skip_prefix(start, "(path)", &p))
+               write_name_to_buf(sb, data->pathname);
+       else
+               die(_("bad ls-files format: %%%.*s"), (int)len, start);
+
+       return len;
+}
+
+static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
+                       const char *format, const char *fullname) {
+       struct show_index_data data = {
+               .pathname = fullname,
+               .istate = repo->index,
+               .ce = ce,
+       };
+       struct strbuf sb = STRBUF_INIT;
+
+       strbuf_expand(&sb, format, expand_show_index, &data);
+       strbuf_addch(&sb, line_terminator);
+       fwrite(sb.buf, sb.len, 1, stdout);
+       strbuf_release(&sb);
+}
+
 static void show_ce(struct repository *repo, struct dir_struct *dir,
                    const struct cache_entry *ce, const char *fullname,
                    const char *tag)
@@ -236,6 +315,12 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,
                                  max_prefix_len, ps_matched,
                                  S_ISDIR(ce->ce_mode) ||
                                  S_ISGITLINK(ce->ce_mode))) {
+               if (format) {
+                       show_ce_fmt(repo, ce, format, fullname);
+                       print_debug(ce);
+                       return;
+               }
+
                tag = get_tag(ce, tag);
 
                if (!show_stage) {
@@ -675,6 +760,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
                         N_("suppress duplicate entries")),
                OPT_BOOL(0, "sparse", &show_sparse_dirs,
                         N_("show sparse directories in the presence of a sparse index")),
+               OPT_STRING_F(0, "format", &format, N_("format"),
+                            N_("format to use for the output"),
+                            PARSE_OPT_NONEG),
                OPT_END()
        };
        int ret = 0;
@@ -699,6 +787,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
        for (i = 0; i < exclude_list.nr; i++) {
                add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
        }
+
+       if (format && (show_stage || show_others || show_killed ||
+               show_resolve_undo || skipping_duplicates || show_eol || show_tag))
+                       usage_msg_opt(_("--format cannot be used with -s, -o, -k, -t, "
+                                     "--resolve-undo, --deduplicate, --eol"),
+                                     ls_files_usage, builtin_ls_files_options);
+
        if (show_tag || show_valid_bit || show_fsmonitor_bit) {
                tag_cached = "H ";
                tag_unmerged = "M ";
index e279be8bb636d6a945f36ad10699b50cf115fd78..c3ea09281afebe0c9aefb690f6f10044142a4d1a 100644 (file)
@@ -142,7 +142,7 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
 }
 
 static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
-                        const char *pathname, unsigned mode, void *context)
+                        const char *pathname, unsigned mode, void *context UNUSED)
 {
        size_t baselen;
        int recurse = 0;
@@ -213,7 +213,7 @@ static void show_tree_common_default_long(struct strbuf *base,
 
 static int show_tree_default(const struct object_id *oid, struct strbuf *base,
                             const char *pathname, unsigned mode,
-                            void *context)
+                            void *context UNUSED)
 {
        int early;
        int recurse;
@@ -230,7 +230,8 @@ static int show_tree_default(const struct object_id *oid, struct strbuf *base,
 }
 
 static int show_tree_long(const struct object_id *oid, struct strbuf *base,
-                         const char *pathname, unsigned mode, void *context)
+                         const char *pathname, unsigned mode,
+                         void *context UNUSED)
 {
        int early;
        int recurse;
@@ -259,7 +260,8 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
 }
 
 static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
-                              const char *pathname, unsigned mode, void *context)
+                              const char *pathname, unsigned mode,
+                              void *context UNUSED)
 {
        int early;
        int recurse;
@@ -279,7 +281,8 @@ static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
 }
 
 static int show_tree_object(const struct object_id *oid, struct strbuf *base,
-                           const char *pathname, unsigned mode, void *context)
+                           const char *pathname, unsigned mode,
+                           void *context UNUSED)
 {
        int early;
        int recurse;
index e695867ee54894dceb5b0460cc9e0670d0f50607..c923bbf2abbdfa9d8a5461fcf5c0402a341a061b 100644 (file)
@@ -25,10 +25,10 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
 
 int cmd_merge_file(int argc, const char **argv, const char *prefix)
 {
-       const char *names[3] = { NULL, NULL, NULL };
-       mmfile_t mmfs[3];
-       mmbuffer_t result = {NULL, 0};
-       xmparam_t xmp = {{0}};
+       const char *names[3] = { 0 };
+       mmfile_t mmfs[3] = { 0 };
+       mmbuffer_t result = { 0 };
+       xmparam_t xmp = { 0 };
        int ret = 0, i = 0, to_stdout = 0;
        int quiet = 0;
        struct option options[] = {
@@ -71,21 +71,24 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
        for (i = 0; i < 3; i++) {
                char *fname;
-               int ret;
+               mmfile_t *mmf = mmfs + i;
 
                if (!names[i])
                        names[i] = argv[i];
 
                fname = prefix_filename(prefix, argv[i]);
-               ret = read_mmfile(mmfs + i, fname);
+
+               if (read_mmfile(mmf, fname))
+                       ret = -1;
+               else if (mmf->size > MAX_XDIFF_SIZE ||
+                        buffer_is_binary(mmf->ptr, mmf->size))
+                       ret = error("Cannot merge binary files: %s",
+                                   argv[i]);
+
                free(fname);
                if (ret)
-                       return -1;
+                       goto cleanup;
 
-               if (mmfs[i].size > MAX_XDIFF_SIZE ||
-                   buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
-                       return error("Cannot merge binary files: %s",
-                                       argv[i]);
        }
 
        xmp.ancestor = names[1];
@@ -93,9 +96,6 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        xmp.file2 = names[2];
        ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
 
-       for (i = 0; i < 3; i++)
-               free(mmfs[i].ptr);
-
        if (ret >= 0) {
                const char *filename = argv[0];
                char *fpath = prefix_filename(prefix, argv[0]);
@@ -116,5 +116,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        if (ret > 127)
                ret = 127;
 
+cleanup:
+       for (i = 0; i < 3; i++)
+               free(mmfs[i].ptr);
+
        return ret;
 }
index 5dc94d6f8804d600a37e75079b59b1960db32ef7..ae5782917b96c57917b60b7e192f74f18e77794c 100644 (file)
@@ -2,13 +2,18 @@
 #include "builtin.h"
 #include "tree-walk.h"
 #include "xdiff-interface.h"
+#include "help.h"
+#include "commit-reach.h"
+#include "merge-ort.h"
 #include "object-store.h"
+#include "parse-options.h"
 #include "repository.h"
 #include "blob.h"
 #include "exec-cmd.h"
 #include "merge-blobs.h"
+#include "quote.h"
 
-static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
+static int line_termination = '\n';
 
 struct merge_list {
        struct merge_list *next;
@@ -28,7 +33,7 @@ static void add_merge_entry(struct merge_list *entry)
        merge_result_end = &entry->next;
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base);
+static void trivial_merge_trees(struct tree_desc t[3], const char *base);
 
 static const char *explanation(struct merge_list *entry)
 {
@@ -225,7 +230,7 @@ static void unresolved_directory(const struct traverse_info *info,
        buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
 #undef ENTRY_OID
 
-       merge_trees(t, newbase);
+       trivial_merge_trees(t, newbase);
 
        free(buf0);
        free(buf1);
@@ -342,7 +347,7 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
        return mask;
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base)
+static void trivial_merge_trees(struct tree_desc t[3], const char *base)
 {
        struct traverse_info info;
 
@@ -366,19 +371,18 @@ static void *get_tree_descriptor(struct repository *r,
        return buf;
 }
 
-int cmd_merge_tree(int argc, const char **argv, const char *prefix)
+static int trivial_merge(const char *base,
+                        const char *branch1,
+                        const char *branch2)
 {
        struct repository *r = the_repository;
        struct tree_desc t[3];
        void *buf1, *buf2, *buf3;
 
-       if (argc != 4)
-               usage(merge_tree_usage);
-
-       buf1 = get_tree_descriptor(r, t+0, argv[1]);
-       buf2 = get_tree_descriptor(r, t+1, argv[2]);
-       buf3 = get_tree_descriptor(r, t+2, argv[3]);
-       merge_trees(t, "");
+       buf1 = get_tree_descriptor(r, t+0, base);
+       buf2 = get_tree_descriptor(r, t+1, branch1);
+       buf3 = get_tree_descriptor(r, t+2, branch2);
+       trivial_merge_trees(t, "");
        free(buf1);
        free(buf2);
        free(buf3);
@@ -386,3 +390,162 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
        show_result();
        return 0;
 }
+
+enum mode {
+       MODE_UNKNOWN,
+       MODE_TRIVIAL,
+       MODE_REAL,
+};
+
+struct merge_tree_options {
+       int mode;
+       int allow_unrelated_histories;
+       int show_messages;
+       int name_only;
+};
+
+static int real_merge(struct merge_tree_options *o,
+                     const char *branch1, const char *branch2,
+                     const char *prefix)
+{
+       struct commit *parent1, *parent2;
+       struct commit_list *merge_bases = NULL;
+       struct merge_options opt;
+       struct merge_result result = { 0 };
+
+       parent1 = get_merge_parent(branch1);
+       if (!parent1)
+               help_unknown_ref(branch1, "merge-tree",
+                                _("not something we can merge"));
+
+       parent2 = get_merge_parent(branch2);
+       if (!parent2)
+               help_unknown_ref(branch2, "merge-tree",
+                                _("not something we can merge"));
+
+       init_merge_options(&opt, the_repository);
+
+       opt.show_rename_progress = 0;
+
+       opt.branch1 = branch1;
+       opt.branch2 = branch2;
+
+       /*
+        * Get the merge bases, in reverse order; see comment above
+        * merge_incore_recursive in merge-ort.h
+        */
+       merge_bases = get_merge_bases(parent1, parent2);
+       if (!merge_bases && !o->allow_unrelated_histories)
+               die(_("refusing to merge unrelated histories"));
+       merge_bases = reverse_commit_list(merge_bases);
+
+       merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+       if (result.clean < 0)
+               die(_("failure to merge"));
+
+       if (o->show_messages == -1)
+               o->show_messages = !result.clean;
+
+       printf("%s%c", oid_to_hex(&result.tree->object.oid), line_termination);
+       if (!result.clean) {
+               struct string_list conflicted_files = STRING_LIST_INIT_NODUP;
+               const char *last = NULL;
+               int i;
+
+               merge_get_conflicted_files(&result, &conflicted_files);
+               for (i = 0; i < conflicted_files.nr; i++) {
+                       const char *name = conflicted_files.items[i].string;
+                       struct stage_info *c = conflicted_files.items[i].util;
+                       if (!o->name_only)
+                               printf("%06o %s %d\t",
+                                      c->mode, oid_to_hex(&c->oid), c->stage);
+                       else if (last && !strcmp(last, name))
+                               continue;
+                       write_name_quoted_relative(
+                               name, prefix, stdout, line_termination);
+                       last = name;
+               }
+               string_list_clear(&conflicted_files, 1);
+       }
+       if (o->show_messages) {
+               putchar(line_termination);
+               merge_display_update_messages(&opt, line_termination == '\0',
+                                             &result);
+       }
+       merge_finalize(&opt, &result);
+       return !result.clean; /* result.clean < 0 handled above */
+}
+
+int cmd_merge_tree(int argc, const char **argv, const char *prefix)
+{
+       struct merge_tree_options o = { .show_messages = -1 };
+       int expected_remaining_argc;
+       int original_argc;
+
+       const char * const merge_tree_usage[] = {
+               N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
+               N_("git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"),
+               NULL
+       };
+       struct option mt_options[] = {
+               OPT_CMDMODE(0, "write-tree", &o.mode,
+                           N_("do a real merge instead of a trivial merge"),
+                           MODE_REAL),
+               OPT_CMDMODE(0, "trivial-merge", &o.mode,
+                           N_("do a trivial merge only"), MODE_TRIVIAL),
+               OPT_BOOL(0, "messages", &o.show_messages,
+                        N_("also show informational/conflict messages")),
+               OPT_SET_INT('z', NULL, &line_termination,
+                           N_("separate paths with the NUL character"), '\0'),
+               OPT_BOOL_F(0, "name-only",
+                          &o.name_only,
+                          N_("list filenames without modes/oids/stages"),
+                          PARSE_OPT_NONEG),
+               OPT_BOOL_F(0, "allow-unrelated-histories",
+                          &o.allow_unrelated_histories,
+                          N_("allow merging unrelated histories"),
+                          PARSE_OPT_NONEG),
+               OPT_END()
+       };
+
+       /* Parse arguments */
+       original_argc = argc - 1; /* ignoring argv[0] */
+       argc = parse_options(argc, argv, prefix, mt_options,
+                            merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+       switch (o.mode) {
+       default:
+               BUG("unexpected command mode %d", o.mode);
+       case MODE_UNKNOWN:
+               switch (argc) {
+               default:
+                       usage_with_options(merge_tree_usage, mt_options);
+               case 2:
+                       o.mode = MODE_REAL;
+                       break;
+               case 3:
+                       o.mode = MODE_TRIVIAL;
+                       break;
+               }
+               expected_remaining_argc = argc;
+               break;
+       case MODE_REAL:
+               expected_remaining_argc = 2;
+               break;
+       case MODE_TRIVIAL:
+               expected_remaining_argc = 3;
+               /* Removal of `--trivial-merge` is expected */
+               original_argc--;
+               break;
+       }
+       if (o.mode == MODE_TRIVIAL && argc < original_argc)
+               die(_("--trivial-merge is incompatible with all other options"));
+
+       if (argc != expected_remaining_argc)
+               usage_with_options(merge_tree_usage, mt_options);
+
+       /* Do the relevant type of merge */
+       if (o.mode == MODE_REAL)
+               return real_merge(&o, argv[0], argv[1], prefix);
+       else
+               return trivial_merge(argv[0], argv[1], argv[2]);
+}
index fcd87a2a090bbdeb28d2834aa3a6d5caa20048e3..5900b81729d8da757d04613781d41f2e7621ebcd 100644 (file)
@@ -313,8 +313,16 @@ static int save_state(struct object_id *stash)
        int len;
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf buffer = STRBUF_INIT;
+       struct lock_file lock_file = LOCK_INIT;
+       int fd;
        int rc = -1;
 
+       fd = repo_hold_locked_index(the_repository, &lock_file, 0);
+       refresh_cache(REFRESH_QUIET);
+       if (0 <= fd)
+               repo_update_index_if_able(the_repository, &lock_file);
+       rollback_lock_file(&lock_file);
+
        strvec_pushl(&cp.args, "stash", "create", NULL);
        cp.out = -1;
        cp.git_cmd = 1;
@@ -375,24 +383,26 @@ static void reset_hard(const struct object_id *oid, int verbose)
 static void restore_state(const struct object_id *head,
                          const struct object_id *stash)
 {
-       struct strbuf sb = STRBUF_INIT;
-       const char *args[] = { "stash", "apply", NULL, NULL };
-
-       if (is_null_oid(stash))
-               return;
+       struct strvec args = STRVEC_INIT;
 
        reset_hard(head, 1);
 
-       args[2] = oid_to_hex(stash);
+       if (is_null_oid(stash))
+               goto refresh_cache;
+
+       strvec_pushl(&args, "stash", "apply", "--index", "--quiet", NULL);
+       strvec_push(&args, oid_to_hex(stash));
 
        /*
         * It is OK to ignore error here, for example when there was
         * nothing to restore.
         */
-       run_command_v_opt(args, RUN_GIT_CMD);
+       run_command_v_opt(args.v, RUN_GIT_CMD);
+       strvec_clear(&args);
 
-       strbuf_release(&sb);
-       refresh_cache(REFRESH_QUIET);
+refresh_cache:
+       if (discard_cache() < 0 || read_cache() < 0)
+               die(_("could not read index"));
 }
 
 /* This is called when no merge was necessary. */
@@ -503,7 +513,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
 {
        struct commit *remote_head;
        struct object_id branch_head;
-       struct strbuf buf = STRBUF_INIT;
        struct strbuf bname = STRBUF_INIT;
        struct merge_remote_desc *desc;
        const char *ptr;
@@ -591,7 +600,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
                oid_to_hex(&remote_head->object.oid), remote);
 cleanup:
        free(found_ref);
-       strbuf_release(&buf);
        strbuf_release(&bname);
 }
 
@@ -759,8 +767,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                else
                        clean = merge_recursive(&o, head, remoteheads->item,
                                                reversed, &result);
-               if (clean < 0)
-                       exit(128);
+               if (clean < 0) {
+                       rollback_lock_file(&lock);
+                       return 2;
+               }
                if (write_locked_index(&the_index, &lock,
                                       COMMIT_LOCK | SKIP_IF_UNCHANGED))
                        die(_("unable to write %s"), get_index_file());
@@ -1604,6 +1614,21 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 */
                refresh_cache(REFRESH_QUIET);
                if (allow_trivial && fast_forward != FF_ONLY) {
+                       /*
+                        * Must first ensure that index matches HEAD before
+                        * attempting a trivial merge.
+                        */
+                       struct tree *head_tree = get_commit_tree(head_commit);
+                       struct strbuf sb = STRBUF_INIT;
+
+                       if (repo_index_has_changes(the_repository, head_tree,
+                                                  &sb)) {
+                               error(_("Your local changes to the following files would be overwritten by merge:\n  %s"),
+                                     sb.buf);
+                               strbuf_release(&sb);
+                               return 2;
+                       }
+
                        /* See if it is really trivial. */
                        git_committer_info(IDENT_STRICT);
                        printf(_("Trying really trivial in-index merge...\n"));
@@ -1660,15 +1685,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * tree in the index -- this means that the index must be in
         * sync with the head commit.  The strategies are responsible
         * to ensure this.
+        *
+        * Stash away the local changes so that we can try more than one
+        * and/or recover from merge strategies bailing while leaving the
+        * index and working tree polluted.
         */
-       if (use_strategies_nr == 1 ||
-           /*
-            * Stash away the local changes so that we can try more than one.
-            */
-           save_state(&stash))
+       if (save_state(&stash))
                oidclr(&stash);
 
-       for (i = 0; !merge_was_ok && i < use_strategies_nr; i++) {
+       for (i = 0; i < use_strategies_nr; i++) {
                int ret, cnt;
                if (i) {
                        printf(_("Rewinding the tree to pristine...\n"));
@@ -1683,7 +1708,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 */
                wt_strategy = use_strategies[i]->name;
 
-               ret = try_merge_strategy(use_strategies[i]->name,
+               ret = try_merge_strategy(wt_strategy,
                                         common, remoteheads,
                                         head_commit);
                /*
@@ -1693,16 +1718,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 */
                if (ret < 2) {
                        if (!ret) {
-                               if (option_commit) {
-                                       /* Automerge succeeded. */
-                                       automerge_was_ok = 1;
-                                       break;
-                               }
+                               /*
+                                * This strategy worked; no point in trying
+                                * another.
+                                */
                                merge_was_ok = 1;
+                               best_strategy = wt_strategy;
+                               break;
                        }
                        cnt = (use_strategies_nr > 1) ? evaluate_result() : 0;
                        if (best_cnt <= 0 || cnt <= best_cnt) {
-                               best_strategy = use_strategies[i]->name;
+                               best_strategy = wt_strategy;
                                best_cnt = cnt;
                        }
                }
@@ -1712,7 +1738,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * If we have a resulting tree, that means the strategy module
         * auto resolved the merge cleanly.
         */
-       if (automerge_was_ok) {
+       if (merge_was_ok && option_commit) {
+               automerge_was_ok = 1;
                ret = finish_automerge(head_commit, head_subsumed,
                                       common, remoteheads,
                                       &result_tree, wt_strategy);
index 5edbb7fe86e81fb09ca2245ba920bc8bccd18726..9b126d6ce0e7f5fbaa4a5616d45c0c9bfa41d5b5 100644 (file)
@@ -78,7 +78,7 @@ static struct option *add_common_options(struct option *prev)
 }
 
 static int git_multi_pack_index_write_config(const char *var, const char *value,
-                                            void *cb)
+                                            void *cb UNUSED)
 {
        if (!strcmp(var, "pack.writebitmaphashcache")) {
                if (git_config_bool(var, value))
@@ -87,6 +87,13 @@ static int git_multi_pack_index_write_config(const char *var, const char *value,
                        opts.flags &= ~MIDX_WRITE_BITMAP_HASH_CACHE;
        }
 
+       if (!strcmp(var, "pack.writebitmaplookuptable")) {
+               if (git_config_bool(var, value))
+                       opts.flags |= MIDX_WRITE_BITMAP_LOOKUP_TABLE;
+               else
+                       opts.flags &= ~MIDX_WRITE_BITMAP_LOOKUP_TABLE;
+       }
+
        /*
         * We should never make a fall-back call to 'git_default_config', since
         * this was already called in 'cmd_multi_pack_index()'.
@@ -104,7 +111,8 @@ static void read_packs_from_stdin(struct string_list *to)
        strbuf_release(&buf);
 }
 
-static int cmd_multi_pack_index_write(int argc, const char **argv)
+static int cmd_multi_pack_index_write(int argc, const char **argv,
+                                     const char *prefix)
 {
        struct option *options;
        static struct option builtin_multi_pack_index_write_options[] = {
@@ -132,9 +140,9 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
 
        if (isatty(2))
                opts.flags |= MIDX_PROGRESS;
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             options, builtin_multi_pack_index_write_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            0);
        if (argc)
                usage_with_options(builtin_multi_pack_index_write_usage,
                                   options);
@@ -160,7 +168,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
                               opts.refs_snapshot, opts.flags);
 }
 
-static int cmd_multi_pack_index_verify(int argc, const char **argv)
+static int cmd_multi_pack_index_verify(int argc, const char **argv,
+                                      const char *prefix)
 {
        struct option *options;
        static struct option builtin_multi_pack_index_verify_options[] = {
@@ -174,9 +183,9 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv)
 
        if (isatty(2))
                opts.flags |= MIDX_PROGRESS;
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             options, builtin_multi_pack_index_verify_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            0);
        if (argc)
                usage_with_options(builtin_multi_pack_index_verify_usage,
                                   options);
@@ -186,7 +195,8 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv)
        return verify_midx_file(the_repository, opts.object_dir, opts.flags);
 }
 
-static int cmd_multi_pack_index_expire(int argc, const char **argv)
+static int cmd_multi_pack_index_expire(int argc, const char **argv,
+                                      const char *prefix)
 {
        struct option *options;
        static struct option builtin_multi_pack_index_expire_options[] = {
@@ -200,9 +210,9 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv)
 
        if (isatty(2))
                opts.flags |= MIDX_PROGRESS;
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             options, builtin_multi_pack_index_expire_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            0);
        if (argc)
                usage_with_options(builtin_multi_pack_index_expire_usage,
                                   options);
@@ -212,7 +222,8 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv)
        return expire_midx_packs(the_repository, opts.object_dir, opts.flags);
 }
 
-static int cmd_multi_pack_index_repack(int argc, const char **argv)
+static int cmd_multi_pack_index_repack(int argc, const char **argv,
+                                      const char *prefix)
 {
        struct option *options;
        static struct option builtin_multi_pack_index_repack_options[] = {
@@ -229,10 +240,10 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv)
 
        if (isatty(2))
                opts.flags |= MIDX_PROGRESS;
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             options,
                             builtin_multi_pack_index_repack_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            0);
        if (argc)
                usage_with_options(builtin_multi_pack_index_repack_usage,
                                   options);
@@ -247,7 +258,15 @@ int cmd_multi_pack_index(int argc, const char **argv,
                         const char *prefix)
 {
        int res;
-       struct option *builtin_multi_pack_index_options = common_opts;
+       parse_opt_subcommand_fn *fn = NULL;
+       struct option builtin_multi_pack_index_options[] = {
+               OPT_SUBCOMMAND("repack", &fn, cmd_multi_pack_index_repack),
+               OPT_SUBCOMMAND("write", &fn, cmd_multi_pack_index_write),
+               OPT_SUBCOMMAND("verify", &fn, cmd_multi_pack_index_verify),
+               OPT_SUBCOMMAND("expire", &fn, cmd_multi_pack_index_expire),
+               OPT_END(),
+       };
+       struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
 
        git_config(git_default_config, NULL);
 
@@ -256,31 +275,12 @@ int cmd_multi_pack_index(int argc, const char **argv,
            the_repository->objects->odb)
                opts.object_dir = xstrdup(the_repository->objects->odb->path);
 
-       argc = parse_options(argc, argv, prefix,
-                            builtin_multi_pack_index_options,
-                            builtin_multi_pack_index_usage,
-                            PARSE_OPT_STOP_AT_NON_OPTION);
-
-       if (!argc)
-               goto usage;
-
-       if (!strcmp(argv[0], "repack"))
-               res = cmd_multi_pack_index_repack(argc, argv);
-       else if (!strcmp(argv[0], "write"))
-               res =  cmd_multi_pack_index_write(argc, argv);
-       else if (!strcmp(argv[0], "verify"))
-               res =  cmd_multi_pack_index_verify(argc, argv);
-       else if (!strcmp(argv[0], "expire"))
-               res =  cmd_multi_pack_index_expire(argc, argv);
-       else {
-               error(_("unrecognized subcommand: %s"), argv[0]);
-               goto usage;
-       }
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_multi_pack_index_usage, 0);
+       FREE_AND_NULL(options);
+
+       res = fn(argc, argv, prefix);
 
        free(opts.object_dir);
        return res;
-
-usage:
-       usage_with_options(builtin_multi_pack_index_usage,
-                          builtin_multi_pack_index_options);
 }
index 83a465ba831adf94561a13f3d358926f516fe9ac..3413ad1c9b14ca7f0ed8946682c293a371b70f17 100644 (file)
 #include "string-list.h"
 #include "parse-options.h"
 #include "submodule.h"
+#include "entry.h"
 
 static const char * const builtin_mv_usage[] = {
        N_("git mv [<options>] <source>... <destination>"),
        NULL
 };
 
+enum update_mode {
+       WORKING_DIRECTORY = (1 << 1),
+       INDEX = (1 << 2),
+       SPARSE = (1 << 3),
+       SKIP_WORKTREE_DIR = (1 << 4),
+};
+
 #define DUP_BASENAME 1
 #define KEEP_TRAILING_SLASH 2
 
@@ -63,7 +71,7 @@ static const char **internal_prefix_pathspec(const char *prefix,
 static const char *add_slash(const char *path)
 {
        size_t len = strlen(path);
-       if (path[len - 1] != '/') {
+       if (len && path[len - 1] != '/') {
                char *with_slash = xmalloc(st_add(len, 2));
                memcpy(with_slash, path, len);
                with_slash[len++] = '/';
@@ -115,6 +123,39 @@ static int index_range_of_same_dir(const char *src, int length,
        return last - first;
 }
 
+/*
+ * Given the path of a directory that does not exist on-disk, check whether the
+ * directory contains any entries in the index with the SKIP_WORKTREE flag
+ * enabled.
+ * Return 1 if such index entries exist.
+ * Return 0 otherwise.
+ */
+static int empty_dir_has_sparse_contents(const char *name)
+{
+       int ret = 0;
+       const char *with_slash = add_slash(name);
+       int length = strlen(with_slash);
+
+       int pos = cache_name_pos(with_slash, length);
+       const struct cache_entry *ce;
+
+       if (pos < 0) {
+               pos = -pos - 1;
+               if (pos >= the_index.cache_nr)
+                       goto free_return;
+               ce = active_cache[pos];
+               if (strncmp(with_slash, ce->name, length))
+                       goto free_return;
+               if (ce_skip_worktree(ce))
+                       ret = 1;
+       }
+
+free_return:
+       if (with_slash != name)
+               free((char *)with_slash);
+       return ret;
+}
+
 int cmd_mv(int argc, const char **argv, const char *prefix)
 {
        int i, flags, gitmodules_modified = 0;
@@ -129,12 +170,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                OPT_END(),
        };
        const char **source, **destination, **dest_path, **submodule_gitfile;
-       enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX, SPARSE } *modes;
+       const char *dst_w_slash;
+       const char **src_dir = NULL;
+       int src_dir_nr = 0, src_dir_alloc = 0;
+       struct strbuf a_src_dir = STRBUF_INIT;
+       enum update_mode *modes, dst_mode = 0;
        struct stat st;
        struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
        struct lock_file lock_file = LOCK_INIT;
        struct cache_entry *ce;
        struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
+       struct string_list dirty_paths = STRING_LIST_INIT_NODUP;
 
        git_config(git_default_config, NULL);
 
@@ -148,7 +194,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                die(_("index file corrupt"));
 
        source = internal_prefix_pathspec(prefix, argv, argc, 0);
-       modes = xcalloc(argc, sizeof(enum update_mode));
+       CALLOC_ARRAY(modes, argc);
+
        /*
         * Keep trailing slash, needed to let
         * "git mv file no-such-dir/" error out, except in the case
@@ -158,6 +205,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
                flags = 0;
        dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
+       dst_w_slash = add_slash(dest_path[0]);
        submodule_gitfile = xcalloc(argc, sizeof(char *));
 
        if (dest_path[0][0] == '\0')
@@ -165,18 +213,37 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
        else if (!lstat(dest_path[0], &st) &&
                        S_ISDIR(st.st_mode)) {
-               dest_path[0] = add_slash(dest_path[0]);
-               destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
+               destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
        } else {
-               if (argc != 1)
+               if (!path_in_sparse_checkout(dst_w_slash, &the_index) &&
+                   empty_dir_has_sparse_contents(dst_w_slash)) {
+                       destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
+                       dst_mode = SKIP_WORKTREE_DIR;
+               } else if (argc != 1) {
                        die(_("destination '%s' is not a directory"), dest_path[0]);
-               destination = dest_path;
+               } else {
+                       destination = dest_path;
+                       /*
+                        * <destination> is a file outside of sparse-checkout
+                        * cone. Insist on cone mode here for backward
+                        * compatibility. We don't want dst_mode to be assigned
+                        * for a file when the repo is using no-cone mode (which
+                        * is deprecated at this point) sparse-checkout. As
+                        * SPARSE here is only considering cone-mode situation.
+                        */
+                       if (!path_in_cone_mode_sparse_checkout(destination[0], &the_index))
+                               dst_mode = SPARSE;
+               }
+       }
+       if (dst_w_slash != dest_path[0]) {
+               free((char *)dst_w_slash);
+               dst_w_slash = NULL;
        }
 
        /* Checking */
        for (i = 0; i < argc; i++) {
                const char *src = source[i], *dst = destination[i];
-               int length, src_is_dir;
+               int length;
                const char *bad = NULL;
                int skip_sparse = 0;
 
@@ -185,54 +252,107 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 
                length = strlen(src);
                if (lstat(src, &st) < 0) {
-                       /* only error if existence is expected. */
-                       if (modes[i] != SPARSE)
+                       int pos;
+                       const struct cache_entry *ce;
+
+                       pos = cache_name_pos(src, length);
+                       if (pos < 0) {
+                               const char *src_w_slash = add_slash(src);
+                               if (!path_in_sparse_checkout(src_w_slash, &the_index) &&
+                                   empty_dir_has_sparse_contents(src)) {
+                                       modes[i] |= SKIP_WORKTREE_DIR;
+                                       goto dir_check;
+                               }
+                               /* only error if existence is expected. */
+                               if (!(modes[i] & SPARSE))
+                                       bad = _("bad source");
+                               goto act_on_entry;
+                       }
+                       ce = active_cache[pos];
+                       if (!ce_skip_worktree(ce)) {
                                bad = _("bad source");
-               } else if (!strncmp(src, dst, length) &&
-                               (dst[length] == 0 || dst[length] == '/')) {
+                               goto act_on_entry;
+                       }
+                       if (!ignore_sparse) {
+                               string_list_append(&only_match_skip_worktree, src);
+                               goto act_on_entry;
+                       }
+                       /* Check if dst exists in index */
+                       if (cache_name_pos(dst, strlen(dst)) < 0) {
+                               modes[i] |= SPARSE;
+                               goto act_on_entry;
+                       }
+                       if (!force) {
+                               bad = _("destination exists");
+                               goto act_on_entry;
+                       }
+                       modes[i] |= SPARSE;
+                       goto act_on_entry;
+               }
+               if (!strncmp(src, dst, length) &&
+                   (dst[length] == 0 || dst[length] == '/')) {
                        bad = _("can not move directory into itself");
-               } else if ((src_is_dir = S_ISDIR(st.st_mode))
-                               && lstat(dst, &st) == 0)
+                       goto act_on_entry;
+               }
+               if (S_ISDIR(st.st_mode)
+                   && lstat(dst, &st) == 0) {
                        bad = _("cannot move directory over file");
-               else if (src_is_dir) {
+                       goto act_on_entry;
+               }
+
+dir_check:
+               if (S_ISDIR(st.st_mode)) {
+                       int j, dst_len, n;
                        int first = cache_name_pos(src, length), last;
 
-                       if (first >= 0)
+                       if (first >= 0) {
                                prepare_move_submodule(src, first,
                                                       submodule_gitfile + i);
-                       else if (index_range_of_same_dir(src, length,
-                                                        &first, &last) < 1)
+                               goto act_on_entry;
+                       } else if (index_range_of_same_dir(src, length,
+                                                          &first, &last) < 1) {
                                bad = _("source directory is empty");
-                       else { /* last - first >= 1 */
-                               int j, dst_len, n;
-
-                               modes[i] = WORKING_DIRECTORY;
-                               n = argc + last - first;
-                               REALLOC_ARRAY(source, n);
-                               REALLOC_ARRAY(destination, n);
-                               REALLOC_ARRAY(modes, n);
-                               REALLOC_ARRAY(submodule_gitfile, n);
-
-                               dst = add_slash(dst);
-                               dst_len = strlen(dst);
-
-                               for (j = 0; j < last - first; j++) {
-                                       const struct cache_entry *ce = active_cache[first + j];
-                                       const char *path = ce->name;
-                                       source[argc + j] = path;
-                                       destination[argc + j] =
-                                               prefix_path(dst, dst_len, path + length + 1);
-                                       modes[argc + j] = ce_skip_worktree(ce) ? SPARSE : INDEX;
-                                       submodule_gitfile[argc + j] = NULL;
-                               }
-                               argc += last - first;
+                               goto act_on_entry;
                        }
-               } else if (!(ce = cache_file_exists(src, length, 0))) {
+
+                       /* last - first >= 1 */
+                       modes[i] |= WORKING_DIRECTORY;
+
+                       ALLOC_GROW(src_dir, src_dir_nr + 1, src_dir_alloc);
+                       src_dir[src_dir_nr++] = src;
+
+                       n = argc + last - first;
+                       REALLOC_ARRAY(source, n);
+                       REALLOC_ARRAY(destination, n);
+                       REALLOC_ARRAY(modes, n);
+                       REALLOC_ARRAY(submodule_gitfile, n);
+
+                       dst = add_slash(dst);
+                       dst_len = strlen(dst);
+
+                       for (j = 0; j < last - first; j++) {
+                               const struct cache_entry *ce = active_cache[first + j];
+                               const char *path = ce->name;
+                               source[argc + j] = path;
+                               destination[argc + j] =
+                                       prefix_path(dst, dst_len, path + length + 1);
+                               memset(modes + argc + j, 0, sizeof(enum update_mode));
+                               modes[argc + j] |= ce_skip_worktree(ce) ? SPARSE : INDEX;
+                               submodule_gitfile[argc + j] = NULL;
+                       }
+                       argc += last - first;
+                       goto act_on_entry;
+               }
+               if (!(ce = cache_file_exists(src, length, 0))) {
                        bad = _("not under version control");
-               } else if (ce_stage(ce)) {
+                       goto act_on_entry;
+               }
+               if (ce_stage(ce)) {
                        bad = _("conflicted");
-               } else if (lstat(dst, &st) == 0 &&
-                        (!ignore_case || strcasecmp(src, dst))) {
+                       goto act_on_entry;
+               }
+               if (lstat(dst, &st) == 0 &&
+                   (!ignore_case || strcasecmp(src, dst))) {
                        bad = _("destination exists");
                        if (force) {
                                /*
@@ -246,34 +366,52 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                                } else
                                        bad = _("Cannot overwrite");
                        }
-               } else if (string_list_has_string(&src_for_dst, dst))
+                       goto act_on_entry;
+               }
+               if (string_list_has_string(&src_for_dst, dst)) {
                        bad = _("multiple sources for the same target");
-               else if (is_dir_sep(dst[strlen(dst) - 1]))
+                       goto act_on_entry;
+               }
+               if (is_dir_sep(dst[strlen(dst) - 1])) {
                        bad = _("destination directory does not exist");
-               else {
-                       /*
-                        * We check if the paths are in the sparse-checkout
-                        * definition as a very final check, since that
-                        * allows us to point the user to the --sparse
-                        * option as a way to have a successful run.
-                        */
-                       if (!ignore_sparse &&
-                           !path_in_sparse_checkout(src, &the_index)) {
-                               string_list_append(&only_match_skip_worktree, src);
-                               skip_sparse = 1;
-                       }
-                       if (!ignore_sparse &&
-                           !path_in_sparse_checkout(dst, &the_index)) {
-                               string_list_append(&only_match_skip_worktree, dst);
-                               skip_sparse = 1;
+                       goto act_on_entry;
+               }
+
+               if (ignore_sparse &&
+                   (dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
+                   index_entry_exists(&the_index, dst, strlen(dst))) {
+                       bad = _("destination exists in the index");
+                       if (force) {
+                               if (verbose)
+                                       warning(_("overwriting '%s'"), dst);
+                               bad = NULL;
+                       } else {
+                               goto act_on_entry;
                        }
+               }
+               /*
+                * We check if the paths are in the sparse-checkout
+                * definition as a very final check, since that
+                * allows us to point the user to the --sparse
+                * option as a way to have a successful run.
+                */
+               if (!ignore_sparse &&
+                   !path_in_sparse_checkout(src, &the_index)) {
+                       string_list_append(&only_match_skip_worktree, src);
+                       skip_sparse = 1;
+               }
+               if (!ignore_sparse &&
+                   !path_in_sparse_checkout(dst, &the_index)) {
+                       string_list_append(&only_match_skip_worktree, dst);
+                       skip_sparse = 1;
+               }
 
-                       if (skip_sparse)
-                               goto remove_entry;
+               if (skip_sparse)
+                       goto remove_entry;
 
-                       string_list_insert(&src_for_dst, dst);
-               }
+               string_list_insert(&src_for_dst, dst);
 
+act_on_entry:
                if (!bad)
                        continue;
                if (!ignore_errors)
@@ -282,14 +420,11 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 remove_entry:
                if (--argc > 0) {
                        int n = argc - i;
-                       memmove(source + i, source + i + 1,
-                               n * sizeof(char *));
-                       memmove(destination + i, destination + i + 1,
-                               n * sizeof(char *));
-                       memmove(modes + i, modes + i + 1,
-                               n * sizeof(enum update_mode));
-                       memmove(submodule_gitfile + i, submodule_gitfile + i + 1,
-                               n * sizeof(char *));
+                       MOVE_ARRAY(source + i, source + i + 1, n);
+                       MOVE_ARRAY(destination + i, destination + i + 1, n);
+                       MOVE_ARRAY(modes + i, modes + i + 1, n);
+                       MOVE_ARRAY(submodule_gitfile + i,
+                                  submodule_gitfile + i + 1, n);
                        i--;
                }
        }
@@ -304,11 +439,19 @@ remove_entry:
                const char *src = source[i], *dst = destination[i];
                enum update_mode mode = modes[i];
                int pos;
+               int sparse_and_dirty = 0;
+               struct checkout state = CHECKOUT_INIT;
+               state.istate = &the_index;
+
+               if (force)
+                       state.force = 1;
                if (show_only || verbose)
                        printf(_("Renaming %s to %s\n"), src, dst);
                if (show_only)
                        continue;
-               if (mode != INDEX && mode != SPARSE && rename(src, dst) < 0) {
+               if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR)) &&
+                   !(dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
+                   rename(src, dst) < 0) {
                        if (ignore_errors)
                                continue;
                        die_errno(_("renaming '%s' failed"), src);
@@ -322,14 +465,86 @@ remove_entry:
                                                              1);
                }
 
-               if (mode == WORKING_DIRECTORY)
+               if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
                        continue;
 
                pos = cache_name_pos(src, strlen(src));
                assert(pos >= 0);
+               if (!(mode & SPARSE) && !lstat(src, &st))
+                       sparse_and_dirty = ce_modified(active_cache[pos], &st, 0);
                rename_cache_entry_at(pos, dst);
+
+               if (ignore_sparse &&
+                   core_apply_sparse_checkout &&
+                   core_sparse_checkout_cone) {
+                       /*
+                        * NEEDSWORK: we are *not* paying attention to
+                        * "out-to-out" move (<source> is out-of-cone and
+                        * <destination> is out-of-cone) at this point. It
+                        * should be added in a future patch.
+                        */
+                       if ((mode & SPARSE) &&
+                           path_in_sparse_checkout(dst, &the_index)) {
+                               /* from out-of-cone to in-cone */
+                               int dst_pos = cache_name_pos(dst, strlen(dst));
+                               struct cache_entry *dst_ce = active_cache[dst_pos];
+
+                               dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
+
+                               if (checkout_entry(dst_ce, &state, NULL, NULL))
+                                       die(_("cannot checkout %s"), dst_ce->name);
+                       } else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
+                                  !(mode & SPARSE) &&
+                                  !path_in_sparse_checkout(dst, &the_index)) {
+                               /* from in-cone to out-of-cone */
+                               int dst_pos = cache_name_pos(dst, strlen(dst));
+                               struct cache_entry *dst_ce = active_cache[dst_pos];
+
+                               /*
+                                * if src is clean, it will suffice to remove it
+                                */
+                               if (!sparse_and_dirty) {
+                                       dst_ce->ce_flags |= CE_SKIP_WORKTREE;
+                                       unlink_or_warn(src);
+                               } else {
+                                       /*
+                                        * if src is dirty, move it to the
+                                        * destination and create leading
+                                        * dirs if necessary
+                                        */
+                                       char *dst_dup = xstrdup(dst);
+                                       string_list_append(&dirty_paths, dst);
+                                       safe_create_leading_directories(dst_dup);
+                                       FREE_AND_NULL(dst_dup);
+                                       rename(src, dst);
+                               }
+                       }
+               }
        }
 
+       /*
+        * cleanup the empty src_dirs
+        */
+       for (i = 0; i < src_dir_nr; i++) {
+               int dummy;
+               strbuf_addstr(&a_src_dir, src_dir[i]);
+               /*
+                * if entries under a_src_dir are all moved away,
+                * recursively remove a_src_dir to cleanup
+                */
+               if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
+                                           &dummy, &dummy) < 1) {
+                       remove_dir_recursively(&a_src_dir, 0);
+               }
+               strbuf_reset(&a_src_dir);
+       }
+
+       strbuf_release(&a_src_dir);
+       free(src_dir);
+
+       if (dirty_paths.nr)
+               advise_on_moving_dirty_path(&dirty_paths);
+
        if (gitmodules_modified)
                stage_updated_gitmodules(&the_index);
 
@@ -338,6 +553,7 @@ remove_entry:
                die(_("Unable to write new index file"));
 
        string_list_clear(&src_for_dst, 0);
+       string_list_clear(&dirty_paths, 0);
        UNLEAK(source);
        UNLEAK(dest_path);
        free(submodule_gitfile);
index 580b1eb170ef5793e8f3f6a231291c87aec47fe1..15535e914a6939d661296798e0b325da9f1ac7b6 100644 (file)
@@ -344,7 +344,8 @@ static int cmp_by_tag_and_age(const void *a_, const void *b_)
        return a->taggerdate != b->taggerdate;
 }
 
-static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
+static int name_ref(const char *path, const struct object_id *oid,
+                   int flags UNUSED, void *cb_data)
 {
        struct object *o = parse_object(the_repository, oid);
        struct name_ref_data *data = cb_data;
index a3d0d15a227f2142f2d9d5fddbe0017d0e7a5c7f..be51f692257f67e2765feb6ff63e8037f3a4f00d 100644 (file)
@@ -994,17 +994,34 @@ static int get_ref(int argc, const char **argv, const char *prefix)
 
 int cmd_notes(int argc, const char **argv, const char *prefix)
 {
-       int result;
        const char *override_notes_ref = NULL;
+       parse_opt_subcommand_fn *fn = NULL;
        struct option options[] = {
                OPT_STRING(0, "ref", &override_notes_ref, N_("notes-ref"),
                           N_("use notes from <notes-ref>")),
+               OPT_SUBCOMMAND("list", &fn, list),
+               OPT_SUBCOMMAND("add", &fn, add),
+               OPT_SUBCOMMAND("copy", &fn, copy),
+               OPT_SUBCOMMAND("append", &fn, append_edit),
+               OPT_SUBCOMMAND("edit", &fn, append_edit),
+               OPT_SUBCOMMAND("show", &fn, show),
+               OPT_SUBCOMMAND("merge", &fn, merge),
+               OPT_SUBCOMMAND("remove", &fn, remove_cmd),
+               OPT_SUBCOMMAND("prune", &fn, prune),
+               OPT_SUBCOMMAND("get-ref", &fn, get_ref),
                OPT_END()
        };
 
        git_config(git_default_config, NULL);
        argc = parse_options(argc, argv, prefix, options, git_notes_usage,
-                            PARSE_OPT_STOP_AT_NON_OPTION);
+                            PARSE_OPT_SUBCOMMAND_OPTIONAL);
+       if (!fn) {
+               if (argc) {
+                       error(_("unknown subcommand: `%s'"), argv[0]);
+                       usage_with_options(git_notes_usage, options);
+               }
+               fn = list;
+       }
 
        if (override_notes_ref) {
                struct strbuf sb = STRBUF_INIT;
@@ -1014,28 +1031,5 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
                strbuf_release(&sb);
        }
 
-       if (argc < 1 || !strcmp(argv[0], "list"))
-               result = list(argc, argv, prefix);
-       else if (!strcmp(argv[0], "add"))
-               result = add(argc, argv, prefix);
-       else if (!strcmp(argv[0], "copy"))
-               result = copy(argc, argv, prefix);
-       else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit"))
-               result = append_edit(argc, argv, prefix);
-       else if (!strcmp(argv[0], "show"))
-               result = show(argc, argv, prefix);
-       else if (!strcmp(argv[0], "merge"))
-               result = merge(argc, argv, prefix);
-       else if (!strcmp(argv[0], "remove"))
-               result = remove_cmd(argc, argv, prefix);
-       else if (!strcmp(argv[0], "prune"))
-               result = prune(argc, argv, prefix);
-       else if (!strcmp(argv[0], "get-ref"))
-               result = get_ref(argc, argv, prefix);
-       else {
-               result = error(_("unknown subcommand: %s"), argv[0]);
-               usage_with_options(git_notes_usage, options);
-       }
-
-       return result ? 1 : 0;
+       return !!fn(argc, argv, prefix);
 }
index 39e28cfcafc3d361dbea42d4c4f7f4c1ca09728b..3658c05cafce7a1735ece0510a9aaacadb46fae9 100644 (file)
@@ -759,8 +759,8 @@ static enum write_one_status write_one(struct hashfile *f,
        return WRITE_ONE_WRITTEN;
 }
 
-static int mark_tagged(const char *path, const struct object_id *oid, int flag,
-                      void *cb_data)
+static int mark_tagged(const char *path UNUSED, const struct object_id *oid,
+                      int flag UNUSED, void *cb_data UNUSED)
 {
        struct object_id peeled;
        struct object_entry *entry = packlist_find(&to_pack, oid);
@@ -3035,7 +3035,8 @@ static void add_tag_chain(const struct object_id *oid)
        }
 }
 
-static int add_ref_tag(const char *tag, const struct object_id *oid, int flag, void *cb_data)
+static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid,
+                      int flag UNUSED, void *cb_data UNUSED)
 {
        struct object_id peeled;
 
@@ -3148,6 +3149,14 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                else
                        write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE;
        }
+
+       if (!strcmp(k, "pack.writebitmaplookuptable")) {
+               if (git_config_bool(k, v))
+                       write_bitmap_options |= BITMAP_OPT_LOOKUP_TABLE;
+               else
+                       write_bitmap_options &= ~BITMAP_OPT_LOOKUP_TABLE;
+       }
+
        if (!strcmp(k, "pack.usebitmaps")) {
                use_bitmap_index_default = git_config_bool(k, v);
                return 0;
@@ -3950,8 +3959,9 @@ static void record_recent_commit(struct commit *commit, void *data)
 }
 
 static int mark_bitmap_preferred_tip(const char *refname,
-                                    const struct object_id *oid, int flags,
-                                    void *_data)
+                                    const struct object_id *oid,
+                                    int flags UNUSED,
+                                    void *data UNUSED)
 {
        struct object_id peeled;
        struct object *object;
index 01155ba67b20d6593e09b239d8a5bbb3eb195535..403a24d7ca670f9a5c56ebfb6d8429b5e5817b54 100644 (file)
@@ -990,6 +990,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        int rebase_unspecified = 0;
        int can_ff;
        int divergent;
+       int ret;
 
        if (!getenv("GIT_REFLOG_ACTION"))
                set_reflog_message(argc, argv);
@@ -1100,7 +1101,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        if (is_null_oid(&orig_head)) {
                if (merge_heads.nr > 1)
                        die(_("Cannot merge multiple branches into empty head."));
-               return pull_into_void(merge_heads.oid, &curr_head);
+               ret = pull_into_void(merge_heads.oid, &curr_head);
+               goto cleanup;
        }
        if (merge_heads.nr > 1) {
                if (opt_rebase)
@@ -1125,8 +1127,6 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
        }
 
        if (opt_rebase) {
-               int ret = 0;
-
                struct object_id newbase;
                struct object_id upstream;
                get_rebase_newbase_and_upstream(&newbase, &upstream, &curr_head,
@@ -1149,12 +1149,16 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                             recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
                        ret = rebase_submodules();
 
-               return ret;
+               goto cleanup;
        } else {
-               int ret = run_merge();
+               ret = run_merge();
                if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
                             recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
                        ret = update_submodules();
-               return ret;
+               goto cleanup;
        }
+
+cleanup:
+       oid_array_clear(&merge_heads);
+       return ret;
 }
index 50318849d657ea298ae8984decdc2ae870a62741..e2a74efb42a795a5139932bd052999d050cab420 100644 (file)
@@ -38,8 +38,10 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
        struct option *options;
-       int res = 0;
+       int i, dash_dash = -1, res = 0;
        struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT;
+       struct object_id oid;
+       const char *three_dots = NULL;
 
        git_config(git_diff_ui_config, NULL);
 
@@ -47,7 +49,7 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
 
        options = parse_options_concat(range_diff_options, diffopt.parseopts);
        argc = parse_options(argc, argv, prefix, options,
-                            builtin_range_diff_usage, 0);
+                            builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
 
        diff_setup_done(&diffopt);
 
@@ -55,40 +57,91 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
        if (!simple_color)
                diffopt.use_color = 1;
 
-       if (argc == 2) {
-               if (!is_range_diff_range(argv[0]))
-                       die(_("not a commit range: '%s'"), argv[0]);
-               strbuf_addstr(&range1, argv[0]);
+       for (i = 0; i < argc; i++)
+               if (!strcmp(argv[i], "--")) {
+                       dash_dash = i;
+                       break;
+               }
+
+       if (dash_dash == 3 ||
+           (dash_dash < 0 && argc > 2 &&
+            !get_oid_committish(argv[0], &oid) &&
+            !get_oid_committish(argv[1], &oid) &&
+            !get_oid_committish(argv[2], &oid))) {
+               if (dash_dash < 0)
+                       ; /* already validated arguments */
+               else if (get_oid_committish(argv[0], &oid))
+                       usage_msg_optf(_("not a revision: '%s'"),
+                                      builtin_range_diff_usage, options,
+                                      argv[0]);
+               else if (get_oid_committish(argv[1], &oid))
+                       usage_msg_optf(_("not a revision: '%s'"),
+                                      builtin_range_diff_usage, options,
+                                      argv[1]);
+               else if (get_oid_committish(argv[2], &oid))
+                       usage_msg_optf(_("not a revision: '%s'"),
+                                      builtin_range_diff_usage, options,
+                                      argv[2]);
 
-               if (!is_range_diff_range(argv[1]))
-                       die(_("not a commit range: '%s'"), argv[1]);
-               strbuf_addstr(&range2, argv[1]);
-       } else if (argc == 3) {
                strbuf_addf(&range1, "%s..%s", argv[0], argv[1]);
                strbuf_addf(&range2, "%s..%s", argv[0], argv[2]);
-       } else if (argc == 1) {
-               const char *b = strstr(argv[0], "..."), *a = argv[0];
+
+               strvec_pushv(&other_arg, argv +
+                            (dash_dash < 0 ? 3 : dash_dash));
+       } else if (dash_dash == 2 ||
+                  (dash_dash < 0 && argc > 1 &&
+                   is_range_diff_range(argv[0]) &&
+                   is_range_diff_range(argv[1]))) {
+               if (dash_dash < 0)
+                       ; /* already validated arguments */
+               else if (!is_range_diff_range(argv[0]))
+                       usage_msg_optf(_("not a commit range: '%s'"),
+                                      builtin_range_diff_usage, options,
+                                      argv[0]);
+               else if (!is_range_diff_range(argv[1]))
+                       usage_msg_optf(_("not a commit range: '%s'"),
+                                      builtin_range_diff_usage, options,
+                                      argv[1]);
+
+               strbuf_addstr(&range1, argv[0]);
+               strbuf_addstr(&range2, argv[1]);
+
+               strvec_pushv(&other_arg, argv +
+                            (dash_dash < 0 ? 2 : dash_dash));
+       } else if (dash_dash == 1 ||
+                  (dash_dash < 0 && argc > 0 &&
+                   (three_dots = strstr(argv[0], "...")))) {
+               const char *a, *b;
                int a_len;
 
-               if (!b) {
-                       error(_("single arg format must be symmetric range"));
-                       usage_with_options(builtin_range_diff_usage, options);
-               }
+               if (dash_dash < 0)
+                       ; /* already validated arguments */
+               else if (!(three_dots = strstr(argv[0], "...")))
+                       usage_msg_optf(_("not a symmetric range: '%s'"),
+                                        builtin_range_diff_usage, options,
+                                        argv[0]);
 
-               a_len = (int)(b - a);
-               if (!a_len) {
+               if (three_dots == argv[0]) {
                        a = "HEAD";
                        a_len = strlen(a);
+               } else {
+                       a = argv[0];
+                       a_len = (int)(three_dots - a);
                }
-               b += 3;
-               if (!*b)
+
+               if (three_dots[3])
+                       b = three_dots + 3;
+               else
                        b = "HEAD";
+
                strbuf_addf(&range1, "%s..%.*s", b, a_len, a);
                strbuf_addf(&range2, "%.*s..%s", a_len, a, b);
-       } else {
-               error(_("need two commit ranges"));
-               usage_with_options(builtin_range_diff_usage, options);
-       }
+
+               strvec_pushv(&other_arg, argv +
+                            (dash_dash < 0 ? 1 : dash_dash));
+       } else
+               usage_msg_opt(_("need two commit ranges"),
+                             builtin_range_diff_usage, options);
        FREE_AND_NULL(options);
 
        range_diff_opts.dual_color = simple_color < 1;
index 70aa7c842f34b2a8cfbdf2c33d3b699bbda0404c..56e4214b44104a445f8b68d185c0aadd3442247d 100644 (file)
@@ -102,6 +102,7 @@ struct rebase_options {
        int reschedule_failed_exec;
        int reapply_cherry_picks;
        int fork_point;
+       int update_refs;
 };
 
 #define REBASE_OPTIONS_INIT {                          \
@@ -298,6 +299,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
                ret = complete_action(the_repository, &replay, flags,
                        shortrevisions, opts->onto_name, opts->onto,
                        &opts->orig_head, &commands, opts->autosquash,
+                       opts->update_refs,
                        &todo_list);
        }
 
@@ -800,6 +802,11 @@ static int rebase_config(const char *var, const char *value, void *data)
                return 0;
        }
 
+       if (!strcmp(var, "rebase.updaterefs")) {
+               opts->update_refs = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "rebase.reschedulefailedexec")) {
                opts->reschedule_failed_exec = git_config_bool(var, value);
                return 0;
@@ -1124,6 +1131,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "autosquash", &options.autosquash,
                         N_("move commits that begin with "
                            "squash!/fixup! under -i")),
+               OPT_BOOL(0, "update-refs", &options.update_refs,
+                        N_("update branches that point to commits "
+                           "that are being rebased")),
                { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
                        N_("GPG-sign commits"),
                        PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
index 31b48e728bedef2fae4c9024726a1222dcc81d7d..44bcea3a5b3add614c72531d112b7b4a9777751a 100644 (file)
@@ -291,7 +291,7 @@ static void show_ref(const char *path, const struct object_id *oid)
 }
 
 static int show_ref_cb(const char *path_full, const struct object_id *oid,
-                      int flag, void *data)
+                      int flag UNUSED, void *data)
 {
        struct oidset *seen = data;
        const char *path = strip_namespace(path_full);
@@ -465,7 +465,7 @@ static void rp_error(const char *err, ...)
        va_end(params);
 }
 
-static int copy_to_sideband(int in, int out, void *arg)
+static int copy_to_sideband(int in, int out UNUSED, void *arg UNUSED)
 {
        char data[128];
        int keepalive_active = 0;
index 4dd297dce86e5212087ee1202d5b9dd1f754f9d1..57c5c0d061c449a0cf782c2cc41688cc042e3c47 100644 (file)
@@ -56,7 +56,8 @@ struct worktree_reflogs {
        struct string_list reflogs;
 };
 
-static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
+static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
+                         int flags UNUSED, void *cb_data)
 {
        struct worktree_reflogs *cb = cb_data;
        struct worktree *worktree = cb->worktree;
@@ -193,6 +194,8 @@ static int expire_unreachable_callback(const struct option *opt,
 {
        struct cmd_reflog_expire_cb *cmd = opt->value;
 
+       BUG_ON_OPT_NEG(unset);
+
        if (parse_expiry_date(arg, &cmd->expire_unreachable))
                die(_("invalid timestamp '%s' given to '--%s'"),
                    arg, opt->long_name);
@@ -207,6 +210,8 @@ static int expire_total_callback(const struct option *opt,
 {
        struct cmd_reflog_expire_cb *cmd = opt->value;
 
+       BUG_ON_OPT_NEG(unset);
+
        if (parse_expiry_date(arg, &cmd->expire_total))
                die(_("invalid timestamp '%s' given to '--%s'"),
                    arg, opt->long_name);
@@ -223,7 +228,7 @@ static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
 
        parse_options(argc, argv, prefix, options, reflog_show_usage,
                      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
-                     PARSE_OPT_KEEP_UNKNOWN);
+                     PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        return cmd_log_reflog(argc, argv, prefix);
 }
@@ -404,40 +409,21 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
 
 int cmd_reflog(int argc, const char **argv, const char *prefix)
 {
+       parse_opt_subcommand_fn *fn = NULL;
        struct option options[] = {
+               OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
+               OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
+               OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
+               OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
                OPT_END()
        };
 
        argc = parse_options(argc, argv, prefix, options, reflog_usage,
+                            PARSE_OPT_SUBCOMMAND_OPTIONAL |
                             PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
-                            PARSE_OPT_KEEP_UNKNOWN |
-                            PARSE_OPT_NO_INTERNAL_HELP);
-
-       /*
-        * With "git reflog" we default to showing it. !argc is
-        * impossible with PARSE_OPT_KEEP_ARGV0.
-        */
-       if (argc == 1)
-               goto log_reflog;
-
-       if (!strcmp(argv[1], "-h"))
-               usage_with_options(reflog_usage, options);
-       else if (*argv[1] == '-')
-               goto log_reflog;
-
-       if (!strcmp(argv[1], "show"))
-               return cmd_reflog_show(argc - 1, argv + 1, prefix);
-       else if (!strcmp(argv[1], "expire"))
-               return cmd_reflog_expire(argc - 1, argv + 1, prefix);
-       else if (!strcmp(argv[1], "delete"))
-               return cmd_reflog_delete(argc - 1, argv + 1, prefix);
-       else if (!strcmp(argv[1], "exists"))
-               return cmd_reflog_exists(argc - 1, argv + 1, prefix);
-
-       /*
-        * Fall-through for e.g. "git reflog -1", "git reflog master",
-        * as well as the plain "git reflog" above goto above.
-        */
-log_reflog:
-       return cmd_log_reflog(argc, argv, prefix);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
+       if (fn)
+               return fn(argc - 1, argv + 1, prefix);
+       else
+               return cmd_log_reflog(argc, argv, prefix);
 }
index a3a0c27d7a09da9f5df1f258d3c21fe426690ea0..985b845a18bae82bfa90d63da78fca8445563d51 100644 (file)
@@ -150,7 +150,7 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
        return 0;
 }
 
-static int add(int argc, const char **argv)
+static int add(int argc, const char **argv, const char *prefix)
 {
        int fetch = 0, fetch_tags = TAGS_DEFAULT;
        unsigned mirror = MIRROR_NONE;
@@ -177,8 +177,8 @@ static int add(int argc, const char **argv)
                OPT_END()
        };
 
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_add_usage,
-                            0);
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_add_usage, 0);
 
        if (argc != 2)
                usage_with_options(builtin_remote_add_usage, options);
@@ -264,7 +264,8 @@ static const char *abbrev_ref(const char *name, const char *prefix)
 }
 #define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
 
-static int config_read_branches(const char *key, const char *value, void *cb)
+static int config_read_branches(const char *key, const char *value,
+                               void *data UNUSED)
 {
        const char *orig_key = key;
        char *name;
@@ -344,12 +345,13 @@ static void read_branches(void)
 
 struct ref_states {
        struct remote *remote;
-       struct string_list new_refs, stale, tracked, heads, push;
+       struct string_list new_refs, skipped, stale, tracked, heads, push;
        int queried;
 };
 
 #define REF_STATES_INIT { \
        .new_refs = STRING_LIST_INIT_DUP, \
+       .skipped = STRING_LIST_INIT_DUP, \
        .stale = STRING_LIST_INIT_DUP, \
        .tracked = STRING_LIST_INIT_DUP, \
        .heads = STRING_LIST_INIT_DUP, \
@@ -368,7 +370,9 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
                                states->remote->fetch.raw[i]);
 
        for (ref = fetch_map; ref; ref = ref->next) {
-               if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))
+               if (omit_name_by_refspec(ref->name, &states->remote->fetch))
+                       string_list_append(&states->skipped, abbrev_branch(ref->name));
+               else if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))
                        string_list_append(&states->new_refs, abbrev_branch(ref->name));
                else
                        string_list_append(&states->tracked, abbrev_branch(ref->name));
@@ -383,6 +387,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
        free_refs(fetch_map);
 
        string_list_sort(&states->new_refs);
+       string_list_sort(&states->skipped);
        string_list_sort(&states->tracked);
        string_list_sort(&states->stale);
 
@@ -534,7 +539,8 @@ struct branches_for_remote {
 };
 
 static int add_branch_for_removal(const char *refname,
-       const struct object_id *oid, int flags, void *cb_data)
+                                 const struct object_id *oid UNUSED,
+                                 int flags UNUSED, void *cb_data)
 {
        struct branches_for_remote *branches = cb_data;
        struct refspec_item refspec;
@@ -576,7 +582,8 @@ struct rename_info {
 };
 
 static int read_remote_branches(const char *refname,
-       const struct object_id *oid, int flags, void *cb_data)
+                               const struct object_id *oid UNUSED,
+                               int flags UNUSED, void *cb_data)
 {
        struct rename_info *rename = cb_data;
        struct strbuf buf = STRBUF_INIT;
@@ -676,7 +683,7 @@ static void handle_push_default(const char* old_name, const char* new_name)
 }
 
 
-static int mv(int argc, const char **argv)
+static int mv(int argc, const char **argv, const char *prefix)
 {
        int show_progress = isatty(2);
        struct option options[] = {
@@ -691,7 +698,7 @@ static int mv(int argc, const char **argv)
        int i, refs_renamed_nr = 0, refspec_updated = 0;
        struct progress *progress = NULL;
 
-       argc = parse_options(argc, argv, NULL, options,
+       argc = parse_options(argc, argv, prefix, options,
                             builtin_remote_rename_usage, 0);
 
        if (argc != 2)
@@ -840,7 +847,7 @@ static int mv(int argc, const char **argv)
        return 0;
 }
 
-static int rm(int argc, const char **argv)
+static int rm(int argc, const char **argv, const char *prefix)
 {
        struct option options[] = {
                OPT_END()
@@ -858,12 +865,14 @@ static int rm(int argc, const char **argv)
        cb_data.skipped = &skipped;
        cb_data.keep = &known_remotes;
 
-       if (argc != 2)
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_rm_usage, 0);
+       if (argc != 1)
                usage_with_options(builtin_remote_rm_usage, options);
 
-       remote = remote_get(argv[1]);
+       remote = remote_get(argv[0]);
        if (!remote_is_configured(remote, 1)) {
-               error(_("No such remote: '%s'"), argv[1]);
+               error(_("No such remote: '%s'"), argv[0]);
                exit(2);
        }
 
@@ -941,6 +950,7 @@ static void clear_push_info(void *util, const char *string)
 static void free_remote_ref_states(struct ref_states *states)
 {
        string_list_clear(&states->new_refs, 0);
+       string_list_clear(&states->skipped, 0);
        string_list_clear(&states->stale, 1);
        string_list_clear(&states->tracked, 0);
        string_list_clear(&states->heads, 0);
@@ -948,7 +958,8 @@ static void free_remote_ref_states(struct ref_states *states)
 }
 
 static int append_ref_to_tracked_list(const char *refname,
-       const struct object_id *oid, int flags, void *cb_data)
+                                     const struct object_id *oid UNUSED,
+                                     int flags, void *cb_data)
 {
        struct ref_states *states = cb_data;
        struct refspec_item refspec;
@@ -1035,6 +1046,8 @@ static int show_remote_info_item(struct string_list_item *item, void *cb_data)
                        arg = states->remote->name;
                } else if (string_list_has_string(&states->tracked, name))
                        arg = _(" tracked");
+               else if (string_list_has_string(&states->skipped, name))
+                       arg = _(" skipped");
                else if (string_list_has_string(&states->stale, name))
                        arg = _(" stale (use 'git remote prune' to remove)");
                else
@@ -1247,7 +1260,7 @@ static int show_all(void)
        return result;
 }
 
-static int show(int argc, const char **argv)
+static int show(int argc, const char **argv, const char *prefix)
 {
        int no_query = 0, result = 0, query_flag = 0;
        struct option options[] = {
@@ -1256,7 +1269,8 @@ static int show(int argc, const char **argv)
        };
        struct show_info info = SHOW_INFO_INIT;
 
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_show_usage,
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_show_usage,
                             0);
 
        if (argc < 1)
@@ -1307,6 +1321,7 @@ static int show(int argc, const char **argv)
                /* remote branch info */
                info.width = 0;
                for_each_string_list(&info.states.new_refs, add_remote_to_show_info, &info);
+               for_each_string_list(&info.states.skipped, add_remote_to_show_info, &info);
                for_each_string_list(&info.states.tracked, add_remote_to_show_info, &info);
                for_each_string_list(&info.states.stale, add_remote_to_show_info, &info);
                if (info.list.nr)
@@ -1349,7 +1364,7 @@ static int show(int argc, const char **argv)
        return result;
 }
 
-static int set_head(int argc, const char **argv)
+static int set_head(int argc, const char **argv, const char *prefix)
 {
        int i, opt_a = 0, opt_d = 0, result = 0;
        struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
@@ -1362,8 +1377,8 @@ static int set_head(int argc, const char **argv)
                         N_("delete refs/remotes/<name>/HEAD")),
                OPT_END()
        };
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
-                            0);
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_sethead_usage, 0);
        if (argc)
                strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
 
@@ -1454,7 +1469,7 @@ static int prune_remote(const char *remote, int dry_run)
        return result;
 }
 
-static int prune(int argc, const char **argv)
+static int prune(int argc, const char **argv, const char *prefix)
 {
        int dry_run = 0, result = 0;
        struct option options[] = {
@@ -1462,8 +1477,8 @@ static int prune(int argc, const char **argv)
                OPT_END()
        };
 
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,
-                            0);
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_prune_usage, 0);
 
        if (argc < 1)
                usage_with_options(builtin_remote_prune_usage, options);
@@ -1474,7 +1489,7 @@ static int prune(int argc, const char **argv)
        return result;
 }
 
-static int get_remote_default(const char *key, const char *value, void *priv)
+static int get_remote_default(const char *key, const char *value UNUSED, void *priv)
 {
        if (strcmp(key, "remotes.default") == 0) {
                int *found = priv;
@@ -1483,7 +1498,7 @@ static int get_remote_default(const char *key, const char *value, void *priv)
        return 0;
 }
 
-static int update(int argc, const char **argv)
+static int update(int argc, const char **argv, const char *prefix)
 {
        int i, prune = -1;
        struct option options[] = {
@@ -1495,7 +1510,8 @@ static int update(int argc, const char **argv)
        int default_defined = 0;
        int retval;
 
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_update_usage,
                             PARSE_OPT_KEEP_ARGV0);
 
        strvec_push(&fetch_argv, "fetch");
@@ -1566,7 +1582,7 @@ static int set_remote_branches(const char *remotename, const char **branches,
        return 0;
 }
 
-static int set_branches(int argc, const char **argv)
+static int set_branches(int argc, const char **argv, const char *prefix)
 {
        int add_mode = 0;
        struct option options[] = {
@@ -1574,7 +1590,7 @@ static int set_branches(int argc, const char **argv)
                OPT_END()
        };
 
-       argc = parse_options(argc, argv, NULL, options,
+       argc = parse_options(argc, argv, prefix, options,
                             builtin_remote_setbranches_usage, 0);
        if (argc == 0) {
                error(_("no remote specified"));
@@ -1585,7 +1601,7 @@ static int set_branches(int argc, const char **argv)
        return set_remote_branches(argv[0], argv + 1, add_mode);
 }
 
-static int get_url(int argc, const char **argv)
+static int get_url(int argc, const char **argv, const char *prefix)
 {
        int i, push_mode = 0, all_mode = 0;
        const char *remotename = NULL;
@@ -1599,7 +1615,8 @@ static int get_url(int argc, const char **argv)
                         N_("return all URLs")),
                OPT_END()
        };
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_geturl_usage, 0);
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_geturl_usage, 0);
 
        if (argc != 1)
                usage_with_options(builtin_remote_geturl_usage, options);
@@ -1638,7 +1655,7 @@ static int get_url(int argc, const char **argv)
        return 0;
 }
 
-static int set_url(int argc, const char **argv)
+static int set_url(int argc, const char **argv, const char *prefix)
 {
        int i, push_mode = 0, add_mode = 0, delete_mode = 0;
        int matches = 0, negative_matches = 0;
@@ -1659,7 +1676,8 @@ static int set_url(int argc, const char **argv)
                            N_("delete URLs")),
                OPT_END()
        };
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_remote_seturl_usage,
                             PARSE_OPT_KEEP_ARGV0);
 
        if (add_mode && delete_mode)
@@ -1730,41 +1748,33 @@ out:
 
 int cmd_remote(int argc, const char **argv, const char *prefix)
 {
+       parse_opt_subcommand_fn *fn = NULL;
        struct option options[] = {
                OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
+               OPT_SUBCOMMAND("add", &fn, add),
+               OPT_SUBCOMMAND("rename", &fn, mv),
+               OPT_SUBCOMMAND_F("rm", &fn, rm, PARSE_OPT_NOCOMPLETE),
+               OPT_SUBCOMMAND("remove", &fn, rm),
+               OPT_SUBCOMMAND("set-head", &fn, set_head),
+               OPT_SUBCOMMAND("set-branches", &fn, set_branches),
+               OPT_SUBCOMMAND("get-url", &fn, get_url),
+               OPT_SUBCOMMAND("set-url", &fn, set_url),
+               OPT_SUBCOMMAND("show", &fn, show),
+               OPT_SUBCOMMAND("prune", &fn, prune),
+               OPT_SUBCOMMAND("update", &fn, update),
                OPT_END()
        };
-       int result;
 
        argc = parse_options(argc, argv, prefix, options, builtin_remote_usage,
-               PARSE_OPT_STOP_AT_NON_OPTION);
+                            PARSE_OPT_SUBCOMMAND_OPTIONAL);
 
-       if (argc < 1)
-               result = show_all();
-       else if (!strcmp(argv[0], "add"))
-               result = add(argc, argv);
-       else if (!strcmp(argv[0], "rename"))
-               result = mv(argc, argv);
-       else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove"))
-               result = rm(argc, argv);
-       else if (!strcmp(argv[0], "set-head"))
-               result = set_head(argc, argv);
-       else if (!strcmp(argv[0], "set-branches"))
-               result = set_branches(argc, argv);
-       else if (!strcmp(argv[0], "get-url"))
-               result = get_url(argc, argv);
-       else if (!strcmp(argv[0], "set-url"))
-               result = set_url(argc, argv);
-       else if (!strcmp(argv[0], "show"))
-               result = show(argc, argv);
-       else if (!strcmp(argv[0], "prune"))
-               result = prune(argc, argv);
-       else if (!strcmp(argv[0], "update"))
-               result = update(argc, argv);
-       else {
-               error(_("Unknown subcommand: %s"), argv[0]);
-               usage_with_options(builtin_remote_usage, options);
+       if (fn) {
+               return !!fn(argc, argv, prefix);
+       } else {
+               if (argc) {
+                       error(_("unknown subcommand: `%s'"), argv[0]);
+                       usage_with_options(builtin_remote_usage, options);
+               }
+               return !!show_all();
        }
-
-       return result ? 1 : 0;
 }
index 4a7ae4cf489a4c34aaabeca064535f07c2df55f7..a5bacc7797435696cd6e23e73f847fc00d39bb7f 100644 (file)
@@ -514,9 +514,9 @@ struct midx_snapshot_ref_data {
        int preferred;
 };
 
-static int midx_snapshot_ref_one(const char *refname,
+static int midx_snapshot_ref_one(const char *refname UNUSED,
                                 const struct object_id *oid,
-                                int flag, void *_data)
+                                int flag UNUSED, void *_data)
 {
        struct midx_snapshot_ref_data *data = _data;
        struct object_id peeled;
@@ -727,7 +727,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        struct child_process cmd = CHILD_PROCESS_INIT;
        struct string_list_item *item;
        struct string_list names = STRING_LIST_INIT_DUP;
-       struct string_list rollback = STRING_LIST_INIT_NODUP;
        struct string_list existing_nonkept_packs = STRING_LIST_INIT_DUP;
        struct string_list existing_kept_packs = STRING_LIST_INIT_DUP;
        struct pack_geometry *geometry = NULL;
@@ -1117,7 +1116,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        }
 
        string_list_clear(&names, 0);
-       string_list_clear(&rollback, 0);
        string_list_clear(&existing_nonkept_packs, 0);
        string_list_clear(&existing_kept_packs, 0);
        clear_pack_geometry(geometry);
index 583702a0980e8ced3f91e1b88a9a1698be16fc6e..a29e911d3099be9d327ecc030d68c56fe046a04a 100644 (file)
@@ -106,6 +106,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
        size_t base_len;
        int had_error = 0;
        struct object_id oid;
+       const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
 
        strbuf_addstr(&ref, git_replace_ref_base);
        base_len = ref.len;
@@ -147,6 +148,8 @@ static int check_ref_valid(struct object_id *object,
                            struct strbuf *ref,
                            int force)
 {
+       const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
+
        strbuf_reset(ref);
        strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
        if (check_refname_format(ref->buf, 0))
index 344fff8f3a9322a7895b607a8236c5461625407d..fdce6f8c85670c8b2b0e20304336debba3190408 100644 (file)
@@ -174,88 +174,6 @@ static void update_index_from_diff(struct diff_queue_struct *q,
        }
 }
 
-static int pathspec_needs_expanded_index(const struct pathspec *pathspec)
-{
-       unsigned int i, pos;
-       int res = 0;
-       char *skip_worktree_seen = NULL;
-
-       /*
-        * When using a magic pathspec, assume for the sake of simplicity that
-        * the index needs to be expanded to match all matchable files.
-        */
-       if (pathspec->magic)
-               return 1;
-
-       for (i = 0; i < pathspec->nr; i++) {
-               struct pathspec_item item = pathspec->items[i];
-
-               /*
-                * If the pathspec item has a wildcard, the index should be expanded
-                * if the pathspec has the possibility of matching a subset of entries inside
-                * of a sparse directory (but not the entire directory).
-                *
-                * If the pathspec item is a literal path, the index only needs to be expanded
-                * if a) the pathspec isn't in the sparse checkout cone (to make sure we don't
-                * expand for in-cone files) and b) it doesn't match any sparse directories
-                * (since we can reset whole sparse directories without expanding them).
-                */
-               if (item.nowildcard_len < item.len) {
-                       /*
-                        * Special case: if the pattern is a path inside the cone
-                        * followed by only wildcards, the pattern cannot match
-                        * partial sparse directories, so we know we don't need to
-                        * expand the index.
-                        *
-                        * Examples:
-                        * - in-cone/foo***: doesn't need expanded index
-                        * - not-in-cone/bar*: may need expanded index
-                        * - **.c: may need expanded index
-                        */
-                       if (strspn(item.original + item.nowildcard_len, "*") == item.len - item.nowildcard_len &&
-                           path_in_cone_mode_sparse_checkout(item.original, &the_index))
-                               continue;
-
-                       for (pos = 0; pos < active_nr; pos++) {
-                               struct cache_entry *ce = active_cache[pos];
-
-                               if (!S_ISSPARSEDIR(ce->ce_mode))
-                                       continue;
-
-                               /*
-                                * If the pre-wildcard length is longer than the sparse
-                                * directory name and the sparse directory is the first
-                                * component of the pathspec, need to expand the index.
-                                */
-                               if (item.nowildcard_len > ce_namelen(ce) &&
-                                   !strncmp(item.original, ce->name, ce_namelen(ce))) {
-                                       res = 1;
-                                       break;
-                               }
-
-                               /*
-                                * If the pre-wildcard length is shorter than the sparse
-                                * directory and the pathspec does not match the whole
-                                * directory, need to expand the index.
-                                */
-                               if (!strncmp(item.original, ce->name, item.nowildcard_len) &&
-                                   wildmatch(item.original, ce->name, 0)) {
-                                       res = 1;
-                                       break;
-                               }
-                       }
-               } else if (!path_in_cone_mode_sparse_checkout(item.original, &the_index) &&
-                          !matches_skip_worktree(pathspec, i, &skip_worktree_seen))
-                       res = 1;
-
-               if (res > 0)
-                       break;
-       }
-
-       free(skip_worktree_seen);
-       return res;
-}
-
 static int read_from_tree(const struct pathspec *pathspec,
                          struct object_id *tree_oid,
                          int intent_to_add)
@@ -273,7 +191,7 @@ static int read_from_tree(const struct pathspec *pathspec,
        opt.change = diff_change;
        opt.add_remove = diff_addremove;
 
-       if (pathspec->nr && the_index.sparse_index && pathspec_needs_expanded_index(pathspec))
+       if (pathspec->nr && pathspec_needs_expanded_index(&the_index, pathspec))
                ensure_full_index(&the_index);
 
        if (do_diff_cache(tree_oid, &opt))
index 30fd8e83eaf2ca767802343d2dcff1825f6b1b50..fba6f5d51f32d1217b89298e1361169b43feb38b 100644 (file)
@@ -46,6 +46,7 @@ static const char rev_list_usage[] =
 "    --parents\n"
 "    --children\n"
 "    --objects | --objects-edge\n"
+"    --disk-usage[=human]\n"
 "    --unpacked\n"
 "    --header | --pretty\n"
 "    --[no-]object-names\n"
@@ -81,6 +82,7 @@ static int arg_show_object_names = 1;
 
 static int show_disk_usage;
 static off_t total_disk_usage;
+static int human_readable;
 
 static off_t get_object_disk_usage(struct object *obj)
 {
@@ -368,6 +370,17 @@ static int show_object_fast(
        return 1;
 }
 
+static void print_disk_usage(off_t size)
+{
+       struct strbuf sb = STRBUF_INIT;
+       if (human_readable)
+               strbuf_humanise_bytes(&sb, size);
+       else
+               strbuf_addf(&sb, "%"PRIuMAX, (uintmax_t)size);
+       puts(sb.buf);
+       strbuf_release(&sb);
+}
+
 static inline int parse_missing_action_value(const char *value)
 {
        if (!strcmp(value, "error")) {
@@ -473,6 +486,7 @@ static int try_bitmap_disk_usage(struct rev_info *revs,
                                 int filter_provided_objects)
 {
        struct bitmap_index *bitmap_git;
+       off_t size_from_bitmap;
 
        if (!show_disk_usage)
                return -1;
@@ -481,8 +495,8 @@ static int try_bitmap_disk_usage(struct rev_info *revs,
        if (!bitmap_git)
                return -1;
 
-       printf("%"PRIuMAX"\n",
-              (uintmax_t)get_disk_usage_from_bitmap(bitmap_git, revs));
+       size_from_bitmap = get_disk_usage_from_bitmap(bitmap_git, revs);
+       print_disk_usage(size_from_bitmap);
        return 0;
 }
 
@@ -624,7 +638,21 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (!strcmp(arg, "--disk-usage")) {
+               if (skip_prefix(arg, "--disk-usage", &arg)) {
+                       if (*arg == '=') {
+                               if (!strcmp(++arg, "human")) {
+                                       human_readable = 1;
+                               } else
+                                       die(_("invalid value for '%s': '%s', the only allowed format is '%s'"),
+                                           "--disk-usage=<format>", arg, "human");
+                       } else if (*arg) {
+                               /*
+                                * Arguably should goto a label to continue chain of ifs?
+                                * Doesn't matter unless we try to add --disk-usage-foo
+                                * afterwards.
+                                */
+                               usage(rev_list_usage);
+                       }
                        show_disk_usage = 1;
                        info.flags |= REV_LIST_QUIET;
                        continue;
@@ -753,7 +781,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        }
 
        if (show_disk_usage)
-               printf("%"PRIuMAX"\n", (uintmax_t)total_disk_usage);
+               print_disk_usage(total_disk_usage);
 
 cleanup:
        release_revisions(&revs);
index b259d8990a681d1804d434cea2f1e28193e6693f..8f61050bde884303fe1ac0fcb8162a99224bf5fd 100644 (file)
@@ -195,7 +195,8 @@ static int show_default(void)
        return 0;
 }
 
-static int show_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static int show_reference(const char *refname, const struct object_id *oid,
+                         int flag UNUSED, void *cb_data UNUSED)
 {
        if (ref_excluded(ref_excludes, refname))
                return 0;
@@ -203,7 +204,8 @@ static int show_reference(const char *refname, const struct object_id *oid, int
        return 0;
 }
 
-static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static int anti_reference(const char *refname, const struct object_id *oid,
+                         int flag UNUSED, void *cb_data UNUSED)
 {
        show_rev(REVERSED, oid, refname);
        return 0;
@@ -479,6 +481,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
                if (!s)
                        s = help;
 
+               if (s == sb.buf)
+                       die(_("missing opt-spec before option flags"));
+
                if (s - sb.buf == 1) /* short option only */
                        o->short_name = *sb.buf;
                else if (sb.buf[1] != ',') /* long option only */
index f84c253f4c6f65ba273263d92658c74378b0de74..ee2a0807f011e817801f1dc45e858b99ced613a3 100644 (file)
@@ -141,7 +141,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 
        argc = parse_options(argc, argv, NULL, options, usage_str,
                        PARSE_OPT_KEEP_ARGV0 |
-                       PARSE_OPT_KEEP_UNKNOWN);
+                       PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        prepare_repo_settings(the_repository);
        the_repository->settings.command_requires_full_index = 0;
@@ -246,6 +246,9 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
        res = run_sequencer(argc, argv, &opts);
        if (res < 0)
                die(_("revert failed"));
+       if (opts.revs)
+               release_revisions(opts.revs);
+       free(opts.revs);
        return res;
 }
 
index 84a935a16e8be447d0bc95ad2a1e5d133452e635..b6ba859fe42571fd868697db1da8dac6ffd2c32e 100644 (file)
@@ -287,6 +287,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        if (!index_only)
                setup_work_tree();
 
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
        hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 
        if (read_cache() < 0)
@@ -296,8 +298,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 
        seen = xcalloc(pathspec.nr, 1);
 
-       /* TODO: audit for interaction with sparse-index. */
-       ensure_full_index(&the_index);
+       if (pathspec_needs_expanded_index(&the_index, &pathspec))
+               ensure_full_index(&the_index);
+
        for (i = 0; i < active_nr; i++) {
                const struct cache_entry *ce = active_cache[i];
 
index 086dfee45aa8be8cc316132ce29bfb93c2ef295a..7a1e1fe7c0ed6d97789c352d37e4870d6f2e2b04 100644 (file)
@@ -381,6 +381,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
                        break;
                case PARSE_OPT_HELP:
                case PARSE_OPT_ERROR:
+               case PARSE_OPT_SUBCOMMAND:
                        exit(129);
                case PARSE_OPT_COMPLETE:
                        exit(0);
index 64c649c6a238605cb847bbf515cbdca58cde990c..d3f5715e3e3af468fa7b1b444454ef30f6313f0c 100644 (file)
@@ -404,7 +404,7 @@ static int append_ref(const char *refname, const struct object_id *oid,
 }
 
 static int append_head_ref(const char *refname, const struct object_id *oid,
-                          int flag, void *cb_data)
+                          int flag UNUSED, void *cb_data UNUSED)
 {
        struct object_id tmp;
        int ofs = 11;
@@ -419,7 +419,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
 }
 
 static int append_remote_ref(const char *refname, const struct object_id *oid,
-                            int flag, void *cb_data)
+                            int flag UNUSED, void *cb_data UNUSED)
 {
        struct object_id tmp;
        int ofs = 13;
@@ -434,7 +434,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
 }
 
 static int append_tag_ref(const char *refname, const struct object_id *oid,
-                         int flag, void *cb_data)
+                         int flag UNUSED, void *cb_data UNUSED)
 {
        if (!starts_with(refname, "refs/tags/"))
                return 0;
index 5fa207a044e0691b9f82627b074645595603c2dd..48569061087416ee0cc78f777094e8b1ed0660db 100644 (file)
@@ -47,7 +47,7 @@ static void show_one(const char *refname, const struct object_id *oid)
 }
 
 static int show_ref(const char *refname, const struct object_id *oid,
-                   int flag, void *cbdata)
+                   int flag UNUSED, void *cbdata UNUSED)
 {
        if (show_head && !strcmp(refname, "HEAD"))
                goto match;
@@ -77,8 +77,9 @@ match:
        return 0;
 }
 
-static int add_existing(const char *refname, const struct object_id *oid,
-                       int flag, void *cbdata)
+static int add_existing(const char *refname,
+                       const struct object_id *oid UNUSED,
+                       int flag UNUSED, void *cbdata)
 {
        struct string_list *list = (struct string_list *)cbdata;
        string_list_insert(list, refname);
index f91e29b56a97eea0f8814a0bfcca45c512a3ab06..287716db68e4198bdec97517ff2cd9c053c9f0b8 100644 (file)
@@ -48,7 +48,7 @@ static char const * const builtin_sparse_checkout_list_usage[] = {
        NULL
 };
 
-static int sparse_checkout_list(int argc, const char **argv)
+static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
 {
        static struct option builtin_sparse_checkout_list_options[] = {
                OPT_END(),
@@ -60,7 +60,7 @@ static int sparse_checkout_list(int argc, const char **argv)
        if (!core_apply_sparse_checkout)
                die(_("this worktree is not sparse"));
 
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_list_options,
                             builtin_sparse_checkout_list_usage, 0);
 
@@ -431,7 +431,7 @@ static struct sparse_checkout_init_opts {
        int sparse_index;
 } init_opts;
 
-static int sparse_checkout_init(int argc, const char **argv)
+static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
 {
        struct pattern_list pl;
        char *sparse_filename;
@@ -452,7 +452,7 @@ static int sparse_checkout_init(int argc, const char **argv)
        init_opts.cone_mode = -1;
        init_opts.sparse_index = -1;
 
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_init_options,
                             builtin_sparse_checkout_init_usage, 0);
 
@@ -767,7 +767,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_add_options,
                             builtin_sparse_checkout_add_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
 
@@ -813,7 +813,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_set_options,
                             builtin_sparse_checkout_set_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
                return 1;
@@ -843,7 +843,8 @@ static struct sparse_checkout_reapply_opts {
        int sparse_index;
 } reapply_opts;
 
-static int sparse_checkout_reapply(int argc, const char **argv)
+static int sparse_checkout_reapply(int argc, const char **argv,
+                                  const char *prefix)
 {
        static struct option builtin_sparse_checkout_reapply_options[] = {
                OPT_BOOL(0, "cone", &reapply_opts.cone_mode,
@@ -859,7 +860,7 @@ static int sparse_checkout_reapply(int argc, const char **argv)
        reapply_opts.cone_mode = -1;
        reapply_opts.sparse_index = -1;
 
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_reapply_options,
                             builtin_sparse_checkout_reapply_usage, 0);
 
@@ -876,7 +877,8 @@ static char const * const builtin_sparse_checkout_disable_usage[] = {
        NULL
 };
 
-static int sparse_checkout_disable(int argc, const char **argv)
+static int sparse_checkout_disable(int argc, const char **argv,
+                                  const char *prefix)
 {
        static struct option builtin_sparse_checkout_disable_options[] = {
                OPT_END(),
@@ -895,7 +897,7 @@ static int sparse_checkout_disable(int argc, const char **argv)
         * forcibly return to a dense checkout regardless of initial state.
         */
 
-       argc = parse_options(argc, argv, NULL,
+       argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_disable_options,
                             builtin_sparse_checkout_disable_usage, 0);
 
@@ -922,39 +924,25 @@ static int sparse_checkout_disable(int argc, const char **argv)
 
 int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
 {
-       static struct option builtin_sparse_checkout_options[] = {
+       parse_opt_subcommand_fn *fn = NULL;
+       struct option builtin_sparse_checkout_options[] = {
+               OPT_SUBCOMMAND("list", &fn, sparse_checkout_list),
+               OPT_SUBCOMMAND("init", &fn, sparse_checkout_init),
+               OPT_SUBCOMMAND("set", &fn, sparse_checkout_set),
+               OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
+               OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
+               OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
                OPT_END(),
        };
 
-       if (argc == 2 && !strcmp(argv[1], "-h"))
-               usage_with_options(builtin_sparse_checkout_usage,
-                                  builtin_sparse_checkout_options);
-
        argc = parse_options(argc, argv, prefix,
                             builtin_sparse_checkout_options,
-                            builtin_sparse_checkout_usage,
-                            PARSE_OPT_STOP_AT_NON_OPTION);
+                            builtin_sparse_checkout_usage, 0);
 
        git_config(git_default_config, NULL);
 
        prepare_repo_settings(the_repository);
        the_repository->settings.command_requires_full_index = 0;
 
-       if (argc > 0) {
-               if (!strcmp(argv[0], "list"))
-                       return sparse_checkout_list(argc, argv);
-               if (!strcmp(argv[0], "init"))
-                       return sparse_checkout_init(argc, argv);
-               if (!strcmp(argv[0], "set"))
-                       return sparse_checkout_set(argc, argv, prefix);
-               if (!strcmp(argv[0], "add"))
-                       return sparse_checkout_add(argc, argv, prefix);
-               if (!strcmp(argv[0], "reapply"))
-                       return sparse_checkout_reapply(argc, argv);
-               if (!strcmp(argv[0], "disable"))
-                       return sparse_checkout_disable(argc, argv);
-       }
-
-       usage_with_options(builtin_sparse_checkout_usage,
-                          builtin_sparse_checkout_options);
+       return fn(argc, argv, prefix);
 }
index 30fa1014605425b3731d5f65c16338a7164f5140..2274aae2556cc1837a3c7036fb52be2e6653a0e7 100644 (file)
@@ -638,9 +638,12 @@ cleanup:
        return ret;
 }
 
-static int reject_reflog_ent(struct object_id *ooid, struct object_id *noid,
-                            const char *email, timestamp_t timestamp, int tz,
-                            const char *message, void *cb_data)
+static int reject_reflog_ent(struct object_id *ooid UNUSED,
+                            struct object_id *noid UNUSED,
+                            const char *email UNUSED,
+                            timestamp_t timestamp UNUSED,
+                            int tz UNUSED, const char *message UNUSED,
+                            void *cb_data UNUSED)
 {
        return 1;
 }
@@ -782,7 +785,7 @@ static int list_stash(int argc, const char **argv, const char *prefix)
 
        argc = parse_options(argc, argv, prefix, options,
                             git_stash_list_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        if (!ref_exists(ref_stash))
                return 0;
@@ -873,7 +876,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
        init_revisions(&rev, prefix);
 
        argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
-                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
+                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
                             PARSE_OPT_KEEP_DASHDASH);
 
        strvec_push(&revision_args, argv[0]);
@@ -979,7 +982,7 @@ static int store_stash(int argc, const char **argv, const char *prefix)
 
        argc = parse_options(argc, argv, prefix, options,
                             git_stash_store_usage,
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        if (argc != 1) {
                if (!quiet)
@@ -1739,6 +1742,11 @@ static int push_stash(int argc, const char **argv, const char *prefix,
                             include_untracked, only_staged);
 }
 
+static int push_stash_unassumed(int argc, const char **argv, const char *prefix)
+{
+       return push_stash(argc, argv, prefix, 0);
+}
+
 static int save_stash(int argc, const char **argv, const char *prefix)
 {
        int keep_index = -1;
@@ -1787,15 +1795,28 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
        pid_t pid = getpid();
        const char *index_file;
        struct strvec args = STRVEC_INIT;
-
+       parse_opt_subcommand_fn *fn = NULL;
        struct option options[] = {
+               OPT_SUBCOMMAND("apply", &fn, apply_stash),
+               OPT_SUBCOMMAND("clear", &fn, clear_stash),
+               OPT_SUBCOMMAND("drop", &fn, drop_stash),
+               OPT_SUBCOMMAND("pop", &fn, pop_stash),
+               OPT_SUBCOMMAND("branch", &fn, branch_stash),
+               OPT_SUBCOMMAND("list", &fn, list_stash),
+               OPT_SUBCOMMAND("show", &fn, show_stash),
+               OPT_SUBCOMMAND("store", &fn, store_stash),
+               OPT_SUBCOMMAND("create", &fn, create_stash),
+               OPT_SUBCOMMAND("push", &fn, push_stash_unassumed),
+               OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
                OPT_END()
        };
 
        git_config(git_stash_config, NULL);
 
        argc = parse_options(argc, argv, prefix, options, git_stash_usage,
-                            PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
+                            PARSE_OPT_SUBCOMMAND_OPTIONAL |
+                            PARSE_OPT_KEEP_UNKNOWN_OPT |
+                            PARSE_OPT_KEEP_DASHDASH);
 
        prepare_repo_settings(the_repository);
        the_repository->settings.command_requires_full_index = 0;
@@ -1804,33 +1825,10 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
        strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
                    (uintmax_t)pid);
 
-       if (!argc)
-               return !!push_stash(0, NULL, prefix, 0);
-       else if (!strcmp(argv[0], "apply"))
-               return !!apply_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "clear"))
-               return !!clear_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "drop"))
-               return !!drop_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "pop"))
-               return !!pop_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "branch"))
-               return !!branch_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "list"))
-               return !!list_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "show"))
-               return !!show_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "store"))
-               return !!store_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "create"))
-               return !!create_stash(argc, argv, prefix);
-       else if (!strcmp(argv[0], "push"))
-               return !!push_stash(argc, argv, prefix, 0);
-       else if (!strcmp(argv[0], "save"))
-               return !!save_stash(argc, argv, prefix);
-       else if (*argv[0] != '-')
-               usage_msg_optf(_("unknown subcommand: %s"),
-                              git_stash_usage, options, argv[0]);
+       if (fn)
+               return !!fn(argc, argv, prefix);
+       else if (!argc)
+               return !!push_stash_unassumed(0, NULL, prefix);
 
        /* Assume 'stash push' */
        strvec_push(&args, "push");
index c597df7528ee56cd1e35c65f409e73a99769a5ee..0b4acb442b209305949a2715ead54d9de518e10f 100644 (file)
 typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
                                  void *cb_data);
 
-static char *repo_get_default_remote(struct repository *repo)
+static int repo_get_default_remote(struct repository *repo, char **default_remote)
 {
-       char *dest = NULL, *ret;
+       char *dest = NULL;
        struct strbuf sb = STRBUF_INIT;
        struct ref_store *store = get_main_ref_store(repo);
        const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
                                                      NULL);
 
        if (!refname)
-               die(_("No such ref: %s"), "HEAD");
+               return die_message(_("No such ref: %s"), "HEAD");
 
        /* detached HEAD */
-       if (!strcmp(refname, "HEAD"))
-               return xstrdup("origin");
+       if (!strcmp(refname, "HEAD")) {
+               *default_remote = xstrdup("origin");
+               return 0;
+       }
 
        if (!skip_prefix(refname, "refs/heads/", &refname))
-               die(_("Expecting a full ref name, got %s"), refname);
+               return die_message(_("Expecting a full ref name, got %s"),
+                                  refname);
 
        strbuf_addf(&sb, "branch.%s.remote", refname);
        if (repo_config_get_string(repo, sb.buf, &dest))
-               ret = xstrdup("origin");
+               *default_remote = xstrdup("origin");
        else
-               ret = dest;
+               *default_remote = dest;
 
        strbuf_release(&sb);
-       return ret;
+       return 0;
 }
 
-static char *get_default_remote_submodule(const char *module_path)
+static int get_default_remote_submodule(const char *module_path, char **default_remote)
 {
        struct repository subrepo;
+       int ret;
 
-       repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
-       return repo_get_default_remote(&subrepo);
+       if (repo_submodule_init(&subrepo, the_repository, module_path,
+                               null_oid()) < 0)
+               return die_message(_("could not get a repository handle for submodule '%s'"),
+                                  module_path);
+       ret = repo_get_default_remote(&subrepo, default_remote);
+       repo_clear(&subrepo);
+
+       return ret;
 }
 
 static char *get_default_remote(void)
 {
-       return repo_get_default_remote(the_repository);
+       char *default_remote;
+       int code = repo_get_default_remote(the_repository, &default_remote);
+
+       if (code)
+               exit(code);
+
+       return default_remote;
 }
 
 static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
@@ -96,32 +112,11 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
        return resolved_url;
 }
 
-static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
 {
-       char *remoteurl, *res;
-       const char *up_path, *url;
-
-       if (argc != 4)
-               die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
-
-       up_path = argv[1];
-       remoteurl = xstrdup(argv[2]);
-       url = argv[3];
-
-       if (!strcmp(up_path, "(null)"))
-               up_path = NULL;
-
-       res = relative_url(remoteurl, url, up_path);
-       puts(res);
-       free(res);
-       free(remoteurl);
-       return 0;
-}
+       const char *super_prefix = get_super_prefix();
 
-static char *do_get_submodule_displaypath(const char *path,
-                                         const char *prefix,
-                                         const char *super_prefix)
-{
        if (prefix && super_prefix) {
                BUG("cannot have prefix '%s' and superprefix '%s'",
                    prefix, super_prefix);
@@ -137,13 +132,6 @@ static char *do_get_submodule_displaypath(const char *path,
        }
 }
 
-/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
-{
-       const char *super_prefix = get_super_prefix();
-       return do_get_submodule_displaypath(path, prefix, super_prefix);
-}
-
 static char *compute_rev_name(const char *sub_path, const char* object_id)
 {
        struct strbuf sb = STRBUF_INIT;
@@ -188,6 +176,11 @@ struct module_list {
 };
 #define MODULE_LIST_INIT { 0 }
 
+static void module_list_release(struct module_list *ml)
+{
+       free(ml->entries);
+}
+
 static int module_list_compute(int argc, const char **argv,
                               const char *prefix,
                               struct pathspec *pathspec,
@@ -195,6 +188,7 @@ static int module_list_compute(int argc, const char **argv,
 {
        int i, result = 0;
        char *ps_matched = NULL;
+
        parse_pathspec(pathspec, 0,
                       PATHSPEC_PREFER_FULL,
                       prefix, argv);
@@ -249,7 +243,7 @@ static void module_list_active(struct module_list *list)
                active_modules.entries[active_modules.nr++] = ce;
        }
 
-       free(list->entries);
+       module_list_release(list);
        *list = active_modules;
 }
 
@@ -272,49 +266,11 @@ static char *get_up_path(const char *path)
        return strbuf_detach(&sb, NULL);
 }
 
-static int module_list(int argc, const char **argv, const char *prefix)
-{
-       int i;
-       struct pathspec pathspec;
-       struct module_list list = MODULE_LIST_INIT;
-
-       struct option module_list_options[] = {
-               OPT_STRING(0, "prefix", &prefix,
-                          N_("path"),
-                          N_("alternative anchor for relative paths")),
-               OPT_END()
-       };
-
-       const char *const git_submodule_helper_usage[] = {
-               N_("git submodule--helper list [--prefix=<path>] [<path>...]"),
-               NULL
-       };
-
-       argc = parse_options(argc, argv, prefix, module_list_options,
-                            git_submodule_helper_usage, 0);
-
-       if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
-               return 1;
-
-       for (i = 0; i < list.nr; i++) {
-               const struct cache_entry *ce = list.entries[i];
-
-               if (ce_stage(ce))
-                       printf("%06o %s U\t", ce->ce_mode,
-                              oid_to_hex(null_oid()));
-               else
-                       printf("%06o %s %d\t", ce->ce_mode,
-                              oid_to_hex(&ce->oid), ce_stage(ce));
-
-               fprintf(stdout, "%s\n", ce->name);
-       }
-       return 0;
-}
-
 static void for_each_listed_submodule(const struct module_list *list,
                                      each_submodule_fn fn, void *cb_data)
 {
        int i;
+
        for (i = 0; i < list->nr; i++)
                fn(list->entries[i], cb_data);
 }
@@ -334,7 +290,6 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
        struct foreach_cb *info = cb_data;
        const char *path = list_item->name;
        const struct object_id *ce_oid = &list_item->oid;
-
        const struct submodule *sub;
        struct child_process cp = CHILD_PROCESS_INIT;
        char *displaypath;
@@ -433,26 +388,25 @@ cleanup:
 static int module_foreach(int argc, const char **argv, const char *prefix)
 {
        struct foreach_cb info = FOREACH_CB_INIT;
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
        struct module_list list = MODULE_LIST_INIT;
-
        struct option module_foreach_options[] = {
                OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
                OPT_BOOL(0, "recursive", &info.recursive,
                         N_("recurse into nested submodules")),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
-               N_("git submodule--helper foreach [--quiet] [--recursive] [--] <command>"),
+               N_("git submodule foreach [--quiet] [--recursive] [--] <command>"),
                NULL
        };
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, module_foreach_options,
                             git_submodule_helper_usage, 0);
 
        if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
-               return 1;
+               goto cleanup;
 
        info.argc = argc;
        info.argv = argv;
@@ -460,7 +414,11 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
 
        for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
 
-       return 0;
+       ret = 0;
+cleanup:
+       module_list_release(&list);
+       clear_pathspec(&pathspec);
+       return ret;
 }
 
 static int starts_with_dot_slash(const char *const path)
@@ -477,22 +435,19 @@ static int starts_with_dot_dot_slash(const char *const path)
 
 struct init_cb {
        const char *prefix;
-       const char *superprefix;
        unsigned int flags;
 };
 #define INIT_CB_INIT { 0 }
 
 static void init_submodule(const char *path, const char *prefix,
-                          const char *superprefix, unsigned int flags)
+                          unsigned int flags)
 {
        const struct submodule *sub;
        struct strbuf sb = STRBUF_INIT;
-       char *upd = NULL, *url = NULL, *displaypath;
+       const char *upd;
+       char *url = NULL, *displaypath;
 
-       /* try superprefix from the environment, if it is not passed explicitly */
-       if (!superprefix)
-               superprefix = get_super_prefix();
-       displaypath = do_get_submodule_displaypath(path, prefix, superprefix);
+       displaypath = get_submodule_displaypath(path, prefix);
 
        sub = submodule_from_path(the_repository, null_oid(), path);
 
@@ -529,6 +484,7 @@ static void init_submodule(const char *path, const char *prefix,
                if (starts_with_dot_dot_slash(url) ||
                    starts_with_dot_slash(url)) {
                        char *oldurl = url;
+
                        url = resolve_relative_url(oldurl, NULL, 0);
                        free(oldurl);
                }
@@ -545,14 +501,15 @@ 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(sb.buf, &upd) &&
+       if (git_config_get_string_tmp(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"),
                                sub->name);
-                       upd = xstrdup("none");
-               } else
-                       upd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));
+                       upd = "none";
+               } else {
+                       upd = submodule_update_type_to_string(sub->update_strategy.type);
+               }
 
                if (git_config_set_gently(sb.buf, upd))
                        die(_("Failed to register update mode for submodule path '%s'"), displaypath);
@@ -560,37 +517,36 @@ static void init_submodule(const char *path, const char *prefix,
        strbuf_release(&sb);
        free(displaypath);
        free(url);
-       free(upd);
 }
 
 static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 {
        struct init_cb *info = cb_data;
-       init_submodule(list_item->name, info->prefix, info->superprefix, info->flags);
+
+       init_submodule(list_item->name, info->prefix, info->flags);
 }
 
 static int module_init(int argc, const char **argv, const char *prefix)
 {
        struct init_cb info = INIT_CB_INIT;
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
-
        struct option module_init_options[] = {
                OPT__QUIET(&quiet, N_("suppress output for initializing a submodule")),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
-               N_("git submodule--helper init [<options>] [<path>]"),
+               N_("git submodule init [<options>] [<path>]"),
                NULL
        };
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, module_init_options,
                             git_submodule_helper_usage, 0);
 
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
-               return 1;
+               goto cleanup;
 
        /*
         * If there are no path args and submodule.active is set then,
@@ -605,7 +561,11 @@ static int module_init(int argc, const char **argv, const char *prefix)
 
        for_each_listed_submodule(&list, init_submodule_cb, &info);
 
-       return 0;
+       ret = 0;
+cleanup:
+       module_list_release(&list);
+       clear_pathspec(&pathspec);
+       return ret;
 }
 
 struct status_cb {
@@ -623,20 +583,23 @@ static void print_status(unsigned int flags, char state, const char *path,
        printf("%c%s %s", state, oid_to_hex(oid), displaypath);
 
        if (state == ' ' || state == '+') {
-               const char *name = compute_rev_name(path, oid_to_hex(oid));
+               char *name = compute_rev_name(path, oid_to_hex(oid));
 
                if (name)
                        printf(" (%s)", name);
+               free(name);
        }
 
        printf("\n");
 }
 
-static int handle_submodule_head_ref(const char *refname,
-                                    const struct object_id *oid, int flags,
+static int handle_submodule_head_ref(const char *refname UNUSED,
+                                    const struct object_id *oid,
+                                    int flags UNUSED,
                                     void *cb_data)
 {
        struct object_id *output = cb_data;
+
        if (oid)
                oidcpy(output, oid);
 
@@ -743,6 +706,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
                                void *cb_data)
 {
        struct status_cb *info = cb_data;
+
        status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
                         info->prefix, info->flags);
 }
@@ -750,27 +714,26 @@ static void status_submodule_cb(const struct cache_entry *list_item,
 static int module_status(int argc, const char **argv, const char *prefix)
 {
        struct status_cb info = STATUS_CB_INIT;
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
-
        struct option module_status_options[] = {
                OPT__QUIET(&quiet, N_("suppress submodule status output")),
                OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
                OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
                N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
                NULL
        };
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, module_status_options,
                             git_submodule_helper_usage, 0);
 
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
-               return 1;
+               goto cleanup;
 
        info.prefix = prefix;
        if (quiet)
@@ -778,25 +741,11 @@ static int module_status(int argc, const char **argv, const char *prefix)
 
        for_each_listed_submodule(&list, status_submodule_cb, &info);
 
-       return 0;
-}
-
-static int module_name(int argc, const char **argv, const char *prefix)
-{
-       const struct submodule *sub;
-
-       if (argc != 2)
-               usage(_("git submodule--helper name <path>"));
-
-       sub = submodule_from_path(the_repository, null_oid(), argv[1]);
-
-       if (!sub)
-               die(_("no submodule mapping found in .gitmodules for path '%s'"),
-                   argv[1]);
-
-       printf("%s\n", sub->name);
-
-       return 0;
+       ret = 0;
+cleanup:
+       module_list_release(&list);
+       clear_pathspec(&pathspec);
+       return ret;
 }
 
 struct module_cb {
@@ -805,16 +754,34 @@ struct module_cb {
        struct object_id oid_src;
        struct object_id oid_dst;
        char status;
-       const char *sm_path;
+       char *sm_path;
 };
 #define MODULE_CB_INIT { 0 }
 
+static void module_cb_release(struct module_cb *mcb)
+{
+       free(mcb->sm_path);
+}
+
 struct module_cb_list {
        struct module_cb **entries;
        int alloc, nr;
 };
 #define MODULE_CB_LIST_INIT { 0 }
 
+static void module_cb_list_release(struct module_cb_list *mcbl)
+{
+       int i;
+
+       for (i = 0; i < mcbl->nr; i++) {
+               struct module_cb *mcb = mcbl->entries[i];
+
+               module_cb_release(mcb);
+               free(mcb);
+       }
+       free(mcbl->entries);
+}
+
 struct summary_cb {
        int argc;
        const char **argv;
@@ -851,7 +818,7 @@ static char *verify_submodule_committish(const char *sm_path,
        return strbuf_detach(&result, NULL);
 }
 
-static void print_submodule_summary(struct summary_cb *info, char *errmsg,
+static void print_submodule_summary(struct summary_cb *info, const char *errmsg,
                                    int total_commits, const char *displaypath,
                                    const char *src_abbrev, const char *dst_abbrev,
                                    struct module_cb *p)
@@ -909,12 +876,13 @@ static void generate_submodule_summary(struct summary_cb *info,
 {
        char *displaypath, *src_abbrev = NULL, *dst_abbrev;
        int missing_src = 0, missing_dst = 0;
-       char *errmsg = NULL;
+       struct strbuf errmsg = STRBUF_INIT;
        int total_commits = -1;
 
        if (!info->cached && oideq(&p->oid_dst, null_oid())) {
                if (S_ISGITLINK(p->mod_dst)) {
                        struct ref_store *refs = get_submodule_ref_store(p->sm_path);
+
                        if (refs)
                                refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
                } else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {
@@ -1009,28 +977,27 @@ static void generate_submodule_summary(struct summary_cb *info,
                 * submodule, i.e., deleted or changed to blob
                 */
                if (S_ISGITLINK(p->mod_dst)) {
-                       struct strbuf errmsg_str = STRBUF_INIT;
                        if (missing_src && missing_dst) {
-                               strbuf_addf(&errmsg_str, "  Warn: %s doesn't contain commits %s and %s\n",
+                               strbuf_addf(&errmsg, "  Warn: %s doesn't contain commits %s and %s\n",
                                            displaypath, oid_to_hex(&p->oid_src),
                                            oid_to_hex(&p->oid_dst));
                        } else {
-                               strbuf_addf(&errmsg_str, "  Warn: %s doesn't contain commit %s\n",
+                               strbuf_addf(&errmsg, "  Warn: %s doesn't contain commit %s\n",
                                            displaypath, missing_src ?
                                            oid_to_hex(&p->oid_src) :
                                            oid_to_hex(&p->oid_dst));
                        }
-                       errmsg = strbuf_detach(&errmsg_str, NULL);
                }
        }
 
-       print_submodule_summary(info, errmsg, total_commits,
-                               displaypath, src_abbrev,
+       print_submodule_summary(info, errmsg.len ? errmsg.buf : NULL,
+                               total_commits, displaypath, src_abbrev,
                                dst_abbrev, p);
 
        free(displaypath);
        free(src_abbrev);
        free(dst_abbrev);
+       strbuf_release(&errmsg);
 }
 
 static void prepare_submodule_summary(struct summary_cb *info,
@@ -1114,6 +1081,9 @@ static int compute_summary_module_list(struct object_id *head_oid,
 {
        struct strvec diff_args = STRVEC_INIT;
        struct rev_info rev;
+       struct setup_revision_opt opt = {
+               .free_removed_argv_elements = 1,
+       };
        struct module_cb_list list = MODULE_CB_LIST_INIT;
        int ret = 0;
 
@@ -1131,7 +1101,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
        init_revisions(&rev, info->prefix);
        rev.abbrev = 0;
        precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
-       setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
+       setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
        rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = submodule_summary_callback;
        rev.diffopt.format_callback_data = &list;
@@ -1158,6 +1128,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
 cleanup:
        strvec_clear(&diff_args);
        release_revisions(&rev);
+       module_cb_list_release(&list);
        return ret;
 }
 
@@ -1171,7 +1142,6 @@ static int module_summary(int argc, const char **argv, const char *prefix)
        enum diff_cmd diff_cmd = DIFF_INDEX;
        struct object_id head_oid;
        int ret;
-
        struct option module_summary_options[] = {
                OPT_BOOL(0, "cached", &cached,
                         N_("use the commit stored in the index instead of the submodule HEAD")),
@@ -1183,9 +1153,8 @@ static int module_summary(int argc, const char **argv, const char *prefix)
                             N_("limit the summary size")),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
-               N_("git submodule--helper summary [<options>] [<commit>] [--] [<path>]"),
+               N_("git submodule summary [<options>] [<commit>] [--] [<path>]"),
                NULL
        };
 
@@ -1245,6 +1214,7 @@ static void sync_submodule(const char *path, const char *prefix,
        char *sub_origin_url, *super_config_url, *displaypath, *default_remote;
        struct strbuf sb = STRBUF_INIT;
        char *sub_config_path = NULL;
+       int code;
 
        if (!is_submodule_active(the_repository, path))
                return;
@@ -1255,6 +1225,7 @@ static void sync_submodule(const char *path, const char *prefix,
                if (starts_with_dot_dot_slash(sub->url) ||
                    starts_with_dot_slash(sub->url)) {
                        char *up_path = get_up_path(path);
+
                        sub_origin_url = resolve_relative_url(sub->url, up_path, 1);
                        super_config_url = resolve_relative_url(sub->url, NULL, 1);
                        free(up_path);
@@ -1283,10 +1254,9 @@ static void sync_submodule(const char *path, const char *prefix,
                goto cleanup;
 
        strbuf_reset(&sb);
-       default_remote = get_default_remote_submodule(path);
-       if (!default_remote)
-               die(_("failed to get the default remote for submodule '%s'"),
-                     path);
+       code = get_default_remote_submodule(path, &default_remote);
+       if (code)
+               exit(code);
 
        remote_key = xstrfmt("remote.%s.url", default_remote);
        free(default_remote);
@@ -1330,34 +1300,34 @@ cleanup:
 static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 {
        struct sync_cb *info = cb_data;
+
        sync_submodule(list_item->name, info->prefix, info->flags);
 }
 
 static int module_sync(int argc, const char **argv, const char *prefix)
 {
        struct sync_cb info = SYNC_CB_INIT;
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
        int recursive = 0;
-
        struct option module_sync_options[] = {
                OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
                OPT_BOOL(0, "recursive", &recursive,
                        N_("recurse into nested submodules")),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
-               N_("git submodule--helper sync [--quiet] [--recursive] [<path>]"),
+               N_("git submodule sync [--quiet] [--recursive] [<path>]"),
                NULL
        };
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, module_sync_options,
                             git_submodule_helper_usage, 0);
 
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
-               return 1;
+               goto cleanup;
 
        info.prefix = prefix;
        if (quiet)
@@ -1367,7 +1337,11 @@ static int module_sync(int argc, const char **argv, const char *prefix)
 
        for_each_listed_submodule(&list, sync_submodule_cb, &info);
 
-       return 0;
+       ret = 0;
+cleanup:
+       module_list_release(&list);
+       clear_pathspec(&pathspec);
+       return ret;
 }
 
 struct deinit_cb {
@@ -1411,6 +1385,7 @@ static void deinit_submodule(const char *path, const char *prefix,
 
                if (!(flags & OPT_FORCE)) {
                        struct child_process cp_rm = CHILD_PROCESS_INIT;
+
                        cp_rm.git_cmd = 1;
                        strvec_pushl(&cp_rm.args, "rm", "-qn",
                                     path, NULL);
@@ -1447,6 +1422,7 @@ static void deinit_submodule(const char *path, const char *prefix,
        /* remove the .git/config entries (unless the user already did it) */
        if (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {
                char *sub_key = xstrfmt("submodule.%s", sub->name);
+
                /*
                 * remove the whole section so we have a clean state when
                 * the user later decides to init this submodule again
@@ -1474,23 +1450,22 @@ static void deinit_submodule_cb(const struct cache_entry *list_item,
 static int module_deinit(int argc, const char **argv, const char *prefix)
 {
        struct deinit_cb info = DEINIT_CB_INIT;
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
        int force = 0;
        int all = 0;
-
        struct option module_deinit_options[] = {
                OPT__QUIET(&quiet, N_("suppress submodule status output")),
                OPT__FORCE(&force, N_("remove submodule working trees even if they contain local changes"), 0),
                OPT_BOOL(0, "all", &all, N_("unregister all submodules")),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
                N_("git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"),
                NULL
        };
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, module_deinit_options,
                             git_submodule_helper_usage, 0);
@@ -1505,7 +1480,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
                die(_("Use '--all' if you really want to deinitialize all submodules"));
 
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
-               return 1;
+               goto cleanup;
 
        info.prefix = prefix;
        if (quiet)
@@ -1515,7 +1490,11 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
 
        for_each_listed_submodule(&list, deinit_submodule_cb, &info);
 
-       return 0;
+       ret = 0;
+cleanup:
+       module_list_release(&list);
+       clear_pathspec(&pathspec);
+       return ret;
 }
 
 struct module_clone_data {
@@ -1525,7 +1504,6 @@ struct module_clone_data {
        const char *url;
        const char *depth;
        struct list_objects_filter_options *filter_options;
-       struct string_list reference;
        unsigned int quiet: 1;
        unsigned int progress: 1;
        unsigned int dissociate: 1;
@@ -1533,7 +1511,6 @@ struct module_clone_data {
        int single_branch;
 };
 #define MODULE_CLONE_DATA_INIT { \
-       .reference = STRING_LIST_INIT_NODUP, \
        .single_branch = -1, \
 }
 
@@ -1574,7 +1551,9 @@ static int add_possible_reference_from_superproject(
                struct strbuf err = STRBUF_INIT;
                strbuf_add(&sb, odb->path, len);
 
-               repo_init(&alternate, sb.buf, NULL);
+               if (repo_init(&alternate, sb.buf, NULL) < 0)
+                       die(_("could not get a repository handle for gitdir '%s'"),
+                           sb.buf);
 
                /*
                 * We need to end the new path with '/' to mark it as a dir,
@@ -1589,7 +1568,9 @@ static int add_possible_reference_from_superproject(
 
                sm_alternate = compute_alternate_path(sb.buf, &err);
                if (sm_alternate) {
-                       string_list_append(sas->reference, xstrdup(sb.buf));
+                       char *p = strbuf_detach(&sb, NULL);
+
+                       string_list_append(sas->reference, p)->util = p;
                        free(sm_alternate);
                } else {
                        switch (sas->error_mode) {
@@ -1648,23 +1629,31 @@ static void prepare_possible_alternates(const char *sm_name,
        free(error_strategy);
 }
 
-static int clone_submodule(struct module_clone_data *clone_data)
+static char *clone_submodule_sm_gitdir(const char *name)
 {
-       char *p, *sm_gitdir;
-       char *sm_alternate = NULL, *error_strategy = NULL;
        struct strbuf sb = STRBUF_INIT;
-       struct child_process cp = CHILD_PROCESS_INIT;
+       char *sm_gitdir;
 
-       submodule_name_to_gitdir(&sb, the_repository, clone_data->name);
+       submodule_name_to_gitdir(&sb, the_repository, name);
        sm_gitdir = absolute_pathdup(sb.buf);
-       strbuf_reset(&sb);
+       strbuf_release(&sb);
 
-       if (!is_absolute_path(clone_data->path)) {
-               strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
-               clone_data->path = strbuf_detach(&sb, NULL);
-       } else {
-               clone_data->path = xstrdup(clone_data->path);
-       }
+       return sm_gitdir;
+}
+
+static int clone_submodule(const struct module_clone_data *clone_data,
+                          struct string_list *reference)
+{
+       char *p;
+       char *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);
+       char *sm_alternate = NULL, *error_strategy = NULL;
+       struct child_process cp = CHILD_PROCESS_INIT;
+       const char *clone_data_path = clone_data->path;
+       char *to_free = NULL;
+
+       if (!is_absolute_path(clone_data->path))
+               clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
+                                                   clone_data->path);
 
        if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
                die(_("refusing to create/use '%s' in another submodule's "
@@ -1674,7 +1663,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
                if (safe_create_leading_directories_const(sm_gitdir) < 0)
                        die(_("could not create directory '%s'"), sm_gitdir);
 
-               prepare_possible_alternates(clone_data->name, &clone_data->reference);
+               prepare_possible_alternates(clone_data->name, reference);
 
                strvec_push(&cp.args, "clone");
                strvec_push(&cp.args, "--no-checkout");
@@ -1684,9 +1673,10 @@ static int clone_submodule(struct module_clone_data *clone_data)
                        strvec_push(&cp.args, "--progress");
                if (clone_data->depth && *(clone_data->depth))
                        strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
-               if (clone_data->reference.nr) {
+               if (reference->nr) {
                        struct string_list_item *item;
-                       for_each_string_list_item(item, &clone_data->reference)
+
+                       for_each_string_list_item(item, reference)
                                strvec_pushl(&cp.args, "--reference",
                                             item->string, NULL);
                }
@@ -1705,7 +1695,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
 
                strvec_push(&cp.args, "--");
                strvec_push(&cp.args, clone_data->url);
-               strvec_push(&cp.args, clone_data->path);
+               strvec_push(&cp.args, clone_data_path);
 
                cp.git_cmd = 1;
                prepare_submodule_repo_env(&cp.env);
@@ -1713,23 +1703,25 @@ static int clone_submodule(struct module_clone_data *clone_data)
 
                if(run_command(&cp))
                        die(_("clone of '%s' into submodule path '%s' failed"),
-                           clone_data->url, clone_data->path);
+                           clone_data->url, clone_data_path);
        } else {
-               if (clone_data->require_init && !access(clone_data->path, X_OK) &&
-                   !is_empty_dir(clone_data->path))
-                       die(_("directory not empty: '%s'"), clone_data->path);
-               if (safe_create_leading_directories_const(clone_data->path) < 0)
-                       die(_("could not create directory '%s'"), clone_data->path);
-               strbuf_addf(&sb, "%s/index", sm_gitdir);
-               unlink_or_warn(sb.buf);
-               strbuf_reset(&sb);
+               char *path;
+
+               if (clone_data->require_init && !access(clone_data_path, X_OK) &&
+                   !is_empty_dir(clone_data_path))
+                       die(_("directory not empty: '%s'"), clone_data_path);
+               if (safe_create_leading_directories_const(clone_data_path) < 0)
+                       die(_("could not create directory '%s'"), clone_data_path);
+               path = xstrfmt("%s/index", sm_gitdir);
+               unlink_or_warn(path);
+               free(path);
        }
 
-       connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
+       connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
 
-       p = git_pathdup_submodule(clone_data->path, "config");
+       p = git_pathdup_submodule(clone_data_path, "config");
        if (!p)
-               die(_("could not get submodule directory for '%s'"), clone_data->path);
+               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);
@@ -1744,9 +1736,9 @@ static int clone_submodule(struct module_clone_data *clone_data)
        free(sm_alternate);
        free(error_strategy);
 
-       strbuf_release(&sb);
        free(sm_gitdir);
        free(p);
+       free(to_free);
        return 0;
 }
 
@@ -1754,7 +1746,9 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 {
        int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
        struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
-       struct list_objects_filter_options filter_options;
+       struct string_list reference = STRING_LIST_INIT_NODUP;
+       struct list_objects_filter_options filter_options =
+               LIST_OBJECTS_FILTER_INIT;
 
        struct option module_clone_options[] = {
                OPT_STRING(0, "prefix", &clone_data.prefix,
@@ -1769,7 +1763,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
                OPT_STRING(0, "url", &clone_data.url,
                           N_("string"),
                           N_("url where to clone the submodule from")),
-               OPT_STRING_LIST(0, "reference", &clone_data.reference,
+               OPT_STRING_LIST(0, "reference", &reference,
                           N_("repo"),
                           N_("reference repository")),
                OPT_BOOL(0, "dissociate", &dissociate,
@@ -1787,7 +1781,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
                OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
                N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
                   "[--reference <repository>] [--name <name>] [--depth <depth>] "
@@ -1796,7 +1789,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
                NULL
        };
 
-       memset(&filter_options, 0, sizeof(filter_options));
        argc = parse_options(argc, argv, prefix, module_clone_options,
                             git_submodule_helper_usage, 0);
 
@@ -1810,31 +1802,33 @@ static int module_clone(int argc, const char **argv, const char *prefix)
                usage_with_options(git_submodule_helper_usage,
                                   module_clone_options);
 
-       clone_submodule(&clone_data);
+       clone_submodule(&clone_data, &reference);
        list_objects_filter_release(&filter_options);
+       string_list_clear(&reference, 1);
        return 0;
 }
 
-static void determine_submodule_update_strategy(struct repository *r,
-                                               int just_cloned,
-                                               const char *path,
-                                               const char *update,
-                                               struct submodule_update_strategy *out)
+static int determine_submodule_update_strategy(struct repository *r,
+                                              int just_cloned,
+                                              const char *path,
+                                              enum submodule_update_type update,
+                                              struct submodule_update_strategy *out)
 {
        const struct submodule *sub = submodule_from_path(r, null_oid(), path);
        char *key;
        const char *val;
+       int ret;
 
        key = xstrfmt("submodule.%s.update", sub->name);
 
        if (update) {
-               if (parse_submodule_update_strategy(update, out) < 0)
-                       die(_("Invalid update mode '%s' for submodule path '%s'"),
-                               update, path);
+               out->type = update;
        } else if (!repo_config_get_string_tmp(r, key, &val)) {
-               if (parse_submodule_update_strategy(val, out) < 0)
-                       die(_("Invalid update mode '%s' configured for submodule path '%s'"),
-                               val, path);
+               if (parse_submodule_update_strategy(val, out) < 0) {
+                       ret = die_message(_("Invalid update mode '%s' configured for submodule path '%s'"),
+                                         val, path);
+                       goto cleanup;
+               }
        } else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
                if (sub->update_strategy.type == SM_UPDATE_COMMAND)
                        BUG("how did we read update = !command from .gitmodules?");
@@ -1849,7 +1843,10 @@ static void determine_submodule_update_strategy(struct repository *r,
             out->type == SM_UPDATE_NONE))
                out->type = SM_UPDATE_CHECKOUT;
 
+       ret = 0;
+cleanup:
        free(key);
+       return ret;
 }
 
 struct update_clone_data {
@@ -1863,7 +1860,7 @@ struct submodule_update_clone {
        int current;
 
        /* configuration parameters which are passed on to the children */
-       struct update_data *update_data;
+       const struct update_data *update_data;
 
        /* to be consumed by update_submodule() */
        struct update_clone_data *update_clone;
@@ -1878,11 +1875,16 @@ struct submodule_update_clone {
 };
 #define SUBMODULE_UPDATE_CLONE_INIT { 0 }
 
+static void submodule_update_clone_release(struct submodule_update_clone *suc)
+{
+       free(suc->update_clone);
+       free(suc->failed_clones);
+}
+
 struct update_data {
        const char *prefix;
-       const char *recursive_prefix;
-       const char *displaypath;
-       const char *update_default;
+       char *displaypath;
+       enum submodule_update_type update_default;
        struct object_id suboid;
        struct string_list references;
        struct submodule_update_strategy update_strategy;
@@ -1917,6 +1919,12 @@ struct update_data {
        .max_jobs = 1, \
 }
 
+static void update_data_release(struct update_data *ud)
+{
+       free(ud->displaypath);
+       module_list_release(&ud->list);
+}
+
 static void next_submodule_warn_missing(struct submodule_update_clone *suc,
                struct strbuf *out, const char *displaypath)
 {
@@ -1949,30 +1957,20 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
        const char *update_string;
        enum submodule_update_type update_type;
        char *key;
-       struct strbuf displaypath_sb = STRBUF_INIT;
+       const struct update_data *ud = suc->update_data;
+       char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
        struct strbuf sb = STRBUF_INIT;
-       const char *displaypath = NULL;
        int needs_cloning = 0;
        int need_free_url = 0;
 
        if (ce_stage(ce)) {
-               if (suc->update_data->recursive_prefix)
-                       strbuf_addf(&sb, "%s/%s", suc->update_data->recursive_prefix, ce->name);
-               else
-                       strbuf_addstr(&sb, ce->name);
-               strbuf_addf(out, _("Skipping unmerged submodule %s"), sb.buf);
+               strbuf_addf(out, _("Skipping unmerged submodule %s"), displaypath);
                strbuf_addch(out, '\n');
                goto cleanup;
        }
 
        sub = submodule_from_path(the_repository, null_oid(), ce->name);
 
-       if (suc->update_data->recursive_prefix)
-               displaypath = relative_path(suc->update_data->recursive_prefix,
-                                           ce->name, &displaypath_sb);
-       else
-               displaypath = ce->name;
-
        if (!sub) {
                next_submodule_warn_missing(suc, out, displaypath);
                goto cleanup;
@@ -2051,6 +2049,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
        strvec_pushl(&child->args, "--url", url, NULL);
        if (suc->update_data->references.nr) {
                struct string_list_item *item;
+
                for_each_string_list_item(item, &suc->update_data->references)
                        strvec_pushl(&child->args, "--reference", item->string, NULL);
        }
@@ -2062,7 +2061,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                                              "--no-single-branch");
 
 cleanup:
-       strbuf_release(&displaypath_sb);
+       free(displaypath);
        strbuf_release(&sb);
        if (need_free_url)
                free((void*)url);
@@ -2083,6 +2082,7 @@ static int update_clone_get_next_task(struct child_process *child,
                ce = suc->update_data->list.entries[suc->current];
                if (prepare_to_clone_next_submodule(ce, child, suc, err)) {
                        int *p = xmalloc(sizeof(*p));
+
                        *p = suc->current;
                        *idx_task_cb = p;
                        suc->current++;
@@ -2098,6 +2098,7 @@ static int update_clone_get_next_task(struct child_process *child,
        index = suc->current - suc->update_data->list.nr;
        if (index < suc->failed_clones_nr) {
                int *p;
+
                ce = suc->failed_clones[index];
                if (!prepare_to_clone_next_submodule(ce, child, suc, err)) {
                        suc->current ++;
@@ -2121,6 +2122,7 @@ static int update_clone_start_failure(struct strbuf *err,
                                      void *idx_task_cb)
 {
        struct submodule_update_clone *suc = suc_cb;
+
        suc->quickstop = 1;
        return 1;
 }
@@ -2132,9 +2134,9 @@ static int update_clone_task_finished(int result,
 {
        const struct cache_entry *ce;
        struct submodule_update_clone *suc = suc_cb;
-
        int *idxP = idx_task_cb;
        int idx = *idxP;
+
        free(idxP);
 
        if (!result)
@@ -2167,19 +2169,20 @@ static int git_update_clone_config(const char *var, const char *value,
                                   void *cb)
 {
        int *max_jobs = cb;
+
        if (!strcmp(var, "submodule.fetchjobs"))
                *max_jobs = parse_submodule_fetchjobs(var, value);
        return 0;
 }
 
-static int is_tip_reachable(const char *path, struct object_id *oid)
+static int is_tip_reachable(const char *path, const struct object_id *oid)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf rev = STRBUF_INIT;
        char *hex = oid_to_hex(oid);
 
        cp.git_cmd = 1;
-       cp.dir = xstrdup(path);
+       cp.dir = path;
        cp.no_stderr = 1;
        strvec_pushl(&cp.args, "rev-list", "-n", "1", hex, "--not", "--all", NULL);
 
@@ -2191,13 +2194,14 @@ static int is_tip_reachable(const char *path, struct object_id *oid)
        return 1;
 }
 
-static int fetch_in_submodule(const char *module_path, int depth, int quiet, struct object_id *oid)
+static int fetch_in_submodule(const char *module_path, int depth, int quiet,
+                             const struct object_id *oid)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
 
        prepare_submodule_repo_env(&cp.env);
        cp.git_cmd = 1;
-       cp.dir = xstrdup(module_path);
+       cp.dir = module_path;
 
        strvec_push(&cp.args, "fetch");
        if (quiet)
@@ -2207,6 +2211,7 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
        if (oid) {
                char *hex = oid_to_hex(oid);
                char *remote = get_default_remote();
+
                strvec_pushl(&cp.args, remote, hex, NULL);
                free(remote);
        }
@@ -2214,11 +2219,11 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, str
        return run_command(&cp);
 }
 
-static int run_update_command(struct update_data *ud, int subforce)
+static int run_update_command(const struct update_data *ud, int subforce)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
        char *oid = oid_to_hex(&ud->oid);
-       int must_die_on_failure = 0;
+       int ret;
 
        switch (ud->update_strategy.type) {
        case SM_UPDATE_CHECKOUT:
@@ -2232,55 +2237,50 @@ static int run_update_command(struct update_data *ud, int subforce)
                strvec_push(&cp.args, "rebase");
                if (ud->quiet)
                        strvec_push(&cp.args, "--quiet");
-               must_die_on_failure = 1;
                break;
        case SM_UPDATE_MERGE:
                cp.git_cmd = 1;
                strvec_push(&cp.args, "merge");
                if (ud->quiet)
                        strvec_push(&cp.args, "--quiet");
-               must_die_on_failure = 1;
                break;
        case SM_UPDATE_COMMAND:
                cp.use_shell = 1;
                strvec_push(&cp.args, ud->update_strategy.command);
-               must_die_on_failure = 1;
                break;
        default:
-               BUG("unexpected update strategy type: %s",
-                   submodule_strategy_to_string(&ud->update_strategy));
+               BUG("unexpected update strategy type: %d",
+                   ud->update_strategy.type);
        }
        strvec_push(&cp.args, oid);
 
-       cp.dir = xstrdup(ud->sm_path);
+       cp.dir = ud->sm_path;
        prepare_submodule_repo_env(&cp.env);
-       if (run_command(&cp)) {
+       if ((ret = run_command(&cp))) {
                switch (ud->update_strategy.type) {
                case SM_UPDATE_CHECKOUT:
                        die_message(_("Unable to checkout '%s' in submodule path '%s'"),
                                    oid, ud->displaypath);
+                       /* No "ret" assignment, use "git checkout"'s */
                        break;
                case SM_UPDATE_REBASE:
-                       die_message(_("Unable to rebase '%s' in submodule path '%s'"),
-                           oid, ud->displaypath);
+                       ret = die_message(_("Unable to rebase '%s' in submodule path '%s'"),
+                                         oid, ud->displaypath);
                        break;
                case SM_UPDATE_MERGE:
-                       die_message(_("Unable to merge '%s' in submodule path '%s'"),
-                           oid, ud->displaypath);
+                       ret = die_message(_("Unable to merge '%s' in submodule path '%s'"),
+                                         oid, ud->displaypath);
                        break;
                case SM_UPDATE_COMMAND:
-                       die_message(_("Execution of '%s %s' failed in submodule path '%s'"),
-                           ud->update_strategy.command, oid, ud->displaypath);
+                       ret = die_message(_("Execution of '%s %s' failed in submodule path '%s'"),
+                                         ud->update_strategy.command, oid, ud->displaypath);
                        break;
                default:
-                       BUG("unexpected update strategy type: %s",
-                           submodule_strategy_to_string(&ud->update_strategy));
+                       BUG("unexpected update strategy type: %d",
+                           ud->update_strategy.type);
                }
-               if (must_die_on_failure)
-                       exit(128);
 
-               /* the command failed, but update must continue */
-               return 1;
+               return ret;
        }
 
        if (ud->quiet)
@@ -2304,14 +2304,14 @@ static int run_update_command(struct update_data *ud, int subforce)
                       ud->displaypath, ud->update_strategy.command, oid);
                break;
        default:
-               BUG("unexpected update strategy type: %s",
-                   submodule_strategy_to_string(&ud->update_strategy));
+               BUG("unexpected update strategy type: %d",
+                   ud->update_strategy.type);
        }
 
        return 0;
 }
 
-static int run_update_procedure(struct update_data *ud)
+static int run_update_procedure(const struct update_data *ud)
 {
        int subforce = is_null_oid(&ud->suboid) || ud->force;
 
@@ -2333,59 +2333,67 @@ static int run_update_procedure(struct update_data *ud)
                 */
                if (!is_tip_reachable(ud->sm_path, &ud->oid) &&
                    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))
-                       die(_("Fetched in submodule path '%s', but it did not "
-                             "contain %s. Direct fetching of that commit failed."),
-                           ud->displaypath, oid_to_hex(&ud->oid));
+                       return die_message(_("Fetched in submodule path '%s', but it did not "
+                                            "contain %s. Direct fetching of that commit failed."),
+                                          ud->displaypath, oid_to_hex(&ud->oid));
        }
 
        return run_update_command(ud, subforce);
 }
 
-static const char *remote_submodule_branch(const char *path)
+static int remote_submodule_branch(const char *path, const char **branch)
 {
        const struct submodule *sub;
-       const char *branch = NULL;
        char *key;
+       *branch = NULL;
 
        sub = submodule_from_path(the_repository, null_oid(), path);
        if (!sub)
-               return NULL;
+               return die_message(_("could not initialize submodule at path '%s'"),
+                                  path);
 
        key = xstrfmt("submodule.%s.branch", sub->name);
-       if (repo_config_get_string_tmp(the_repository, key, &branch))
-               branch = sub->branch;
+       if (repo_config_get_string_tmp(the_repository, key, branch))
+               *branch = sub->branch;
        free(key);
 
-       if (!branch)
-               return "HEAD";
+       if (!*branch) {
+               *branch = "HEAD";
+               return 0;
+       }
 
-       if (!strcmp(branch, ".")) {
+       if (!strcmp(*branch, ".")) {
                const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 
                if (!refname)
-                       die(_("No such ref: %s"), "HEAD");
+                       return die_message(_("No such ref: %s"), "HEAD");
 
                /* detached HEAD */
                if (!strcmp(refname, "HEAD"))
-                       die(_("Submodule (%s) branch configured to inherit "
-                             "branch from superproject, but the superproject "
-                             "is not on any branch"), sub->name);
+                       return die_message(_("Submodule (%s) branch configured to inherit "
+                                            "branch from superproject, but the superproject "
+                                            "is not on any branch"), sub->name);
 
                if (!skip_prefix(refname, "refs/heads/", &refname))
-                       die(_("Expecting a full ref name, got %s"), refname);
-               return refname;
+                       return die_message(_("Expecting a full ref name, got %s"),
+                                          refname);
+
+               *branch = refname;
+               return 0;
        }
 
-       return branch;
+       /* Our "branch" is coming from repo_config_get_string_tmp() */
+       return 0;
 }
 
-static void ensure_core_worktree(const char *path)
+static int ensure_core_worktree(const char *path)
 {
        const char *cw;
        struct repository subrepo;
 
        if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
-               die(_("could not get a repository handle for submodule '%s'"), path);
+               return die_message(_("could not get a repository handle for submodule '%s'"),
+                                  path);
 
        if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
                char *cfg_file, *abs_path;
@@ -2403,15 +2411,39 @@ static void ensure_core_worktree(const char *path)
                free(abs_path);
                strbuf_release(&sb);
        }
+
+       repo_clear(&subrepo);
+       return 0;
+}
+
+static const char *submodule_update_type_to_label(enum submodule_update_type type)
+{
+       switch (type) {
+       case SM_UPDATE_CHECKOUT:
+               return "checkout";
+       case SM_UPDATE_MERGE:
+               return "merge";
+       case SM_UPDATE_REBASE:
+               return "rebase";
+       case SM_UPDATE_UNSPECIFIED:
+       case SM_UPDATE_NONE:
+       case SM_UPDATE_COMMAND:
+               break;
+       }
+       BUG("unreachable with type %d", type);
 }
 
-static void update_data_to_args(struct update_data *update_data, struct strvec *args)
+static void update_data_to_args(const struct update_data *update_data,
+                               struct strvec *args)
 {
+       enum submodule_update_type update_type = update_data->update_default;
+
+       if (update_data->displaypath) {
+               strvec_push(args, "--super-prefix");
+               strvec_pushf(args, "%s/", update_data->displaypath);
+       }
        strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
        strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
-       if (update_data->recursive_prefix)
-               strvec_pushl(args, "--recursive-prefix",
-                            update_data->recursive_prefix, NULL);
        if (update_data->quiet)
                strvec_push(args, "--quiet");
        if (update_data->force)
@@ -2430,10 +2462,13 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *
                strvec_push(args, "--require-init");
        if (update_data->depth)
                strvec_pushf(args, "--depth=%d", update_data->depth);
-       if (update_data->update_default)
-               strvec_pushl(args, "--update", update_data->update_default, NULL);
+       if (update_type != SM_UPDATE_UNSPECIFIED)
+               strvec_pushf(args, "--%s",
+                            submodule_update_type_to_label(update_type));
+
        if (update_data->references.nr) {
                struct string_list_item *item;
+
                for_each_string_list_item(item, &update_data->references)
                        strvec_pushl(args, "--reference", item->string, NULL);
        }
@@ -2453,66 +2488,62 @@ static void update_data_to_args(struct update_data *update_data, struct strvec *
 
 static int update_submodule(struct update_data *update_data)
 {
-       char *prefixed_path;
-
-       ensure_core_worktree(update_data->sm_path);
-
-       if (update_data->recursive_prefix)
-               prefixed_path = xstrfmt("%s%s", update_data->recursive_prefix,
-                                       update_data->sm_path);
-       else
-               prefixed_path = xstrdup(update_data->sm_path);
-
-       update_data->displaypath = get_submodule_displaypath(prefixed_path,
-                                                            update_data->prefix);
-       free(prefixed_path);
+       int ret;
 
-       determine_submodule_update_strategy(the_repository, update_data->just_cloned,
-                                           update_data->sm_path, update_data->update_default,
-                                           &update_data->update_strategy);
+       ret = determine_submodule_update_strategy(the_repository,
+                                                 update_data->just_cloned,
+                                                 update_data->sm_path,
+                                                 update_data->update_default,
+                                                 &update_data->update_strategy);
+       if (ret)
+               return ret;
 
        if (update_data->just_cloned)
                oidcpy(&update_data->suboid, null_oid());
        else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
-               die(_("Unable to find current revision in submodule path '%s'"),
-                       update_data->displaypath);
+               return die_message(_("Unable to find current revision in submodule path '%s'"),
+                                  update_data->displaypath);
 
        if (update_data->remote) {
-               char *remote_name = get_default_remote_submodule(update_data->sm_path);
-               const char *branch = remote_submodule_branch(update_data->sm_path);
-               char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+               char *remote_name;
+               const char *branch;
+               char *remote_ref;
+               int code;
+
+               code = get_default_remote_submodule(update_data->sm_path, &remote_name);
+               if (code)
+                       return code;
+               code = remote_submodule_branch(update_data->sm_path, &branch);
+               if (code)
+                       return code;
+               remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+               free(remote_name);
 
                if (!update_data->nofetch) {
                        if (fetch_in_submodule(update_data->sm_path, update_data->depth,
                                              0, NULL))
-                               die(_("Unable to fetch in submodule path '%s'"),
-                                   update_data->sm_path);
+                               return die_message(_("Unable to fetch in submodule path '%s'"),
+                                                  update_data->sm_path);
                }
 
                if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
-                       die(_("Unable to find %s revision in submodule path '%s'"),
-                           remote_ref, update_data->sm_path);
+                       return die_message(_("Unable to find %s revision in submodule path '%s'"),
+                                          remote_ref, update_data->sm_path);
 
                free(remote_ref);
        }
 
-       if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
-               if (run_update_procedure(update_data))
-                       return 1;
+       if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {
+               ret = run_update_procedure(update_data);
+               if (ret)
+                       return ret;
+       }
 
        if (update_data->recursive) {
                struct child_process cp = CHILD_PROCESS_INIT;
                struct update_data next = *update_data;
-               int res;
 
-               if (update_data->recursive_prefix)
-                       prefixed_path = xstrfmt("%s%s/", update_data->recursive_prefix,
-                                               update_data->sm_path);
-               else
-                       prefixed_path = xstrfmt("%s/", update_data->sm_path);
-
-               next.recursive_prefix = get_submodule_displaypath(prefixed_path,
-                                                                 update_data->prefix);
                next.prefix = NULL;
                oidcpy(&next.oid, null_oid());
                oidcpy(&next.suboid, null_oid());
@@ -2522,16 +2553,11 @@ static int update_submodule(struct update_data *update_data)
                prepare_submodule_repo_env(&cp.env);
                update_data_to_args(&next, &cp.args);
 
-               /* die() if child process die()'d */
-               res = run_command(&cp);
-               if (!res)
-                       return 0;
-               die_message(_("Failed to recurse into submodule path '%s'"),
-                           update_data->displaypath);
-               if (res == 128)
-                       exit(res);
-               else if (res)
-                       return 1;
+               ret = run_command(&cp);
+               if (ret)
+                       die_message(_("Failed to recurse into submodule path '%s'"),
+                                   update_data->displaypath);
+               return ret;
        }
 
        return 0;
@@ -2539,7 +2565,7 @@ static int update_submodule(struct update_data *update_data)
 
 static int update_submodules(struct update_data *update_data)
 {
-       int i, res = 0;
+       int i, ret = 0;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
 
        suc.update_data = update_data;
@@ -2557,33 +2583,48 @@ static int update_submodules(struct update_data *update_data)
         * - the listener can avoid doing any work if fetching failed.
         */
        if (suc.quickstop) {
-               res = 1;
+               ret = 1;
                goto cleanup;
        }
 
        for (i = 0; i < suc.update_clone_nr; i++) {
                struct update_clone_data ucd = suc.update_clone[i];
+               int code;
 
                oidcpy(&update_data->oid, &ucd.oid);
                update_data->just_cloned = ucd.just_cloned;
                update_data->sm_path = ucd.sub->path;
 
-               if (update_submodule(update_data))
-                       res = 1;
+               code = ensure_core_worktree(update_data->sm_path);
+               if (code)
+                       goto fail;
+
+               update_data->displaypath = get_submodule_displaypath(
+                       update_data->sm_path, update_data->prefix);
+               code = update_submodule(update_data);
+               FREE_AND_NULL(update_data->displaypath);
+fail:
+               if (!code)
+                       continue;
+               ret = code;
+               if (ret == 128)
+                       goto cleanup;
        }
 
 cleanup:
+       submodule_update_clone_release(&suc);
        string_list_clear(&update_data->references, 0);
-       return res;
+       return ret;
 }
 
 static int module_update(int argc, const char **argv, const char *prefix)
 {
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
+       struct pathspec pathspec2 = { 0 };
        struct update_data opt = UPDATE_DATA_INIT;
-       struct list_objects_filter_options filter_options;
+       struct list_objects_filter_options filter_options =
+               LIST_OBJECTS_FILTER_INIT;
        int ret;
-
        struct option module_update_options[] = {
                OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
                OPT_BOOL(0, "init", &opt.init,
@@ -2597,13 +2638,15 @@ static int module_update(int argc, const char **argv, const char *prefix)
                OPT_STRING(0, "prefix", &opt.prefix,
                           N_("path"),
                           N_("path into the working tree")),
-               OPT_STRING(0, "recursive-prefix", &opt.recursive_prefix,
-                          N_("path"),
-                          N_("path into the working tree, across nested "
-                             "submodule boundaries")),
-               OPT_STRING(0, "update", &opt.update_default,
-                          N_("string"),
-                          N_("rebase, merge, checkout or none")),
+               OPT_SET_INT(0, "checkout", &opt.update_default,
+                       N_("use the 'checkout' update strategy (default)"),
+                       SM_UPDATE_CHECKOUT),
+               OPT_SET_INT('m', "merge", &opt.update_default,
+                       N_("use the 'merge' update strategy"),
+                       SM_UPDATE_MERGE),
+               OPT_SET_INT('r', "rebase", &opt.update_default,
+                       N_("use the 'rebase' update strategy"),
+                       SM_UPDATE_REBASE),
                OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
                           N_("reference repository")),
                OPT_BOOL(0, "dissociate", &opt.dissociate,
@@ -2619,13 +2662,12 @@ static int module_update(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "progress", &opt.progress,
                            N_("force cloning progress")),
                OPT_BOOL(0, "require-init", &opt.require_init,
-                          N_("disallow cloning into non-empty directory")),
+                          N_("disallow cloning into non-empty directory, implies --init")),
                OPT_BOOL(0, "single-branch", &opt.single_branch,
                         N_("clone only one branch, HEAD or --branch")),
                OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
                N_("git submodule [--quiet] update"
                " [--init [--filter=<filter-spec>]] [--remote]"
@@ -2639,10 +2681,12 @@ 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);
 
-       memset(&filter_options, 0, sizeof(filter_options));
        argc = parse_options(argc, argv, prefix, module_update_options,
                             git_submodule_helper_usage, 0);
 
+       if (opt.require_init)
+               opt.init = 1;
+
        if (filter_options.choice && !opt.init) {
                usage_with_options(git_submodule_helper_usage,
                                   module_update_options);
@@ -2651,13 +2695,11 @@ static int module_update(int argc, const char **argv, const char *prefix)
        opt.filter_options = &filter_options;
 
        if (opt.update_default)
-               if (parse_submodule_update_strategy(opt.update_default,
-                                                   &opt.update_strategy) < 0)
-                       die(_("bad value for update parameter"));
+               opt.update_strategy.type = opt.update_default;
 
        if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0) {
-               list_objects_filter_release(&filter_options);
-               return 1;
+               ret = 1;
+               goto cleanup;
        }
 
        if (pathspec.nr)
@@ -2668,8 +2710,11 @@ static int module_update(int argc, const char **argv, const char *prefix)
                struct init_cb info = INIT_CB_INIT;
 
                if (module_list_compute(argc, argv, opt.prefix,
-                                       &pathspec, &list) < 0)
-                       return 1;
+                                       &pathspec2, &list) < 0) {
+                       module_list_release(&list);
+                       ret = 1;
+                       goto cleanup;
+               }
 
                /*
                 * If there are no path args and submodule.active is set then,
@@ -2679,15 +2724,19 @@ static int module_update(int argc, const char **argv, const char *prefix)
                        module_list_active(&list);
 
                info.prefix = opt.prefix;
-               info.superprefix = opt.recursive_prefix;
                if (opt.quiet)
                        info.flags |= OPT_QUIET;
 
                for_each_listed_submodule(&list, init_submodule_cb, &info);
+               module_list_release(&list);
        }
 
        ret = update_submodules(&opt);
+cleanup:
+       update_data_release(&opt);
        list_objects_filter_release(&filter_options);
+       clear_pathspec(&pathspec);
+       clear_pathspec(&pathspec2);
        return ret;
 }
 
@@ -2771,10 +2820,9 @@ static int push_check(int argc, const char **argv, const char *prefix)
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 {
        int i;
-       struct pathspec pathspec;
+       struct pathspec pathspec = { 0 };
        struct module_list list = MODULE_LIST_INIT;
        unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;
-
        struct option embed_gitdir_options[] = {
                OPT_STRING(0, "prefix", &prefix,
                           N_("path"),
@@ -2783,53 +2831,26 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
                        ABSORB_GITDIR_RECURSE_SUBMODULES),
                OPT_END()
        };
-
        const char *const git_submodule_helper_usage[] = {
-               N_("git submodule--helper absorb-git-dirs [<options>] [<path>...]"),
+               N_("git submodule absorbgitdirs [<options>] [<path>...]"),
                NULL
        };
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, embed_gitdir_options,
                             git_submodule_helper_usage, 0);
 
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
-               return 1;
+               goto cleanup;
 
        for (i = 0; i < list.nr; i++)
                absorb_git_dir_into_superproject(list.entries[i]->name, flags);
 
-       return 0;
-}
-
-static int is_active(int argc, const char **argv, const char *prefix)
-{
-       if (argc != 2)
-               die("submodule--helper is-active takes exactly 1 argument");
-
-       return !is_submodule_active(the_repository, argv[1]);
-}
-
-/*
- * Exit non-zero if any of the submodule names given on the command line is
- * invalid. If no names are given, filter stdin to print only valid names
- * (which is primarily intended for testing).
- */
-static int check_name(int argc, const char **argv, const char *prefix)
-{
-       if (argc > 1) {
-               while (*++argv) {
-                       if (check_submodule_name(*argv) < 0)
-                               return 1;
-               }
-       } else {
-               struct strbuf buf = STRBUF_INIT;
-               while (strbuf_getline(&buf, stdin) != EOF) {
-                       if (!check_submodule_name(buf.buf))
-                               printf("%s\n", buf.buf);
-               }
-               strbuf_release(&buf);
-       }
-       return 0;
+       ret = 0;
+cleanup:
+       clear_pathspec(&pathspec);
+       module_list_release(&list);
+       return ret;
 }
 
 static int module_config(int argc, const char **argv, const char *prefix)
@@ -2838,7 +2859,6 @@ static int module_config(int argc, const char **argv, const char *prefix)
                CHECK_WRITEABLE = 1,
                DO_UNSET = 2
        } command = 0;
-
        struct option module_config_options[] = {
                OPT_CMDMODE(0, "check-writeable", &command,
                            N_("check if it is safe to write to the .gitmodules file"),
@@ -2884,13 +2904,12 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
        const char *newurl;
        const char *path;
        char *config_name;
-
        struct option options[] = {
                OPT__QUIET(&quiet, N_("suppress output for setting url of a submodule")),
                OPT_END()
        };
        const char *const usage[] = {
-               N_("git submodule--helper set-url [--quiet] <path> <newurl>"),
+               N_("git submodule set-url [--quiet] <path> <newurl>"),
                NULL
        };
 
@@ -2915,13 +2934,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
        const char *opt_branch = NULL;
        const char *path;
        char *config_name;
-
-       /*
-        * We accept the `quiet` option for uniformity across subcommands,
-        * though there is nothing to make less verbose in this subcommand.
-        */
        struct option options[] = {
+               /*
+                * We accept the `quiet` option for uniformity across subcommands,
+                * though there is nothing to make less verbose in this subcommand.
+                */
                OPT_NOOP_NOARG('q', "quiet"),
+
                OPT_BOOL('d', "default", &opt_default,
                        N_("set the default tracking branch to master")),
                OPT_STRING('b', "branch", &opt_branch, N_("branch"),
@@ -2929,8 +2948,8 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
        const char *const usage[] = {
-               N_("git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"),
-               N_("git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
+               N_("git submodule set-branch [-q|--quiet] (-d|--default) <path>"),
+               N_("git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
                NULL
        };
 
@@ -2956,7 +2975,6 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
 {
        enum branch_track track;
        int quiet = 0, force = 0, reflog = 0, dry_run = 0;
-
        struct option options[] = {
                OPT__QUIET(&quiet, N_("print only error messages")),
                OPT__FORCE(&force, N_("force creation"), 0),
@@ -3019,8 +3037,10 @@ static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
        if (!capture_command(&cp_remote, &sb_remote_out, 0)) {
                char *next_line;
                char *line = sb_remote_out.buf;
+
                while ((next_line = strchr(line, '\n')) != NULL) {
                        size_t len = next_line - line;
+
                        if (strip_suffix_mem(line, &len, " (fetch)"))
                                strbuf_addf(msg, "  %.*s\n", (int)len, line);
                        line = next_line + 1;
@@ -3034,6 +3054,8 @@ static int add_submodule(const struct add_data *add_data)
 {
        char *submod_gitdir_path;
        struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
+       struct string_list reference = STRING_LIST_INIT_NODUP;
+       int ret = -1;
 
        /* perhaps the path already exists and is already a git repo, else clone it */
        if (is_directory(add_data->sm_path)) {
@@ -3050,6 +3072,7 @@ static int add_submodule(const struct add_data *add_data)
                free(submod_gitdir_path);
        } else {
                struct child_process cp = CHILD_PROCESS_INIT;
+
                submod_gitdir_path = xstrfmt(".git/modules/%s", add_data->sm_name);
 
                if (is_directory(submod_gitdir_path)) {
@@ -3088,15 +3111,17 @@ static int add_submodule(const struct add_data *add_data)
                clone_data.url = add_data->realrepo;
                clone_data.quiet = add_data->quiet;
                clone_data.progress = add_data->progress;
-               if (add_data->reference_path)
-                       string_list_append(&clone_data.reference,
-                                          xstrdup(add_data->reference_path));
+               if (add_data->reference_path) {
+                       char *p = xstrdup(add_data->reference_path);
+
+                       string_list_append(&reference, p)->util = p;
+               }
                clone_data.dissociate = add_data->dissociate;
                if (add_data->depth >= 0)
                        clone_data.depth = xstrfmt("%d", add_data->depth);
 
-               if (clone_submodule(&clone_data))
-                       return -1;
+               if (clone_submodule(&clone_data, &reference))
+                       goto cleanup;
 
                prepare_submodule_repo_env(&cp.env);
                cp.git_cmd = 1;
@@ -3115,7 +3140,10 @@ static int add_submodule(const struct add_data *add_data)
                if (run_command(&cp))
                        die(_("unable to checkout submodule '%s'"), add_data->sm_path);
        }
-       return 0;
+       ret = 0;
+cleanup:
+       string_list_clear(&reference, 1);
+       return ret;
 }
 
 static int config_submodule_in_gitmodules(const char *name, const char *var, const char *value)
@@ -3136,7 +3164,7 @@ static int config_submodule_in_gitmodules(const char *name, const char *var, con
 static void configure_added_submodule(struct add_data *add_data)
 {
        char *key;
-       char *val = NULL;
+       const char *val;
        struct child_process add_submod = CHILD_PROCESS_INIT;
        struct child_process add_gitmodules = CHILD_PROCESS_INIT;
 
@@ -3181,7 +3209,7 @@ 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_string("submodule.active", &val) && val) {
+       if (!git_config_get_string_tmp("submodule.active", &val)) {
                /*
                 * If the submodule being added isn't already covered by the
                 * current configured pathspec, set the submodule's active flag
@@ -3255,7 +3283,6 @@ static int module_add(int argc, const char **argv, const char *prefix)
        int force = 0, quiet = 0, progress = 0, dissociate = 0;
        struct add_data add_data = ADD_DATA_INIT;
        char *to_free = NULL;
-
        struct option options[] = {
                OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
                           N_("branch of repository to add as submodule")),
@@ -3272,11 +3299,12 @@ static int module_add(int argc, const char **argv, const char *prefix)
                OPT_INTEGER(0, "depth", &add_data.depth, N_("depth for shallow clones")),
                OPT_END()
        };
-
        const char *const usage[] = {
-               N_("git submodule--helper add [<options>] [--] <repository> [<path>]"),
+               N_("git submodule add [<options>] [--] <repository> [<path>]"),
                NULL
        };
+       struct strbuf sb = STRBUF_INIT;
+       int ret = 1;
 
        argc = parse_options(argc, argv, prefix, options, usage, 0);
 
@@ -3296,8 +3324,12 @@ static int module_add(int argc, const char **argv, const char *prefix)
        else
                add_data.sm_path = xstrdup(argv[1]);
 
-       if (prefix && *prefix && !is_absolute_path(add_data.sm_path))
-               add_data.sm_path = xstrfmt("%s%s", prefix, add_data.sm_path);
+       if (prefix && *prefix && !is_absolute_path(add_data.sm_path)) {
+               char *sm_path = add_data.sm_path;
+
+               add_data.sm_path = xstrfmt("%s%s", prefix, sm_path);
+               free(sm_path);
+       }
 
        if (starts_with_dot_dot_slash(add_data.repo) ||
            starts_with_dot_slash(add_data.repo)) {
@@ -3326,20 +3358,17 @@ static int module_add(int argc, const char **argv, const char *prefix)
        die_on_repo_without_commits(add_data.sm_path);
 
        if (!force) {
-               int exit_code = -1;
-               struct strbuf sb = STRBUF_INIT;
                struct child_process cp = CHILD_PROCESS_INIT;
+
                cp.git_cmd = 1;
                cp.no_stdout = 1;
                strvec_pushl(&cp.args, "add", "--dry-run", "--ignore-missing",
                             "--no-warn-embedded-repo", add_data.sm_path, NULL);
-               if ((exit_code = pipe_command(&cp, NULL, 0, NULL, 0, &sb, 0))) {
+               if ((ret = pipe_command(&cp, NULL, 0, NULL, 0, &sb, 0))) {
                        strbuf_complete_line(&sb);
                        fputs(sb.buf, stderr);
-                       free(add_data.sm_path);
-                       return exit_code;
+                       goto cleanup;
                }
-               strbuf_release(&sb);
        }
 
        if(!add_data.sm_name)
@@ -3354,15 +3383,17 @@ static int module_add(int argc, const char **argv, const char *prefix)
        add_data.progress = !!progress;
        add_data.dissociate = !!dissociate;
 
-       if (add_submodule(&add_data)) {
-               free(add_data.sm_path);
-               return 1;
-       }
+       if (add_submodule(&add_data))
+               goto cleanup;
        configure_added_submodule(&add_data);
+
+       ret = 0;
+cleanup:
        free(add_data.sm_path);
        free(to_free);
+       strbuf_release(&sb);
 
-       return 0;
+       return ret;
 }
 
 #define SUPPORT_SUPER_PREFIX (1<<0)
@@ -3374,22 +3405,17 @@ struct cmd_struct {
 };
 
 static struct cmd_struct commands[] = {
-       {"list", module_list, 0},
-       {"name", module_name, 0},
-       {"clone", module_clone, 0},
-       {"add", module_add, SUPPORT_SUPER_PREFIX},
-       {"update", module_update, 0},
-       {"resolve-relative-url-test", resolve_relative_url_test, 0},
+       {"clone", module_clone, SUPPORT_SUPER_PREFIX},
+       {"add", module_add, 0},
+       {"update", module_update, SUPPORT_SUPER_PREFIX},
        {"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
-       {"init", module_init, SUPPORT_SUPER_PREFIX},
+       {"init", module_init, 0},
        {"status", module_status, SUPPORT_SUPER_PREFIX},
        {"sync", module_sync, SUPPORT_SUPER_PREFIX},
        {"deinit", module_deinit, 0},
-       {"summary", module_summary, SUPPORT_SUPER_PREFIX},
+       {"summary", module_summary, 0},
        {"push-check", push_check, 0},
-       {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
-       {"is-active", is_active, 0},
-       {"check-name", check_name, 0},
+       {"absorbgitdirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
        {"config", module_config, 0},
        {"set-url", module_set_url, 0},
        {"set-branch", module_set_branch, 0},
index e547a08d6c7ce517a5a26598ade75356da93cdab..1b0f10225f0c2630fab0f67534e7135b30571c66 100644 (file)
@@ -71,6 +71,8 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
                if (!strcmp(argv[0], "HEAD") &&
                    !starts_with(argv[1], "refs/"))
                        die("Refusing to point HEAD outside of refs/");
+               if (check_refname_format(argv[1], REFNAME_ALLOW_ONELEVEL) < 0)
+                       die("Refusing to set '%s' to invalid ref '%s'", argv[0], argv[1]);
                ret = !!create_symref(argv[0], argv[1], msg);
                break;
        default:
index 56d05e2725db45f1fc2ffba48fc4930dddd13ed7..43789b8ef294d8aa3fc9517f65712ac90e1fa60c 100644 (file)
@@ -97,15 +97,27 @@ static void use(int bytes)
        display_throughput(progress, consumed_bytes);
 }
 
+/*
+ * Decompress zstream from the standard input into a newly
+ * allocated buffer of specified size and return the buffer.
+ * The caller is responsible to free the returned buffer.
+ *
+ * But for dry_run mode, "get_data()" is only used to check the
+ * integrity of data, and the returned buffer is not used at all.
+ * Therefore, in dry_run mode, "get_data()" will release the small
+ * allocated buffer which is reused to hold temporary zstream output
+ * and return NULL instead of returning garbage data.
+ */
 static void *get_data(unsigned long size)
 {
        git_zstream stream;
-       void *buf = xmallocz(size);
+       unsigned long bufsize = dry_run && size > 8192 ? 8192 : size;
+       void *buf = xmallocz(bufsize);
 
        memset(&stream, 0, sizeof(stream));
 
        stream.next_out = buf;
-       stream.avail_out = size;
+       stream.avail_out = bufsize;
        stream.next_in = fill(1);
        stream.avail_in = len;
        git_inflate_init(&stream);
@@ -125,8 +137,17 @@ static void *get_data(unsigned long size)
                }
                stream.next_in = fill(1);
                stream.avail_in = len;
+               if (dry_run) {
+                       /* reuse the buffer in dry_run mode */
+                       stream.next_out = buf;
+                       stream.avail_out = bufsize > size - stream.total_out ?
+                                                  size - stream.total_out :
+                                                  bufsize;
+               }
        }
        git_inflate_end(&stream);
+       if (dry_run)
+               FREE_AND_NULL(buf);
        return buf;
 }
 
@@ -326,10 +347,70 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
 {
        void *buf = get_data(size);
 
-       if (!dry_run && buf)
+       if (buf)
                write_object(nr, type, buf, size);
-       else
-               free(buf);
+}
+
+struct input_zstream_data {
+       git_zstream *zstream;
+       unsigned char buf[8192];
+       int status;
+};
+
+static const void *feed_input_zstream(struct input_stream *in_stream,
+                                     unsigned long *readlen)
+{
+       struct input_zstream_data *data = in_stream->data;
+       git_zstream *zstream = data->zstream;
+       void *in = fill(1);
+
+       if (in_stream->is_finished) {
+               *readlen = 0;
+               return NULL;
+       }
+
+       zstream->next_out = data->buf;
+       zstream->avail_out = sizeof(data->buf);
+       zstream->next_in = in;
+       zstream->avail_in = len;
+
+       data->status = git_inflate(zstream, 0);
+
+       in_stream->is_finished = data->status != Z_OK;
+       use(len - zstream->avail_in);
+       *readlen = sizeof(data->buf) - zstream->avail_out;
+
+       return data->buf;
+}
+
+static void stream_blob(unsigned long size, unsigned nr)
+{
+       git_zstream zstream = { 0 };
+       struct input_zstream_data data = { 0 };
+       struct input_stream in_stream = {
+               .read = feed_input_zstream,
+               .data = &data,
+       };
+       struct obj_info *info = &obj_list[nr];
+
+       data.zstream = &zstream;
+       git_inflate_init(&zstream);
+
+       if (stream_loose_object(&in_stream, size, &info->oid))
+               die(_("failed to write object in stream"));
+
+       if (data.status != Z_STREAM_END)
+               die(_("inflate returned (%d)"), data.status);
+       git_inflate_end(&zstream);
+
+       if (strict) {
+               struct blob *blob = lookup_blob(the_repository, &info->oid);
+
+               if (!blob)
+                       die(_("invalid blob object from stream"));
+               blob->object.flags |= FLAG_WRITTEN;
+       }
+       info->obj = NULL;
 }
 
 static int resolve_against_held(unsigned nr, const struct object_id *base,
@@ -359,10 +440,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                oidread(&base_oid, fill(the_hash_algo->rawsz));
                use(the_hash_algo->rawsz);
                delta_data = get_data(delta_size);
-               if (dry_run || !delta_data) {
-                       free(delta_data);
+               if (!delta_data)
                        return;
-               }
                if (has_object_file(&base_oid))
                        ; /* Ok we have this one */
                else if (resolve_against_held(nr, &base_oid,
@@ -398,10 +477,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                        die("offset value out of bound for delta base object");
 
                delta_data = get_data(delta_size);
-               if (dry_run || !delta_data) {
-                       free(delta_data);
+               if (!delta_data)
                        return;
-               }
                lo = 0;
                hi = nr;
                while (lo < hi) {
@@ -468,9 +545,14 @@ static void unpack_one(unsigned nr)
        }
 
        switch (type) {
+       case OBJ_BLOB:
+               if (!dry_run && size > big_file_threshold) {
+                       stream_blob(size, nr);
+                       return;
+               }
+               /* fallthrough */
        case OBJ_COMMIT:
        case OBJ_TREE:
-       case OBJ_BLOB:
        case OBJ_TAG:
                unpack_non_delta_entry(type, size, nr);
                return;
index cd62eef240ee40262fe3308fb05ee57ca3fdc765..c6710b2552006df0a3bc70fcddcde81fa2476783 100644 (file)
@@ -1112,31 +1112,24 @@ static int repair(int ac, const char **av, const char *prefix)
 
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
+       parse_opt_subcommand_fn *fn = NULL;
        struct option options[] = {
+               OPT_SUBCOMMAND("add", &fn, add),
+               OPT_SUBCOMMAND("prune", &fn, prune),
+               OPT_SUBCOMMAND("list", &fn, list),
+               OPT_SUBCOMMAND("lock", &fn, lock_worktree),
+               OPT_SUBCOMMAND("unlock", &fn, unlock_worktree),
+               OPT_SUBCOMMAND("move", &fn, move_worktree),
+               OPT_SUBCOMMAND("remove", &fn, remove_worktree),
+               OPT_SUBCOMMAND("repair", &fn, repair),
                OPT_END()
        };
 
        git_config(git_worktree_config, NULL);
 
-       if (ac < 2)
-               usage_with_options(worktree_usage, options);
        if (!prefix)
                prefix = "";
-       if (!strcmp(av[1], "add"))
-               return add(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "prune"))
-               return prune(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "list"))
-               return list(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "lock"))
-               return lock_worktree(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "unlock"))
-               return unlock_worktree(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "move"))
-               return move_worktree(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "remove"))
-               return remove_worktree(ac - 1, av + 1, prefix);
-       if (!strcmp(av[1], "repair"))
-               return repair(ac - 1, av + 1, prefix);
-       usage_with_options(worktree_usage, options);
+
+       ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+       return fn(ac, av, prefix);
 }
index 98ec8938424406ef5973df797b8eca37fda71041..855b68ec23bdb1bdc85c1184a9c144c226f0245c 100644 (file)
@@ -340,6 +340,8 @@ void fsync_loose_object_bulk_checkin(int fd, const char *filename)
         */
        if (!bulk_fsync_objdir ||
            git_fsync(fd, FSYNC_WRITEOUT_ONLY) < 0) {
+               if (errno == ENOSYS)
+                       warning(_("core.fsyncMethod = batch is unsupported on this platform"));
                fsync_or_die(fd, filename);
        }
 }
diff --git a/bundle-uri.c b/bundle-uri.c
new file mode 100644 (file)
index 0000000..4a8cc74
--- /dev/null
@@ -0,0 +1,168 @@
+#include "cache.h"
+#include "bundle-uri.h"
+#include "bundle.h"
+#include "object-store.h"
+#include "refs.h"
+#include "run-command.h"
+
+static int find_temp_filename(struct strbuf *name)
+{
+       int fd;
+       /*
+        * Find a temporary filename that is available. This is briefly
+        * racy, but unlikely to collide.
+        */
+       fd = odb_mkstemp(name, "bundles/tmp_uri_XXXXXX");
+       if (fd < 0) {
+               warning(_("failed to create temporary file"));
+               return -1;
+       }
+
+       close(fd);
+       unlink(name->buf);
+       return 0;
+}
+
+static int download_https_uri_to_file(const char *file, const char *uri)
+{
+       int result = 0;
+       struct child_process cp = CHILD_PROCESS_INIT;
+       FILE *child_in = NULL, *child_out = NULL;
+       struct strbuf line = STRBUF_INIT;
+       int found_get = 0;
+
+       strvec_pushl(&cp.args, "git-remote-https", uri, NULL);
+       cp.in = -1;
+       cp.out = -1;
+
+       if (start_command(&cp))
+               return 1;
+
+       child_in = fdopen(cp.in, "w");
+       if (!child_in) {
+               result = 1;
+               goto cleanup;
+       }
+
+       child_out = fdopen(cp.out, "r");
+       if (!child_out) {
+               result = 1;
+               goto cleanup;
+       }
+
+       fprintf(child_in, "capabilities\n");
+       fflush(child_in);
+
+       while (!strbuf_getline(&line, child_out)) {
+               if (!line.len)
+                       break;
+               if (!strcmp(line.buf, "get"))
+                       found_get = 1;
+       }
+       strbuf_release(&line);
+
+       if (!found_get) {
+               result = error(_("insufficient capabilities"));
+               goto cleanup;
+       }
+
+       fprintf(child_in, "get %s %s\n\n", uri, file);
+
+cleanup:
+       if (child_in)
+               fclose(child_in);
+       if (finish_command(&cp))
+               return 1;
+       if (child_out)
+               fclose(child_out);
+       return result;
+}
+
+static int copy_uri_to_file(const char *filename, const char *uri)
+{
+       const char *out;
+
+       if (starts_with(uri, "https:") ||
+           starts_with(uri, "http:"))
+               return download_https_uri_to_file(filename, uri);
+
+       if (skip_prefix(uri, "file://", &out))
+               uri = out;
+
+       /* Copy as a file */
+       return copy_file(filename, uri, 0);
+}
+
+static int unbundle_from_file(struct repository *r, const char *file)
+{
+       int result = 0;
+       int bundle_fd;
+       struct bundle_header header = BUNDLE_HEADER_INIT;
+       struct string_list_item *refname;
+       struct strbuf bundle_ref = STRBUF_INIT;
+       size_t bundle_prefix_len;
+
+       if ((bundle_fd = read_bundle_header(file, &header)) < 0)
+               return 1;
+
+       if ((result = unbundle(r, &header, bundle_fd, NULL)))
+               return 1;
+
+       /*
+        * Convert all refs/heads/ from the bundle into refs/bundles/
+        * in the local repository.
+        */
+       strbuf_addstr(&bundle_ref, "refs/bundles/");
+       bundle_prefix_len = bundle_ref.len;
+
+       for_each_string_list_item(refname, &header.references) {
+               struct object_id *oid = refname->util;
+               struct object_id old_oid;
+               const char *branch_name;
+               int has_old;
+
+               if (!skip_prefix(refname->string, "refs/heads/", &branch_name))
+                       continue;
+
+               strbuf_setlen(&bundle_ref, bundle_prefix_len);
+               strbuf_addstr(&bundle_ref, branch_name);
+
+               has_old = !read_ref(bundle_ref.buf, &old_oid);
+               update_ref("fetched bundle", bundle_ref.buf, oid,
+                          has_old ? &old_oid : NULL,
+                          REF_SKIP_OID_VERIFICATION,
+                          UPDATE_REFS_MSG_ON_ERR);
+       }
+
+       bundle_header_release(&header);
+       return result;
+}
+
+int fetch_bundle_uri(struct repository *r, const char *uri)
+{
+       int result = 0;
+       struct strbuf filename = STRBUF_INIT;
+
+       if ((result = find_temp_filename(&filename)))
+               goto cleanup;
+
+       if ((result = copy_uri_to_file(filename.buf, uri))) {
+               warning(_("failed to download bundle from URI '%s'"), uri);
+               goto cleanup;
+       }
+
+       if ((result = !is_bundle(filename.buf, 0))) {
+               warning(_("file at URI '%s' is not a bundle"), uri);
+               goto cleanup;
+       }
+
+       if ((result = unbundle_from_file(r, filename.buf))) {
+               warning(_("failed to unbundle bundle from URI '%s'"), uri);
+               goto cleanup;
+       }
+
+cleanup:
+       unlink(filename.buf);
+       strbuf_release(&filename);
+       return result;
+}
diff --git a/bundle-uri.h b/bundle-uri.h
new file mode 100644 (file)
index 0000000..8a152f1
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef BUNDLE_URI_H
+#define BUNDLE_URI_H
+
+struct repository;
+
+/**
+ * Fetch data from the given 'uri' and unbundle the bundle data found
+ * based on that information.
+ *
+ * Returns non-zero if no bundle information is found at the given 'uri'.
+ */
+int fetch_bundle_uri(struct repository *r, const char *uri);
+
+#endif
index 0c052f54964f110688c6b2edf02f4c7dfca8a623..68ff39a0a74085a218f16d07619fad0adad1972c 100644 (file)
--- a/bundle.h
+++ b/bundle.h
@@ -18,6 +18,7 @@ struct bundle_header {
 { \
        .prerequisites = STRING_LIST_INIT_DUP, \
        .references = STRING_LIST_INIT_DUP, \
+       .filter = LIST_OBJECTS_FILTER_INIT, \
 }
 void bundle_header_init(struct bundle_header *header);
 void bundle_header_release(struct bundle_header *header);
index 56db0b5026b675a77a3962802ebf38c083ae107b..c97111cccf2eda3a53be9dfce637fa2c35464f4d 100644 (file)
@@ -857,9 +857,7 @@ int cache_tree_matches_traversal(struct cache_tree *root,
        return 0;
 }
 
-static void verify_one_sparse(struct repository *r,
-                             struct index_state *istate,
-                             struct cache_tree *it,
+static void verify_one_sparse(struct index_state *istate,
                              struct strbuf *path,
                              int pos)
 {
@@ -910,7 +908,7 @@ static int verify_one(struct repository *r,
                        return 1;
 
                if (pos >= 0) {
-                       verify_one_sparse(r, istate, it, path, pos);
+                       verify_one_sparse(istate, path, pos);
                        return 0;
                }
 
diff --git a/cache.h b/cache.h
index 33fc8337c6aaef7942bd8b0c5b59637b115a9e44..26ed03bd6de626e497af549fe4fecfe27acaf699 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -475,8 +475,7 @@ extern struct index_state the_index;
 
 /*
  * Values in this enum (except those outside the 3 bit range) are part
- * of pack file format. See Documentation/technical/pack-format.txt
- * for more information.
+ * of pack file format. See gitformat-pack(5) for more information.
  */
 enum object_type {
        OBJ_BAD = -1,
@@ -1017,7 +1016,6 @@ void reset_shared_repository(void);
  * commands that do not want replace references to be active.
  */
 extern int read_replace_refs;
-extern char *git_replace_ref_base;
 
 /*
  * These values are used to help identify parts of a repository to fsync.
@@ -1697,6 +1695,12 @@ struct ident_split {
  */
 int split_ident_line(struct ident_split *, const char *, int);
 
+/*
+ * Given a commit or tag object buffer and the commit or tag headers, replaces
+ * the idents in the headers with their canonical versions using the mailmap mechanism.
+ */
+void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);
+
 /*
  * Compare split idents for equality or strict ordering. Note that we
  * compare only the ident part of the line, ignoring any timestamp.
index f095519f8dba9672530430ced23eb5c66e7b8e67..1b0cc2b57db8667f3cbc9ae8b6223dd7997e7485 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -276,6 +276,7 @@ linux-musl)
 linux-leaks)
        export SANITIZE=leak
        export GIT_TEST_PASSING_SANITIZE_LEAK=true
+       export GIT_TEST_SANITIZE_LEAK_LOG=true
        ;;
 esac
 
diff --git a/color.c b/color.c
index 4f884c6b3dc1d98c99d3b5e5be0e990f58434d8e..f05d8a81d72115edbf47d34950a31615a15ea98e 100644 (file)
--- a/color.c
+++ b/color.c
@@ -415,7 +415,7 @@ int want_color_fd(int fd, int var)
        return var;
 }
 
-int git_color_config(const char *var, const char *value, void *cb)
+int git_color_config(const char *var, const char *value, void *cb UNUSED)
 {
        if (!strcmp(var, "color.ui")) {
                git_use_color_default = git_config_colorbool(var, value);
index 9bd6f3c48f4d1853e4cc5df7a9685696f63d72ce..54b2a50f5f1dfeb2121f73a43417a7855d6fe1f4 100644 (file)
 # specified here, which can only have "guide" attribute and nothing
 # else.
 #
+# User-facing repository, command and file interfaces such as
+# documentation for the .gitmodules, .mailmap etc. files lives in man
+# sections 5 and 7. These entries can only have the "userinterfaces"
+# attribute and nothing else.
+#
+# Git's file formats and protocols, such as documentation for the
+# *.bundle format lives in man section 5. These entries can only have
+# the "developerinterfaces" attribute and nothing else.
+#
 ### command list (do not change this line)
 # command name                          category [category] [category]
 git-add                                 mainporcelain           worktree
@@ -82,6 +91,7 @@ git-cvsimport                           foreignscminterface
 git-cvsserver                           foreignscminterface
 git-daemon                              synchingrepositories
 git-describe                            mainporcelain
+git-diagnose                            ancillaryinterrogators
 git-diff                                mainporcelain           info
 git-diff-files                          plumbinginterrogators
 git-diff-index                          plumbinginterrogators
@@ -189,29 +199,42 @@ git-var                                 plumbinginterrogators
 git-verify-commit                       ancillaryinterrogators
 git-verify-pack                         plumbinginterrogators
 git-verify-tag                          ancillaryinterrogators
+git-version                             ancillaryinterrogators
 git-whatchanged                         ancillaryinterrogators          complete
 git-worktree                            mainporcelain
 git-write-tree                          plumbingmanipulators
-gitattributes                           guide
-gitcli                                  guide
+gitattributes                           userinterfaces
+gitcli                                  userinterfaces
 gitcore-tutorial                        guide
 gitcredentials                          guide
 gitcvs-migration                        guide
 gitdiffcore                             guide
 giteveryday                             guide
 gitfaq                                  guide
+gitformat-bundle                        developerinterfaces
+gitformat-chunk                         developerinterfaces
+gitformat-commit-graph                  developerinterfaces
+gitformat-index                         developerinterfaces
+gitformat-pack                          developerinterfaces
+gitformat-signature                     developerinterfaces
 gitglossary                             guide
-githooks                                guide
-gitignore                               guide
+githooks                                userinterfaces
+gitignore                               userinterfaces
 gitk                                    mainporcelain
-gitmailmap                              guide
-gitmodules                              guide
+gitmailmap                              userinterfaces
+gitmodules                              userinterfaces
 gitnamespaces                           guide
+gitprotocol-capabilities                developerinterfaces
+gitprotocol-common                      developerinterfaces
+gitprotocol-http                        developerinterfaces
+gitprotocol-pack                        developerinterfaces
+gitprotocol-v2                          developerinterfaces
 gitremote-helpers                       guide
-gitrepository-layout                    guide
-gitrevisions                            guide
+gitrepository-layout                    userinterfaces
+gitrevisions                            userinterfaces
 gitsubmodules                           guide
 gittutorial                             guide
 gittutorial-2                           guide
 gitweb                                  ancillaryinterrogators
 gitworkflows                            guide
+scalar                                  mainporcelain
index a487d49c3e48a5eea0bee945d07cd2e37723994c..a7d8755932884cfcb05fad4c539c3b8be8322897 100644 (file)
@@ -252,7 +252,8 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
        }
        graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
-       ret = parse_commit_graph(r, graph_map, graph_size);
+       prepare_repo_settings(r);
+       ret = parse_commit_graph(&r->settings, graph_map, graph_size);
 
        if (ret)
                ret->odb = odb;
@@ -321,7 +322,7 @@ static int graph_read_bloom_data(const unsigned char *chunk_start,
        return 0;
 }
 
-struct commit_graph *parse_commit_graph(struct repository *r,
+struct commit_graph *parse_commit_graph(struct repo_settings *s,
                                        void *graph_map, size_t graph_size)
 {
        const unsigned char *data;
@@ -359,8 +360,6 @@ struct commit_graph *parse_commit_graph(struct repository *r,
                return NULL;
        }
 
-       prepare_repo_settings(r);
-
        graph = alloc_commit_graph();
 
        graph->hash_len = the_hash_algo->rawsz;
@@ -390,7 +389,7 @@ struct commit_graph *parse_commit_graph(struct repository *r,
        pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges);
        pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs);
 
-       if (get_configured_generation_version(r) >= 2) {
+       if (s->commit_graph_generation_version >= 2) {
                pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
                        &graph->chunk_generation_data);
                pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
@@ -400,7 +399,7 @@ struct commit_graph *parse_commit_graph(struct repository *r,
                        graph->read_generation_data = 1;
        }
 
-       if (r->settings.commit_graph_read_changed_paths) {
+       if (s->commit_graph_read_changed_paths) {
                pair_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
                           &graph->chunk_bloom_indexes);
                read_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
@@ -902,7 +901,7 @@ struct commit *lookup_commit_in_graph(struct repository *repo, const struct obje
        struct commit *commit;
        uint32_t pos;
 
-       if (!repo->objects->commit_graph)
+       if (!prepare_commit_graph(repo))
                return NULL;
        if (!search_commit_pos_in_graph(id, repo->objects->commit_graph, &pos))
                return NULL;
@@ -1640,9 +1639,9 @@ struct refs_cb_data {
        struct progress *progress;
 };
 
-static int add_ref_to_set(const char *refname,
+static int add_ref_to_set(const char *refname UNUSED,
                          const struct object_id *oid,
-                         int flags, void *cb_data)
+                         int flags UNUSED, void *cb_data)
 {
        struct object_id peeled;
        struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
@@ -2266,6 +2265,8 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
        }
 
 out:
+       if(dir)
+               closedir(dir);
        strbuf_release(&path);
 }
 
index f23b9e9026d2ea5c048351b92b5068a8a5a117e5..37faee6b66d59c693dc9ee829dbd5ad61654fe3c 100644 (file)
@@ -108,7 +108,12 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
                                                 struct object_directory *odb);
 struct commit_graph *read_commit_graph_one(struct repository *r,
                                           struct object_directory *odb);
-struct commit_graph *parse_commit_graph(struct repository *r,
+
+/*
+ * Callers should initialize the repo_settings with prepare_repo_settings()
+ * prior to calling parse_commit_graph().
+ */
+struct commit_graph *parse_commit_graph(struct repo_settings *s,
                                        void *graph_map, size_t graph_size);
 
 /*
index 1fb1b2ea90c5953eb465d3b108c01f23fb442a32..89b8efc6116883d032912cdc38429b5a8ba5f2f6 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -642,10 +642,11 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm
        return commit_list_insert(item, pp);
 }
 
-static int commit_list_compare_by_date(const void *a, const void *b)
+static int commit_list_compare_by_date(const struct commit_list *a,
+                                      const struct commit_list *b)
 {
-       timestamp_t a_date = ((const struct commit_list *)a)->item->date;
-       timestamp_t b_date = ((const struct commit_list *)b)->item->date;
+       timestamp_t a_date = a->item->date;
+       timestamp_t b_date = b->item->date;
        if (a_date < b_date)
                return 1;
        if (a_date > b_date)
@@ -653,20 +654,11 @@ static int commit_list_compare_by_date(const void *a, const void *b)
        return 0;
 }
 
-static void *commit_list_get_next(const void *a)
-{
-       return ((const struct commit_list *)a)->next;
-}
-
-static void commit_list_set_next(void *a, void *next)
-{
-       ((struct commit_list *)a)->next = next;
-}
+DEFINE_LIST_SORT(static, commit_list_sort, struct commit_list, next);
 
 void commit_list_sort_by_date(struct commit_list **list)
 {
-       *list = llist_mergesort(*list, commit_list_get_next, commit_list_set_next,
-                               commit_list_compare_by_date);
+       commit_list_sort(list, commit_list_compare_by_date);
 }
 
 struct commit *pop_most_recent_commit(struct commit_list **list,
@@ -959,8 +951,9 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
 }
 
 static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
-                                 const char *ident, timestamp_t timestamp,
-                                 int tz, const char *message, void *cbdata)
+                                 const char *ident UNUSED,
+                                 timestamp_t timestamp UNUSED, int tz UNUSED,
+                                 const char *message UNUSED, void *cbdata)
 {
        struct rev_collect *revs = cbdata;
 
index c531372f3ff0f13839a2056568cbaa7fd37f98a8..0a22861f1ceb28547002a237e7201eb920eb9d68 100644 (file)
@@ -40,6 +40,7 @@ int main(int argc, const char **argv)
 
        git_resolve_executable_dir(argv[0]);
 
+       setlocale(LC_CTYPE, "");
        git_setup_gettext();
 
        initialize_the_repository();
diff --git a/compat/disk.h b/compat/disk.h
new file mode 100644 (file)
index 0000000..50a32e3
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef COMPAT_DISK_H
+#define COMPAT_DISK_H
+
+#include "git-compat-util.h"
+
+static int get_disk_info(struct strbuf *out)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int res = 0;
+
+#ifdef GIT_WINDOWS_NATIVE
+       char volume_name[MAX_PATH], fs_name[MAX_PATH];
+       DWORD serial_number, component_length, flags;
+       ULARGE_INTEGER avail2caller, total, avail;
+
+       strbuf_realpath(&buf, ".", 1);
+       if (!GetDiskFreeSpaceExA(buf.buf, &avail2caller, &total, &avail)) {
+               error(_("could not determine free disk size for '%s'"),
+                     buf.buf);
+               res = -1;
+               goto cleanup;
+       }
+
+       strbuf_setlen(&buf, offset_1st_component(buf.buf));
+       if (!GetVolumeInformationA(buf.buf, volume_name, sizeof(volume_name),
+                                  &serial_number, &component_length, &flags,
+                                  fs_name, sizeof(fs_name))) {
+               error(_("could not get info for '%s'"), buf.buf);
+               res = -1;
+               goto cleanup;
+       }
+       strbuf_addf(out, "Available space on '%s': ", buf.buf);
+       strbuf_humanise_bytes(out, avail2caller.QuadPart);
+       strbuf_addch(out, '\n');
+#else
+       struct statvfs stat;
+
+       strbuf_realpath(&buf, ".", 1);
+       if (statvfs(buf.buf, &stat) < 0) {
+               error_errno(_("could not determine free disk size for '%s'"),
+                           buf.buf);
+               res = -1;
+               goto cleanup;
+       }
+
+       strbuf_addf(out, "Available space on '%s': ", buf.buf);
+       strbuf_humanise_bytes(out, (off_t)stat.f_bsize * (off_t)stat.f_bavail);
+       strbuf_addf(out, " (mount flags 0x%lx)\n", stat.f_flag);
+#endif
+
+cleanup:
+       strbuf_release(&buf);
+       return res;
+}
+
+#endif /* COMPAT_DISK_H */
index 907655720bb41e303e5ce86ae367778608b08548..e5ec5b0a9f73bcf04085b5d62d7b123690ce937e 100644 (file)
@@ -24,6 +24,59 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
        return FSMONITOR_REASON_OK;
 }
 
+/*
+ * Check if monitoring remote working directories is allowed.
+ *
+ * By default, monitoring remote working directories is
+ * disabled.  Users may override this behavior in enviroments where
+ * they have proper support.
+ */
+static int check_config_allowremote(struct repository *r)
+{
+       int allow;
+
+       if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
+               return allow;
+
+       return -1; /* fsmonitor.allowremote not set */
+}
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Error if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+       HANDLE h;
+       FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+       h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                       FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+       if (h == INVALID_HANDLE_VALUE) {
+               error(_("[GLE %ld] unable to open for read '%ls'"),
+                     GetLastError(), wpath);
+               return -1;
+       }
+
+       if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+               &proto_info, sizeof(proto_info))) {
+               error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+                     GetLastError(), wpath);
+               CloseHandle(h);
+               return -1;
+       }
+
+       CloseHandle(h);
+
+       trace_printf_key(&trace_fsmonitor,
+                               "check_remote_protocol('%ls') remote protocol %#8.8lx",
+                               wpath, proto_info.Protocol);
+
+       return 0;
+}
+
 /*
  * Remote working directories are problematic for FSMonitor.
  *
@@ -76,6 +129,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
  */
 static enum fsmonitor_reason check_remote(struct repository *r)
 {
+       int ret;
        wchar_t wpath[MAX_PATH];
        wchar_t wfullpath[MAX_PATH];
        size_t wlen;
@@ -115,6 +169,20 @@ static enum fsmonitor_reason check_remote(struct repository *r)
                trace_printf_key(&trace_fsmonitor,
                                 "check_remote('%s') true",
                                 r->worktree);
+
+               ret = check_remote_protocol(wfullpath);
+               if (ret < 0)
+                       return FSMONITOR_REASON_ERROR;
+
+               switch (check_config_allowremote(r)) {
+               case 0: /* config overrides and disables */
+                       return FSMONITOR_REASON_REMOTE;
+               case 1: /* config overrides and enables */
+                       return FSMONITOR_REASON_OK;
+               default:
+                       break; /* config has no opinion */
+               }
+
                return FSMONITOR_REASON_REMOTE;
        }
 
index 7db330c52dcc2326f245f8984e259f0a8dac1294..ea490a7ced431a798629ca86ac904052d99f839a 100644 (file)
@@ -477,7 +477,7 @@ struct escape_sequence_entry {
        char sequence[FLEX_ARRAY];
 };
 
-static int sequence_entry_cmp(const void *hashmap_cmp_fn_data,
+static int sequence_entry_cmp(const void *hashmap_cmp_fn_data UNUSED,
                              const struct escape_sequence_entry *e1,
                              const struct escape_sequence_entry *e2,
                              const void *keydata)
index 9b0e9c93285fb33a69ab3ee0b20ae95ad2e202e1..cbb5a3bab74f6f6f292c1628ed889e57f0157d10 100644 (file)
--- a/config.c
+++ b/config.c
@@ -81,6 +81,17 @@ static enum config_scope current_parsing_scope;
 static int pack_compression_seen;
 static int zlib_compression_seen;
 
+/*
+ * Config that comes from trusted scopes, namely:
+ * - CONFIG_SCOPE_SYSTEM (e.g. /etc/gitconfig)
+ * - CONFIG_SCOPE_GLOBAL (e.g. $HOME/.gitconfig, $XDG_CONFIG_HOME/git)
+ * - CONFIG_SCOPE_COMMAND (e.g. "-c" option, environment variables)
+ *
+ * This is declared here for code cleanliness, but unlike the other
+ * static variables, this does not hold config parser state.
+ */
+static struct config_set protected_config;
+
 static int config_file_fgetc(struct config_source *conf)
 {
        return getc_unlocked(conf->u.file);
@@ -351,7 +362,8 @@ static void populate_remote_urls(struct config_include_data *inc)
        current_parsing_scope = store_scope;
 }
 
-static int forbid_remote_url(const char *var, const char *value, void *data)
+static int forbid_remote_url(const char *var, const char *value UNUSED,
+                            void *data UNUSED)
 {
        const char *remote_name;
        size_t remote_name_len;
@@ -1968,6 +1980,8 @@ int git_config_from_file_with_options(config_fn_t fn, const char *filename,
        int ret = -1;
        FILE *f;
 
+       if (!filename)
+               BUG("filename cannot be NULL");
        f = fopen_or_warn(filename, "r");
        if (f) {
                ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename,
@@ -2324,10 +2338,10 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
        return 0;
 }
 
-static int config_set_element_cmp(const void *unused_cmp_data,
+static int config_set_element_cmp(const void *cmp_data UNUSED,
                                  const struct hashmap_entry *eptr,
                                  const struct hashmap_entry *entry_or_key,
-                                 const void *unused_keydata)
+                                 const void *keydata UNUSED)
 {
        const struct config_set_element *e1, *e2;
 
@@ -2378,6 +2392,11 @@ int git_configset_add_file(struct config_set *cs, const char *filename)
        return git_config_from_file(config_set_callback, filename, cs);
 }
 
+int git_configset_add_parameters(struct config_set *cs)
+{
+       return git_config_from_parameters(config_set_callback, cs);
+}
+
 int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
 {
        const struct string_list *values = NULL;
@@ -2619,6 +2638,36 @@ int repo_config_get_pathname(struct repository *repo,
        return ret;
 }
 
+/* Read values into protected_config. */
+static void read_protected_config(void)
+{
+       char *xdg_config = NULL, *user_config = NULL, *system_config = NULL;
+
+       git_configset_init(&protected_config);
+
+       system_config = git_system_config();
+       git_global_config(&user_config, &xdg_config);
+
+       if (system_config)
+               git_configset_add_file(&protected_config, system_config);
+       if (xdg_config)
+               git_configset_add_file(&protected_config, xdg_config);
+       if (user_config)
+               git_configset_add_file(&protected_config, user_config);
+       git_configset_add_parameters(&protected_config);
+
+       free(system_config);
+       free(xdg_config);
+       free(user_config);
+}
+
+void git_protected_config(config_fn_t fn, void *data)
+{
+       if (!protected_config.hash_initialized)
+               read_protected_config();
+       configset_iter(&protected_config, fn, data);
+}
+
 /* Functions used historically to read configuration from 'the_repository' */
 void git_config(config_fn_t fn, void *data)
 {
index 7654f61c6349a6e8deec22f4e2c79b35d45059ba..ca994d771475a961da458454beabbb66bf63b949 100644 (file)
--- a/config.h
+++ b/config.h
@@ -446,6 +446,15 @@ void git_configset_init(struct config_set *cs);
  */
 int git_configset_add_file(struct config_set *cs, const char *filename);
 
+/**
+ * Parses command line options and environment variables, and adds the
+ * variable-value pairs to the `config_set`. Returns 0 on success, or -1
+ * if there is an error in parsing. The caller decides whether to free
+ * the incomplete configset or continue using it when the function
+ * returns -1.
+ */
+int git_configset_add_parameters(struct config_set *cs);
+
 /**
  * Finds and returns the value list, sorted in order of increasing priority
  * for the configuration variable `key` and config set `cs`. When the
@@ -505,6 +514,13 @@ int repo_config_get_maybe_bool(struct repository *repo,
 int repo_config_get_pathname(struct repository *repo,
                             const char *key, const char **dest);
 
+/*
+ * Functions for reading protected config. By definition, protected
+ * config ignores repository config, so these do not take a `struct
+ * repository` parameter.
+ */
+void git_protected_config(config_fn_t fn, void *data);
+
 /**
  * Querying For Specific Variables
  * -------------------------------
index 7dcd04820429481adf3d504ca187c7d5263f3cee..38ff86678a03a96dffa57507364a6f706ddb44d0 100644 (file)
@@ -237,9 +237,6 @@ AC_MSG_NOTICE([CHECKS for site configuration])
 # tests.  These tests take up a significant amount of the total test time
 # but are not needed unless you plan to talk to SVN repos.
 #
-# Define PPC_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for PowerPC.
-#
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
 #
 # Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
index 2237109b57fd12ad58b1ff1ed8bcbb4a3bffc5a5..ea2a531be87494d9db48fc5dd72aa5c6ffb606b2 100644 (file)
@@ -610,7 +610,7 @@ unset(CMAKE_REQUIRED_INCLUDES)
 #programs
 set(PROGRAMS_BUILT
        git git-daemon git-http-backend git-sh-i18n--envsubst
-       git-shell)
+       git-shell scalar)
 
 if(NOT CURL_FOUND)
        list(APPEND excluded_progs git-http-fetch git-http-push)
@@ -757,6 +757,9 @@ target_link_libraries(git-sh-i18n--envsubst common-main)
 add_executable(git-shell ${CMAKE_SOURCE_DIR}/shell.c)
 target_link_libraries(git-shell common-main)
 
+add_executable(scalar ${CMAKE_SOURCE_DIR}/scalar.c)
+target_link_libraries(scalar common-main)
+
 if(CURL_FOUND)
        add_library(http_obj OBJECT ${CMAKE_SOURCE_DIR}/http.c)
 
@@ -903,7 +906,7 @@ list(TRANSFORM git_perl_scripts PREPEND "${CMAKE_BINARY_DIR}/")
 
 #install
 foreach(program ${PROGRAMS_BUILT})
-if(program STREQUAL "git" OR program STREQUAL "git-shell")
+if(program MATCHES "^(git|git-shell|scalar)$")
 install(TARGETS ${program}
        RUNTIME DESTINATION bin)
 else()
@@ -977,7 +980,7 @@ endif()
 
 #wrapper scripts
 set(wrapper_scripts
-       git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext)
+       git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext scalar)
 
 set(wrapper_test_scripts
        test-fake-ssh test-tool)
@@ -1076,7 +1079,7 @@ if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH})
                "string(REPLACE \"\${GIT_BUILD_DIR_REPL}\" \"GIT_BUILD_DIR=\\\"$TEST_DIRECTORY/../${BUILD_DIR_RELATIVE}\\\"\" content \"\${content}\")\n"
                "file(WRITE ${CMAKE_SOURCE_DIR}/t/test-lib.sh \${content})")
        #misc copies
-       file(COPY ${CMAKE_SOURCE_DIR}/t/chainlint.sed DESTINATION ${CMAKE_BINARY_DIR}/t/)
+       file(COPY ${CMAKE_SOURCE_DIR}/t/chainlint.pl DESTINATION ${CMAKE_BINARY_DIR}/t/)
        file(COPY ${CMAKE_SOURCE_DIR}/po/is.po DESTINATION ${CMAKE_BINARY_DIR}/po/)
        file(COPY ${CMAKE_SOURCE_DIR}/mergetools/tkdiff DESTINATION ${CMAKE_BINARY_DIR}/mergetools/)
        file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-prompt.sh DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
index 9a4f00cb1bdc2e189fa3ccb41d842988e2430a92..aa759379508895ba002c531a13bde3f8995f9251 100644 (file)
@@ -1,60 +1,58 @@
 @@
-expression dst, src, n, E;
+type T;
+T *dst_ptr;
+T *src_ptr;
+expression n;
 @@
-  memcpy(dst, src, n * sizeof(
-- E[...]
-+ *(E)
-  ))
+- memcpy(dst_ptr, src_ptr, (n) * \( sizeof(T)
+-                                \| sizeof(*(dst_ptr))
+-                                \| sizeof(*(src_ptr))
+-                                \| sizeof(dst_ptr[...])
+-                                \| sizeof(src_ptr[...])
+-                                \) )
++ COPY_ARRAY(dst_ptr, src_ptr, n)
 
 @@
 type T;
-T *ptr;
-T[] arr;
-expression E, n;
+T *dst_ptr;
+T[] src_arr;
+expression n;
 @@
-(
-  memcpy(ptr, E,
-- n * sizeof(*(ptr))
-+ n * sizeof(T)
-  )
-|
-  memcpy(arr, E,
-- n * sizeof(*(arr))
-+ n * sizeof(T)
-  )
-|
-  memcpy(E, ptr,
-- n * sizeof(*(ptr))
-+ n * sizeof(T)
-  )
-|
-  memcpy(E, arr,
-- n * sizeof(*(arr))
-+ n * sizeof(T)
-  )
-)
+- memcpy(dst_ptr, src_arr, (n) * \( sizeof(T)
+-                                \| sizeof(*(dst_ptr))
+-                                \| sizeof(*(src_arr))
+-                                \| sizeof(dst_ptr[...])
+-                                \| sizeof(src_arr[...])
+-                                \) )
++ COPY_ARRAY(dst_ptr, src_arr, n)
 
 @@
 type T;
-T *dst_ptr;
+T[] dst_arr;
 T *src_ptr;
+expression n;
+@@
+- memcpy(dst_arr, src_ptr, (n) * \( sizeof(T)
+-                                \| sizeof(*(dst_arr))
+-                                \| sizeof(*(src_ptr))
+-                                \| sizeof(dst_arr[...])
+-                                \| sizeof(src_ptr[...])
+-                                \) )
++ COPY_ARRAY(dst_arr, src_ptr, n)
+
+@@
+type T;
 T[] dst_arr;
 T[] src_arr;
 expression n;
 @@
-(
-- memcpy(dst_ptr, src_ptr, (n) * sizeof(T))
-+ COPY_ARRAY(dst_ptr, src_ptr, n)
-|
-- memcpy(dst_ptr, src_arr, (n) * sizeof(T))
-+ COPY_ARRAY(dst_ptr, src_arr, n)
-|
-- memcpy(dst_arr, src_ptr, (n) * sizeof(T))
-+ COPY_ARRAY(dst_arr, src_ptr, n)
-|
-- memcpy(dst_arr, src_arr, (n) * sizeof(T))
+- memcpy(dst_arr, src_arr, (n) * \( sizeof(T)
+-                                \| sizeof(*(dst_arr))
+-                                \| sizeof(*(src_arr))
+-                                \| sizeof(dst_arr[...])
+-                                \| sizeof(src_arr[...])
+-                                \) )
 + COPY_ARRAY(dst_arr, src_arr, n)
-)
 
 @@
 type T;
diff --git a/contrib/coccinelle/tests/free.c b/contrib/coccinelle/tests/free.c
new file mode 100644 (file)
index 0000000..96d4abc
--- /dev/null
@@ -0,0 +1,11 @@
+int use_FREE_AND_NULL(int *v)
+{
+       free(*v);
+       *v = NULL;
+}
+
+int need_no_if(int *v)
+{
+       if (v)
+               free(v);
+}
diff --git a/contrib/coccinelle/tests/free.res b/contrib/coccinelle/tests/free.res
new file mode 100644 (file)
index 0000000..f90fd9f
--- /dev/null
@@ -0,0 +1,9 @@
+int use_FREE_AND_NULL(int *v)
+{
+       FREE_AND_NULL(*v);
+}
+
+int need_no_if(int *v)
+{
+       free(v);
+}
diff --git a/contrib/coccinelle/tests/unused.c b/contrib/coccinelle/tests/unused.c
new file mode 100644 (file)
index 0000000..8294d73
--- /dev/null
@@ -0,0 +1,82 @@
+void test_strbuf(void)
+{
+       struct strbuf sb1 = STRBUF_INIT;
+       struct strbuf sb2 = STRBUF_INIT;
+       struct strbuf sb3 = STRBUF_INIT;
+       struct strbuf sb4 = STRBUF_INIT;
+       struct strbuf sb5;
+       struct strbuf sb6 = { 0 };
+       struct strbuf sb7 = STRBUF_INIT;
+       struct strbuf sb8 = STRBUF_INIT;
+       struct strbuf *sp1;
+       struct strbuf *sp2;
+       struct strbuf *sp3;
+       struct strbuf *sp4 = xmalloc(sizeof(struct strbuf));
+       struct strbuf *sp5 = xmalloc(sizeof(struct strbuf));
+       struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
+       struct strbuf *sp7;
+
+       strbuf_init(&sb5, 0);
+       strbuf_init(sp1, 0);
+       strbuf_init(sp2, 0);
+       strbuf_init(sp3, 0);
+       strbuf_init(sp4, 0);
+       strbuf_init(sp5, 0);
+       strbuf_init(sp6, 0);
+       strbuf_init(sp7, 0);
+       sp7 = xmalloc(sizeof(struct strbuf));
+
+       use_before(&sb3);
+       use_as_str("%s", sb7.buf);
+       use_as_str("%s", sp1->buf);
+       use_as_str("%s", sp6->buf);
+       pass_pp(&sp3);
+
+       strbuf_release(&sb1);
+       strbuf_reset(&sb2);
+       strbuf_release(&sb3);
+       strbuf_release(&sb4);
+       strbuf_release(&sb5);
+       strbuf_release(&sb6);
+       strbuf_release(&sb7);
+       strbuf_release(sp1);
+       strbuf_release(sp2);
+       strbuf_release(sp3);
+       strbuf_release(sp4);
+       strbuf_release(sp5);
+       strbuf_release(sp6);
+       strbuf_release(sp7);
+
+       use_after(&sb4);
+
+       if (when_strict())
+               return;
+       strbuf_release(&sb8);
+}
+
+void test_other(void)
+{
+       struct string_list l = STRING_LIST_INIT_DUP;
+       struct strbuf sb = STRBUF_INIT;
+
+       string_list_clear(&l, 0);
+       string_list_clear(&sb, 0);
+}
+
+void test_worktrees(void)
+{
+       struct worktree **w1 = get_worktrees();
+       struct worktree **w2 = get_worktrees();
+       struct worktree **w3;
+       struct worktree **w4;
+
+       w3 = get_worktrees();
+       w4 = get_worktrees();
+
+       use_it(w4);
+
+       free_worktrees(w1);
+       free_worktrees(w2);
+       free_worktrees(w3);
+       free_worktrees(w4);
+}
diff --git a/contrib/coccinelle/tests/unused.res b/contrib/coccinelle/tests/unused.res
new file mode 100644 (file)
index 0000000..6d3e745
--- /dev/null
@@ -0,0 +1,45 @@
+void test_strbuf(void)
+{
+       struct strbuf sb3 = STRBUF_INIT;
+       struct strbuf sb4 = STRBUF_INIT;
+       struct strbuf sb7 = STRBUF_INIT;
+       struct strbuf *sp1;
+       struct strbuf *sp3;
+       struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
+       strbuf_init(sp1, 0);
+       strbuf_init(sp3, 0);
+       strbuf_init(sp6, 0);
+
+       use_before(&sb3);
+       use_as_str("%s", sb7.buf);
+       use_as_str("%s", sp1->buf);
+       use_as_str("%s", sp6->buf);
+       pass_pp(&sp3);
+
+       strbuf_release(&sb3);
+       strbuf_release(&sb4);
+       strbuf_release(&sb7);
+       strbuf_release(sp1);
+       strbuf_release(sp3);
+       strbuf_release(sp6);
+
+       use_after(&sb4);
+
+       if (when_strict())
+               return;
+}
+
+void test_other(void)
+{
+}
+
+void test_worktrees(void)
+{
+       struct worktree **w4;
+
+       w4 = get_worktrees();
+
+       use_it(w4);
+
+       free_worktrees(w4);
+}
diff --git a/contrib/coccinelle/unused.cocci b/contrib/coccinelle/unused.cocci
new file mode 100644 (file)
index 0000000..d84046f
--- /dev/null
@@ -0,0 +1,43 @@
+// This rule finds sequences of "unused" declerations and uses of a
+// variable, where "unused" is defined to include only calling the
+// equivalent of alloc, init & free functions on the variable.
+@@
+type T;
+identifier I;
+// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring)
+constant INIT_MACRO =~ "_INIT";
+identifier MALLOC1 =~ "^x?[mc]alloc$";
+identifier INIT_ASSIGN1 =~ "^get_worktrees$";
+identifier INIT_CALL1 =~ "^[a-z_]*_init$";
+identifier REL1 =~ "^[a-z_]*_(release|reset|clear|free)$";
+identifier REL2 =~ "^(release|clear|free)_[a-z_]*$";
+@@
+
+(
+- T I;
+|
+- T I = { 0 };
+|
+- T I = INIT_MACRO;
+|
+- T I = MALLOC1(...);
+|
+- T I = INIT_ASSIGN1(...);
+)
+
+<... when != \( I \| &I \)
+(
+- \( INIT_CALL1 \)( \( I \| &I \), ...);
+|
+- I = \( INIT_ASSIGN1 \)(...);
+|
+- I = MALLOC1(...);
+)
+...>
+
+(
+- \( REL1 \| REL2 \)( \( I \| &I \), ...);
+|
+- \( REL1 \| REL2 \)( \( &I \| I \) );
+)
+  ... when != \( I \| &I \)
index 1435548e004687fcc21a9e1b8922aa3bd39b8515..57972c2845c135dc45aeb560d289aade4caa5e5d 100644 (file)
 # single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
 # by setting GIT_PS1_OMITSPARSESTATE.
 #
+# If you would like to see a notification on the prompt when there are
+# unresolved conflicts, set GIT_PS1_SHOWCONFLICTSTATE to "yes". The
+# prompt will include "|CONFLICT".
+#
 # If you would like to see more information about the identity of
 # commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
 # to one of these values:
@@ -508,6 +512,12 @@ __git_ps1 ()
                r="$r $step/$total"
        fi
 
+       local conflict="" # state indicator for unresolved conflicts
+       if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] &&
+          [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
+               conflict="|CONFLICT"
+       fi
+
        local w=""
        local i=""
        local s=""
@@ -572,7 +582,7 @@ __git_ps1 ()
        fi
 
        local f="$h$w$i$s$u$p"
-       local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}"
+       local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}"
 
        if [ $pcmode = yes ]; then
                if [ "${__git_printf_supports_v-}" != yes ]; then
index 07227d02287618394d649ae915a1b42d93140950..bf2777308a56b6f233553196821ab2750e269e8d 100755 (executable)
@@ -3,16 +3,9 @@
        cd ../../../t
        test_description='git-credential-netrc'
        . ./test-lib.sh
+       . "$TEST_DIRECTORY"/lib-perl.sh
 
-       if ! test_have_prereq PERL; then
-               skip_all='skipping perl interface tests, perl not available'
-               test_done
-       fi
-
-       perl -MTest::More -e 0 2>/dev/null || {
-               skip_all="Perl Test::More unavailable, skipping test"
-               test_done
-       }
+       skip_all_if_no_Test_More
 
        # set up test repository
 
                'set up test repository' \
                'git config --add gpg.program test.git-config-gpg'
 
-       # The external test will outputs its own plan
-       test_external_has_tap=1
-
        export PERL5LIB="$GITPERLLIB"
-       test_external \
-               'git-credential-netrc' \
+       test_expect_success 'git-credential-netrc' '
                perl "$GIT_BUILD_DIR"/contrib/credential/netrc/test.pl
+       '
 
        test_done
 )
diff --git a/contrib/scalar/.gitignore b/contrib/scalar/.gitignore
deleted file mode 100644 (file)
index ff3d47e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/*.exe
-/scalar
diff --git a/contrib/scalar/Makefile b/contrib/scalar/Makefile
deleted file mode 100644 (file)
index 37f283f..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# The default target of this Makefile is...
-all::
-
-# Import tree-wide shared Makefile behavior and libraries
-include ../../shared.mak
-
-include ../../config.mak.uname
--include ../../config.mak.autogen
--include ../../config.mak
-
-TARGETS = scalar$(X) scalar.o
-GITLIBS = ../../common-main.o ../../libgit.a ../../xdiff/lib.a
-
-all:: scalar$(X) ../../bin-wrappers/scalar
-
-$(GITLIBS):
-       $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(subst ../../,,$@)
-
-$(TARGETS): $(GITLIBS) scalar.c
-       $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(patsubst %,contrib/scalar/%,$@)
-
-clean:
-       $(RM) $(TARGETS) ../../bin-wrappers/scalar
-
-../../bin-wrappers/scalar: ../../wrap-for-bin.sh Makefile
-       @mkdir -p ../../bin-wrappers
-       $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-            -e 's|@@BUILD_DIR@@|$(shell cd ../.. && pwd)|' \
-            -e 's|@@PROG@@|contrib/scalar/scalar$(X)|' < $< > $@ && \
-       chmod +x $@
-
-test: all
-       $(MAKE) -C t
-
-.PHONY: $(GITLIBS) all clean test FORCE
diff --git a/contrib/scalar/README.md b/contrib/scalar/README.md
deleted file mode 100644 (file)
index 634b577..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-# Scalar - an opinionated repository management tool
-
-Scalar is an add-on to Git that helps users take advantage of advanced
-performance features in Git. Originally implemented in C# using .NET Core,
-based on the learnings from the VFS for Git project, most of the techniques
-developed by the Scalar project have been integrated into core Git already:
-
-* partial clone,
-* commit graphs,
-* multi-pack index,
-* sparse checkout (cone mode),
-* scheduled background maintenance,
-* etc
-
-This directory contains the remaining parts of Scalar that are not (yet) in
-core Git.
-
-## Roadmap
-
-The idea is to populate this directory via incremental patch series and
-eventually move to a top-level directory next to `gitk-git/` and to `git-gui/`. The
-current plan involves the following patch series:
-
-- `scalar-the-beginning`: The initial patch series which sets up
-  `contrib/scalar/` and populates it with a minimal `scalar` command that
-  demonstrates the fundamental ideas.
-
-- `scalar-c-and-C`: The `scalar` command learns about two options that can be
-  specified before the command, `-c <key>=<value>` and `-C <directory>`.
-
-- `scalar-diagnose`: The `scalar` command is taught the `diagnose` subcommand.
-
-- `scalar-and-builtin-fsmonitor`: The built-in FSMonitor is enabled in `scalar
-  register` and in `scalar clone`, for an enormous performance boost when
-  working in large worktrees. This patch series necessarily depends on Jeff
-  Hostetler's FSMonitor patch series to be integrated into Git.
-
-- `scalar-gentler-config-locking`: Scalar enlistments are registered in the
-  user's Git config. This usually does not represent any problem because it is
-  rare for a user to register an enlistment. However, in Scalar's functional
-  tests, Scalar enlistments are created galore, and in parallel, which can lead
-  to lock contention. This patch series works around that problem by re-trying
-  to lock the config file in a gentle fashion.
-
-- `scalar-extra-docs`: Add some extensive documentation that has been written
-  in the original Scalar project (all subject to discussion, of course).
-
-- `optionally-install-scalar`: Now that Scalar is feature (and documentation)
-  complete and is verified in CI builds, let's offer to install it.
-
-- `move-scalar-to-toplevel`: Now that Scalar is complete, let's move it next to
-  `gitk-git/` and to `git-gui/`, making it a top-level command.
-
-The following two patch series exist in Microsoft's fork of Git and are
-publicly available. There is no current plan to upstream them, not because I
-want to withhold these patches, but because I don't think the Git community is
-interested in these patches.
-
-There are some interesting ideas there, but the implementation is too specific
-to Azure Repos and/or VFS for Git to be of much help in general (and also: my
-colleagues tried to upstream some patches already and the enthusiasm for
-integrating things related to Azure Repos and VFS for Git can be summarized in
-very, very few words).
-
-These still exist mainly because the GVFS protocol is what Azure Repos has
-instead of partial clone, while Git is focused on improving partial clone:
-
-- `scalar-with-gvfs`: The primary purpose of this patch series is to support
-  existing Scalar users whose repositories are hosted in Azure Repos (which
-  does not support Git's partial clones, but supports its predecessor, the GVFS
-  protocol, which is used by Scalar to emulate the partial clone).
-
-  Since the GVFS protocol will never be supported by core Git, this patch
-  series will remain in Microsoft's fork of Git.
-
-- `run-scalar-functional-tests`: The Scalar project developed a quite
-  comprehensive set of integration tests (or, "Functional Tests"). They are the
-  sole remaining part of the original C#-based Scalar project, and this patch
-  adds a GitHub workflow that runs them all.
-
-  Since the tests partially depend on features that are only provided in the
-  `scalar-with-gvfs` patch series, this patch cannot be upstreamed.
diff --git a/contrib/scalar/t/Makefile b/contrib/scalar/t/Makefile
deleted file mode 100644 (file)
index 01e82e5..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-# Import tree-wide shared Makefile behavior and libraries
-include ../../../shared.mak
-
-# Run scalar tests
-#
-# Copyright (c) 2005,2021 Junio C Hamano, Johannes Schindelin
-#
-
--include ../../../config.mak.autogen
--include ../../../config.mak
-
-SHELL_PATH ?= $(SHELL)
-PERL_PATH ?= /usr/bin/perl
-RM ?= rm -f
-PROVE ?= prove
-DEFAULT_TEST_TARGET ?= test
-TEST_LINT ?= test-lint
-
-ifdef TEST_OUTPUT_DIRECTORY
-TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results
-else
-TEST_RESULTS_DIRECTORY = ../../../t/test-results
-endif
-
-# Shell quote;
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
-PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
-TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY))
-
-T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
-
-all: $(DEFAULT_TEST_TARGET)
-
-test: $(TEST_LINT)
-       $(MAKE) aggregate-results-and-cleanup
-
-prove: $(TEST_LINT)
-       @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
-       $(MAKE) clean-except-prove-cache
-
-$(T):
-       @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
-
-clean-except-prove-cache:
-       $(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
-       $(RM) -r valgrind/bin
-
-clean: clean-except-prove-cache
-       $(RM) .prove
-
-test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax
-
-test-lint-duplicates:
-       @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \
-               test -z "$$dups" || { \
-               echo >&2 "duplicate test numbers:" $$dups; exit 1; }
-
-test-lint-executable:
-       @bad=`for i in $(T); do test -x "$$i" || echo $$i; done` && \
-               test -z "$$bad" || { \
-               echo >&2 "non-executable tests:" $$bad; exit 1; }
-
-test-lint-shell-syntax:
-       @'$(PERL_PATH_SQ)' ../../../t/check-non-portable-shell.pl $(T)
-
-aggregate-results-and-cleanup: $(T)
-       $(MAKE) aggregate-results
-       $(MAKE) clean
-
-aggregate-results:
-       for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \
-               echo "$$f"; \
-       done | '$(SHELL_PATH_SQ)' ../../../t/aggregate-results.sh
-
-valgrind:
-       $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
-
-test-results:
-       mkdir -p test-results
-
-.PHONY: $(T) aggregate-results clean valgrind
index 1af1d9653e94b39623f8435957c6e7537c41c60a..7562a395c2456bf4588a26e6fa847cced5bb71c2 100755 (executable)
@@ -50,6 +50,14 @@ m,message=    use the given message as the commit message for the merge commit
 
 indent=0
 
+# Usage: say [MSG...]
+say () {
+       if test -z "$arg_quiet"
+       then
+               printf '%s\n' "$*"
+       fi
+}
+
 # Usage: debug [MSG...]
 debug () {
        if test -n "$arg_debug"
@@ -60,7 +68,7 @@ debug () {
 
 # Usage: progress [MSG...]
 progress () {
-       if test -z "$GIT_QUIET"
+       if test -z "$arg_quiet"
        then
                if test -z "$arg_debug"
                then
@@ -146,6 +154,7 @@ main () {
        eval "$set_args"
 
        # Begin "real" flag parsing.
+       arg_quiet=
        arg_debug=
        arg_prefix=
        arg_split_branch=
@@ -161,7 +170,7 @@ main () {
 
                case "$opt" in
                -q)
-                       GIT_QUIET=1
+                       arg_quiet=1
                        ;;
                -d)
                        arg_debug=1
@@ -252,7 +261,7 @@ main () {
        dir="$(dirname "$arg_prefix/.")"
 
        debug "command: {$arg_command}"
-       debug "quiet: {$GIT_QUIET}"
+       debug "quiet: {$arg_quiet}"
        debug "dir: {$dir}"
        debug "opts: {$*}"
        debug
index 276898eb6bd720ac63a87a0f3d7a2bebb542cb37..4655e0987b32a837e966832eaebf89ed3ea829e9 100644 (file)
@@ -47,10 +47,11 @@ pre-clean:
        $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
 
 clean-except-prove-cache:
-       $(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
+       $(RM) -r 'trash directory'.*
        $(RM) -r valgrind/bin
 
 clean: clean-except-prove-cache
+       $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
        $(RM) .prove
 
 test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax
index 4d153729da0f185207b85d103905b30e3183796b..95e6a5244fc26c029abff85bb37a4e9fae71acba 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -619,7 +619,7 @@ struct filter_params {
        const char *path;
 };
 
-static int filter_buffer_or_fd(int in, int out, void *data)
+static int filter_buffer_or_fd(int in UNUSED, int out, void *data)
 {
        /*
         * Spawn cmd and feed the buffer contents through its stdin.
@@ -1008,7 +1008,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
        return 0;
 }
 
-static int read_convert_config(const char *var, const char *value, void *cb)
+static int read_convert_config(const char *var, const char *value, void *cb UNUSED)
 {
        const char *key, *name;
        size_t namelen;
index aa98b2e54146f7de1f349f16a9a01e754a3a0b73..26f9e99e1a978921d9ec19725c09a88247548d95 100644 (file)
@@ -316,7 +316,7 @@ static regex_t *island_regexes;
 static unsigned int island_regexes_alloc, island_regexes_nr;
 static const char *core_island_name;
 
-static int island_config_callback(const char *k, const char *v, void *cb)
+static int island_config_callback(const char *k, const char *v, void *cb UNUSED)
 {
        if (!strcmp(k, "pack.island")) {
                struct strbuf re = STRBUF_INIT;
@@ -365,7 +365,7 @@ static void add_ref_to_island(const char *island_name, const struct object_id *o
 }
 
 static int find_island_for_ref(const char *refname, const struct object_id *oid,
-                              int flags, void *data)
+                              int flags UNUSED, void *data UNUSED)
 {
        /*
         * We should advertise 'ARRAY_SIZE(matches) - 2' as the max,
diff --git a/diagnose.c b/diagnose.c
new file mode 100644 (file)
index 0000000..8f26569
--- /dev/null
@@ -0,0 +1,311 @@
+#include "cache.h"
+#include "diagnose.h"
+#include "compat/disk.h"
+#include "archive.h"
+#include "dir.h"
+#include "help.h"
+#include "strvec.h"
+#include "object-store.h"
+#include "packfile.h"
+
+struct archive_dir {
+       const char *path;
+       int recursive;
+};
+
+struct diagnose_option {
+       enum diagnose_mode mode;
+       const char *option_name;
+};
+
+static struct diagnose_option diagnose_options[] = {
+       { DIAGNOSE_STATS, "stats" },
+       { DIAGNOSE_ALL, "all" },
+};
+
+int option_parse_diagnose(const struct option *opt, const char *arg, int unset)
+{
+       int i;
+       enum diagnose_mode *diagnose = opt->value;
+
+       if (!arg) {
+               *diagnose = unset ? DIAGNOSE_NONE : DIAGNOSE_STATS;
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(diagnose_options); i++) {
+               if (!strcmp(arg, diagnose_options[i].option_name)) {
+                       *diagnose = diagnose_options[i].mode;
+                       return 0;
+               }
+       }
+
+       return error(_("invalid --%s value '%s'"), opt->long_name, arg);
+}
+
+static void dir_file_stats_objects(const char *full_path, size_t full_path_len,
+                                  const char *file_name, void *data)
+{
+       struct strbuf *buf = data;
+       struct stat st;
+
+       if (!stat(full_path, &st))
+               strbuf_addf(buf, "%-70s %16" PRIuMAX "\n", file_name,
+                           (uintmax_t)st.st_size);
+}
+
+static int dir_file_stats(struct object_directory *object_dir, void *data)
+{
+       struct strbuf *buf = data;
+
+       strbuf_addf(buf, "Contents of %s:\n", object_dir->path);
+
+       for_each_file_in_pack_dir(object_dir->path, dir_file_stats_objects,
+                                 data);
+
+       return 0;
+}
+
+/*
+ * Get the d_type of a dirent. If the d_type is unknown, derive it from
+ * stat.st_mode.
+ *
+ * Note that 'path' is assumed to have a trailing slash. It is also modified
+ * in-place during the execution of the function, but is then reverted to its
+ * original value before returning.
+ */
+static unsigned char get_dtype(struct dirent *e, struct strbuf *path)
+{
+       struct stat st;
+       unsigned char dtype = DTYPE(e);
+       size_t base_path_len;
+
+       if (dtype != DT_UNKNOWN)
+               return dtype;
+
+       /* d_type unknown in dirent, try to fall back on lstat results */
+       base_path_len = path->len;
+       strbuf_addstr(path, e->d_name);
+       if (lstat(path->buf, &st))
+               goto cleanup;
+
+       /* determine d_type from st_mode */
+       if (S_ISREG(st.st_mode))
+               dtype = DT_REG;
+       else if (S_ISDIR(st.st_mode))
+               dtype = DT_DIR;
+       else if (S_ISLNK(st.st_mode))
+               dtype = DT_LNK;
+
+cleanup:
+       strbuf_setlen(path, base_path_len);
+       return dtype;
+}
+
+static int count_files(struct strbuf *path)
+{
+       DIR *dir = opendir(path->buf);
+       struct dirent *e;
+       int count = 0;
+
+       if (!dir)
+               return 0;
+
+       while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
+               if (get_dtype(e, path) == DT_REG)
+                       count++;
+
+       closedir(dir);
+       return count;
+}
+
+static void loose_objs_stats(struct strbuf *buf, const char *path)
+{
+       DIR *dir = opendir(path);
+       struct dirent *e;
+       int count;
+       int total = 0;
+       unsigned char c;
+       struct strbuf count_path = STRBUF_INIT;
+       size_t base_path_len;
+
+       if (!dir)
+               return;
+
+       strbuf_addstr(buf, "Object directory stats for ");
+       strbuf_add_absolute_path(buf, path);
+       strbuf_addstr(buf, ":\n");
+
+       strbuf_add_absolute_path(&count_path, path);
+       strbuf_addch(&count_path, '/');
+       base_path_len = count_path.len;
+
+       while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
+               if (get_dtype(e, &count_path) == DT_DIR &&
+                   strlen(e->d_name) == 2 &&
+                   !hex_to_bytes(&c, e->d_name, 1)) {
+                       strbuf_setlen(&count_path, base_path_len);
+                       strbuf_addf(&count_path, "%s/", e->d_name);
+                       total += (count = count_files(&count_path));
+                       strbuf_addf(buf, "%s : %7d files\n", e->d_name, count);
+               }
+
+       strbuf_addf(buf, "Total: %d loose objects", total);
+
+       strbuf_release(&count_path);
+       closedir(dir);
+}
+
+static int add_directory_to_archiver(struct strvec *archiver_args,
+                                    const char *path, int recurse)
+{
+       int at_root = !*path;
+       DIR *dir;
+       struct dirent *e;
+       struct strbuf buf = STRBUF_INIT;
+       size_t len;
+       int res = 0;
+
+       dir = opendir(at_root ? "." : path);
+       if (!dir) {
+               if (errno == ENOENT) {
+                       warning(_("could not archive missing directory '%s'"), path);
+                       return 0;
+               }
+               return error_errno(_("could not open directory '%s'"), path);
+       }
+
+       if (!at_root)
+               strbuf_addf(&buf, "%s/", path);
+       len = buf.len;
+       strvec_pushf(archiver_args, "--prefix=%s", buf.buf);
+
+       while (!res && (e = readdir_skip_dot_and_dotdot(dir))) {
+               struct strbuf abspath = STRBUF_INIT;
+               unsigned char dtype;
+
+               strbuf_add_absolute_path(&abspath, at_root ? "." : path);
+               strbuf_addch(&abspath, '/');
+               dtype = get_dtype(e, &abspath);
+
+               strbuf_setlen(&buf, len);
+               strbuf_addstr(&buf, e->d_name);
+
+               if (dtype == DT_REG)
+                       strvec_pushf(archiver_args, "--add-file=%s", buf.buf);
+               else if (dtype != DT_DIR)
+                       warning(_("skipping '%s', which is neither file nor "
+                                 "directory"), buf.buf);
+               else if (recurse &&
+                        add_directory_to_archiver(archiver_args,
+                                                  buf.buf, recurse) < 0)
+                       res = -1;
+
+               strbuf_release(&abspath);
+       }
+
+       closedir(dir);
+       strbuf_release(&buf);
+       return res;
+}
+
+int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode)
+{
+       struct strvec archiver_args = STRVEC_INIT;
+       char **argv_copy = NULL;
+       int stdout_fd = -1, archiver_fd = -1;
+       struct strbuf buf = STRBUF_INIT;
+       int res, i;
+       struct archive_dir archive_dirs[] = {
+               { ".git", 0 },
+               { ".git/hooks", 0 },
+               { ".git/info", 0 },
+               { ".git/logs", 1 },
+               { ".git/objects/info", 0 }
+       };
+
+       if (mode == DIAGNOSE_NONE) {
+               res = 0;
+               goto diagnose_cleanup;
+       }
+
+       stdout_fd = dup(STDOUT_FILENO);
+       if (stdout_fd < 0) {
+               res = error_errno(_("could not duplicate stdout"));
+               goto diagnose_cleanup;
+       }
+
+       archiver_fd = xopen(zip_path->buf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+       if (dup2(archiver_fd, STDOUT_FILENO) < 0) {
+               res = error_errno(_("could not redirect output"));
+               goto diagnose_cleanup;
+       }
+
+       init_zip_archiver();
+       strvec_pushl(&archiver_args, "git-diagnose", "--format=zip", NULL);
+
+       strbuf_reset(&buf);
+       strbuf_addstr(&buf, "Collecting diagnostic info\n\n");
+       get_version_info(&buf, 1);
+
+       strbuf_addf(&buf, "Repository root: %s\n", the_repository->worktree);
+       get_disk_info(&buf);
+       write_or_die(stdout_fd, buf.buf, buf.len);
+       strvec_pushf(&archiver_args,
+                    "--add-virtual-file=diagnostics.log:%.*s",
+                    (int)buf.len, buf.buf);
+
+       strbuf_reset(&buf);
+       strbuf_addstr(&buf, "--add-virtual-file=packs-local.txt:");
+       dir_file_stats(the_repository->objects->odb, &buf);
+       foreach_alt_odb(dir_file_stats, &buf);
+       strvec_push(&archiver_args, buf.buf);
+
+       strbuf_reset(&buf);
+       strbuf_addstr(&buf, "--add-virtual-file=objects-local.txt:");
+       loose_objs_stats(&buf, ".git/objects");
+       strvec_push(&archiver_args, buf.buf);
+
+       /* Only include this if explicitly requested */
+       if (mode == DIAGNOSE_ALL) {
+               for (i = 0; i < ARRAY_SIZE(archive_dirs); i++) {
+                       if (add_directory_to_archiver(&archiver_args,
+                                                     archive_dirs[i].path,
+                                                     archive_dirs[i].recursive)) {
+                               res = error_errno(_("could not add directory '%s' to archiver"),
+                                                 archive_dirs[i].path);
+                               goto diagnose_cleanup;
+                       }
+               }
+       }
+
+       strvec_pushl(&archiver_args, "--prefix=",
+                    oid_to_hex(the_hash_algo->empty_tree), "--", NULL);
+
+       /* `write_archive()` modifies the `argv` passed to it. Let it. */
+       argv_copy = xmemdupz(archiver_args.v,
+                            sizeof(char *) * archiver_args.nr);
+       res = write_archive(archiver_args.nr, (const char **)argv_copy, NULL,
+                           the_repository, NULL, 0);
+       if (res) {
+               error(_("failed to write archive"));
+               goto diagnose_cleanup;
+       }
+
+       fprintf(stderr, "\n"
+               "Diagnostics complete.\n"
+               "All of the gathered info is captured in '%s'\n",
+               zip_path->buf);
+
+diagnose_cleanup:
+       if (archiver_fd >= 0) {
+               dup2(stdout_fd, STDOUT_FILENO);
+               close(stdout_fd);
+               close(archiver_fd);
+       }
+       free(argv_copy);
+       strvec_clear(&archiver_args);
+       strbuf_release(&buf);
+
+       return res;
+}
diff --git a/diagnose.h b/diagnose.h
new file mode 100644 (file)
index 0000000..7a4951a
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef DIAGNOSE_H
+#define DIAGNOSE_H
+
+#include "strbuf.h"
+#include "parse-options.h"
+
+enum diagnose_mode {
+       DIAGNOSE_NONE,
+       DIAGNOSE_STATS,
+       DIAGNOSE_ALL
+};
+
+int option_parse_diagnose(const struct option *opt, const char *arg, int unset);
+
+int create_diagnostics_archive(struct strbuf *zip_path, enum diagnose_mode mode);
+
+#endif /* DIAGNOSE_H */
index 7f64156b8bfec6bb5ec17038eee0d73c68487988..85cbefa5afd7c00e903232011ef3d2ff7aca4a8f 100644 (file)
@@ -20,9 +20,20 @@ static void suppress(struct rev_info *revs)
        revs->remerge_diff = 0;
 }
 
-static void set_separate(struct rev_info *revs)
+static void common_setup(struct rev_info *revs)
 {
        suppress(revs);
+       revs->merges_need_diff = 1;
+}
+
+static void set_none(struct rev_info *revs)
+{
+       suppress(revs);
+}
+
+static void set_separate(struct rev_info *revs)
+{
+       common_setup(revs);
        revs->separate_merges = 1;
        revs->simplify_history = 0;
 }
@@ -35,21 +46,21 @@ static void set_first_parent(struct rev_info *revs)
 
 static void set_combined(struct rev_info *revs)
 {
-       suppress(revs);
+       common_setup(revs);
        revs->combine_merges = 1;
        revs->dense_combined_merges = 0;
 }
 
 static void set_dense_combined(struct rev_info *revs)
 {
-       suppress(revs);
+       common_setup(revs);
        revs->combine_merges = 1;
        revs->dense_combined_merges = 1;
 }
 
 static void set_remerge_diff(struct rev_info *revs)
 {
-       suppress(revs);
+       common_setup(revs);
        revs->remerge_diff = 1;
        revs->simplify_history = 0;
 }
@@ -57,18 +68,18 @@ static void set_remerge_diff(struct rev_info *revs)
 static diff_merges_setup_func_t func_by_opt(const char *optarg)
 {
        if (!strcmp(optarg, "off") || !strcmp(optarg, "none"))
-               return suppress;
+               return set_none;
        if (!strcmp(optarg, "1") || !strcmp(optarg, "first-parent"))
                return set_first_parent;
-       else if (!strcmp(optarg, "separate"))
+       if (!strcmp(optarg, "separate"))
                return set_separate;
-       else if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
+       if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
                return set_combined;
-       else if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
+       if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
                return set_dense_combined;
-       else if (!strcmp(optarg, "r") || !strcmp(optarg, "remerge"))
+       if (!strcmp(optarg, "r") || !strcmp(optarg, "remerge"))
                return set_remerge_diff;
-       else if (!strcmp(optarg, "m") || !strcmp(optarg, "on"))
+       if (!strcmp(optarg, "m") || !strcmp(optarg, "on"))
                return set_to_default;
        return NULL;
 }
@@ -81,10 +92,6 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
                die(_("invalid value for '%s': '%s'"), "--diff-merges", optarg);
 
        func(revs);
-
-       /* NOTE: the merges_need_diff flag is cleared by func() call */
-       if (func != suppress)
-               revs->merges_need_diff = 1;
 }
 
 /*
@@ -115,6 +122,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
 
        if (!suppress_m_parsing && !strcmp(arg, "-m")) {
                set_to_default(revs);
+               revs->merges_need_diff = 0;
        } else if (!strcmp(arg, "-c")) {
                set_combined(revs);
                revs->merges_imply_patch = 1;
@@ -125,7 +133,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
                set_remerge_diff(revs);
                revs->merges_imply_patch = 1;
        } else if (!strcmp(arg, "--no-diff-merges")) {
-               suppress(revs);
+               set_none(revs);
        } else if (!strcmp(arg, "--combined-all-paths")) {
                revs->combined_all_paths = 1;
        } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
@@ -139,7 +147,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
 
 void diff_merges_suppress(struct rev_info *revs)
 {
-       suppress(revs);
+       set_none(revs);
 }
 
 void diff_merges_default_to_first_parent(struct rev_info *revs)
index 9a8b09346bd3da77daa1cd755486d68ae37e9a39..18edbdf4b59ec020cc58e3d16d01d92edfdc302e 100644 (file)
@@ -243,7 +243,9 @@ int diff_no_index(struct rev_info *revs,
                  int argc, const char **argv)
 {
        int i, no_index;
+       int ret = 1;
        const char *paths[2];
+       char *to_free[ARRAY_SIZE(paths)] = { 0 };
        struct strbuf replacement = STRBUF_INIT;
        const char *prefix = revs->prefix;
        struct option no_index_options[] = {
@@ -265,7 +267,7 @@ int diff_no_index(struct rev_info *revs,
        }
        FREE_AND_NULL(options);
        for (i = 0; i < 2; i++) {
-               const char *p = argv[argc - 2 + i];
+               const char *p = argv[i];
                if (!strcmp(p, "-"))
                        /*
                         * stdin should be spelled as "-"; if you have
@@ -273,7 +275,7 @@ int diff_no_index(struct rev_info *revs,
                         */
                        p = file_from_standard_input;
                else if (prefix)
-                       p = prefix_filename(prefix, p);
+                       p = to_free[i] = prefix_filename(prefix, p);
                paths[i] = p;
        }
 
@@ -295,16 +297,20 @@ int diff_no_index(struct rev_info *revs,
        revs->diffopt.flags.exit_with_status = 1;
 
        if (queue_diff(&revs->diffopt, paths[0], paths[1]))
-               return 1;
+               goto out;
        diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
 
-       strbuf_release(&replacement);
-
        /*
         * The return code for --no-index imitates diff(1):
         * 0 = no changes, 1 = changes, else error
         */
-       return diff_result_code(&revs->diffopt, 0);
+       ret = diff_result_code(&revs->diffopt, 0);
+
+out:
+       for (i = 0; i < ARRAY_SIZE(to_free); i++)
+               free(to_free[i]);
+       strbuf_release(&replacement);
+       return ret;
 }
diff --git a/diff.c b/diff.c
index e71cf758861bd7596ce122611a4c92fe6b27d8c5..648f6717a5597c30c423256a25e0fece08cd30de 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -264,7 +264,8 @@ void init_diff_ui_defaults(void)
        diff_detect_rename_default = DIFF_DETECT_RENAME;
 }
 
-int git_diff_heuristic_config(const char *var, const char *value, void *cb)
+int git_diff_heuristic_config(const char *var, const char *value,
+                             void *cb UNUSED)
 {
        if (!strcmp(var, "diff.indentheuristic"))
                diff_indent_heuristic = git_config_bool(var, value);
@@ -916,7 +917,7 @@ struct interned_diff_symbol {
 static int interned_diff_symbol_cmp(const void *hashmap_cmp_fn_data,
                                    const struct hashmap_entry *eptr,
                                    const struct hashmap_entry *entry_or_key,
-                                   const void *keydata)
+                                   const void *keydata UNUSED)
 {
        const struct diff_options *diffopt = hashmap_cmp_fn_data;
        const struct emitted_diff_symbol *a, *b;
@@ -1289,7 +1290,6 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
 {
        static const char *nneof = " No newline at end of file\n";
        const char *context, *reset, *set, *set_sign, *meta, *fraginfo;
-       struct strbuf sb = STRBUF_INIT;
 
        enum diff_symbol s = eds->s;
        const char *line = eds->line;
@@ -1521,7 +1521,6 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
        default:
                BUG("unknown diff symbol");
        }
-       strbuf_release(&sb);
 }
 
 static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
@@ -3362,23 +3361,23 @@ struct userdiff_driver *get_textconv(struct repository *r,
        return userdiff_get_textconv(r, one->driver);
 }
 
-static struct strbuf *additional_headers(struct diff_options *o,
-                                        const char *path)
+static struct string_list *additional_headers(struct diff_options *o,
+                                             const char *path)
 {
        if (!o->additional_path_headers)
                return NULL;
        return strmap_get(o->additional_path_headers, path);
 }
 
-static void add_formatted_headers(struct strbuf *msg,
-                                 struct strbuf *more_headers,
+static void add_formatted_header(struct strbuf *msg,
+                                 const char *header,
                                  const char *line_prefix,
                                  const char *meta,
                                  const char *reset)
 {
-       char *next, *newline;
+       const char *next, *newline;
 
-       for (next = more_headers->buf; *next; next = newline) {
+       for (next = header; *next; next = newline) {
                newline = strchrnul(next, '\n');
                strbuf_addf(msg, "%s%s%.*s%s\n", line_prefix, meta,
                            (int)(newline - next), next, reset);
@@ -3387,6 +3386,34 @@ static void add_formatted_headers(struct strbuf *msg,
        }
 }
 
+static void add_formatted_headers(struct strbuf *msg,
+                                 struct string_list *more_headers,
+                                 const char *line_prefix,
+                                 const char *meta,
+                                 const char *reset)
+{
+       int i;
+
+       for (i = 0; i < more_headers->nr; i++)
+               add_formatted_header(msg, more_headers->items[i].string,
+                                    line_prefix, meta, reset);
+}
+
+static int diff_filepair_is_phoney(struct diff_filespec *one,
+                                  struct diff_filespec *two)
+{
+       /*
+        * This function specifically looks for pairs injected by
+        * create_filepairs_for_header_only_notifications().  Such
+        * pairs are "phoney" in that they do not represent any
+        * content or even mode difference, but were inserted because
+        * diff_queued_diff previously had no pair associated with
+        * that path but we needed some pair to avoid losing the
+        * "remerge CONFLICT" header associated with the path.
+        */
+       return !DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two);
+}
+
 static void builtin_diff(const char *name_a,
                         const char *name_b,
                         struct diff_filespec *one,
@@ -3418,14 +3445,16 @@ static void builtin_diff(const char *name_a,
 
        if (o->submodule_format == DIFF_SUBMODULE_LOG &&
            (!one->mode || S_ISGITLINK(one->mode)) &&
-           (!two->mode || S_ISGITLINK(two->mode))) {
+           (!two->mode || S_ISGITLINK(two->mode)) &&
+           (!diff_filepair_is_phoney(one, two))) {
                show_submodule_diff_summary(o, one->path ? one->path : two->path,
                                &one->oid, &two->oid,
                                two->dirty_submodule);
                return;
        } else if (o->submodule_format == DIFF_SUBMODULE_INLINE_DIFF &&
                   (!one->mode || S_ISGITLINK(one->mode)) &&
-                  (!two->mode || S_ISGITLINK(two->mode))) {
+                  (!two->mode || S_ISGITLINK(two->mode)) &&
+                  (!diff_filepair_is_phoney(one, two))) {
                show_submodule_inline_diff(o, one->path ? one->path : two->path,
                                &one->oid, &two->oid,
                                two->dirty_submodule);
@@ -3445,12 +3474,12 @@ static void builtin_diff(const char *name_a,
        b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
        lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
        lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
-       if (!DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two)) {
+       if (diff_filepair_is_phoney(one, two)) {
                /*
-                * We should only reach this point for pairs from
+                * We should only reach this point for pairs generated from
                 * create_filepairs_for_header_only_notifications().  For
-                * these, we should avoid the "/dev/null" special casing
-                * above, meaning we avoid showing such pairs as either
+                * these, we want to avoid the "/dev/null" special casing
+                * above, because we do not want such pairs shown as either
                 * "new file" or "deleted file" below.
                 */
                lbl[0] = a_one;
@@ -4314,7 +4343,7 @@ static void fill_metainfo(struct strbuf *msg,
        const char *set = diff_get_color(use_color, DIFF_METAINFO);
        const char *reset = diff_get_color(use_color, DIFF_RESET);
        const char *line_prefix = diff_line_prefix(o);
-       struct strbuf *more_headers = NULL;
+       struct string_list *more_headers = NULL;
 
        *must_show_header = 1;
        strbuf_init(msg, PATH_MAX * 2 + 300);
@@ -5650,7 +5679,7 @@ int diff_opt_parse(struct diff_options *options,
 
        ac = parse_options(ac, av, prefix, options->parseopts, NULL,
                           PARSE_OPT_KEEP_DASHDASH |
-                          PARSE_OPT_KEEP_UNKNOWN |
+                          PARSE_OPT_KEEP_UNKNOWN_OPT |
                           PARSE_OPT_NO_INTERNAL_HELP |
                           PARSE_OPT_ONE_SHOT |
                           PARSE_OPT_STOP_AT_NON_OPTION);
@@ -5841,6 +5870,7 @@ static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
 {
        int include_conflict_headers =
            (additional_headers(o, p->one->path) &&
+            !o->pickaxe_opts &&
             (!o->filter || filter_bit_tst(DIFF_STATUS_UNMERGED, o)));
 
        /*
@@ -5896,6 +5926,8 @@ int diff_queue_is_empty(struct diff_options *o)
        int i;
        int include_conflict_headers =
            (o->additional_path_headers &&
+            strmap_get_size(o->additional_path_headers) &&
+            !o->pickaxe_opts &&
             (!o->filter || filter_bit_tst(DIFF_STATUS_UNMERGED, o)));
 
        if (include_conflict_headers)
diff --git a/dir.c b/dir.c
index d7cfb08e441825f421f91a982063e00be4168c71..75429508200a9d8b591d23586ecab69fe6011a0d 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -655,10 +655,10 @@ void parse_path_pattern(const char **pattern,
        *patternlen = len;
 }
 
-int pl_hashmap_cmp(const void *unused_cmp_data,
+int pl_hashmap_cmp(const void *cmp_data UNUSED,
                   const struct hashmap_entry *a,
                   const struct hashmap_entry *b,
-                  const void *key)
+                  const void *key UNUSED)
 {
        const struct pattern_entry *ee1 =
                        container_of(a, struct pattern_entry, ent);
@@ -1244,8 +1244,7 @@ int match_basename(const char *basename, int basenamelen,
 
 int match_pathname(const char *pathname, int pathlen,
                   const char *base, int baselen,
-                  const char *pattern, int prefix, int patternlen,
-                  unsigned flags)
+                  const char *pattern, int prefix, int patternlen)
 {
        const char *name;
        int namelen;
@@ -1347,8 +1346,7 @@ static struct path_pattern *last_matching_pattern_from_list(const char *pathname
                if (match_pathname(pathname, pathlen,
                                   pattern->base,
                                   pattern->baselen ? pattern->baselen - 1 : 0,
-                                  exclude, prefix, pattern->patternlen,
-                                  pattern->flags)) {
+                                  exclude, prefix, pattern->patternlen)) {
                        res = pattern;
                        break;
                }
diff --git a/dir.h b/dir.h
index 7bc862030cfb3bbc97cd3b9f6523696662e12633..674747d93af7ad903b1e78a1418ff07c914a69ec 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -414,7 +414,7 @@ int match_basename(const char *, int,
                   const char *, int, int, unsigned);
 int match_pathname(const char *, int,
                   const char *, int,
-                  const char *, int, int, unsigned);
+                  const char *, int, int);
 
 struct path_pattern *last_matching_pattern(struct dir_struct *dir,
                                           struct index_state *istate,
index b3296ce7d15140bff12299b25d1450f69f8508ee..18d042b467d26a9cb3b228db1ef5afa2d903e72c 100644 (file)
@@ -56,7 +56,6 @@ const char *askpass_program;
 const char *excludes_file;
 enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
 int read_replace_refs = 1;
-char *git_replace_ref_base;
 enum eol core_eol = EOL_UNSET;
 int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
 char *check_roundtrip_encoding = "SHIFT-JIS";
@@ -162,6 +161,7 @@ const char *getenv_safe(struct strvec *argv, const char *name)
 
 void setup_git_env(const char *git_dir)
 {
+       char *git_replace_ref_base;
        const char *shallow_file;
        const char *replace_ref_base;
        struct set_gitdir_args args = { NULL };
@@ -182,9 +182,10 @@ void setup_git_env(const char *git_dir)
        if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
                read_replace_refs = 0;
        replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
-       free(git_replace_ref_base);
        git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
                                                          : "refs/replace/");
+       update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
+
        free(git_namespace);
        git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
        shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
@@ -333,10 +334,10 @@ static void set_git_dir_1(const char *path)
        setup_git_env(path);
 }
 
-static void update_relative_gitdir(const char *name,
+static void update_relative_gitdir(const char *name UNUSED,
                                   const char *old_cwd,
                                   const char *new_cwd,
-                                  void *data)
+                                  void *data UNUSED)
 {
        char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
        struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
index cb6647d65703aca1ec1ec7014ac433de31852fcc..998fc2fa1ed4abd32ad0e723115f568768134d3e 100644 (file)
@@ -26,6 +26,7 @@
 #include "commit-reach.h"
 #include "commit-graph.h"
 #include "sigchain.h"
+#include "mergesort.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -175,8 +176,10 @@ static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
        return 0;
 }
 
-static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
-                                  int flag, void *cb_data)
+static int rev_list_insert_ref_oid(const char *refname UNUSED,
+                                  const struct object_id *oid,
+                                  int flag UNUSED,
+                                  void *cb_data)
 {
        return rev_list_insert_ref(cb_data, oid);
 }
@@ -292,6 +295,29 @@ static void mark_tips(struct fetch_negotiator *negotiator,
        return;
 }
 
+static void send_filter(struct fetch_pack_args *args,
+                       struct strbuf *req_buf,
+                       int server_supports_filter)
+{
+       if (args->filter_options.choice) {
+               const char *spec =
+                       expand_list_objects_filter_spec(&args->filter_options);
+               if (server_supports_filter) {
+                       print_verbose(args, _("Server supports filter"));
+                       packet_buf_write(req_buf, "filter %s", spec);
+                       trace2_data_string("fetch", the_repository,
+                                          "filter/effective", spec);
+               } else {
+                       warning("filtering not recognized by server, ignoring");
+                       trace2_data_string("fetch", the_repository,
+                                          "filter/unsupported", spec);
+               }
+       } else {
+               trace2_data_string("fetch", the_repository,
+                                  "filter/none", "");
+       }
+}
+
 static int find_common(struct fetch_negotiator *negotiator,
                       struct fetch_pack_args *args,
                       int fd[2], struct object_id *result_oid,
@@ -299,6 +325,7 @@ static int find_common(struct fetch_negotiator *negotiator,
 {
        int fetching;
        int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
+       int negotiation_round = 0, haves = 0;
        const struct object_id *oid;
        unsigned in_vain = 0;
        int got_continue = 0;
@@ -389,11 +416,7 @@ static int find_common(struct fetch_negotiator *negotiator,
                        packet_buf_write(&req_buf, "deepen-not %s", s->string);
                }
        }
-       if (server_supports_filtering && args->filter_options.choice) {
-               const char *spec =
-                       expand_list_objects_filter_spec(&args->filter_options);
-               packet_buf_write(&req_buf, "filter %s", spec);
-       }
+       send_filter(args, &req_buf, server_supports_filtering);
        packet_buf_flush(&req_buf);
        state_len = req_buf.len;
 
@@ -441,9 +464,19 @@ static int find_common(struct fetch_negotiator *negotiator,
                packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
                print_verbose(args, "have %s", oid_to_hex(oid));
                in_vain++;
+               haves++;
                if (flush_at <= ++count) {
                        int ack;
 
+                       negotiation_round++;
+                       trace2_region_enter_printf("negotiation_v0_v1", "round",
+                                                  the_repository, "%d",
+                                                  negotiation_round);
+                       trace2_data_intmax("negotiation_v0_v1", the_repository,
+                                          "haves_added", haves);
+                       trace2_data_intmax("negotiation_v0_v1", the_repository,
+                                          "in_vain", in_vain);
+                       haves = 0;
                        packet_buf_flush(&req_buf);
                        send_request(args, fd[1], &req_buf);
                        strbuf_setlen(&req_buf, state_len);
@@ -465,6 +498,9 @@ static int find_common(struct fetch_negotiator *negotiator,
                                                      ack, oid_to_hex(result_oid));
                                switch (ack) {
                                case ACK:
+                                       trace2_region_leave_printf("negotiation_v0_v1", "round",
+                                                                  the_repository, "%d",
+                                                                  negotiation_round);
                                        flushes = 0;
                                        multi_ack = 0;
                                        retval = 0;
@@ -490,6 +526,7 @@ static int find_common(struct fetch_negotiator *negotiator,
                                                const char *hex = oid_to_hex(result_oid);
                                                packet_buf_write(&req_buf, "have %s\n", hex);
                                                state_len = req_buf.len;
+                                               haves++;
                                                /*
                                                 * Reset in_vain because an ack
                                                 * for this commit has not been
@@ -508,6 +545,9 @@ static int find_common(struct fetch_negotiator *negotiator,
                                }
                        } while (ack);
                        flushes--;
+                       trace2_region_leave_printf("negotiation_v0_v1", "round",
+                                                  the_repository, "%d",
+                                                  negotiation_round);
                        if (got_continue && MAX_IN_VAIN < in_vain) {
                                print_verbose(args, _("giving up"));
                                break; /* give up */
@@ -518,6 +558,8 @@ static int find_common(struct fetch_negotiator *negotiator,
        }
 done:
        trace2_region_leave("fetch-pack", "negotiation_v0_v1", the_repository);
+       trace2_data_intmax("negotiation_v0_v1", the_repository, "total_rounds",
+                          negotiation_round);
        if (!got_ready || !no_done) {
                packet_buf_write(&req_buf, "done\n");
                send_request(args, fd[1], &req_buf);
@@ -560,8 +602,10 @@ static int mark_complete(const struct object_id *oid)
        return 0;
 }
 
-static int mark_complete_oid(const char *refname, const struct object_id *oid,
-                            int flag, void *cb_data)
+static int mark_complete_oid(const char *refname UNUSED,
+                            const struct object_id *oid,
+                            int flag UNUSED,
+                            void *cb_data UNUSED)
 {
        return mark_complete(oid);
 }
@@ -799,7 +843,7 @@ static int everything_local(struct fetch_pack_args *args,
        return retval;
 }
 
-static int sideband_demux(int in, int out, void *data)
+static int sideband_demux(int in UNUSED, int out, void *data)
 {
        int *xd = data;
        int ret;
@@ -1025,6 +1069,13 @@ static int get_pack(struct fetch_pack_args *args,
        return 0;
 }
 
+static int ref_compare_name(const struct ref *a, const struct ref *b)
+{
+       return strcmp(a->name, b->name);
+}
+
+DEFINE_LIST_SORT(static, sort_ref_list, struct ref, next);
+
 static int cmp_ref_by_name(const void *a_, const void *b_)
 {
        const struct ref *a = *((const struct ref **)a_);
@@ -1323,15 +1374,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
                die(_("Server does not support shallow requests"));
 
        /* Add filter */
-       if (server_supports_feature("fetch", "filter", 0) &&
-           args->filter_options.choice) {
-               const char *spec =
-                       expand_list_objects_filter_spec(&args->filter_options);
-               print_verbose(args, _("Server supports filter"));
-               packet_buf_write(&req_buf, "filter %s", spec);
-       } else if (args->filter_options.choice) {
-               warning("filtering not recognized by server, ignoring");
-       }
+       send_filter(args, &req_buf,
+                   server_supports_feature("fetch", "filter", 0));
 
        if (server_supports_feature("fetch", "packfile-uris", 0)) {
                int i;
@@ -1361,6 +1405,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
 
        haves_added = add_haves(negotiator, &req_buf, haves_to_send);
        *in_vain += haves_added;
+       trace2_data_intmax("negotiation_v2", the_repository, "haves_added", haves_added);
+       trace2_data_intmax("negotiation_v2", the_repository, "in_vain", *in_vain);
        if (!haves_added || (seen_ack && *in_vain >= MAX_IN_VAIN)) {
                /* Send Done */
                packet_buf_write(&req_buf, "done\n");
@@ -1603,6 +1649,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        struct oidset common = OIDSET_INIT;
        struct packet_reader reader;
        int in_vain = 0, negotiation_started = 0;
+       int negotiation_round = 0;
        int haves_to_send = INITIAL_FLUSH;
        struct fetch_negotiator negotiator_alloc;
        struct fetch_negotiator *negotiator;
@@ -1659,12 +1706,20 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                                    "negotiation_v2",
                                                    the_repository);
                        }
+                       negotiation_round++;
+                       trace2_region_enter_printf("negotiation_v2", "round",
+                                                  the_repository, "%d",
+                                                  negotiation_round);
                        if (send_fetch_request(negotiator, fd[1], args, ref,
                                               &common,
                                               &haves_to_send, &in_vain,
                                               reader.use_sideband,
-                                              seen_ack))
+                                              seen_ack)) {
+                               trace2_region_leave_printf("negotiation_v2", "round",
+                                                          the_repository, "%d",
+                                                          negotiation_round);
                                state = FETCH_GET_PACK;
+                       }
                        else
                                state = FETCH_PROCESS_ACKS;
                        break;
@@ -1677,6 +1732,9 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                seen_ack = 1;
                                oidset_insert(&common, &common_oid);
                        }
+                       trace2_region_leave_printf("negotiation_v2", "round",
+                                                  the_repository, "%d",
+                                                  negotiation_round);
                        if (received_ready) {
                                /*
                                 * Don't check for response delimiter; get_pack() will
@@ -1692,6 +1750,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                        trace2_region_leave("fetch-pack",
                                            "negotiation_v2",
                                            the_repository);
+                       trace2_data_intmax("negotiation_v2", the_repository,
+                                          "total_rounds", negotiation_round);
                        /* Check for shallow-info section */
                        if (process_section_header(&reader, "shallow-info", 1))
                                receive_shallow_info(args, &reader, shallows, si);
@@ -2071,6 +2131,7 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
        int in_vain = 0;
        int seen_ack = 0;
        int last_iteration = 0;
+       int negotiation_round = 0;
        timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
 
        fetch_negotiator_init(the_repository, &negotiator);
@@ -2084,11 +2145,17 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
                           add_to_object_array,
                           &nt_object_array);
 
+       trace2_region_enter("fetch-pack", "negotiate_using_fetch", the_repository);
        while (!last_iteration) {
                int haves_added;
                struct object_id common_oid;
                int received_ready = 0;
 
+               negotiation_round++;
+
+               trace2_region_enter_printf("negotiate_using_fetch", "round",
+                                          the_repository, "%d",
+                                          negotiation_round);
                strbuf_reset(&req_buf);
                write_fetch_command_and_capabilities(&req_buf, server_options);
 
@@ -2099,6 +2166,11 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
                if (!haves_added || (seen_ack && in_vain >= MAX_IN_VAIN))
                        last_iteration = 1;
 
+               trace2_data_intmax("negotiate_using_fetch", the_repository,
+                                  "haves_added", haves_added);
+               trace2_data_intmax("negotiate_using_fetch", the_repository,
+                                  "in_vain", in_vain);
+
                /* Send request */
                packet_buf_flush(&req_buf);
                if (write_in_full(fd[1], req_buf.buf, req_buf.len) < 0)
@@ -2131,7 +2203,13 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips,
                                                 REACH_SCRATCH, 0,
                                                 min_generation))
                        last_iteration = 1;
+               trace2_region_leave_printf("negotiation", "round",
+                                          the_repository, "%d",
+                                          negotiation_round);
        }
+       trace2_region_enter("fetch-pack", "negotiate_using_fetch", the_repository);
+       trace2_data_intmax("negotiate_using_fetch", the_repository,
+                          "total_rounds", negotiation_round);
        clear_common_flag(acked_commits);
        strbuf_release(&req_buf);
 }
diff --git a/fuzz-commit-graph.c b/fuzz-commit-graph.c
deleted file mode 100644 (file)
index e7cf6d5..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "commit-graph.h"
-#include "repository.h"
-
-struct commit_graph *parse_commit_graph(struct repository *r,
-                                       void *graph_map, size_t graph_size);
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
-       struct commit_graph *g;
-
-       initialize_the_repository();
-       g = parse_commit_graph(the_repository, (void *)data, size);
-       repo_clear(the_repository);
-       free_commit_graph(g);
-
-       return 0;
-}
index bb5ba1fe7cc5979255fe79fd8dfc0085fc8df8f1..f139008d0a385140f354e6d2b36bd520c1b555b4 100644 (file)
--- a/gettext.c
+++ b/gettext.c
@@ -10,7 +10,6 @@
 #include "config.h"
 
 #ifndef NO_GETTEXT
-#      include <locale.h>
 #      include <libintl.h>
 #      ifdef GIT_WINDOWS_NATIVE
 
@@ -80,7 +79,6 @@ static int test_vsnprintf(const char *fmt, ...)
 
 static void init_gettext_charset(const char *domain)
 {
-       setlocale(LC_CTYPE, "");
        charset = locale_charset();
        bind_textdomain_codeset(domain, charset);
 
index 6aee4d92e710f694dc43d34568073d343b6fbe60..bac663353d3b1ad87e5757df1ffbca27215f6678 100644 (file)
@@ -189,6 +189,13 @@ struct strbuf;
 #define _NETBSD_SOURCE 1
 #define _SGI_SOURCE 1
 
+#if defined(__GNUC__)
+#define UNUSED __attribute__((unused)) \
+       __attribute__((deprecated ("parameter declared as UNUSED")))
+#else
+#define UNUSED
+#endif
+
 #if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
 # if !defined(_WIN32_WINNT)
 #  define _WIN32_WINNT 0x0600
@@ -215,6 +222,7 @@ struct strbuf;
 #endif
 #include <errno.h>
 #include <limits.h>
+#include <locale.h>
 #ifdef NEEDS_SYS_PARAM_H
 #include <sys/param.h>
 #endif
@@ -261,6 +269,7 @@ static inline int is_xplatform_dir_sep(int c)
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
+#include <sys/statvfs.h>
 #include <termios.h>
 #ifndef NO_SYS_SELECT_H
 #include <sys/select.h>
@@ -397,7 +406,9 @@ typedef uintmax_t timestamp_t;
 #endif
 
 #ifndef platform_core_config
-static inline int noop_core_config(const char *var, const char *value, void *cb)
+static inline int noop_core_config(const char *var UNUSED,
+                                  const char *value UNUSED,
+                                  void *cb UNUSED)
 {
        return 0;
 }
@@ -490,7 +501,8 @@ static inline void extract_id_from_env(const char *env, uid_t *id)
        }
 }
 
-static inline int is_path_owned_by_current_uid(const char *path, struct strbuf *report)
+static inline int is_path_owned_by_current_uid(const char *path,
+                                              struct strbuf *report UNUSED)
 {
        struct stat st;
        uid_t euid;
@@ -568,8 +580,11 @@ static inline int git_has_dir_sep(const char *path)
 /* The sentinel attribute is valid from gcc version 4.0 */
 #if defined(__GNUC__) && (__GNUC__ >= 4)
 #define LAST_ARG_MUST_BE_NULL __attribute__((sentinel))
+/* warn_unused_result exists as of gcc 3.4.0, but be lazy and check 4.0 */
+#define RESULT_MUST_BE_USED __attribute__ ((warn_unused_result))
 #else
 #define LAST_ARG_MUST_BE_NULL
+#define RESULT_MUST_BE_USED
 #endif
 
 #define MAYBE_UNUSED __attribute__((__unused__))
index 4349566c89163ea21dfb8388f494cdcdf86604c9..c68f49454cd83f48ce3452df178766606effbad9 100755 (executable)
@@ -102,7 +102,7 @@ resolve_full_httpd () {
 
 start_httpd () {
        if test -f "$fqgitdir/pid"; then
-               say "Instance already running. Restarting..."
+               echo "Instance already running. Restarting..."
                stop_httpd
        fi
 
index 343fe7bccd0d64f0caff1ad5d3f981729a8e5fc9..77e93121bf8c19714b19097b4739b206230677cb 100755 (executable)
@@ -5,6 +5,16 @@
 #
 # Resolve two trees, using enhanced multi-base read-tree.
 
+. git-sh-setup
+
+# Abort if index does not match HEAD
+if ! git diff-index --quiet --cached HEAD --
+then
+    gettextln "Error: Your local changes to the following files would be overwritten by merge"
+    git diff-index --cached --name-only HEAD -- | sed -e 's/^/    /'
+    exit 2
+fi
+
 # The first parameters up to -- are merge bases; the rest are heads.
 bases= head= remotes= sep_seen=
 for arg
index 77dc19daa61de1e7eb850292f3fd6a963b580130..d26a980e5acb66eda31d32e075d90736bcac4e3a 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -2259,7 +2259,7 @@ class P4Submit(Command, P4UserMap):
                                 raw=True):
                             if regexp.search(line):
                                 if verbose:
-                                    print("got keyword match on %s in %s in %s" % (regex.pattern, line, file))
+                                    print("got keyword match on %s in %s in %s" % (regexp.pattern, line, file))
                                 kwfiles[file] = regexp
                                 break
 
@@ -4402,19 +4402,16 @@ class P4Unshelve(Command):
     def renameBranch(self, branch_name):
         """Rename the existing branch to branch_name.N ."""
 
-        found = True
         for i in range(0, 1000):
             backup_branch_name = "{0}.{1}".format(branch_name, i)
             if not gitBranchExists(backup_branch_name):
                 # Copy ref to backup
                 gitUpdateRef(backup_branch_name, branch_name)
                 gitDeleteRef(branch_name)
-                found = True
                 print("renamed old unshelve branch to {0}".format(backup_branch_name))
                 break
-
-        if not found:
-            sys.exit("gave up trying to rename existing branch {0}".format(sync.branch))
+        else:
+            sys.exit("gave up trying to rename existing branch {0}".format(branch_name))
 
     def findLastP4Revision(self, starting_point):
         """Look back from starting_point for the first commit created by git-p4
index d92df37e9924719b2aa6d1c84a88d56811d2bd4f..ce273fe0e48d997cb067e77707026616a9302eb2 100644 (file)
@@ -57,15 +57,6 @@ die_with_status () {
        exit "$status"
 }
 
-GIT_QUIET=
-
-say () {
-       if test -z "$GIT_QUIET"
-       then
-               printf '%s\n' "$*"
-       fi
-}
-
 if test -n "$OPTIONS_SPEC"; then
        usage() {
                "$0" -h
@@ -285,13 +276,6 @@ get_author_ident_from_commit () {
        parse_ident_from_commit author AUTHOR
 }
 
-# Clear repo-local GIT_* environment variables. Useful when switching to
-# another repository (e.g. when entering a submodule). See also the env
-# list in git_connect()
-clear_local_git_env() {
-       unset $(git rev-parse --local-env-vars)
-}
-
 # Generate a virtual base file for a two-file merge. Uses git apply to
 # remove lines from $1 that are not in $2, leaving only common lines.
 create_virtual_base() {
index fd0b4a2c947762b023999191ff6f3b5c78cb58fc..5e5d21c010f7d4337dbf95cd50eeaf8c97791ba8 100755 (executable)
@@ -30,6 +30,7 @@ GIT_PROTOCOL_FROM_USER=0
 export GIT_PROTOCOL_FROM_USER
 
 command=
+quiet=
 branch=
 force=
 reference=
@@ -40,8 +41,9 @@ require_init=
 files=
 remote=
 nofetch=
-update=
-prefix=
+rebase=
+merge=
+checkout=
 custom_name=
 depth=
 progress=
@@ -56,17 +58,6 @@ isnumber()
        n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
 }
 
-# Sanitize the local git environment for use within a submodule. We
-# can't simply use clear_local_git_env since we want to preserve some
-# of the settings from GIT_CONFIG_PARAMETERS.
-sanitize_submodule_env()
-{
-       save_config=$GIT_CONFIG_PARAMETERS
-       clear_local_git_env
-       GIT_CONFIG_PARAMETERS=$save_config
-       export GIT_CONFIG_PARAMETERS
-}
-
 #
 # Add a new submodule to the working tree, .gitmodules and the index
 #
@@ -90,7 +81,7 @@ cmd_add()
                        force=$1
                        ;;
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        ;;
                --progress)
                        progress=1
@@ -138,7 +129,7 @@ cmd_add()
                usage
        fi
 
-       git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper add ${GIT_QUIET:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add ${quiet:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@"
 }
 
 #
@@ -154,7 +145,7 @@ cmd_foreach()
        do
                case "$1" in
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        ;;
                --recursive)
                        recursive=1
@@ -169,7 +160,7 @@ cmd_foreach()
                shift
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
 }
 
 #
@@ -184,7 +175,7 @@ cmd_init()
        do
                case "$1" in
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        ;;
                --)
                        shift
@@ -200,7 +191,7 @@ cmd_init()
                shift
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper init ${GIT_QUIET:+--quiet} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init ${quiet:+--quiet} -- "$@"
 }
 
 #
@@ -217,7 +208,7 @@ cmd_deinit()
                        force=$1
                        ;;
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        ;;
                --all)
                        deinit_all=t
@@ -236,7 +227,7 @@ cmd_deinit()
                shift
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${quiet:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
 }
 
 #
@@ -251,10 +242,7 @@ cmd_update()
        do
                case "$1" in
                -q|--quiet)
-                       GIT_QUIET=1
-                       ;;
-               -v)
-                       unset GIT_QUIET
+                       quiet=1
                        ;;
                --progress)
                        progress=1
@@ -263,7 +251,6 @@ cmd_update()
                        init=1
                        ;;
                --require-init)
-                       init=1
                        require_init=1
                        ;;
                --remote)
@@ -276,7 +263,7 @@ cmd_update()
                        force=$1
                        ;;
                -r|--rebase)
-                       update="rebase"
+                       rebase=1
                        ;;
                --reference)
                        case "$2" in '') usage ;; esac
@@ -290,13 +277,13 @@ cmd_update()
                        dissociate=1
                        ;;
                -m|--merge)
-                       update="merge"
+                       merge=1
                        ;;
                --recursive)
                        recursive=1
                        ;;
                --checkout)
-                       update="checkout"
+                       checkout=1
                        ;;
                --recommend-shallow)
                        recommend_shallow="--recommend-shallow"
@@ -349,7 +336,7 @@ cmd_update()
        done
 
        git ${wt_prefix:+-C "$wt_prefix"} submodule--helper update \
-               ${GIT_QUIET:+--quiet} \
+               ${quiet:+--quiet} \
                ${force:+--force} \
                ${progress:+"--progress"} \
                ${remote:+--remote} \
@@ -357,8 +344,9 @@ cmd_update()
                ${init:+--init} \
                ${nofetch:+--no-fetch} \
                ${wt_prefix:+--prefix "$wt_prefix"} \
-               ${prefix:+--recursive-prefix "$prefix"} \
-               ${update:+--update "$update"} \
+               ${rebase:+--rebase} \
+               ${merge:+--merge} \
+               ${checkout:+--checkout} \
                ${reference:+"$reference"} \
                ${dissociate:+"--dissociate"} \
                ${depth:+"$depth"} \
@@ -409,7 +397,7 @@ cmd_set_branch() {
                shift
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${GIT_QUIET:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${quiet:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
 }
 
 #
@@ -422,7 +410,7 @@ cmd_set_url() {
        do
                case "$1" in
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        ;;
                --)
                        shift
@@ -438,7 +426,7 @@ cmd_set_url() {
                shift
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${GIT_QUIET:+--quiet} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${quiet:+--quiet} -- "$@"
 }
 
 #
@@ -459,7 +447,7 @@ cmd_summary() {
        do
                case "$1" in
                --cached)
-                       cached="$1"
+                       cached=1
                        ;;
                --files)
                        files="$1"
@@ -509,7 +497,7 @@ cmd_status()
        do
                case "$1" in
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        ;;
                --cached)
                        cached=1
@@ -531,7 +519,7 @@ cmd_status()
                shift
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${quiet:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@"
 }
 #
 # Sync remote urls for submodules
@@ -544,7 +532,7 @@ cmd_sync()
        do
                case "$1" in
                -q|--quiet)
-                       GIT_QUIET=1
+                       quiet=1
                        shift
                        ;;
                --recursive)
@@ -564,12 +552,12 @@ cmd_sync()
                esac
        done
 
-       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} -- "$@"
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
 }
 
 cmd_absorbgitdirs()
 {
-       git submodule--helper absorb-git-dirs --prefix "$wt_prefix" "$@"
+       git submodule--helper absorbgitdirs --prefix "$wt_prefix" "$@"
 }
 
 # This loop parses the command line arguments to find the
@@ -585,18 +573,10 @@ do
                command=$1
                ;;
        -q|--quiet)
-               GIT_QUIET=1
-               ;;
-       -b|--branch)
-               case "$2" in
-               '')
-                       usage
-                       ;;
-               esac
-               branch="$2"; shift
+               quiet=1
                ;;
        --cached)
-               cached="$1"
+               cached=1
                ;;
        --)
                break
@@ -622,12 +602,6 @@ then
     fi
 fi
 
-# "-b branch" is accepted only by "add" and "set-branch"
-if test -n "$branch" && (test "$command" != add || test "$command" != set-branch)
-then
-       usage
-fi
-
 # "--cached" is accepted only by "status" and "summary"
 if test -n "$cached" && test "$command" != status && test "$command" != summary
 then
diff --git a/git.c b/git.c
index d7a7a82008b41e80c17176a9865ff49bf538031a..da411c53822a1893f7774ae721b5931452741bba 100644 (file)
--- a/git.c
+++ b/git.c
@@ -489,14 +489,14 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 static struct cmd_struct commands[] = {
        { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
        { "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },
-       { "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
+       { "annotate", cmd_annotate, RUN_SETUP },
        { "apply", cmd_apply, RUN_SETUP_GENTLY },
        { "archive", cmd_archive, RUN_SETUP_GENTLY },
        { "bisect--helper", cmd_bisect__helper, RUN_SETUP },
        { "blame", cmd_blame, RUN_SETUP },
        { "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
        { "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
-       { "bundle", cmd_bundle, RUN_SETUP_GENTLY | NO_PARSEOPT },
+       { "bundle", cmd_bundle, RUN_SETUP_GENTLY },
        { "cat-file", cmd_cat_file, RUN_SETUP },
        { "check-attr", cmd_check_attr, RUN_SETUP },
        { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
@@ -514,7 +514,7 @@ static struct cmd_struct commands[] = {
        { "column", cmd_column, RUN_SETUP_GENTLY },
        { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
        { "commit-graph", cmd_commit_graph, RUN_SETUP },
-       { "commit-tree", cmd_commit_tree, RUN_SETUP | NO_PARSEOPT },
+       { "commit-tree", cmd_commit_tree, RUN_SETUP },
        { "config", cmd_config, RUN_SETUP_GENTLY | DELAY_PAGER_CONFIG },
        { "count-objects", cmd_count_objects, RUN_SETUP },
        { "credential", cmd_credential, RUN_SETUP_GENTLY | NO_PARSEOPT },
@@ -522,6 +522,7 @@ static struct cmd_struct commands[] = {
        { "credential-cache--daemon", cmd_credential_cache_daemon },
        { "credential-store", cmd_credential_store },
        { "describe", cmd_describe, RUN_SETUP },
+       { "diagnose", cmd_diagnose, RUN_SETUP_GENTLY },
        { "diff", cmd_diff, NO_PARSEOPT },
        { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
        { "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
@@ -553,9 +554,9 @@ static struct cmd_struct commands[] = {
        { "ls-files", cmd_ls_files, RUN_SETUP },
        { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
        { "ls-tree", cmd_ls_tree, RUN_SETUP },
-       { "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY | NO_PARSEOPT },
+       { "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
        { "mailsplit", cmd_mailsplit, NO_PARSEOPT },
-       { "maintenance", cmd_maintenance, RUN_SETUP | NO_PARSEOPT },
+       { "maintenance", cmd_maintenance, RUN_SETUP },
        { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
        { "merge-base", cmd_merge_base, RUN_SETUP },
        { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
@@ -565,8 +566,8 @@ static struct cmd_struct commands[] = {
        { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
        { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
        { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
-       { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT },
-       { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT },
+       { "merge-tree", cmd_merge_tree, RUN_SETUP },
+       { "mktag", cmd_mktag, RUN_SETUP },
        { "mktree", cmd_mktree, RUN_SETUP },
        { "multi-pack-index", cmd_multi_pack_index, RUN_SETUP },
        { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
@@ -627,7 +628,7 @@ static struct cmd_struct commands[] = {
        { "verify-tag", cmd_verify_tag, RUN_SETUP },
        { "version", cmd_version },
        { "whatchanged", cmd_whatchanged, RUN_SETUP },
-       { "worktree", cmd_worktree, RUN_SETUP | NO_PARSEOPT },
+       { "worktree", cmd_worktree, RUN_SETUP },
        { "write-tree", cmd_write_tree, RUN_SETUP },
 };
 
index f13e23c4de41a602537043c0b21fab7ccb65df0b..3b68ab2d672c4afae62f8f4dc024e0911027b58d 100644 (file)
@@ -1,8 +1,8 @@
-# The default target of this Makefile is...
-all::
+ifndef MAK_DIR_GITWEB
+$(error do not run gitweb/Makefile stand-alone anymore. The "gitweb" and \
+"install-gitweb" targets now live in the top-level Makefile)
+endif
 
-# Define V=1 to have a more verbose compile.
-#
 # Define JSMIN to point to JavaScript minifier that functions as
 # a filter to have static/gitweb.js minified.
 #
@@ -10,13 +10,6 @@ all::
 # version of static/gitweb.css
 #
 
-prefix ?= $(HOME)
-bindir ?= $(prefix)/bin
-gitwebdir ?= /var/www/cgi-bin
-
-RM ?= rm -f
-INSTALL ?= install
-
 # default configuration for gitweb
 GITWEB_CONFIG = gitweb_config.perl
 GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
@@ -30,89 +23,45 @@ GITWEB_STRICT_EXPORT =
 GITWEB_BASE_URL =
 GITWEB_LIST =
 GITWEB_HOMETEXT = indextext.html
-GITWEB_CSS = static/gitweb.css
+GITWEB_CSS_IN = static/gitweb.css
+GITWEB_CSS = $(GITWEB_CSS_IN)
 GITWEB_LOGO = static/git-logo.png
 GITWEB_FAVICON = static/git-favicon.png
-GITWEB_JS = static/gitweb.js
+GITWEB_JS_IN = static/gitweb.js
+GITWEB_JS = $(GITWEB_JS_IN)
 GITWEB_SITE_HTML_HEAD_STRING =
 GITWEB_SITE_HEADER =
 GITWEB_SITE_FOOTER =
 HIGHLIGHT_BIN = highlight
 
-# include user config
--include ../config.mak.autogen
--include ../config.mak
--include config.mak
-
-# determine version
-../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
-       $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
-
-ifneq ($(MAKECMDGOALS),clean)
--include ../GIT-VERSION-FILE
-endif
-
-### Build rules
-
-SHELL_PATH ?= $(SHELL)
-PERL_PATH  ?= /usr/bin/perl
+# What targets we'll add to 'all' for "make gitweb"
+GITWEB_ALL =
+GITWEB_ALL += gitweb.cgi
+GITWEB_ALL += $(GITWEB_JS)
 
-# Shell quote;
-bindir_SQ = $(subst ','\'',$(bindir))#'
-gitwebdir_SQ = $(subst ','\'',$(gitwebdir))#'
-gitwebstaticdir_SQ = $(subst ','\'',$(gitwebdir)/static)#'
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))#'
-PERL_PATH_SQ  = $(subst ','\'',$(PERL_PATH))#'
-DESTDIR_SQ    = $(subst ','\'',$(DESTDIR))#'
-
-# Quiet generation (unless V=1)
-QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
-QUIET_SUBDIR1  =
-
-ifneq ($(findstring $(MAKEFLAGS),w),w)
-PRINT_DIR = --no-print-directory
-else # "make -w"
-NO_SUBDIR = :
-endif
-
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
-       QUIET          = @
-       QUIET_GEN      = $(QUIET)echo '   ' GEN $@;
-       QUIET_SUBDIR0  = +@subdir=
-       QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
-                        $(MAKE) $(PRINT_DIR) -C $$subdir
-       export V
-       export QUIET
-       export QUIET_GEN
-       export QUIET_SUBDIR0
-       export QUIET_SUBDIR1
-endif
-endif
-
-all:: gitweb.cgi static/gitweb.js
+MAK_DIR_GITWEB_ALL = $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_ALL))
 
 GITWEB_PROGRAMS = gitweb.cgi
 
+GITWEB_JS_MIN = static/gitweb.min.js
 ifdef JSMIN
-GITWEB_FILES += static/gitweb.min.js
-GITWEB_JS = static/gitweb.min.js
-all:: static/gitweb.min.js
-static/gitweb.min.js: static/gitweb.js GITWEB-BUILD-OPTIONS
+GITWEB_JS = $(GITWEB_JS_MIN)
+GITWEB_ALL += $(MAK_DIR_GITWEB)$(GITWEB_JS_MIN)
+$(MAK_DIR_GITWEB)$(GITWEB_JS_MIN): $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS
+$(MAK_DIR_GITWEB)$(GITWEB_JS_MIN): $(MAK_DIR_GITWEB)$(GITWEB_JS_IN)
        $(QUIET_GEN)$(JSMIN) <$< >$@
-else
-GITWEB_FILES += static/gitweb.js
 endif
+GITWEB_FILES += $(GITWEB_JS)
 
+GITWEB_CSS_MIN = static/gitweb.min.css
 ifdef CSSMIN
-GITWEB_FILES += static/gitweb.min.css
-GITWEB_CSS = static/gitweb.min.css
-all:: static/gitweb.min.css
-static/gitweb.min.css: static/gitweb.css GITWEB-BUILD-OPTIONS
+GITWEB_CSS = $(GITWEB_CSS_MIN)
+GITWEB_ALL += $(MAK_DIR_GITWEB)$(GITWEB_CSS_MIN)
+$(MAK_DIR_GITWEB)$(GITWEB_CSS_MIN): $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS
+$(MAK_DIR_GITWEB)$(GITWEB_CSS_MIN): $(MAK_DIR_GITWEB)$(GITWEB_CSS_IN)
        $(QUIET_GEN)$(CSSMIN) <$< >$@
-else
-GITWEB_FILES += static/gitweb.css
 endif
+GITWEB_FILES += $(GITWEB_CSS)
 
 GITWEB_FILES += static/git-logo.png static/git-favicon.png
 
@@ -120,6 +69,7 @@ GITWEB_FILES += static/git-logo.png static/git-favicon.png
 #
 # js/lib/common-lib.js should be always first, then js/lib/*.js,
 # then the rest of files; js/gitweb.js should be last (if it exists)
+GITWEB_JSLIB_FILES =
 GITWEB_JSLIB_FILES += static/js/lib/common-lib.js
 GITWEB_JSLIB_FILES += static/js/lib/datetime.js
 GITWEB_JSLIB_FILES += static/js/lib/cookies.js
@@ -152,46 +102,45 @@ GITWEB_REPLACE = \
        -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
        -e 's|++HIGHLIGHT_BIN++|$(HIGHLIGHT_BIN)|g'
 
-GITWEB-BUILD-OPTIONS: FORCE
+.PHONY: FORCE
+$(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS: FORCE
        @rm -f $@+
        @echo "x" '$(PERL_PATH_SQ)' $(GITWEB_REPLACE) "$(JSMIN)|$(CSSMIN)" >$@+
        @cmp -s $@+ $@ && rm -f $@+ || mv -f $@+ $@
 
-gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS
+$(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)GITWEB-BUILD-OPTIONS
+$(MAK_DIR_GITWEB)gitweb.cgi: $(MAK_DIR_GITWEB)gitweb.perl
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
                $(GITWEB_REPLACE) $< >$@+ && \
        chmod +x $@+ && \
        mv $@+ $@
 
-static/gitweb.js: $(GITWEB_JSLIB_FILES)
+$(MAK_DIR_GITWEB)static/gitweb.js: $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_JSLIB_FILES))
        $(QUIET_GEN)$(RM) $@ $@+ && \
        cat $^ >$@+ && \
        mv $@+ $@
 
-### Testing rules
-
-test:
-       $(MAKE) -C ../t gitweb-test
-
-test-installed:
-       GITWEB_TEST_INSTALLED='$(DESTDIR_SQ)$(gitwebdir_SQ)' \
-               $(MAKE) -C ../t gitweb-test
-
 ### Installation rules
 
-install: all
+.PHONY: install-gitweb
+install-gitweb: $(MAK_DIR_GITWEB_ALL)
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebdir_SQ)'
-       $(INSTALL) -m 755 $(GITWEB_PROGRAMS) '$(DESTDIR_SQ)$(gitwebdir_SQ)'
+       $(INSTALL) -m 755 $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_PROGRAMS)) '$(DESTDIR_SQ)$(gitwebdir_SQ)'
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
-       $(INSTALL) -m 644 $(GITWEB_FILES) '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
+       $(INSTALL) -m 644 $(addprefix $(MAK_DIR_GITWEB),$(GITWEB_FILES)) \
+               '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
+ifndef NO_GITWEB
+ifndef NO_PERL
+install: install-gitweb
+endif
+endif
 
 ### Cleaning rules
 
-clean:
-       $(RM) gitweb.cgi static/gitweb.js \
-               static/gitweb.min.js static/gitweb.min.css \
-               GITWEB-BUILD-OPTIONS
-
-.PHONY: all clean install test test-installed .FORCE-GIT-VERSION-FILE FORCE
-
+.PHONY: gitweb-clean
+gitweb-clean:
+       $(RM) $(addprefix $(MAK_DIR_GITWEB),gitweb.cgi $(GITWEB_JS_IN) \
+               $(GITWEB_JS_MIN) $(GITWEB_CSS_MIN) \
+               GITWEB-BUILD-OPTIONS)
+clean: gitweb-clean
index 1835487ab2aeed33a4aa3e6dbde84df7ae7e6d1b..e66eb3d9bad7cf627d5ed35e13e32dafb556d5cd 100755 (executable)
@@ -3560,23 +3560,6 @@ sub parse_commit_text {
                $title =~ s/^    //;
                if ($title ne "") {
                        $co{'title'} = chop_str($title, 80, 5);
-                       # remove leading stuff of merges to make the interesting part visible
-                       if (length($title) > 50) {
-                               $title =~ s/^Automatic //;
-                               $title =~ s/^merge (of|with) /Merge ... /i;
-                               if (length($title) > 50) {
-                                       $title =~ s/(http|rsync):\/\///;
-                               }
-                               if (length($title) > 50) {
-                                       $title =~ s/(master|www|rsync)\.//;
-                               }
-                               if (length($title) > 50) {
-                                       $title =~ s/kernel.org:?//;
-                               }
-                               if (length($title) > 50) {
-                                       $title =~ s/\/pub\/scm//;
-                               }
-                       }
                        $co{'title_short'} = chop_str($title, 50, 5);
                        last;
                }
index 947b58ad4da364bc7890a6ca30d065ee56d9fc8d..9aa714bdeea81e3c781cd8413b9299263030d85d 100644 (file)
@@ -165,15 +165,17 @@ static struct {
        { 0, "TRUST_", GPG_STATUS_TRUST_LEVEL },
 };
 
-static struct {
+/* Keep the order same as enum signature_trust_level */
+static struct sigcheck_gpg_trust_level {
        const char *key;
+       const char *display_key;
        enum signature_trust_level value;
 } sigcheck_gpg_trust_level[] = {
-       { "UNDEFINED", TRUST_UNDEFINED },
-       { "NEVER", TRUST_NEVER },
-       { "MARGINAL", TRUST_MARGINAL },
-       { "FULLY", TRUST_FULLY },
-       { "ULTIMATE", TRUST_ULTIMATE },
+       { "UNDEFINED", "undefined", TRUST_UNDEFINED },
+       { "NEVER", "never", TRUST_NEVER },
+       { "MARGINAL", "marginal", TRUST_MARGINAL },
+       { "FULLY", "fully", TRUST_FULLY },
+       { "ULTIMATE", "ultimate", TRUST_ULTIMATE },
 };
 
 static void replace_cstring(char **field, const char *line, const char *next)
@@ -697,7 +699,7 @@ void set_signing_key(const char *key)
        configured_signing_key = xstrdup(key);
 }
 
-int git_gpg_config(const char *var, const char *value, void *cb)
+int git_gpg_config(const char *var, const char *value, void *cb UNUSED)
 {
        struct gpg_format *fmt = NULL;
        char *fmtname = NULL;
@@ -905,6 +907,20 @@ const char *get_signing_key(void)
        return git_committer_info(IDENT_STRICT | IDENT_NO_DATE);
 }
 
+const char *gpg_trust_level_to_str(enum signature_trust_level level)
+{
+       struct sigcheck_gpg_trust_level *trust;
+
+       if (level < 0 || level >= ARRAY_SIZE(sigcheck_gpg_trust_level))
+               BUG("invalid trust level requested %d", level);
+
+       trust = &sigcheck_gpg_trust_level[level];
+       if (trust->value != level)
+               BUG("sigcheck_gpg_trust_level[] unsorted");
+
+       return sigcheck_gpg_trust_level[level].display_key;
+}
+
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
 {
        return use_format->sign_buffer(buffer, signature, signing_key);
index b30cbdcd3da546888fb1f8f206205c2373ad633b..8a9ef41779e2fe91305dcb1b13cf66a282446cf6 100644 (file)
@@ -71,6 +71,14 @@ size_t parse_signed_buffer(const char *buf, size_t size);
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
                const char *signing_key);
 
+
+/*
+ * Returns corresponding string in lowercase for a given member of
+ * enum signature_trust_level. For example, `TRUST_ULTIMATE` will
+ * return "ultimate".
+ */
+const char *gpg_trust_level_to_str(enum signature_trust_level level);
+
 int git_gpg_config(const char *, const char *, void *);
 void set_signing_key(const char *);
 const char *get_signing_key(void);
diff --git a/grep.c b/grep.c
index 82eb7da1022ecc0c08a83ca7bc46e18602ff275b..52a894c989087c70f215fc46d9f17489de546d8c 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1615,7 +1615,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
                                return 0;
                        goto next_line;
                }
-               if (hit) {
+               if (hit && (opt->max_count < 0 || count < opt->max_count)) {
                        count++;
                        if (opt->status_only)
                                return 1;
diff --git a/grep.h b/grep.h
index c722d25ed9d272fd333162a64ba367bc19ff77da..bdcadce61b8027adc760cd6e7fc51aa4e94c3d06 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -171,6 +171,7 @@ struct grep_opt {
        int show_hunk_mark;
        int file_break;
        int heading;
+       int max_count;
        void *priv;
 
        void (*output)(struct grep_opt *opt, const void *data, size_t size);
@@ -181,6 +182,7 @@ struct grep_opt {
        .relative = 1, \
        .pathname = 1, \
        .max_depth = -1, \
+       .max_count = -1, \
        .pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \
        .colors = { \
                [GREP_COLOR_CONTEXT] = "", \
diff --git a/hash.h b/hash.h
index 5d40368f18a4d38ef3a62ae3ff378b0167e35a74..36b64165fc96375457415a6348eeebd2944c41f9 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -4,9 +4,7 @@
 #include "git-compat-util.h"
 #include "repository.h"
 
-#if defined(SHA1_PPC)
-#include "ppc/sha1.h"
-#elif defined(SHA1_APPLE)
+#if defined(SHA1_APPLE)
 #include <CommonCrypto/CommonDigest.h>
 #elif defined(SHA1_OPENSSL)
 #include <openssl/sha.h>
@@ -16,7 +14,9 @@
 #include "block-sha1/sha1.h"
 #endif
 
-#if defined(SHA256_GCRYPT)
+#if defined(SHA256_NETTLE)
+#include "sha256/nettle.h"
+#elif defined(SHA256_GCRYPT)
 #define SHA256_NEEDS_CLONE_HELPER
 #include "sha256/gcrypt.h"
 #elif defined(SHA256_OPENSSL)
@@ -30,7 +30,7 @@
  * platform's underlying implementation of SHA-1; could be OpenSSL,
  * blk_SHA, Apple CommonCrypto, etc...  Note that the relevant
  * SHA-1 header may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1 and ppc-sha1, so we list
+ * own implementations like block-sha1, so we list
  * the default for OpenSSL compatible SHA-1 implementations here.
  */
 #define platform_SHA_CTX       SHA_CTX
index 134d2eec804c2eb4851689901f47c251f73b01de..cf5fea87eb02bf753d408f1eeb00f5de2a02e907 100644 (file)
--- a/hashmap.c
+++ b/hashmap.c
@@ -142,10 +142,10 @@ static inline struct hashmap_entry **find_entry_ptr(const struct hashmap *map,
        return e;
 }
 
-static int always_equal(const void *unused_cmp_data,
-                       const struct hashmap_entry *unused1,
-                       const struct hashmap_entry *unused2,
-                       const void *unused_keydata)
+static int always_equal(const void *cmp_data UNUSED,
+                       const struct hashmap_entry *entry1 UNUSED,
+                       const struct hashmap_entry *entry2 UNUSED,
+                       const void *keydata UNUSED)
 {
        return 0;
 }
@@ -313,7 +313,7 @@ struct pool_entry {
        unsigned char data[FLEX_ARRAY];
 };
 
-static int pool_entry_cmp(const void *unused_cmp_data,
+static int pool_entry_cmp(const void *cmp_data UNUSED,
                          const struct hashmap_entry *eptr,
                          const struct hashmap_entry *entry_or_key,
                          const void *keydata)
diff --git a/help.c b/help.c
index 41c41c2aa11757645be53662b6d42011d93b00e2..d04542d8261dd4e8eb2287edc3623492b34f3ce4 100644 (file)
--- a/help.c
+++ b/help.c
@@ -38,19 +38,30 @@ static struct category_description main_categories[] = {
        { CAT_plumbinginterrogators, N_("Low-level Commands / Interrogators") },
        { CAT_synchingrepositories, N_("Low-level Commands / Syncing Repositories") },
        { CAT_purehelpers, N_("Low-level Commands / Internal Helpers") },
+       { CAT_userinterfaces, N_("User-facing repository, command and file interfaces") },
+       { CAT_developerinterfaces, N_("Developer-facing file formats, protocols and other interfaces") },
        { 0, NULL }
 };
 
 static const char *drop_prefix(const char *name, uint32_t category)
 {
        const char *new_name;
-
-       if (skip_prefix(name, "git-", &new_name))
-               return new_name;
-       if (category == CAT_guide && skip_prefix(name, "git", &new_name))
+       const char *prefix;
+
+       switch (category) {
+       case CAT_guide:
+       case CAT_userinterfaces:
+       case CAT_developerinterfaces:
+               prefix = "git";
+               break;
+       default:
+               prefix = "git-";
+               break;
+       }
+       if (skip_prefix(name, prefix, &new_name))
                return new_name;
-       return name;
 
+       return name;
 }
 
 static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)
@@ -426,6 +437,26 @@ void list_guides_help(void)
        putchar('\n');
 }
 
+void list_user_interfaces_help(void)
+{
+       struct category_description catdesc[] = {
+               { CAT_userinterfaces, N_("User-facing repository, command and file interfaces:") },
+               { 0, NULL }
+       };
+       print_cmd_by_category(catdesc, NULL);
+       putchar('\n');
+}
+
+void list_developer_interfaces_help(void)
+{
+       struct category_description catdesc[] = {
+               { CAT_developerinterfaces, N_("File formats, protocols and other developer interfaces:") },
+               { 0, NULL }
+       };
+       print_cmd_by_category(catdesc, NULL);
+       putchar('\n');
+}
+
 static int get_alias(const char *var, const char *value, void *data)
 {
        struct string_list *list = data;
@@ -750,8 +781,9 @@ struct similar_ref_cb {
        struct string_list *similar_refs;
 };
 
-static int append_similar_ref(const char *refname, const struct object_id *oid,
-                             int flags, void *cb_data)
+static int append_similar_ref(const char *refname,
+                             const struct object_id *oid UNUSED,
+                             int flags UNUSED, void *cb_data)
 {
        struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
        char *branch = strrchr(refname, '/') + 1;
diff --git a/help.h b/help.h
index 971a3ad855acdc2d02697993ed8a7730626b8572..af073a7a0263e7bdacf6dd01f13235b2a655f360 100644 (file)
--- a/help.h
+++ b/help.h
@@ -22,6 +22,8 @@ static inline void mput_char(char c, unsigned int num)
 void list_common_cmds_help(void);
 void list_all_cmds_help(int show_external_commands, int show_aliases);
 void list_guides_help(void);
+void list_user_interfaces_help(void);
+void list_developer_interfaces_help(void);
 
 void list_all_main_cmds(struct string_list *list);
 void list_all_other_cmds(struct string_list *list);
index 58b83a9f66bc9ffbd44b71f2414e59c647187700..6eb3b2fe51c6fe839f2dec5dd584cf174d5b5f73 100644 (file)
@@ -505,7 +505,7 @@ static void run_service(const char **argv, int buffer_input)
 }
 
 static int show_text_ref(const char *name, const struct object_id *oid,
-                        int flag, void *cb_data)
+                        int flag UNUSED, void *cb_data)
 {
        const char *name_nons = strip_namespace(name);
        struct strbuf *buf = cb_data;
diff --git a/http.c b/http.c
index 168ca30c5588444ba01c8da16e3e17e7c8b5bf44..5d0502f51fd85d49ab2fa03995b8afcc585b12cc 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1775,7 +1775,7 @@ static void write_accept_language(struct strbuf *buf)
  *   LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1"
  *   LANGUAGE= LANG=C -> ""
  */
-static const char *get_accept_language(void)
+const char *http_get_accept_language_header(void)
 {
        if (!cached_accept_language) {
                struct strbuf buf = STRBUF_INIT;
@@ -1829,7 +1829,7 @@ static int http_request(const char *url,
                                         fwrite_buffer);
        }
 
-       accept_language = get_accept_language();
+       accept_language = http_get_accept_language_header();
 
        if (accept_language)
                headers = curl_slist_append(headers, accept_language);
diff --git a/http.h b/http.h
index ba303cfb372825fb0731faebee1ccc7cb9728b29..3c94c479100947041768b88d9e5ee10651e57520 100644 (file)
--- a/http.h
+++ b/http.h
@@ -178,6 +178,9 @@ int http_fetch_ref(const char *base, struct ref *ref);
 int http_get_info_packs(const char *base_url,
                        struct packed_git **packs_head);
 
+/* Helper for getting Accept-Language header */
+const char *http_get_accept_language_header(void);
+
 struct http_pack_request {
        char *url;
 
diff --git a/ident.c b/ident.c
index 89ca5b47008ee50749744914dd80a009d9adcaff..6de76f9421d57f38c478cca68fcb97c4ede2d36c 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -8,6 +8,7 @@
 #include "cache.h"
 #include "config.h"
 #include "date.h"
+#include "mailmap.h"
 
 static struct strbuf git_default_name = STRBUF_INIT;
 static struct strbuf git_default_email = STRBUF_INIT;
@@ -346,6 +347,79 @@ person_only:
        return 0;
 }
 
+/*
+ * Returns the difference between the new and old length of the ident line.
+ */
+static ssize_t rewrite_ident_line(const char *person, size_t len,
+                                  struct strbuf *buf,
+                                  struct string_list *mailmap)
+{
+       size_t namelen, maillen;
+       const char *name;
+       const char *mail;
+       struct ident_split ident;
+
+       if (split_ident_line(&ident, person, len))
+               return 0;
+
+       mail = ident.mail_begin;
+       maillen = ident.mail_end - ident.mail_begin;
+       name = ident.name_begin;
+       namelen = ident.name_end - ident.name_begin;
+
+       if (map_user(mailmap, &mail, &maillen, &name, &namelen)) {
+               struct strbuf namemail = STRBUF_INIT;
+               size_t newlen;
+
+               strbuf_addf(&namemail, "%.*s <%.*s>",
+                           (int)namelen, name, (int)maillen, mail);
+
+               strbuf_splice(buf, ident.name_begin - buf->buf,
+                             ident.mail_end - ident.name_begin + 1,
+                             namemail.buf, namemail.len);
+               newlen = namemail.len;
+
+               strbuf_release(&namemail);
+
+               return newlen - (ident.mail_end - ident.name_begin);
+       }
+
+       return 0;
+}
+
+void apply_mailmap_to_header(struct strbuf *buf, const char **header,
+                              struct string_list *mailmap)
+{
+       size_t buf_offset = 0;
+
+       if (!mailmap)
+               return;
+
+       for (;;) {
+               const char *person, *line;
+               size_t i;
+               int found_header = 0;
+
+               line = buf->buf + buf_offset;
+               if (!*line || *line == '\n')
+                       return; /* End of headers */
+
+               for (i = 0; header[i]; i++)
+                       if (skip_prefix(line, header[i], &person)) {
+                               const char *endp = strchrnul(person, '\n');
+                               found_header = 1;
+                               buf_offset += endp - line;
+                               buf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);
+                               break;
+                       }
+
+               if (!found_header) {
+                       buf_offset = strchrnul(line, '\n') - buf->buf;
+                       if (buf->buf[buf_offset] == '\n')
+                               buf_offset++;
+               }
+       }
+}
 
 static void ident_env_hint(enum want_ident whose_ident)
 {
@@ -594,7 +668,7 @@ static int set_ident(const char *var, const char *value)
        return 0;
 }
 
-int git_ident_config(const char *var, const char *value, void *data)
+int git_ident_config(const char *var, const char *value, void *data UNUSED)
 {
        if (!strcmp(var, "user.useconfigonly")) {
                ident_use_config_only = git_config_bool(var, value);
index 4b25287886dfe7368582dd615d424e66e6f320f9..533966023804776ec19ca06c7e84b4b264c07314 100644 (file)
@@ -108,7 +108,7 @@ int gently_parse_list_objects_filter(
 
        strbuf_addf(errbuf, _("invalid filter-spec '%s'"), arg);
 
-       memset(filter_options, 0, sizeof(*filter_options));
+       list_objects_filter_init(filter_options);
        return 1;
 }
 
@@ -143,6 +143,7 @@ static int parse_combine_subfilter(
 
        ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
                      filter_options->sub_alloc);
+       list_objects_filter_init(&filter_options->sub[new_index]);
 
        decoded = url_percent_decode(subspec->buf);
 
@@ -187,10 +188,8 @@ static int parse_combine_filter(
 
 cleanup:
        strbuf_list_free(subspecs);
-       if (result) {
+       if (result)
                list_objects_filter_release(filter_options);
-               memset(filter_options, 0, sizeof(*filter_options));
-       }
        return result;
 }
 
@@ -204,10 +203,10 @@ static int allow_unencoded(char ch)
 static void filter_spec_append_urlencode(
        struct list_objects_filter_options *filter, const char *raw)
 {
-       struct strbuf buf = STRBUF_INIT;
-       strbuf_addstr_urlencode(&buf, raw, allow_unencoded);
-       trace_printf("Add to combine filter-spec: %s\n", buf.buf);
-       string_list_append(&filter->filter_spec, strbuf_detach(&buf, NULL));
+       size_t orig_len = filter->filter_spec.len;
+       strbuf_addstr_urlencode(&filter->filter_spec, raw, allow_unencoded);
+       trace_printf("Add to combine filter-spec: %s\n",
+                    filter->filter_spec.buf + orig_len);
 }
 
 /*
@@ -225,13 +224,13 @@ static void transform_to_combine_type(
                struct list_objects_filter_options *sub_array =
                        xcalloc(initial_sub_alloc, sizeof(*sub_array));
                sub_array[0] = *filter_options;
-               memset(filter_options, 0, sizeof(*filter_options));
+               list_objects_filter_init(filter_options);
                filter_options->sub = sub_array;
                filter_options->sub_alloc = initial_sub_alloc;
        }
        filter_options->sub_nr = 1;
        filter_options->choice = LOFC_COMBINE;
-       string_list_append(&filter_options->filter_spec, xstrdup("combine:"));
+       strbuf_addstr(&filter_options->filter_spec, "combine:");
        filter_spec_append_urlencode(
                filter_options,
                list_objects_filter_spec(&filter_options->sub[0]));
@@ -239,7 +238,7 @@ static void transform_to_combine_type(
         * We don't need the filter_spec strings for subfilter specs, only the
         * top level.
         */
-       string_list_clear(&filter_options->sub[0].filter_spec, /*free_util=*/0);
+       strbuf_release(&filter_options->sub[0].filter_spec);
 }
 
 void list_objects_filter_die_if_populated(
@@ -256,26 +255,32 @@ void parse_list_objects_filter(
        struct strbuf errbuf = STRBUF_INIT;
        int parse_error;
 
+       if (!filter_options->filter_spec.buf)
+               BUG("filter_options not properly initialized");
+
        if (!filter_options->choice) {
-               string_list_append(&filter_options->filter_spec, xstrdup(arg));
+               strbuf_addstr(&filter_options->filter_spec, arg);
 
                parse_error = gently_parse_list_objects_filter(
                        filter_options, arg, &errbuf);
        } else {
+               struct list_objects_filter_options *sub;
+
                /*
                 * Make filter_options an LOFC_COMBINE spec so we can trivially
                 * add subspecs to it.
                 */
                transform_to_combine_type(filter_options);
 
-               string_list_append(&filter_options->filter_spec, xstrdup("+"));
+               strbuf_addch(&filter_options->filter_spec, '+');
                filter_spec_append_urlencode(filter_options, arg);
                ALLOC_GROW_BY(filter_options->sub, filter_options->sub_nr, 1,
                              filter_options->sub_alloc);
+               sub = &filter_options->sub[filter_options->sub_nr - 1];
 
-               parse_error = gently_parse_list_objects_filter(
-                       &filter_options->sub[filter_options->sub_nr - 1], arg,
-                       &errbuf);
+               list_objects_filter_init(sub);
+               parse_error = gently_parse_list_objects_filter(sub, arg,
+                                                              &errbuf);
        }
        if (parse_error)
                die("%s", errbuf.buf);
@@ -299,31 +304,18 @@ int opt_parse_list_objects_filter(const struct option *opt,
 
 const char *list_objects_filter_spec(struct list_objects_filter_options *filter)
 {
-       if (!filter->filter_spec.nr)
+       if (!filter->filter_spec.len)
                BUG("no filter_spec available for this filter");
-       if (filter->filter_spec.nr != 1) {
-               struct strbuf concatted = STRBUF_INIT;
-               strbuf_add_separated_string_list(
-                       &concatted, "", &filter->filter_spec);
-               string_list_clear(&filter->filter_spec, /*free_util=*/0);
-               string_list_append(
-                       &filter->filter_spec, strbuf_detach(&concatted, NULL));
-       }
-
-       return filter->filter_spec.items[0].string;
+       return filter->filter_spec.buf;
 }
 
 const char *expand_list_objects_filter_spec(
        struct list_objects_filter_options *filter)
 {
        if (filter->choice == LOFC_BLOB_LIMIT) {
-               struct strbuf expanded_spec = STRBUF_INIT;
-               strbuf_addf(&expanded_spec, "blob:limit=%lu",
+               strbuf_release(&filter->filter_spec);
+               strbuf_addf(&filter->filter_spec, "blob:limit=%lu",
                            filter->blob_limit_value);
-               string_list_clear(&filter->filter_spec, /*free_util=*/0);
-               string_list_append(
-                       &filter->filter_spec,
-                       strbuf_detach(&expanded_spec, NULL));
        }
 
        return list_objects_filter_spec(filter);
@@ -336,12 +328,12 @@ void list_objects_filter_release(
 
        if (!filter_options)
                return;
-       string_list_clear(&filter_options->filter_spec, /*free_util=*/0);
+       strbuf_release(&filter_options->filter_spec);
        free(filter_options->sparse_oid_name);
        for (sub = 0; sub < filter_options->sub_nr; sub++)
                list_objects_filter_release(&filter_options->sub[sub]);
        free(filter_options->sub);
-       memset(filter_options, 0, sizeof(*filter_options));
+       list_objects_filter_init(filter_options);
 }
 
 void partial_clone_register(
@@ -394,11 +386,11 @@ void partial_clone_get_default_filter_spec(
        /*
         * Parse default value, but silently ignore it if it is invalid.
         */
-       if (!promisor)
+       if (!promisor || !promisor->partial_clone_filter)
                return;
 
-       string_list_append(&filter_options->filter_spec,
-                          promisor->partial_clone_filter);
+       strbuf_addstr(&filter_options->filter_spec,
+                     promisor->partial_clone_filter);
        gently_parse_list_objects_filter(filter_options,
                                         promisor->partial_clone_filter,
                                         &errbuf);
@@ -410,16 +402,21 @@ void list_objects_filter_copy(
        const struct list_objects_filter_options *src)
 {
        int i;
-       struct string_list_item *item;
 
        /* Copy everything. We will overwrite the pointers shortly. */
        memcpy(dest, src, sizeof(struct list_objects_filter_options));
 
-       string_list_init_dup(&dest->filter_spec);
-       for_each_string_list_item(item, &src->filter_spec)
-               string_list_append(&dest->filter_spec, item->string);
+       strbuf_init(&dest->filter_spec, 0);
+       strbuf_addbuf(&dest->filter_spec, &src->filter_spec);
+       dest->sparse_oid_name = xstrdup_or_null(src->sparse_oid_name);
 
        ALLOC_ARRAY(dest->sub, dest->sub_alloc);
        for (i = 0; i < src->sub_nr; i++)
                list_objects_filter_copy(&dest->sub[i], &src->sub[i]);
 }
+
+void list_objects_filter_init(struct list_objects_filter_options *filter_options)
+{
+       struct list_objects_filter_options blank = LIST_OBJECTS_FILTER_INIT;
+       memcpy(filter_options, &blank, sizeof(*filter_options));
+}
index ffc02d77e760009d3e4eec78d5d9abff3fe1e634..7eeadab2dd0551c5eea8f7f14cd741841317230e 100644 (file)
@@ -35,7 +35,7 @@ struct list_objects_filter_options {
         * To get the raw filter spec given by the user, use the result of
         * list_objects_filter_spec().
         */
-       struct string_list filter_spec;
+       struct strbuf filter_spec;
 
        /*
         * 'choice' is determined by parsing the filter-spec.  This indicates
@@ -69,6 +69,9 @@ struct list_objects_filter_options {
         */
 };
 
+#define LIST_OBJECTS_FILTER_INIT { .filter_spec = STRBUF_INIT }
+void list_objects_filter_init(struct list_objects_filter_options *filter_options);
+
 /*
  * Parse value of the argument to the "filter" keyword.
  * On the command line this looks like:
index 14b83620191019e465291d13be023df794ffb645..8955d7e1f6eec73ef797781c2bd0d76d43d1ef19 100644 (file)
@@ -249,7 +249,8 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
 static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
 static const char *default_ll_merge;
 
-static int read_merge_config(const char *var, const char *value, void *cb)
+static int read_merge_config(const char *var, const char *value,
+                            void *cb UNUSED)
 {
        struct ll_merge_driver *fn;
        const char *key, *name;
index d0ac0a6327a18f5eeee6fc43f036c9a2618fd672..1dd5fcbf7be433740d83382db4c401d438a51720 100644 (file)
@@ -135,12 +135,15 @@ static int ref_filter_match(const char *refname,
 }
 
 static int add_ref_decoration(const char *refname, const struct object_id *oid,
-                             int flags, void *cb_data)
+                             int flags UNUSED,
+                             void *cb_data)
 {
+       int i;
        struct object *obj;
        enum object_type objtype;
        enum decoration_type deco_type = DECORATION_NONE;
        struct decoration_filter *filter = (struct decoration_filter *)cb_data;
+       const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
 
        if (filter && !ref_filter_match(refname, filter))
                return 0;
@@ -165,16 +168,21 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
                return 0;
        obj = lookup_object_by_type(the_repository, oid, objtype);
 
-       if (starts_with(refname, "refs/heads/"))
-               deco_type = DECORATION_REF_LOCAL;
-       else if (starts_with(refname, "refs/remotes/"))
-               deco_type = DECORATION_REF_REMOTE;
-       else if (starts_with(refname, "refs/tags/"))
-               deco_type = DECORATION_REF_TAG;
-       else if (!strcmp(refname, "refs/stash"))
-               deco_type = DECORATION_REF_STASH;
-       else if (!strcmp(refname, "HEAD"))
-               deco_type = DECORATION_REF_HEAD;
+       for (i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
+               struct ref_namespace_info *info = &ref_namespace[i];
+
+               if (!info->decoration)
+                       continue;
+               if (info->exact) {
+                       if (!strcmp(refname, info->ref)) {
+                               deco_type = info->decoration;
+                               break;
+                       }
+               } else if (starts_with(refname, info->ref)) {
+                       deco_type = info->decoration;
+                       break;
+               }
+       }
 
        add_name_decoration(deco_type, refname, obj);
        while (obj->type == OBJ_TAG) {
@@ -956,8 +964,7 @@ static void cleanup_additional_headers(struct diff_options *o)
 
 static int do_remerge_diff(struct rev_info *opt,
                           struct commit_list *parents,
-                          struct object_id *oid,
-                          struct commit *commit)
+                          struct object_id *oid)
 {
        struct merge_options o;
        struct commit_list *bases;
@@ -1052,7 +1059,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
                                        "for octopus merges.\n");
                                return 1;
                        }
-                       return do_remerge_diff(opt, parents, oid, commit);
+                       return do_remerge_diff(opt, parents, oid);
                }
                if (opt->combine_merges)
                        return do_diff_combined(opt, commit);
index 98e69373c8404ead982595fc9dbda5c4fe8137a1..fa0d01b47c1286767068df928e83dd74c5f7b49e 100644 (file)
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -136,7 +136,8 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
        strbuf_release(&namespaced);
 }
 
-static int ls_refs_config(const char *var, const char *value, void *data)
+static int ls_refs_config(const char *var, const char *value,
+                         void *data UNUSED)
 {
        /*
         * We only serve fetches over v2 for now, so respect only "uploadpack"
index ad041061695223566ebfb2b9dacfc5aa7d215733..748924a69ba3262088c444c0145bc407750daa0a 100644 (file)
@@ -10,8 +10,8 @@ static int unclean(struct merge_options *opt, struct tree *head)
        struct strbuf sb = STRBUF_INIT;
 
        if (head && repo_index_has_changes(opt->repo, head, &sb)) {
-               fprintf(stderr, _("Your local changes to the following files would be overwritten by merge:\n  %s"),
-                   sb.buf);
+               error(_("Your local changes to the following files would be overwritten by merge:\n  %s"),
+                     sb.buf);
                strbuf_release(&sb);
                return -1;
        }
index ebb9a75425137eaf38bb5647802744e32cadbf16..99dcee2db8afa4c06f88739601e98bc3cf3dd64c 100644 (file)
@@ -349,13 +349,15 @@ struct merge_options_internal {
        struct mem_pool pool;
 
        /*
-        * output: special messages and conflict notices for various paths
+        * conflicts: logical conflicts and messages stored by _primary_ path
         *
         * This is a map of pathnames (a subset of the keys in "paths" above)
-        * to strbufs.  It gathers various warning/conflict/notice messages
-        * for later processing.
+        * to struct string_list, with each item's `util` containing a
+        * `struct logical_conflict_info`. Note, though, that for each path,
+        * it only stores the logical conflicts for which that path is the
+        * primary path; the path might be part of additional conflicts.
         */
-       struct strmap output;
+       struct strmap conflicts;
 
        /*
         * renames: various data relating to rename detection
@@ -385,8 +387,24 @@ struct merge_options_internal {
 
        /* call_depth: recursion level counter for merging merge bases */
        int call_depth;
+
+       /* field that holds submodule conflict information */
+       struct string_list conflicted_submodules;
+};
+
+struct conflicted_submodule_item {
+       char *abbrev;
+       int flag;
 };
 
+static void conflicted_submodule_item_free(void *util, const char *str)
+{
+       struct conflicted_submodule_item *item = util;
+
+       free(item->abbrev);
+       free(item);
+}
+
 struct version_info {
        struct object_id oid;
        unsigned short mode;
@@ -481,6 +499,100 @@ struct conflict_info {
        unsigned match_mask:3;
 };
 
+enum conflict_and_info_types {
+       /* "Simple" conflicts and informational messages */
+       INFO_AUTO_MERGING = 0,
+       CONFLICT_CONTENTS,       /* text file that failed to merge */
+       CONFLICT_BINARY,
+       CONFLICT_FILE_DIRECTORY,
+       CONFLICT_DISTINCT_MODES,
+       CONFLICT_MODIFY_DELETE,
+
+       /* Regular rename */
+       CONFLICT_RENAME_RENAME,   /* same file renamed differently */
+       CONFLICT_RENAME_COLLIDES, /* rename/add or two files renamed to 1 */
+       CONFLICT_RENAME_DELETE,
+
+       /* Basic directory rename */
+       CONFLICT_DIR_RENAME_SUGGESTED,
+       INFO_DIR_RENAME_APPLIED,
+
+       /* Special directory rename cases */
+       INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME,
+       CONFLICT_DIR_RENAME_FILE_IN_WAY,
+       CONFLICT_DIR_RENAME_COLLISION,
+       CONFLICT_DIR_RENAME_SPLIT,
+
+       /* Basic submodule */
+       INFO_SUBMODULE_FAST_FORWARDING,
+       CONFLICT_SUBMODULE_FAILED_TO_MERGE,
+
+       /* Special submodule cases broken out from FAILED_TO_MERGE */
+       CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION,
+       CONFLICT_SUBMODULE_NOT_INITIALIZED,
+       CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE,
+       CONFLICT_SUBMODULE_MAY_HAVE_REWINDS,
+       CONFLICT_SUBMODULE_NULL_MERGE_BASE,
+
+       /* Keep this entry _last_ in the list */
+       NB_CONFLICT_TYPES,
+};
+
+/*
+ * Short description of conflict type, relied upon by external tools.
+ *
+ * We can add more entries, but DO NOT change any of these strings.  Also,
+ * Order MUST match conflict_info_and_types.
+ */
+static const char *type_short_descriptions[] = {
+       /*** "Simple" conflicts and informational messages ***/
+       [INFO_AUTO_MERGING] = "Auto-merging",
+       [CONFLICT_CONTENTS] = "CONFLICT (contents)",
+       [CONFLICT_BINARY] = "CONFLICT (binary)",
+       [CONFLICT_FILE_DIRECTORY] = "CONFLICT (file/directory)",
+       [CONFLICT_DISTINCT_MODES] = "CONFLICT (distinct modes)",
+       [CONFLICT_MODIFY_DELETE] = "CONFLICT (modify/delete)",
+
+       /*** Regular rename ***/
+       [CONFLICT_RENAME_RENAME] = "CONFLICT (rename/rename)",
+       [CONFLICT_RENAME_COLLIDES] = "CONFLICT (rename involved in collision)",
+       [CONFLICT_RENAME_DELETE] = "CONFLICT (rename/delete)",
+
+       /*** Basic directory rename ***/
+       [CONFLICT_DIR_RENAME_SUGGESTED] =
+               "CONFLICT (directory rename suggested)",
+       [INFO_DIR_RENAME_APPLIED] = "Path updated due to directory rename",
+
+       /*** Special directory rename cases ***/
+       [INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME] =
+               "Directory rename skipped since directory was renamed on both sides",
+       [CONFLICT_DIR_RENAME_FILE_IN_WAY] =
+               "CONFLICT (file in way of directory rename)",
+       [CONFLICT_DIR_RENAME_COLLISION] = "CONFLICT(directory rename collision)",
+       [CONFLICT_DIR_RENAME_SPLIT] = "CONFLICT(directory rename unclear split)",
+
+       /*** Basic submodule ***/
+       [INFO_SUBMODULE_FAST_FORWARDING] = "Fast forwarding submodule",
+       [CONFLICT_SUBMODULE_FAILED_TO_MERGE] = "CONFLICT (submodule)",
+
+       /*** Special submodule cases broken out from FAILED_TO_MERGE ***/
+       [CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION] =
+               "CONFLICT (submodule with possible resolution)",
+       [CONFLICT_SUBMODULE_NOT_INITIALIZED] =
+               "CONFLICT (submodule not initialized)",
+       [CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE] =
+               "CONFLICT (submodule history not available)",
+       [CONFLICT_SUBMODULE_MAY_HAVE_REWINDS] =
+               "CONFLICT (submodule may have rewinds)",
+       [CONFLICT_SUBMODULE_NULL_MERGE_BASE] =
+               "CONFLICT (submodule lacks merge base)"
+};
+
+struct logical_conflict_info {
+       enum conflict_and_info_types type;
+       struct strvec paths;
+};
+
 /*** Function Grouping: various utility functions ***/
 
 /*
@@ -567,24 +679,32 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
                struct strmap_entry *e;
 
                /* Release and free each strbuf found in output */
-               strmap_for_each_entry(&opti->output, &iter, e) {
-                       struct strbuf *sb = e->value;
-                       strbuf_release(sb);
+               strmap_for_each_entry(&opti->conflicts, &iter, e) {
+                       struct string_list *list = e->value;
+                       for (int i = 0; i < list->nr; i++) {
+                               struct logical_conflict_info *info =
+                                       list->items[i].util;
+                               strvec_clear(&info->paths);
+                       }
                        /*
-                        * While strictly speaking we don't need to free(sb)
-                        * here because we could pass free_values=1 when
-                        * calling strmap_clear() on opti->output, that would
-                        * require strmap_clear to do another
-                        * strmap_for_each_entry() loop, so we just free it
-                        * while we're iterating anyway.
+                        * While strictly speaking we don't need to
+                        * free(conflicts) here because we could pass
+                        * free_values=1 when calling strmap_clear() on
+                        * opti->conflicts, that would require strmap_clear
+                        * to do another strmap_for_each_entry() loop, so we
+                        * just free it while we're iterating anyway.
                         */
-                       free(sb);
+                       string_list_clear(list, 1);
+                       free(list);
                }
-               strmap_clear(&opti->output, 0);
+               strmap_clear(&opti->conflicts, 0);
        }
 
        mem_pool_discard(&opti->pool, 0);
 
+       string_list_clear_func(&opti->conflicted_submodules,
+                                       conflicted_submodule_item_free);
+
        /* Clean out callback_data as well. */
        FREE_AND_NULL(renames->callback_data);
        renames->callback_data_nr = renames->callback_data_alloc = 0;
@@ -627,29 +747,57 @@ static void format_commit(struct strbuf *sb,
        strbuf_addch(sb, '\n');
 }
 
-__attribute__((format (printf, 4, 5)))
+__attribute__((format (printf, 8, 9)))
 static void path_msg(struct merge_options *opt,
-                    const char *path,
+                    enum conflict_and_info_types type,
                     int omittable_hint, /* skippable under --remerge-diff */
+                    const char *primary_path,
+                    const char *other_path_1, /* may be NULL */
+                    const char *other_path_2, /* may be NULL */
+                    struct string_list *other_paths, /* may be NULL */
                     const char *fmt, ...)
 {
        va_list ap;
-       struct strbuf *sb, *dest;
+       struct string_list *path_conflicts;
+       struct logical_conflict_info *info;
+       struct strbuf buf = STRBUF_INIT;
+       struct strbuf *dest;
        struct strbuf tmp = STRBUF_INIT;
 
+       /* Sanity checks */
+       assert(omittable_hint ==
+              !starts_with(type_short_descriptions[type], "CONFLICT") ||
+              type == CONFLICT_DIR_RENAME_SUGGESTED);
        if (opt->record_conflict_msgs_as_headers && omittable_hint)
                return; /* Do not record mere hints in headers */
        if (opt->priv->call_depth && opt->verbosity < 5)
                return; /* Ignore messages from inner merges */
 
-       sb = strmap_get(&opt->priv->output, path);
-       if (!sb) {
-               sb = xmalloc(sizeof(*sb));
-               strbuf_init(sb, 0);
-               strmap_put(&opt->priv->output, path, sb);
+       /* Ensure path_conflicts (ptr to array of logical_conflict) allocated */
+       path_conflicts = strmap_get(&opt->priv->conflicts, primary_path);
+       if (!path_conflicts) {
+               path_conflicts = xmalloc(sizeof(*path_conflicts));
+               string_list_init_dup(path_conflicts);
+               strmap_put(&opt->priv->conflicts, primary_path, path_conflicts);
        }
 
-       dest = (opt->record_conflict_msgs_as_headers ? &tmp : sb);
+       /* Add a logical_conflict at the end to store info from this call */
+       info = xcalloc(1, sizeof(*info));
+       info->type = type;
+       strvec_init(&info->paths);
+
+       /* Handle the list of paths */
+       strvec_push(&info->paths, primary_path);
+       if (other_path_1)
+               strvec_push(&info->paths, other_path_1);
+       if (other_path_2)
+               strvec_push(&info->paths, other_path_2);
+       if (other_paths)
+               for (int i = 0; i < other_paths->nr; i++)
+               strvec_push(&info->paths, other_paths->items[i].string);
+
+       /* Handle message and its format, in normal case */
+       dest = (opt->record_conflict_msgs_as_headers ? &tmp : &buf);
 
        va_start(ap, fmt);
        if (opt->priv->call_depth) {
@@ -660,32 +808,32 @@ static void path_msg(struct merge_options *opt,
        strbuf_vaddf(dest, fmt, ap);
        va_end(ap);
 
+       /* Handle specialized formatting of message under --remerge-diff */
        if (opt->record_conflict_msgs_as_headers) {
                int i_sb = 0, i_tmp = 0;
 
                /* Start with the specified prefix */
                if (opt->msg_header_prefix)
-                       strbuf_addf(sb, "%s ", opt->msg_header_prefix);
+                       strbuf_addf(&buf, "%s ", opt->msg_header_prefix);
 
                /* Copy tmp to sb, adding spaces after newlines */
-               strbuf_grow(sb, sb->len + 2*tmp.len); /* more than sufficient */
+               strbuf_grow(&buf, buf.len + 2*tmp.len); /* more than sufficient */
                for (; i_tmp < tmp.len; i_tmp++, i_sb++) {
                        /* Copy next character from tmp to sb */
-                       sb->buf[sb->len + i_sb] = tmp.buf[i_tmp];
+                       buf.buf[buf.len + i_sb] = tmp.buf[i_tmp];
 
                        /* If we copied a newline, add a space */
                        if (tmp.buf[i_tmp] == '\n')
-                               sb->buf[++i_sb] = ' ';
+                               buf.buf[++i_sb] = ' ';
                }
                /* Update length and ensure it's NUL-terminated */
-               sb->len += i_sb;
-               sb->buf[sb->len] = '\0';
+               buf.len += i_sb;
+               buf.buf[buf.len] = '\0';
 
                strbuf_release(&tmp);
        }
-
-       /* Add final newline character to sb */
-       strbuf_addch(sb, '\n');
+       string_list_append_nodup(path_conflicts, strbuf_detach(&buf, NULL))
+               ->util = info;
 }
 
 static struct diff_filespec *pool_alloc_filespec(struct mem_pool *pool,
@@ -1614,38 +1762,50 @@ static int merge_submodule(struct merge_options *opt,
 
        int i;
        int search = !opt->priv->call_depth;
+       int sub_not_initialized = 1;
+       int sub_flag = CONFLICT_SUBMODULE_FAILED_TO_MERGE;
 
        /* store fallback answer in result in case we fail */
        oidcpy(result, opt->priv->call_depth ? o : a);
 
        /* we can not handle deletion conflicts */
-       if (is_null_oid(o))
-               return 0;
-       if (is_null_oid(a))
-               return 0;
-       if (is_null_oid(b))
-               return 0;
+       if (is_null_oid(a) || is_null_oid(b))
+               BUG("submodule deleted on one side; this should be handled outside of merge_submodule()");
+
+       if ((sub_not_initialized = repo_submodule_init(&subrepo,
+               opt->repo, path, null_oid()))) {
+               path_msg(opt, CONFLICT_SUBMODULE_NOT_INITIALIZED, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s (not checked out)"),
+                        path);
+               sub_flag = CONFLICT_SUBMODULE_NOT_INITIALIZED;
+               goto cleanup;
+       }
 
-       if (repo_submodule_init(&subrepo, opt->repo, path, null_oid())) {
-               path_msg(opt, path, 0,
-                               _("Failed to merge submodule %s (not checked out)"),
-                               path);
-               return 0;
+       if (is_null_oid(o)) {
+               path_msg(opt, CONFLICT_SUBMODULE_NULL_MERGE_BASE, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s (no merge base)"),
+                        path);
+               goto cleanup;
        }
 
        if (!(commit_o = lookup_commit_reference(&subrepo, o)) ||
            !(commit_a = lookup_commit_reference(&subrepo, a)) ||
            !(commit_b = lookup_commit_reference(&subrepo, b))) {
-               path_msg(opt, path, 0,
+               path_msg(opt, CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE, 0,
+                        path, NULL, NULL, NULL,
                         _("Failed to merge submodule %s (commits not present)"),
                         path);
+               sub_flag = CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE;
                goto cleanup;
        }
 
        /* check whether both changes are forward */
        if (!repo_in_merge_bases(&subrepo, commit_o, commit_a) ||
            !repo_in_merge_bases(&subrepo, commit_o, commit_b)) {
-               path_msg(opt, path, 0,
+               path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0,
+                        path, NULL, NULL, NULL,
                         _("Failed to merge submodule %s "
                           "(commits don't follow merge-base)"),
                         path);
@@ -1655,7 +1815,8 @@ static int merge_submodule(struct merge_options *opt,
        /* Case #1: a is contained in b or vice versa */
        if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
                oidcpy(result, b);
-               path_msg(opt, path, 1,
+               path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
+                        path, NULL, NULL, NULL,
                         _("Note: Fast-forwarding submodule %s to %s"),
                         path, oid_to_hex(b));
                ret = 1;
@@ -1663,7 +1824,8 @@ static int merge_submodule(struct merge_options *opt,
        }
        if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
                oidcpy(result, a);
-               path_msg(opt, path, 1,
+               path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
+                        path, NULL, NULL, NULL,
                         _("Note: Fast-forwarding submodule %s to %s"),
                         path, oid_to_hex(a));
                ret = 1;
@@ -1686,30 +1848,27 @@ static int merge_submodule(struct merge_options *opt,
                                         &merges);
        switch (parent_count) {
        case 0:
-               path_msg(opt, path, 0, _("Failed to merge submodule %s"), path);
+               path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
+                        path, NULL, NULL, NULL,
+                        _("Failed to merge submodule %s"), path);
                break;
 
        case 1:
                format_commit(&sb, 4, &subrepo,
                              (struct commit *)merges.objects[0].item);
-               path_msg(opt, path, 0,
+               path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, 0,
+                        path, NULL, NULL, NULL,
                         _("Failed to merge submodule %s, but a possible merge "
-                          "resolution exists:\n%s\n"),
+                          "resolution exists: %s"),
                         path, sb.buf);
-               path_msg(opt, path, 1,
-                        _("If this is correct simply add it to the index "
-                          "for example\n"
-                          "by using:\n\n"
-                          "  git update-index --cacheinfo 160000 %s \"%s\"\n\n"
-                          "which will accept this suggestion.\n"),
-                        oid_to_hex(&merges.objects[0].item->oid), path);
                strbuf_release(&sb);
                break;
        default:
                for (i = 0; i < merges.nr; i++)
                        format_commit(&sb, 4, &subrepo,
                                      (struct commit *)merges.objects[i].item);
-               path_msg(opt, path, 0,
+               path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, 0,
+                        path, NULL, NULL, NULL,
                         _("Failed to merge submodule %s, but multiple "
                           "possible merges exist:\n%s"), path, sb.buf);
                strbuf_release(&sb);
@@ -1717,7 +1876,23 @@ static int merge_submodule(struct merge_options *opt,
 
        object_array_clear(&merges);
 cleanup:
-       repo_clear(&subrepo);
+       if (!opt->priv->call_depth && !ret) {
+               struct string_list *csub = &opt->priv->conflicted_submodules;
+               struct conflicted_submodule_item *util;
+               const char *abbrev;
+
+               util = xmalloc(sizeof(*util));
+               util->flag = sub_flag;
+               util->abbrev = NULL;
+               if (!sub_not_initialized) {
+                       abbrev = repo_find_unique_abbrev(&subrepo, b, DEFAULT_ABBREV);
+                       util->abbrev = xstrdup(abbrev);
+               }
+               string_list_append(csub, path)->util = util;
+       }
+
+       if (!sub_not_initialized)
+               repo_clear(&subrepo);
        return ret;
 }
 
@@ -1835,7 +2010,8 @@ static int merge_3way(struct merge_options *opt,
                                &src1, name1, &src2, name2,
                                &opt->priv->attr_index, &ll_opts);
        if (merge_status == LL_MERGE_BINARY_CONFLICT)
-               path_msg(opt, path, 0,
+               path_msg(opt, CONFLICT_BINARY, 0,
+                        path, NULL, NULL, NULL,
                         "warning: Cannot merge binary files: %s (%s vs. %s)",
                         path, name1, name2);
 
@@ -1947,7 +2123,8 @@ static int handle_content_merge(struct merge_options *opt,
                if (ret)
                        return -1;
                clean &= (merge_status == 0);
-               path_msg(opt, path, 1, _("Auto-merging %s"), path);
+               path_msg(opt, INFO_AUTO_MERGING, 1, path, NULL, NULL, NULL,
+                        _("Auto-merging %s"), path);
        } else if (S_ISGITLINK(a->mode)) {
                int two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));
                clean = merge_submodule(opt, pathnames[0],
@@ -2085,21 +2262,24 @@ static char *handle_path_level_conflicts(struct merge_options *opt,
                c_info->reported_already = 1;
                strbuf_add_separated_string_list(&collision_paths, ", ",
                                                 &c_info->source_files);
-               path_msg(opt, new_path, 0,
-                        _("CONFLICT (implicit dir rename): Existing file/dir "
-                          "at %s in the way of implicit directory rename(s) "
-                          "putting the following path(s) there: %s."),
-                      new_path, collision_paths.buf);
+               path_msg(opt, CONFLICT_DIR_RENAME_FILE_IN_WAY, 0,
+                        new_path, NULL, NULL, &c_info->source_files,
+                        _("CONFLICT (implicit dir rename): Existing "
+                          "file/dir at %s in the way of implicit "
+                          "directory rename(s) putting the following "
+                          "path(s) there: %s."),
+                        new_path, collision_paths.buf);
                clean = 0;
        } else if (c_info->source_files.nr > 1) {
                c_info->reported_already = 1;
                strbuf_add_separated_string_list(&collision_paths, ", ",
                                                 &c_info->source_files);
-               path_msg(opt, new_path, 0,
-                        _("CONFLICT (implicit dir rename): Cannot map more "
-                          "than one path to %s; implicit directory renames "
-                          "tried to put these paths there: %s"),
-                      new_path, collision_paths.buf);
+               path_msg(opt, CONFLICT_DIR_RENAME_COLLISION, 0,
+                        new_path, NULL, NULL, &c_info->source_files,
+                        _("CONFLICT (implicit dir rename): Cannot map "
+                          "more than one path to %s; implicit directory "
+                          "renames tried to put these paths there: %s"),
+                        new_path, collision_paths.buf);
                clean = 0;
        }
 
@@ -2153,13 +2333,14 @@ static void get_provisional_directory_renames(struct merge_options *opt,
                        continue;
 
                if (bad_max == max) {
-                       path_msg(opt, source_dir, 0,
-                              _("CONFLICT (directory rename split): "
-                                "Unclear where to rename %s to; it was "
-                                "renamed to multiple other directories, with "
-                                "no destination getting a majority of the "
-                                "files."),
-                              source_dir);
+                       path_msg(opt, CONFLICT_DIR_RENAME_SPLIT, 0,
+                                source_dir, NULL, NULL, NULL,
+                                _("CONFLICT (directory rename split): "
+                                  "Unclear where to rename %s to; it was "
+                                  "renamed to multiple other directories, "
+                                  "with no destination getting a majority of "
+                                  "the files."),
+                                source_dir);
                        *clean = 0;
                } else {
                        strmap_put(&renames->dir_renames[side],
@@ -2334,7 +2515,8 @@ static char *check_for_directory_rename(struct merge_options *opt,
        new_dir = rename_info->value; /* old_dir = rename_info->key; */
        otherinfo = strmap_get_entry(dir_rename_exclusions, new_dir);
        if (otherinfo) {
-               path_msg(opt, rename_info->key, 1,
+               path_msg(opt, INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME, 1,
+                        rename_info->key, path, new_dir, NULL,
                         _("WARNING: Avoiding applying %s -> %s rename "
                           "to %s, because %s itself was renamed."),
                         rename_info->key, new_dir, path, new_dir);
@@ -2475,14 +2657,16 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
        if (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE) {
                /* Notify user of updated path */
                if (pair->status == 'A')
-                       path_msg(opt, new_path, 1,
+                       path_msg(opt, INFO_DIR_RENAME_APPLIED, 1,
+                                new_path, old_path, NULL, NULL,
                                 _("Path updated: %s added in %s inside a "
                                   "directory that was renamed in %s; moving "
                                   "it to %s."),
                                 old_path, branch_with_new_path,
                                 branch_with_dir_rename, new_path);
                else
-                       path_msg(opt, new_path, 1,
+                       path_msg(opt, INFO_DIR_RENAME_APPLIED, 1,
+                                new_path, old_path, NULL, NULL,
                                 _("Path updated: %s renamed to %s in %s, "
                                   "inside a directory that was renamed in %s; "
                                   "moving it to %s."),
@@ -2495,7 +2679,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
                 */
                ci->path_conflict = 1;
                if (pair->status == 'A')
-                       path_msg(opt, new_path, 1,
+                       path_msg(opt, CONFLICT_DIR_RENAME_SUGGESTED, 1,
+                                new_path, old_path, NULL, NULL,
                                 _("CONFLICT (file location): %s added in %s "
                                   "inside a directory that was renamed in %s, "
                                   "suggesting it should perhaps be moved to "
@@ -2503,7 +2688,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
                                 old_path, branch_with_new_path,
                                 branch_with_dir_rename, new_path);
                else
-                       path_msg(opt, new_path, 1,
+                       path_msg(opt, CONFLICT_DIR_RENAME_SUGGESTED, 1,
+                                new_path, old_path, NULL, NULL,
                                 _("CONFLICT (file location): %s renamed to %s "
                                   "in %s, inside a directory that was renamed "
                                   "in %s, suggesting it should perhaps be "
@@ -2659,7 +2845,8 @@ static int process_renames(struct merge_options *opt,
                         * and remove the setting of base->path_conflict to 1.
                         */
                        base->path_conflict = 1;
-                       path_msg(opt, oldpath, 0,
+                       path_msg(opt, CONFLICT_RENAME_RENAME, 0,
+                                pathnames[0], pathnames[1], pathnames[2], NULL,
                                 _("CONFLICT (rename/rename): %s renamed to "
                                   "%s in %s and to %s in %s."),
                                 pathnames[0],
@@ -2754,7 +2941,8 @@ static int process_renames(struct merge_options *opt,
                        memcpy(&newinfo->stages[target_index], &merged,
                               sizeof(merged));
                        if (!clean) {
-                               path_msg(opt, newpath, 0,
+                               path_msg(opt, CONFLICT_RENAME_COLLIDES, 0,
+                                        newpath, oldpath, NULL, NULL,
                                         _("CONFLICT (rename involved in "
                                           "collision): rename of %s -> %s has "
                                           "content conflicts AND collides "
@@ -2773,7 +2961,8 @@ static int process_renames(struct merge_options *opt,
                         */
 
                        newinfo->path_conflict = 1;
-                       path_msg(opt, newpath, 0,
+                       path_msg(opt, CONFLICT_RENAME_DELETE, 0,
+                                newpath, oldpath, NULL, NULL,
                                 _("CONFLICT (rename/delete): %s renamed "
                                   "to %s in %s, but deleted in %s."),
                                 oldpath, newpath, rename_branch, delete_branch);
@@ -2797,7 +2986,8 @@ static int process_renames(struct merge_options *opt,
                        } else if (source_deleted) {
                                /* rename/delete */
                                newinfo->path_conflict = 1;
-                               path_msg(opt, newpath, 0,
+                               path_msg(opt, CONFLICT_RENAME_DELETE, 0,
+                                        newpath, oldpath, NULL, NULL,
                                         _("CONFLICT (rename/delete): %s renamed"
                                           " to %s in %s, but deleted in %s."),
                                         oldpath, newpath,
@@ -3712,7 +3902,8 @@ static void process_entry(struct merge_options *opt,
                path = unique_path(opt, path, branch);
                strmap_put(&opt->priv->paths, path, new_ci);
 
-               path_msg(opt, path, 0,
+               path_msg(opt, CONFLICT_FILE_DIRECTORY, 0,
+                        path, old_path, NULL, NULL,
                         _("CONFLICT (file/directory): directory in the way "
                           "of %s from %s; moving it to %s instead."),
                         old_path, branch, path);
@@ -3788,15 +3979,23 @@ static void process_entry(struct merge_options *opt,
                                rename_b = 1;
                        }
 
+                       if (rename_a)
+                               a_path = unique_path(opt, path, opt->branch1);
+                       if (rename_b)
+                               b_path = unique_path(opt, path, opt->branch2);
+
                        if (rename_a && rename_b) {
-                               path_msg(opt, path, 0,
+                               path_msg(opt, CONFLICT_DISTINCT_MODES, 0,
+                                        path, a_path, b_path, NULL,
                                         _("CONFLICT (distinct types): %s had "
                                           "different types on each side; "
                                           "renamed both of them so each can "
                                           "be recorded somewhere."),
                                         path);
                        } else {
-                               path_msg(opt, path, 0,
+                               path_msg(opt, CONFLICT_DISTINCT_MODES, 0,
+                                        path, rename_a ? a_path : b_path,
+                                        NULL, NULL,
                                         _("CONFLICT (distinct types): %s had "
                                           "different types on each side; "
                                           "renamed one of them so each can be "
@@ -3833,14 +4032,10 @@ static void process_entry(struct merge_options *opt,
 
                        /* Insert entries into opt->priv_paths */
                        assert(rename_a || rename_b);
-                       if (rename_a) {
-                               a_path = unique_path(opt, path, opt->branch1);
+                       if (rename_a)
                                strmap_put(&opt->priv->paths, a_path, ci);
-                       }
 
-                       if (rename_b)
-                               b_path = unique_path(opt, path, opt->branch2);
-                       else
+                       if (!rename_b)
                                b_path = path;
                        strmap_put(&opt->priv->paths, b_path, new_ci);
 
@@ -3891,7 +4086,8 @@ static void process_entry(struct merge_options *opt,
                                reason = _("add/add");
                        if (S_ISGITLINK(merged_file.mode))
                                reason = _("submodule");
-                       path_msg(opt, path, 0,
+                       path_msg(opt, CONFLICT_CONTENTS, 0,
+                                path, NULL, NULL, NULL,
                                 _("CONFLICT (%s): Merge conflict in %s"),
                                 reason, path);
                }
@@ -3935,7 +4131,8 @@ static void process_entry(struct merge_options *opt,
                         * since the contents were not modified.
                         */
                } else {
-                       path_msg(opt, path, 0,
+                       path_msg(opt, CONFLICT_MODIFY_DELETE, 0,
+                                path, NULL, NULL, NULL,
                                 _("CONFLICT (modify/delete): %s deleted in %s "
                                   "and modified in %s.  Version %s of %s left "
                                   "in tree."),
@@ -4223,21 +4420,8 @@ static int record_conflicted_index_entries(struct merge_options *opt)
                         * the CE_SKIP_WORKTREE bit and manually write those
                         * files to the working disk here.
                         */
-                       if (ce_skip_worktree(ce)) {
-                               struct stat st;
-
-                               if (!lstat(path, &st)) {
-                                       char *new_name = unique_path(opt,
-                                                                    path,
-                                                                    "cruft");
-
-                                       path_msg(opt, path, 1,
-                                                _("Note: %s not up to date and in way of checking out conflicted version; old copy renamed to %s"),
-                                                path, new_name);
-                                       errs |= rename(path, new_name);
-                               }
+                       if (ce_skip_worktree(ce))
                                errs |= checkout_entry(ce, &state, NULL, NULL);
-                       }
 
                        /*
                         * Mark this cache entry for removal and instead add
@@ -4279,6 +4463,152 @@ static int record_conflicted_index_entries(struct merge_options *opt)
        return errs;
 }
 
+static void print_submodule_conflict_suggestion(struct string_list *csub) {
+       struct string_list_item *item;
+       struct strbuf msg = STRBUF_INIT;
+       struct strbuf tmp = STRBUF_INIT;
+       struct strbuf subs = STRBUF_INIT;
+
+       if (!csub->nr)
+               return;
+
+       strbuf_add_separated_string_list(&subs, " ", csub);
+       for_each_string_list_item(item, csub) {
+               struct conflicted_submodule_item *util = item->util;
+
+               /*
+                * NEEDSWORK: The steps to resolve these errors deserve a more
+                * detailed explanation than what is currently printed below.
+                */
+               if (util->flag == CONFLICT_SUBMODULE_NOT_INITIALIZED ||
+                   util->flag == CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE)
+                       continue;
+
+               /*
+                * TRANSLATORS: This is a line of advice to resolve a merge
+                * conflict in a submodule. The first argument is the submodule
+                * name, and the second argument is the abbreviated id of the
+                * commit that needs to be merged.  For example:
+                *  - go to submodule (mysubmodule), and either merge commit abc1234"
+                */
+               strbuf_addf(&tmp, _(" - go to submodule (%s), and either merge commit %s\n"
+                                   "   or update to an existing commit which has merged those changes\n"),
+                           item->string, util->abbrev);
+       }
+
+       /*
+        * TRANSLATORS: This is a detailed message for resolving submodule
+        * conflicts.  The first argument is string containing one step per
+        * submodule.  The second is a space-separated list of submodule names.
+        */
+       strbuf_addf(&msg,
+                   _("Recursive merging with submodules currently only supports trivial cases.\n"
+                     "Please manually handle the merging of each conflicted submodule.\n"
+                     "This can be accomplished with the following steps:\n"
+                     "%s"
+                     " - come back to superproject and run:\n\n"
+                     "      git add %s\n\n"
+                     "   to record the above merge or update\n"
+                     " - resolve any other conflicts in the superproject\n"
+                     " - commit the resulting index in the superproject\n"),
+                   tmp.buf, subs.buf);
+
+       printf("%s", msg.buf);
+
+       strbuf_release(&subs);
+       strbuf_release(&tmp);
+       strbuf_release(&msg);
+}
+
+void merge_display_update_messages(struct merge_options *opt,
+                                  int detailed,
+                                  struct merge_result *result)
+{
+       struct merge_options_internal *opti = result->priv;
+       struct hashmap_iter iter;
+       struct strmap_entry *e;
+       struct string_list olist = STRING_LIST_INIT_NODUP;
+
+       if (opt->record_conflict_msgs_as_headers)
+               BUG("Either display conflict messages or record them as headers, not both");
+
+       trace2_region_enter("merge", "display messages", opt->repo);
+
+       /* Hack to pre-allocate olist to the desired size */
+       ALLOC_GROW(olist.items, strmap_get_size(&opti->conflicts),
+                  olist.alloc);
+
+       /* Put every entry from output into olist, then sort */
+       strmap_for_each_entry(&opti->conflicts, &iter, e) {
+               string_list_append(&olist, e->key)->util = e->value;
+       }
+       string_list_sort(&olist);
+
+       /* Iterate over the items, printing them */
+       for (int path_nr = 0; path_nr < olist.nr; ++path_nr) {
+               struct string_list *conflicts = olist.items[path_nr].util;
+               for (int i = 0; i < conflicts->nr; i++) {
+                       struct logical_conflict_info *info =
+                               conflicts->items[i].util;
+
+                       if (detailed) {
+                               printf("%lu", (unsigned long)info->paths.nr);
+                               putchar('\0');
+                               for (int n = 0; n < info->paths.nr; n++) {
+                                       fputs(info->paths.v[n], stdout);
+                                       putchar('\0');
+                               }
+                               fputs(type_short_descriptions[info->type],
+                                     stdout);
+                               putchar('\0');
+                       }
+                       puts(conflicts->items[i].string);
+                       if (detailed)
+                               putchar('\0');
+               }
+       }
+       string_list_clear(&olist, 0);
+
+       print_submodule_conflict_suggestion(&opti->conflicted_submodules);
+
+       /* Also include needed rename limit adjustment now */
+       diff_warn_rename_limit("merge.renamelimit",
+                              opti->renames.needed_limit, 0);
+
+       trace2_region_leave("merge", "display messages", opt->repo);
+}
+
+void merge_get_conflicted_files(struct merge_result *result,
+                               struct string_list *conflicted_files)
+{
+       struct hashmap_iter iter;
+       struct strmap_entry *e;
+       struct merge_options_internal *opti = result->priv;
+
+       strmap_for_each_entry(&opti->conflicted, &iter, e) {
+               const char *path = e->key;
+               struct conflict_info *ci = e->value;
+               int i;
+
+               VERIFY_CI(ci);
+
+               for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
+                       struct stage_info *si;
+
+                       if (!(ci->filemask & (1ul << i)))
+                               continue;
+
+                       si = xmalloc(sizeof(*si));
+                       si->stage = i+1;
+                       si->mode = ci->stages[i].mode;
+                       oidcpy(&si->oid, &ci->stages[i].oid);
+                       string_list_append(conflicted_files, path)->util = si;
+               }
+       }
+       /* string_list_sort() uses a stable sort, so we're good */
+       string_list_sort(conflicted_files);
+}
+
 void merge_switch_to_result(struct merge_options *opt,
                            struct tree *head,
                            struct merge_result *result,
@@ -4321,43 +4651,8 @@ void merge_switch_to_result(struct merge_options *opt,
                fclose(fp);
                trace2_region_leave("merge", "write_auto_merge", opt->repo);
        }
-
-       if (display_update_msgs) {
-               struct merge_options_internal *opti = result->priv;
-               struct hashmap_iter iter;
-               struct strmap_entry *e;
-               struct string_list olist = STRING_LIST_INIT_NODUP;
-               int i;
-
-               if (opt->record_conflict_msgs_as_headers)
-                       BUG("Either display conflict messages or record them as headers, not both");
-
-               trace2_region_enter("merge", "display messages", opt->repo);
-
-               /* Hack to pre-allocate olist to the desired size */
-               ALLOC_GROW(olist.items, strmap_get_size(&opti->output),
-                          olist.alloc);
-
-               /* Put every entry from output into olist, then sort */
-               strmap_for_each_entry(&opti->output, &iter, e) {
-                       string_list_append(&olist, e->key)->util = e->value;
-               }
-               string_list_sort(&olist);
-
-               /* Iterate over the items, printing them */
-               for (i = 0; i < olist.nr; ++i) {
-                       struct strbuf *sb = olist.items[i].util;
-
-                       printf("%s", sb->buf);
-               }
-               string_list_clear(&olist, 0);
-
-               /* Also include needed rename limit adjustment now */
-               diff_warn_rename_limit("merge.renamelimit",
-                                      opti->renames.needed_limit, 0);
-
-               trace2_region_leave("merge", "display messages", opt->repo);
-       }
+       if (display_update_msgs)
+               merge_display_update_messages(opt, /* detailed */ 0, result);
 
        merge_finalize(opt, result);
 }
@@ -4477,6 +4772,7 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
        trace2_region_enter("merge", "allocate/init", opt->repo);
        if (opt->priv) {
                clear_or_reinit_internal_opts(opt->priv, 1);
+               string_list_init_nodup(&opt->priv->conflicted_submodules);
                trace2_region_leave("merge", "allocate/init", opt->repo);
                return;
        }
@@ -4531,11 +4827,11 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
        strmap_init_with_options(&opt->priv->conflicted, pool, 0);
 
        /*
-        * keys & strbufs in output will sometimes need to outlive "paths",
-        * so it will have a copy of relevant keys.  It's probably a small
-        * subset of the overall paths that have special output.
+        * keys & string_lists in conflicts will sometimes need to outlive
+        * "paths", so it will have a copy of relevant keys.  It's probably
+        * a small subset of the overall paths that have special output.
         */
-       strmap_init(&opt->priv->output);
+       strmap_init(&opt->priv->conflicts);
 
        trace2_region_leave("merge", "allocate/init", opt->repo);
 }
@@ -4636,7 +4932,8 @@ redo:
        trace2_region_leave("merge", "process_entries", opt->repo);
 
        /* Set return values */
-       result->path_messages = &opt->priv->output;
+       result->path_messages = &opt->priv->conflicts;
+
        result->tree = parse_tree_indirect(&working_tree_oid);
        /* existence of conflicted entries implies unclean */
        result->clean &= strmap_empty(&opt->priv->conflicted);
index fe599b8786891c74cbc5e911689f4a4d319152cd..a994c9a5fcdb040b3ecb80db0489a50c1394ac75 100644 (file)
@@ -2,6 +2,7 @@
 #define MERGE_ORT_H
 
 #include "merge-recursive.h"
+#include "hash.h"
 
 struct commit;
 struct tree;
@@ -27,7 +28,7 @@ struct merge_result {
        /*
         * Special messages and conflict notices for various paths
         *
-        * This is a map of pathnames to strbufs.  It contains various
+        * This is a map of pathnames to a string_list. It contains various
         * warning/conflict/notice messages (possibly multiple per path)
         * that callers may want to use.
         */
@@ -80,6 +81,35 @@ void merge_switch_to_result(struct merge_options *opt,
                            int update_worktree_and_index,
                            int display_update_msgs);
 
+/*
+ * Display messages about conflicts and which files were 3-way merged.
+ * Automatically called by merge_switch_to_result() with stream == stdout,
+ * so only call this when bypassing merge_switch_to_result().
+ */
+void merge_display_update_messages(struct merge_options *opt,
+                                  int detailed,
+                                  struct merge_result *result);
+
+struct stage_info {
+       struct object_id oid;
+       int mode;
+       int stage;
+};
+
+/*
+ * Provide a list of path -> {struct stage_info*} mappings for
+ * all conflicted files.  Note that each path could appear up to three
+ * times in the list, corresponding to 3 different stage entries.  In short,
+ * this basically provides the info that would be printed by `ls-files -u`.
+ *
+ * result should have been populated by a call to
+ * one of the merge_incore_[non]recursive() functions.
+ *
+ * conflicted_files should be empty before calling this function.
+ */
+void merge_get_conflicted_files(struct merge_result *result,
+                               struct string_list *conflicted_files);
+
 /* Do needed cleanup when not calling merge_switch_to_result() */
 void merge_finalize(struct merge_options *opt,
                    struct merge_result *result);
index b83a129b4313d9c6a4f6434fbe2002068ef7a542..4ddd3adea003e32fb7f16fbfa56a886a5d4a0712 100644 (file)
@@ -45,7 +45,7 @@ struct path_hashmap_entry {
        char path[FLEX_ARRAY];
 };
 
-static int path_hashmap_cmp(const void *cmp_data,
+static int path_hashmap_cmp(const void *cmp_data UNUSED,
                            const struct hashmap_entry *eptr,
                            const struct hashmap_entry *entry_or_key,
                            const void *keydata)
@@ -89,10 +89,10 @@ static struct dir_rename_entry *dir_rename_find_entry(struct hashmap *hashmap,
        return hashmap_get_entry(hashmap, &key, ent, NULL);
 }
 
-static int dir_rename_cmp(const void *unused_cmp_data,
+static int dir_rename_cmp(const void *cmp_data UNUSED,
                          const struct hashmap_entry *eptr,
                          const struct hashmap_entry *entry_or_key,
-                         const void *unused_keydata)
+                         const void *keydata UNUSED)
 {
        const struct dir_rename_entry *e1, *e2;
 
@@ -134,10 +134,10 @@ static struct collision_entry *collision_find_entry(struct hashmap *hashmap,
        return hashmap_get_entry(hashmap, &key, ent, NULL);
 }
 
-static int collision_cmp(const void *unused_cmp_data,
+static int collision_cmp(const void *cmp_data UNUSED,
                         const struct hashmap_entry *eptr,
                         const struct hashmap_entry *entry_or_key,
-                        const void *unused_keydata)
+                        const void *keydata UNUSED)
 {
        const struct collision_entry *e1, *e2;
 
@@ -456,7 +456,7 @@ static void unpack_trees_finish(struct merge_options *opt)
        clear_unpack_trees_porcelain(&opt->priv->unpack_opts);
 }
 
-static int save_files_dirs(const struct object_id *oid,
+static int save_files_dirs(const struct object_id *oid UNUSED,
                           struct strbuf *base, const char *path,
                           unsigned int mode, void *context)
 {
diff --git a/mergesort.c b/mergesort.c
deleted file mode 100644 (file)
index bd9c6ef..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "cache.h"
-#include "mergesort.h"
-
-/* Combine two sorted lists.  Take from `list` on equality. */
-static void *llist_merge(void *list, void *other,
-                        void *(*get_next_fn)(const void *),
-                        void (*set_next_fn)(void *, void *),
-                        int (*compare_fn)(const void *, const void *))
-{
-       void *result = list, *tail;
-
-       if (compare_fn(list, other) > 0) {
-               result = other;
-               goto other;
-       }
-       for (;;) {
-               do {
-                       tail = list;
-                       list = get_next_fn(list);
-                       if (!list) {
-                               set_next_fn(tail, other);
-                               return result;
-                       }
-               } while (compare_fn(list, other) <= 0);
-               set_next_fn(tail, other);
-       other:
-               do {
-                       tail = other;
-                       other = get_next_fn(other);
-                       if (!other) {
-                               set_next_fn(tail, list);
-                               return result;
-                       }
-               } while (compare_fn(list, other) > 0);
-               set_next_fn(tail, list);
-       }
-}
-
-/*
- * Perform an iterative mergesort using an array of sublists.
- *
- * n is the number of items.
- * ranks[i] is undefined if n & 2^i == 0, and assumed empty.
- * ranks[i] contains a sublist of length 2^i otherwise.
- *
- * The number of bits in a void pointer limits the number of objects
- * that can be created, and thus the number of array elements necessary
- * to be able to sort any valid list.
- *
- * Adding an item to this array is like incrementing a binary number;
- * positional values for set bits correspond to sublist lengths.
- */
-void *llist_mergesort(void *list,
-                     void *(*get_next_fn)(const void *),
-                     void (*set_next_fn)(void *, void *),
-                     int (*compare_fn)(const void *, const void *))
-{
-       void *ranks[bitsizeof(void *)];
-       size_t n = 0;
-       int i;
-
-       while (list) {
-               void *next = get_next_fn(list);
-               if (next)
-                       set_next_fn(list, NULL);
-               for (i = 0; n & ((size_t)1 << i); i++)
-                       list = llist_merge(ranks[i], list, get_next_fn,
-                                          set_next_fn, compare_fn);
-               n++;
-               ranks[i] = list;
-               list = next;
-       }
-
-       for (i = 0; n; i++, n >>= 1) {
-               if (!(n & 1))
-                       continue;
-               if (list)
-                       list = llist_merge(ranks[i], list, get_next_fn,
-                                          set_next_fn, compare_fn);
-               else
-                       list = ranks[i];
-       }
-       return list;
-}
index 644cff1f9640f4f3a146d7217a8deab34282ff53..7c36f08bd5f9668521ff993986b757b9766ec1c0 100644 (file)
 #ifndef MERGESORT_H
 #define MERGESORT_H
 
+/* Combine two sorted lists.  Take from `list` on equality. */
+#define DEFINE_LIST_MERGE_INTERNAL(name, type)                         \
+static type *name##__merge(type *list, type *other,                    \
+                          int (*compare_fn)(const type *, const type *))\
+{                                                                      \
+       type *result = list, *tail;                                     \
+       int prefer_list = compare_fn(list, other) <= 0;                 \
+                                                                       \
+       if (!prefer_list) {                                             \
+               result = other;                                         \
+               SWAP(list, other);                                      \
+       }                                                               \
+       for (;;) {                                                      \
+               do {                                                    \
+                       tail = list;                                    \
+                       list = name##__get_next(list);                  \
+                       if (!list) {                                    \
+                               name##__set_next(tail, other);          \
+                               return result;                          \
+                       }                                               \
+               } while (compare_fn(list, other) < prefer_list);        \
+               name##__set_next(tail, other);                          \
+               prefer_list ^= 1;                                       \
+               SWAP(list, other);                                      \
+       }                                                               \
+}
+
 /*
- * Sort linked list in place.
- * - get_next_fn() returns the next element given an element of a linked list.
- * - set_next_fn() takes two elements A and B, and makes B the "next" element
- *   of A on the list.
- * - compare_fn() takes two elements A and B, and returns negative, 0, positive
- *   as the same sign as "subtracting" B from A.
+ * Perform an iterative mergesort using an array of sublists.
+ *
+ * n is the number of items.
+ * ranks[i] is undefined if n & 2^i == 0, and assumed empty.
+ * ranks[i] contains a sublist of length 2^i otherwise.
+ *
+ * The number of bits in a void pointer limits the number of objects
+ * that can be created, and thus the number of array elements necessary
+ * to be able to sort any valid list.
+ *
+ * Adding an item to this array is like incrementing a binary number;
+ * positional values for set bits correspond to sublist lengths.
  */
-void *llist_mergesort(void *list,
-                     void *(*get_next_fn)(const void *),
-                     void (*set_next_fn)(void *, void *),
-                     int (*compare_fn)(const void *, const void *));
+#define DEFINE_LIST_SORT_INTERNAL(scope, name, type)                   \
+scope void name(type **listp,                                          \
+               int (*compare_fn)(const type *, const type *))          \
+{                                                                      \
+       type *list = *listp;                                            \
+       type *ranks[bitsizeof(type *)];                                 \
+       size_t n = 0;                                                   \
+                                                                       \
+       if (!list)                                                      \
+               return;                                                 \
+                                                                       \
+       for (;;) {                                                      \
+               int i;                                                  \
+               size_t m;                                               \
+               type *next = name##__get_next(list);                    \
+               if (next)                                               \
+                       name##__set_next(list, NULL);                   \
+               for (i = 0, m = n;; i++, m >>= 1) {                     \
+                       if (m & 1) {                                    \
+                               list = name##__merge(ranks[i], list,    \
+                                                   compare_fn);        \
+                       } else if (next) {                              \
+                               break;                                  \
+                       } else if (!m) {                                \
+                               *listp = list;                          \
+                               return;                                 \
+                       }                                               \
+               }                                                       \
+               n++;                                                    \
+               ranks[i] = list;                                        \
+               list = next;                                            \
+       }                                                               \
+}
+
+#define DECLARE_LIST_SORT(scope, name, type)                   \
+scope void name(type **listp,                                  \
+               int (*compare_fn)(const type *, const type *))
+
+#define DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, \
+                              on_get_next, on_set_next)        \
+                                                               \
+static inline type *name##__get_next(const type *elem)         \
+{                                                              \
+       on_get_next;                                            \
+       return elem->next_member;                               \
+}                                                              \
+                                                               \
+static inline void name##__set_next(type *elem, type *next)    \
+{                                                              \
+       on_set_next;                                            \
+       elem->next_member = next;                               \
+}                                                              \
+                                                               \
+DEFINE_LIST_MERGE_INTERNAL(name, type)                         \
+DEFINE_LIST_SORT_INTERNAL(scope, name, type)                   \
+DECLARE_LIST_SORT(scope, name, type)
+
+#define DEFINE_LIST_SORT(scope, name, type, next_member) \
+DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, (void)0, (void)0)
 
 #endif
diff --git a/midx.c b/midx.c
index 5f0dd386b0266b6549c85499ab50e964ed868f1d..c27d0e5f1510c32ad7cbf0fca8dc1d05ec4917a3 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -577,6 +577,78 @@ static void fill_pack_entry(uint32_t pack_int_id,
        entry->preferred = !!preferred;
 }
 
+struct midx_fanout {
+       struct pack_midx_entry *entries;
+       uint32_t nr;
+       uint32_t alloc;
+};
+
+static void midx_fanout_grow(struct midx_fanout *fanout, uint32_t nr)
+{
+       ALLOC_GROW(fanout->entries, nr, fanout->alloc);
+}
+
+static void midx_fanout_sort(struct midx_fanout *fanout)
+{
+       QSORT(fanout->entries, fanout->nr, midx_oid_compare);
+}
+
+static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
+                                       struct multi_pack_index *m,
+                                       uint32_t cur_fanout,
+                                       int preferred_pack)
+{
+       uint32_t start = 0, end;
+       uint32_t cur_object;
+
+       if (cur_fanout)
+               start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
+       end = ntohl(m->chunk_oid_fanout[cur_fanout]);
+
+       for (cur_object = start; cur_object < end; cur_object++) {
+               if ((preferred_pack > -1) &&
+                   (preferred_pack == nth_midxed_pack_int_id(m, cur_object))) {
+                       /*
+                        * Objects from preferred packs are added
+                        * separately.
+                        */
+                       continue;
+               }
+
+               midx_fanout_grow(fanout, fanout->nr + 1);
+               nth_midxed_pack_midx_entry(m,
+                                          &fanout->entries[fanout->nr],
+                                          cur_object);
+               fanout->entries[fanout->nr].preferred = 0;
+               fanout->nr++;
+       }
+}
+
+static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
+                                       struct pack_info *info,
+                                       uint32_t cur_pack,
+                                       int preferred,
+                                       uint32_t cur_fanout)
+{
+       struct packed_git *pack = info[cur_pack].p;
+       uint32_t start = 0, end;
+       uint32_t cur_object;
+
+       if (cur_fanout)
+               start = get_pack_fanout(pack, cur_fanout - 1);
+       end = get_pack_fanout(pack, cur_fanout);
+
+       for (cur_object = start; cur_object < end; cur_object++) {
+               midx_fanout_grow(fanout, fanout->nr + 1);
+               fill_pack_entry(cur_pack,
+                               info[cur_pack].p,
+                               cur_object,
+                               &fanout->entries[fanout->nr],
+                               preferred);
+               fanout->nr++;
+       }
+}
+
 /*
  * It is possible to artificially get into a state where there are many
  * duplicate copies of objects. That can create high memory pressure if
@@ -595,8 +667,8 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
                                                  int preferred_pack)
 {
        uint32_t cur_fanout, cur_pack, cur_object;
-       uint32_t alloc_fanout, alloc_objects, total_objects = 0;
-       struct pack_midx_entry *entries_by_fanout = NULL;
+       uint32_t alloc_objects, total_objects = 0;
+       struct midx_fanout fanout = { 0 };
        struct pack_midx_entry *deduplicated_entries = NULL;
        uint32_t start_pack = m ? m->num_packs : 0;
 
@@ -608,74 +680,51 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
         * slices to be evenly distributed, with some noise. Hence,
         * allocate slightly more than one 256th.
         */
-       alloc_objects = alloc_fanout = total_objects > 3200 ? total_objects / 200 : 16;
+       alloc_objects = fanout.alloc = total_objects > 3200 ? total_objects / 200 : 16;
 
-       ALLOC_ARRAY(entries_by_fanout, alloc_fanout);
+       ALLOC_ARRAY(fanout.entries, fanout.alloc);
        ALLOC_ARRAY(deduplicated_entries, alloc_objects);
        *nr_objects = 0;
 
        for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
-               uint32_t nr_fanout = 0;
-
-               if (m) {
-                       uint32_t start = 0, end;
-
-                       if (cur_fanout)
-                               start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
-                       end = ntohl(m->chunk_oid_fanout[cur_fanout]);
-
-                       for (cur_object = start; cur_object < end; cur_object++) {
-                               ALLOC_GROW(entries_by_fanout, nr_fanout + 1, alloc_fanout);
-                               nth_midxed_pack_midx_entry(m,
-                                                          &entries_by_fanout[nr_fanout],
-                                                          cur_object);
-                               if (nth_midxed_pack_int_id(m, cur_object) == preferred_pack)
-                                       entries_by_fanout[nr_fanout].preferred = 1;
-                               else
-                                       entries_by_fanout[nr_fanout].preferred = 0;
-                               nr_fanout++;
-                       }
-               }
+               fanout.nr = 0;
+
+               if (m)
+                       midx_fanout_add_midx_fanout(&fanout, m, cur_fanout,
+                                                   preferred_pack);
 
                for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++) {
-                       uint32_t start = 0, end;
                        int preferred = cur_pack == preferred_pack;
-
-                       if (cur_fanout)
-                               start = get_pack_fanout(info[cur_pack].p, cur_fanout - 1);
-                       end = get_pack_fanout(info[cur_pack].p, cur_fanout);
-
-                       for (cur_object = start; cur_object < end; cur_object++) {
-                               ALLOC_GROW(entries_by_fanout, nr_fanout + 1, alloc_fanout);
-                               fill_pack_entry(cur_pack,
-                                               info[cur_pack].p,
-                                               cur_object,
-                                               &entries_by_fanout[nr_fanout],
-                                               preferred);
-                               nr_fanout++;
-                       }
+                       midx_fanout_add_pack_fanout(&fanout,
+                                                   info, cur_pack,
+                                                   preferred, cur_fanout);
                }
 
-               QSORT(entries_by_fanout, nr_fanout, midx_oid_compare);
+               if (-1 < preferred_pack && preferred_pack < start_pack)
+                       midx_fanout_add_pack_fanout(&fanout, info,
+                                                   preferred_pack, 1,
+                                                   cur_fanout);
+
+               midx_fanout_sort(&fanout);
 
                /*
                 * The batch is now sorted by OID and then mtime (descending).
                 * Take only the first duplicate.
                 */
-               for (cur_object = 0; cur_object < nr_fanout; cur_object++) {
-                       if (cur_object && oideq(&entries_by_fanout[cur_object - 1].oid,
-                                               &entries_by_fanout[cur_object].oid))
+               for (cur_object = 0; cur_object < fanout.nr; cur_object++) {
+                       if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
+                                               &fanout.entries[cur_object].oid))
                                continue;
 
                        ALLOC_GROW(deduplicated_entries, *nr_objects + 1, alloc_objects);
                        memcpy(&deduplicated_entries[*nr_objects],
-                              &entries_by_fanout[cur_object],
+                              &fanout.entries[cur_object],
                               sizeof(struct pack_midx_entry));
                        (*nr_objects)++;
                }
        }
 
-       free(entries_by_fanout);
+       free(fanout.entries);
        return deduplicated_entries;
 }
 
@@ -1053,40 +1102,37 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
        return cb.commits;
 }
 
-static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,
-                            struct write_midx_context *ctx,
-                            const char *refs_snapshot,
+static int write_midx_bitmap(const char *midx_name,
+                            const unsigned char *midx_hash,
+                            struct packing_data *pdata,
+                            struct commit **commits,
+                            uint32_t commits_nr,
+                            uint32_t *pack_order,
                             unsigned flags)
 {
-       struct packing_data pdata;
-       struct pack_idx_entry **index;
-       struct commit **commits = NULL;
-       uint32_t i, commits_nr;
+       int ret, i;
        uint16_t options = 0;
-       char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name, hash_to_hex(midx_hash));
-       int ret;
-
-       if (!ctx->entries_nr)
-               BUG("cannot write a bitmap without any objects");
+       struct pack_idx_entry **index;
+       char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
+                                       hash_to_hex(midx_hash));
 
        if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
                options |= BITMAP_OPT_HASH_CACHE;
 
-       prepare_midx_packing_data(&pdata, ctx);
-
-       commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, ctx);
+       if (flags & MIDX_WRITE_BITMAP_LOOKUP_TABLE)
+               options |= BITMAP_OPT_LOOKUP_TABLE;
 
        /*
         * Build the MIDX-order index based on pdata.objects (which is already
         * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
         * this order).
         */
-       ALLOC_ARRAY(index, pdata.nr_objects);
-       for (i = 0; i < pdata.nr_objects; i++)
-               index[i] = &pdata.objects[i].idx;
+       ALLOC_ARRAY(index, pdata->nr_objects);
+       for (i = 0; i < pdata->nr_objects; i++)
+               index[i] = &pdata->objects[i].idx;
 
        bitmap_writer_show_progress(flags & MIDX_PROGRESS);
-       bitmap_writer_build_type_index(&pdata, index, pdata.nr_objects);
+       bitmap_writer_build_type_index(pdata, index, pdata->nr_objects);
 
        /*
         * bitmap_writer_finish expects objects in lex order, but pack_order
@@ -1101,16 +1147,16 @@ static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,
         * happens between bitmap_writer_build_type_index() and
         * bitmap_writer_finish().
         */
-       for (i = 0; i < pdata.nr_objects; i++)
-               index[ctx->pack_order[i]] = &pdata.objects[i].idx;
+       for (i = 0; i < pdata->nr_objects; i++)
+               index[pack_order[i]] = &pdata->objects[i].idx;
 
        bitmap_writer_select_commits(commits, commits_nr, -1);
-       ret = bitmap_writer_build(&pdata);
+       ret = bitmap_writer_build(pdata);
        if (ret < 0)
                goto cleanup;
 
        bitmap_writer_set_checksum(midx_hash);
-       bitmap_writer_finish(index, pdata.nr_objects, bitmap_name, options);
+       bitmap_writer_finish(index, pdata->nr_objects, bitmap_name, options);
 
 cleanup:
        free(index);
@@ -1443,14 +1489,40 @@ static int write_midx_internal(const char *object_dir,
        if (flags & MIDX_WRITE_REV_INDEX &&
            git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
                write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
+
        if (flags & MIDX_WRITE_BITMAP) {
-               if (write_midx_bitmap(midx_name.buf, midx_hash, &ctx,
-                                     refs_snapshot, flags) < 0) {
+               struct packing_data pdata;
+               struct commit **commits;
+               uint32_t commits_nr;
+
+               if (!ctx.entries_nr)
+                       BUG("cannot write a bitmap without any objects");
+
+               prepare_midx_packing_data(&pdata, &ctx);
+
+               commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, &ctx);
+
+               /*
+                * The previous steps translated the information from
+                * 'entries' into information suitable for constructing
+                * bitmaps. We no longer need that array, so clear it to
+                * reduce memory pressure.
+                */
+               FREE_AND_NULL(ctx.entries);
+               ctx.entries_nr = 0;
+
+               if (write_midx_bitmap(midx_name.buf, midx_hash, &pdata,
+                                     commits, commits_nr, ctx.pack_order,
+                                     flags) < 0) {
                        error(_("could not write multi-pack bitmap"));
                        result = 1;
                        goto cleanup;
                }
        }
+       /*
+        * NOTE: Do not use ctx.entries beyond this point, since it might
+        * have been freed in the previous if block.
+        */
 
        if (ctx.m)
                close_object_store(the_repository->objects);
diff --git a/midx.h b/midx.h
index 22e8e53288ec226f7673d8a0f277961d5bb1d856..5578cd7b835e2b396e502e8abaf4560ab765c850 100644 (file)
--- a/midx.h
+++ b/midx.h
@@ -47,6 +47,7 @@ struct multi_pack_index {
 #define MIDX_WRITE_REV_INDEX (1 << 1)
 #define MIDX_WRITE_BITMAP (1 << 2)
 #define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3)
+#define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)
 
 const unsigned char *get_midx_checksum(struct multi_pack_index *m);
 void get_midx_filename(struct strbuf *out, const char *object_dir);
index 7487d331240e2aa25d1ecfbe22cee9eb4998df50..cd009c7c8ae455324bc9e48aa0f1f4df24211b66 100644 (file)
@@ -18,7 +18,7 @@ struct dir_entry {
        char name[FLEX_ARRAY];
 };
 
-static int dir_entry_cmp(const void *unused_cmp_data,
+static int dir_entry_cmp(const void *cmp_data UNUSED,
                         const struct hashmap_entry *eptr,
                         const struct hashmap_entry *entry_or_key,
                         const void *keydata)
@@ -120,7 +120,7 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
                add_dir_entry(istate, ce);
 }
 
-static int cache_entry_cmp(const void *unused_cmp_data,
+static int cache_entry_cmp(const void *cmp_data UNUSED,
                           const struct hashmap_entry *eptr,
                           const struct hashmap_entry *entry_or_key,
                           const void *remove)
index 434189ae5dc64a2b6bbdac01d82f4f284f9855c6..b7e79feaf042290c041fbcec439fc2aa8e84a3df 100644 (file)
@@ -36,7 +36,8 @@ static void rev_list_push(struct negotiation_state *ns,
 }
 
 static int clear_marks(const char *refname, const struct object_id *oid,
-                      int flag, void *cb_data)
+                      int flag UNUSED,
+                      void *cb_data UNUSED)
 {
        struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
 
index 1236e7922484a2d9b98c0d87fb0973c0b6aa6587..c4398f5ae15d320b5f7167105a08d94fe6bbf4fa 100644 (file)
@@ -72,7 +72,8 @@ static struct entry *rev_list_push(struct data *data, struct commit *commit, int
 }
 
 static int clear_marks(const char *refname, const struct object_id *oid,
-                      int flag, void *cb_data)
+                      int flag UNUSED,
+                      void *cb_data UNUSED)
 {
        struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
 
diff --git a/notes.c b/notes.c
index 7452e71cc8dd289c7ace9361a6c6e090b8b113f9..f2805d51bb15131c46d41fa9554c43ab2e9a492d 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -924,8 +924,9 @@ out:
        return ret;
 }
 
-static int string_list_add_one_ref(const char *refname, const struct object_id *oid,
-                                  int flag, void *cb)
+static int string_list_add_one_ref(const char *refname,
+                                  const struct object_id *oid UNUSED,
+                                  int flag UNUSED, void *cb)
 {
        struct string_list *refs = cb;
        if (!unsorted_string_list_has_string(refs, refname))
@@ -1005,6 +1006,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 
        if (!notes_ref)
                notes_ref = default_notes_ref();
+       update_ref_namespace(NAMESPACE_NOTES, xstrdup(notes_ref));
 
        if (!combine_notes)
                combine_notes = combine_notes_concatenate;
index 6c8e3b16602300923ea2dec61c39e40f624237b8..5b270f046dda1d4234af6174cd80c07f64f9dff6 100644 (file)
@@ -1951,6 +1951,96 @@ static int create_tmpfile(struct strbuf *tmp, const char *filename)
        return fd;
 }
 
+/**
+ * Common steps for loose object writers to start writing loose
+ * objects:
+ *
+ * - Create tmpfile for the loose object.
+ * - Setup zlib stream for compression.
+ * - Start to feed header to zlib stream.
+ *
+ * Returns a "fd", which should later be provided to
+ * end_loose_object_common().
+ */
+static int start_loose_object_common(struct strbuf *tmp_file,
+                                    const char *filename, unsigned flags,
+                                    git_zstream *stream,
+                                    unsigned char *buf, size_t buflen,
+                                    git_hash_ctx *c,
+                                    char *hdr, int hdrlen)
+{
+       int fd;
+
+       fd = create_tmpfile(tmp_file, filename);
+       if (fd < 0) {
+               if (flags & HASH_SILENT)
+                       return -1;
+               else if (errno == EACCES)
+                       return error(_("insufficient permission for adding "
+                                      "an object to repository database %s"),
+                                    get_object_directory());
+               else
+                       return error_errno(
+                               _("unable to create temporary file"));
+       }
+
+       /*  Setup zlib stream for compression */
+       git_deflate_init(stream, zlib_compression_level);
+       stream->next_out = buf;
+       stream->avail_out = buflen;
+       the_hash_algo->init_fn(c);
+
+       /*  Start to feed header to zlib stream */
+       stream->next_in = (unsigned char *)hdr;
+       stream->avail_in = hdrlen;
+       while (git_deflate(stream, 0) == Z_OK)
+               ; /* nothing */
+       the_hash_algo->update_fn(c, hdr, hdrlen);
+
+       return fd;
+}
+
+/**
+ * Common steps for the inner git_deflate() loop for writing loose
+ * objects. Returns what git_deflate() returns.
+ */
+static int write_loose_object_common(git_hash_ctx *c,
+                                    git_zstream *stream, const int flush,
+                                    unsigned char *in0, const int fd,
+                                    unsigned char *compressed,
+                                    const size_t compressed_len)
+{
+       int ret;
+
+       ret = git_deflate(stream, flush ? Z_FINISH : 0);
+       the_hash_algo->update_fn(c, in0, stream->next_in - in0);
+       if (write_buffer(fd, compressed, stream->next_out - compressed) < 0)
+               die(_("unable to write loose object file"));
+       stream->next_out = compressed;
+       stream->avail_out = compressed_len;
+
+       return ret;
+}
+
+/**
+ * Common steps for loose object writers to end writing loose objects:
+ *
+ * - End the compression of zlib stream.
+ * - Get the calculated oid to "oid".
+ */
+static int end_loose_object_common(git_hash_ctx *c, git_zstream *stream,
+                                  struct object_id *oid)
+{
+       int ret;
+
+       ret = git_deflate_end_gently(stream);
+       if (ret != Z_OK)
+               return ret;
+       the_hash_algo->final_oid_fn(oid, c);
+
+       return Z_OK;
+}
+
 static int write_loose_object(const struct object_id *oid, char *hdr,
                              int hdrlen, const void *buf, unsigned long len,
                              time_t mtime, unsigned flags)
@@ -1968,50 +2058,29 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
 
        loose_object_path(the_repository, &filename, oid);
 
-       fd = create_tmpfile(&tmp_file, filename.buf);
-       if (fd < 0) {
-               if (flags & HASH_SILENT)
-                       return -1;
-               else if (errno == EACCES)
-                       return error(_("insufficient permission for adding an object to repository database %s"), get_object_directory());
-               else
-                       return error_errno(_("unable to create temporary file"));
-       }
-
-       /* Set it up */
-       git_deflate_init(&stream, zlib_compression_level);
-       stream.next_out = compressed;
-       stream.avail_out = sizeof(compressed);
-       the_hash_algo->init_fn(&c);
-
-       /* First header.. */
-       stream.next_in = (unsigned char *)hdr;
-       stream.avail_in = hdrlen;
-       while (git_deflate(&stream, 0) == Z_OK)
-               ; /* nothing */
-       the_hash_algo->update_fn(&c, hdr, hdrlen);
+       fd = start_loose_object_common(&tmp_file, filename.buf, flags,
+                                      &stream, compressed, sizeof(compressed),
+                                      &c, hdr, hdrlen);
+       if (fd < 0)
+               return -1;
 
        /* Then the data itself.. */
        stream.next_in = (void *)buf;
        stream.avail_in = len;
        do {
                unsigned char *in0 = stream.next_in;
-               ret = git_deflate(&stream, Z_FINISH);
-               the_hash_algo->update_fn(&c, in0, stream.next_in - in0);
-               if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
-                       die(_("unable to write loose object file"));
-               stream.next_out = compressed;
-               stream.avail_out = sizeof(compressed);
+
+               ret = write_loose_object_common(&c, &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 = git_deflate_end_gently(&stream);
+       ret = end_loose_object_common(&c, &stream, &parano_oid);
        if (ret != Z_OK)
                die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
                    ret);
-       the_hash_algo->final_oid_fn(&parano_oid, &c);
        if (!oideq(oid, &parano_oid))
                die(_("confused by unstable object source data for %s"),
                    oid_to_hex(oid));
@@ -2050,6 +2119,110 @@ static int freshen_packed_object(const struct object_id *oid)
        return 1;
 }
 
+int stream_loose_object(struct input_stream *in_stream, size_t len,
+                       struct object_id *oid)
+{
+       int fd, ret, err = 0, flush = 0;
+       unsigned char compressed[4096];
+       git_zstream stream;
+       git_hash_ctx c;
+       struct strbuf tmp_file = STRBUF_INIT;
+       struct strbuf filename = STRBUF_INIT;
+       int dirlen;
+       char hdr[MAX_HEADER_LEN];
+       int hdrlen;
+
+       if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
+               prepare_loose_object_bulk_checkin();
+
+       /* Since oid is not determined, save tmp file to odb path. */
+       strbuf_addf(&filename, "%s/", get_object_directory());
+       hdrlen = format_object_header(hdr, sizeof(hdr), OBJ_BLOB, len);
+
+       /*
+        * Common steps for write_loose_object and stream_loose_object to
+        * start writing loose objects:
+        *
+        *  - Create tmpfile for the loose object.
+        *  - Setup zlib stream for compression.
+        *  - Start to feed header to zlib stream.
+        */
+       fd = start_loose_object_common(&tmp_file, filename.buf, 0,
+                                      &stream, compressed, sizeof(compressed),
+                                      &c, hdr, hdrlen);
+       if (fd < 0) {
+               err = -1;
+               goto cleanup;
+       }
+
+       /* Then the data itself.. */
+       do {
+               unsigned char *in0 = stream.next_in;
+
+               if (!stream.avail_in && !in_stream->is_finished) {
+                       const void *in = in_stream->read(in_stream, &stream.avail_in);
+                       stream.next_in = (void *)in;
+                       in0 = (unsigned char *)in;
+                       /* All data has been read. */
+                       if (in_stream->is_finished)
+                               flush = 1;
+               }
+               ret = write_loose_object_common(&c, &stream, flush, in0, fd,
+                                               compressed, sizeof(compressed));
+               /*
+                * Unlike write_loose_object(), we do not have the entire
+                * buffer. If we get Z_BUF_ERROR due to too few input bytes,
+                * then we'll replenish them in the next input_stream->read()
+                * call when we loop.
+                */
+       } while (ret == Z_OK || ret == Z_BUF_ERROR);
+
+       if (stream.total_in != len + hdrlen)
+               die(_("write stream object %ld != %"PRIuMAX), stream.total_in,
+                   (uintmax_t)len + hdrlen);
+
+       /*
+        * Common steps for write_loose_object and stream_loose_object to
+        * end writing loose oject:
+        *
+        *  - End the compression of zlib stream.
+        *  - Get the calculated oid.
+        */
+       if (ret != Z_STREAM_END)
+               die(_("unable to stream deflate new object (%d)"), ret);
+       ret = end_loose_object_common(&c, &stream, oid);
+       if (ret != Z_OK)
+               die(_("deflateEnd on stream object failed (%d)"), ret);
+       close_loose_object(fd, tmp_file.buf);
+
+       if (freshen_packed_object(oid) || freshen_loose_object(oid)) {
+               unlink_or_warn(tmp_file.buf);
+               goto cleanup;
+       }
+
+       loose_object_path(the_repository, &filename, oid);
+
+       /* We finally know the object path, and create the missing dir. */
+       dirlen = directory_size(filename.buf);
+       if (dirlen) {
+               struct strbuf dir = STRBUF_INIT;
+               strbuf_add(&dir, filename.buf, dirlen);
+
+               if (mkdir_in_gitdir(dir.buf) && errno != EEXIST) {
+                       err = error_errno(_("unable to create directory %s"), dir.buf);
+                       strbuf_release(&dir);
+                       goto cleanup;
+               }
+               strbuf_release(&dir);
+       }
+
+       err = finalize_object_file(tmp_file.buf, filename.buf);
+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,
                            unsigned flags)
index 4d2746574cde0b813a73772c13d71a30db696128..2dd1a0f56e1e442dec47dfbbcdd46d58aecc812c 100644 (file)
@@ -1306,7 +1306,8 @@ struct handle_one_ref_cb {
 };
 
 static int handle_one_ref(const char *path, const struct object_id *oid,
-                         int flag, void *cb_data)
+                         int flag UNUSED,
+                         void *cb_data)
 {
        struct handle_one_ref_cb *cb = cb_data;
        struct commit_list **list = cb->list;
@@ -1384,8 +1385,11 @@ struct grab_nth_branch_switch_cbdata {
        struct strbuf *sb;
 };
 
-static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,
-                                 const char *email, timestamp_t timestamp, int tz,
+static int grab_nth_branch_switch(struct object_id *ooid UNUSED,
+                                 struct object_id *noid UNUSED,
+                                 const char *email UNUSED,
+                                 timestamp_t timestamp UNUSED,
+                                 int tz UNUSED,
                                  const char *message, void *cb_data)
 {
        struct grab_nth_branch_switch_cbdata *cb = cb_data;
index 539ea439046dc18625917769040c7f824c490c24..1be57abaf10d7aa527df7f22ebaf660f6430d4d8 100644 (file)
@@ -46,6 +46,12 @@ struct object_directory {
        char *path;
 };
 
+struct input_stream {
+       const void *(*read)(struct input_stream *, unsigned long *len);
+       void *data;
+       int is_finished;
+};
+
 KHASH_INIT(odb_path_map, const char * /* key: odb_path */,
        struct object_directory *, 1, fspathhash, fspatheq)
 
@@ -135,7 +141,7 @@ struct packed_git {
 
 struct multi_pack_index;
 
-static inline int pack_map_entry_cmp(const void *unused_cmp_data,
+static inline int pack_map_entry_cmp(const void *cmp_data UNUSED,
                                     const struct hashmap_entry *entry,
                                     const struct hashmap_entry *entry2,
                                     const void *keydata)
@@ -269,6 +275,8 @@ static inline int write_object_file(const void *buf, unsigned long len,
 int write_object_file_literally(const void *buf, unsigned long len,
                                const char *type, struct object_id *oid,
                                unsigned flags);
+int stream_loose_object(struct input_stream *in_stream, size_t len,
+                       struct object_id *oid);
 
 /*
  * Add an object file to the in-memory object store, without writing it
index 588b8156f1d634a5cb9c25038961ca9a0d28d255..8a74eb85e94603458e0fe7eafbc58a40a3380b10 100644 (file)
--- a/object.c
+++ b/object.c
@@ -233,7 +233,8 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
                if (commit) {
                        if (parse_commit_buffer(r, commit, buffer, size, 1))
                                return NULL;
-                       if (!get_cached_commit_buffer(r, commit, NULL)) {
+                       if (save_commit_buffer &&
+                           !get_cached_commit_buffer(r, commit, NULL)) {
                                set_commit_buffer(r, commit, buffer, size);
                                *eaten_p = 1;
                        }
@@ -263,8 +264,11 @@ struct object *parse_object_or_die(const struct object_id *oid,
        die(_("unable to parse object: %s"), name ? name : oid_to_hex(oid));
 }
 
-struct object *parse_object(struct repository *r, const struct object_id *oid)
+struct object *parse_object_with_flags(struct repository *r,
+                                      const struct object_id *oid,
+                                      enum parse_object_flags flags)
 {
+       int skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK);
        unsigned long size;
        enum object_type type;
        int eaten;
@@ -276,10 +280,16 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)
        if (obj && obj->parsed)
                return obj;
 
+       if (skip_hash) {
+               struct commit *commit = lookup_commit_in_graph(r, repl);
+               if (commit)
+                       return &commit->object;
+       }
+
        if ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||
            (!obj && repo_has_object_file(r, oid) &&
             oid_object_info(r, oid, NULL) == OBJ_BLOB)) {
-               if (stream_object_signature(r, repl) < 0) {
+               if (!skip_hash && stream_object_signature(r, repl) < 0) {
                        error(_("hash mismatch %s"), oid_to_hex(oid));
                        return NULL;
                }
@@ -289,7 +299,8 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)
 
        buffer = repo_read_object_file(r, oid, &type, &size);
        if (buffer) {
-               if (check_object_signature(r, repl, buffer, size, type) < 0) {
+               if (!skip_hash &&
+                   check_object_signature(r, repl, buffer, size, type) < 0) {
                        free(buffer);
                        error(_("hash mismatch %s"), oid_to_hex(repl));
                        return NULL;
@@ -304,6 +315,11 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)
        return NULL;
 }
 
+struct object *parse_object(struct repository *r, const struct object_id *oid)
+{
+       return parse_object_with_flags(r, oid, 0);
+}
+
 struct object_list *object_list_insert(struct object *item,
                                       struct object_list **list_p)
 {
index a2219464c2b31043692fb9c0d224fdf0b1c2c253..31ebe114585bb14cb95f4c74486635754d199955 100644 (file)
--- a/object.h
+++ b/object.h
@@ -59,7 +59,7 @@ struct object_array {
 
 /*
  * object flag allocation:
- * revision.h:               0---------10         15             23------26
+ * revision.h:               0---------10         15             23------27
  * fetch-pack.c:             01    67
  * negotiator/default.c:       2--5
  * walker.c:                 0-2
@@ -128,7 +128,13 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet);
  *
  * Returns NULL if the object is missing or corrupt.
  */
+enum parse_object_flags {
+       PARSE_OBJECT_SKIP_HASH_CHECK = 1 << 0,
+};
 struct object *parse_object(struct repository *r, const struct object_id *oid);
+struct object *parse_object_with_flags(struct repository *r,
+                                      const struct object_id *oid,
+                                      enum parse_object_flags flags);
 
 /*
  * Like parse_object, but will die() instead of returning NULL. If the
index 286a04a53c20119fe567eec4accbaba4d9f04a97..49965fe856814393c9381788dced2b05d35aed1f 100644 (file)
--- a/oidmap.c
+++ b/oidmap.c
@@ -1,7 +1,7 @@
 #include "cache.h"
 #include "oidmap.h"
 
-static int oidmap_neq(const void *hashmap_cmp_fn_data,
+static int oidmap_neq(const void *hashmap_cmp_fn_data UNUSED,
                      const struct hashmap_entry *e1,
                      const struct hashmap_entry *e2,
                      const void *keydata)
diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore
new file mode 100644 (file)
index 0000000..9acb744
--- /dev/null
@@ -0,0 +1,3 @@
+fuzz-commit-graph
+fuzz-pack-headers
+fuzz-pack-idx
diff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c
new file mode 100644 (file)
index 0000000..914026f
--- /dev/null
@@ -0,0 +1,27 @@
+#include "commit-graph.h"
+#include "repository.h"
+
+struct commit_graph *parse_commit_graph(struct repo_settings *s,
+                                       void *graph_map, size_t graph_size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+       struct commit_graph *g;
+
+       initialize_the_repository();
+       /*
+        * Initialize the_repository with commit-graph settings that would
+        * normally be read from the repository's gitdir. We want to avoid
+        * touching the disk to keep the individual fuzz-test cases as fast as
+        * possible.
+        */
+       the_repository->settings.commit_graph_generation_version = 2;
+       the_repository->settings.commit_graph_read_changed_paths = 1;
+       g = parse_commit_graph(&the_repository->settings, (void *)data, size);
+       repo_clear(the_repository);
+       free_commit_graph(g);
+
+       return 0;
+}
similarity index 100%
rename from fuzz-pack-idx.c
rename to oss-fuzz/fuzz-pack-idx.c
index c43375bd344f22473adcd7cac09c9f1572e27079..a213f5eddc5df2401f1232f37514050ea91efc31 100644 (file)
@@ -649,21 +649,18 @@ static const struct object_id *oid_access(size_t pos, const void *table)
 }
 
 static void write_selected_commits_v1(struct hashfile *f,
-                                     struct pack_idx_entry **index,
-                                     uint32_t index_nr)
+                                     uint32_t *commit_positions,
+                                     off_t *offsets)
 {
        int i;
 
        for (i = 0; i < writer.selected_nr; ++i) {
                struct bitmapped_commit *stored = &writer.selected[i];
 
-               int commit_pos =
-                       oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
+               if (offsets)
+                       offsets[i] = hashfile_total(f);
 
-               if (commit_pos < 0)
-                       BUG("trying to write commit not in index");
-
-               hashwrite_be32(f, commit_pos);
+               hashwrite_be32(f, commit_positions[i]);
                hashwrite_u8(f, stored->xor_offset);
                hashwrite_u8(f, stored->flags);
 
@@ -671,6 +668,79 @@ static void write_selected_commits_v1(struct hashfile *f,
        }
 }
 
+static int table_cmp(const void *_va, const void *_vb, void *_data)
+{
+       uint32_t *commit_positions = _data;
+       uint32_t a = commit_positions[*(uint32_t *)_va];
+       uint32_t b = commit_positions[*(uint32_t *)_vb];
+
+       if (a > b)
+               return 1;
+       else if (a < b)
+               return -1;
+
+       return 0;
+}
+
+static void write_lookup_table(struct hashfile *f,
+                              uint32_t *commit_positions,
+                              off_t *offsets)
+{
+       uint32_t i;
+       uint32_t *table, *table_inv;
+
+       ALLOC_ARRAY(table, writer.selected_nr);
+       ALLOC_ARRAY(table_inv, writer.selected_nr);
+
+       for (i = 0; i < writer.selected_nr; i++)
+               table[i] = i;
+
+       /*
+        * At the end of this sort table[j] = i means that the i'th
+        * bitmap corresponds to j'th bitmapped commit (among the selected
+        * commits) in lex order of OIDs.
+        */
+       QSORT_S(table, writer.selected_nr, table_cmp, commit_positions);
+
+       /* table_inv helps us discover that relationship (i'th bitmap
+        * to j'th commit by j = table_inv[i])
+        */
+       for (i = 0; i < writer.selected_nr; i++)
+               table_inv[table[i]] = i;
+
+       trace2_region_enter("pack-bitmap-write", "writing_lookup_table", the_repository);
+       for (i = 0; i < writer.selected_nr; i++) {
+               struct bitmapped_commit *selected = &writer.selected[table[i]];
+               uint32_t xor_offset = selected->xor_offset;
+               uint32_t xor_row;
+
+               if (xor_offset) {
+                       /*
+                        * xor_index stores the index (in the bitmap entries)
+                        * of the corresponding xor bitmap. But we need to convert
+                        * this index into lookup table's index. So, table_inv[xor_index]
+                        * gives us the index position w.r.t. the lookup table.
+                        *
+                        * If "k = table[i] - xor_offset" then the xor base is the k'th
+                        * bitmap. `table_inv[k]` gives us the position of that bitmap
+                        * in the lookup table.
+                        */
+                       uint32_t xor_index = table[i] - xor_offset;
+                       xor_row = table_inv[xor_index];
+               } else {
+                       xor_row = 0xffffffff;
+               }
+
+               hashwrite_be32(f, commit_positions[table[i]]);
+               hashwrite_be64(f, (uint64_t)offsets[table[i]]);
+               hashwrite_be32(f, xor_row);
+       }
+       trace2_region_leave("pack-bitmap-write", "writing_lookup_table", the_repository);
+
+       free(table);
+       free(table_inv);
+}
+
 static void write_hash_cache(struct hashfile *f,
                             struct pack_idx_entry **index,
                             uint32_t index_nr)
@@ -683,7 +753,7 @@ static void write_hash_cache(struct hashfile *f,
        }
 }
 
-void bitmap_writer_set_checksum(unsigned char *sha1)
+void bitmap_writer_set_checksum(const unsigned char *sha1)
 {
        hashcpy(writer.pack_checksum, sha1);
 }
@@ -697,6 +767,9 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
        static uint16_t flags = BITMAP_OPT_FULL_DAG;
        struct strbuf tmp_file = STRBUF_INIT;
        struct hashfile *f;
+       uint32_t *commit_positions = NULL;
+       off_t *offsets = NULL;
+       uint32_t i;
 
        struct bitmap_disk_header header;
 
@@ -715,7 +788,26 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
        dump_bitmap(f, writer.trees);
        dump_bitmap(f, writer.blobs);
        dump_bitmap(f, writer.tags);
-       write_selected_commits_v1(f, index, index_nr);
+
+       if (options & BITMAP_OPT_LOOKUP_TABLE)
+               CALLOC_ARRAY(offsets, index_nr);
+
+       ALLOC_ARRAY(commit_positions, writer.selected_nr);
+
+       for (i = 0; i < writer.selected_nr; i++) {
+               struct bitmapped_commit *stored = &writer.selected[i];
+               int commit_pos = oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
+
+               if (commit_pos < 0)
+                       BUG(_("trying to write commit not in index"));
+
+               commit_positions[i] = commit_pos;
+       }
+
+       write_selected_commits_v1(f, commit_positions, offsets);
+
+       if (options & BITMAP_OPT_LOOKUP_TABLE)
+               write_lookup_table(f, commit_positions, offsets);
 
        if (options & BITMAP_OPT_HASH_CACHE)
                write_hash_cache(f, index, index_nr);
@@ -730,4 +822,6 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
                die_errno("unable to rename temporary bitmap file to '%s'", filename);
 
        strbuf_release(&tmp_file);
+       free(commit_positions);
+       free(offsets);
 }
index 36134222d7a00acc1ebf5d52b3c3d817c10af8e9..440407f1be742c7e2a19a62f5adb968d409bcc29 100644 (file)
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "commit.h"
+#include "strbuf.h"
 #include "tag.h"
 #include "diff.h"
 #include "revision.h"
@@ -82,6 +83,12 @@ struct bitmap_index {
        /* The checksum of the packfile or MIDX; points into map. */
        const unsigned char *checksum;
 
+       /*
+        * If not NULL, this point into the commit table extension
+        * (within the memory mapped region `map`).
+        */
+       unsigned char *table_lookup;
+
        /*
         * Extended index.
         *
@@ -138,7 +145,7 @@ static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
                index->map_size - index->map_pos);
 
        if (bitmap_size < 0) {
-               error("Failed to load bitmap index (corrupted?)");
+               error(_("failed to load bitmap index (corrupted?)"));
                ewah_pool_free(b);
                return NULL;
        }
@@ -160,14 +167,14 @@ static int load_bitmap_header(struct bitmap_index *index)
        size_t header_size = sizeof(*header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz;
 
        if (index->map_size < header_size + the_hash_algo->rawsz)
-               return error("Corrupted bitmap index (too small)");
+               return error(_("corrupted bitmap index (too small)"));
 
        if (memcmp(header->magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)) != 0)
-               return error("Corrupted bitmap index file (wrong header)");
+               return error(_("corrupted bitmap index file (wrong header)"));
 
        index->version = ntohs(header->version);
        if (index->version != 1)
-               return error("Unsupported version for bitmap index file (%d)", index->version);
+               return error(_("unsupported version '%d' for bitmap index file"), index->version);
 
        /* Parse known bitmap format options */
        {
@@ -176,15 +183,25 @@ static int load_bitmap_header(struct bitmap_index *index)
                unsigned char *index_end = index->map + index->map_size - the_hash_algo->rawsz;
 
                if ((flags & BITMAP_OPT_FULL_DAG) == 0)
-                       return error("Unsupported options for bitmap index file "
+                       BUG("unsupported options for bitmap index file "
                                "(Git requires BITMAP_OPT_FULL_DAG)");
 
                if (flags & BITMAP_OPT_HASH_CACHE) {
                        if (cache_size > index_end - index->map - header_size)
-                               return error("corrupted bitmap index file (too short to fit hash cache)");
+                               return error(_("corrupted bitmap index file (too short to fit hash cache)"));
                        index->hashes = (void *)(index_end - cache_size);
                        index_end -= cache_size;
                }
+
+               if (flags & BITMAP_OPT_LOOKUP_TABLE) {
+                       size_t table_size = st_mult(ntohl(header->entry_count),
+                                                   BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH);
+                       if (table_size > index_end - index->map - header_size)
+                               return error(_("corrupted bitmap index file (too short to fit lookup table)"));
+                       if (git_env_bool("GIT_TEST_READ_COMMIT_TABLE", 1))
+                               index->table_lookup = (void *)(index_end - table_size);
+                       index_end -= table_size;
+               }
        }
 
        index->entry_count = ntohl(header->entry_count);
@@ -211,11 +228,13 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
 
        hash_pos = kh_put_oid_map(index->bitmaps, stored->oid, &ret);
 
-       /* a 0 return code means the insertion succeeded with no changes,
-        * because the SHA1 already existed on the map. this is bad, there
-        * shouldn't be duplicated commits in the index */
+       /*
+        * A 0 return code means the insertion succeeded with no changes,
+        * because the SHA1 already existed on the map. This is bad, there
+        * shouldn't be duplicated commits in the index.
+        */
        if (ret == 0) {
-               error("Duplicate entry in bitmap index: %s", oid_to_hex(oid));
+               error(_("duplicate entry in bitmap index: '%s'"), oid_to_hex(oid));
                return NULL;
        }
 
@@ -259,14 +278,14 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
                struct object_id oid;
 
                if (index->map_size - index->map_pos < 6)
-                       return error("corrupt ewah bitmap: truncated header for entry %d", i);
+                       return error(_("corrupt ewah bitmap: truncated header for entry %d"), i);
 
                commit_idx_pos = read_be32(index->map, &index->map_pos);
                xor_offset = read_u8(index->map, &index->map_pos);
                flags = read_u8(index->map, &index->map_pos);
 
                if (nth_bitmap_object_oid(index, &oid, commit_idx_pos) < 0)
-                       return error("corrupt ewah bitmap: commit index %u out of range",
+                       return error(_("corrupt ewah bitmap: commit index %u out of range"),
                                     (unsigned)commit_idx_pos);
 
                bitmap = read_bitmap_1(index);
@@ -274,13 +293,13 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
                        return -1;
 
                if (xor_offset > MAX_XOR_OFFSET || xor_offset > i)
-                       return error("Corrupted bitmap pack index");
+                       return error(_("corrupted bitmap pack index"));
 
                if (xor_offset > 0) {
                        xor_bitmap = recent_bitmaps[(i - xor_offset) % MAX_XOR_OFFSET];
 
                        if (!xor_bitmap)
-                               return error("Invalid XOR offset in bitmap pack index");
+                               return error(_("invalid XOR offset in bitmap pack index"));
                }
 
                recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap(
@@ -313,17 +332,21 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
                              struct multi_pack_index *midx)
 {
        struct stat st;
-       char *idx_name = midx_bitmap_filename(midx);
-       int fd = git_open(idx_name);
+       char *bitmap_name = midx_bitmap_filename(midx);
+       int fd = git_open(bitmap_name);
        uint32_t i;
        struct packed_git *preferred;
 
-       free(idx_name);
-
-       if (fd < 0)
+       if (fd < 0) {
+               if (errno != ENOENT)
+                       warning_errno("cannot open '%s'", bitmap_name);
+               free(bitmap_name);
                return -1;
+       }
+       free(bitmap_name);
 
        if (fstat(fd, &st)) {
+               error_errno(_("cannot fstat bitmap file"));
                close(fd);
                return -1;
        }
@@ -332,7 +355,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
                struct strbuf buf = STRBUF_INIT;
                get_midx_filename(&buf, midx->object_dir);
                /* ignore extra bitmap file; we can only handle one */
-               warning("ignoring extra bitmap file: %s", buf.buf);
+               warning(_("ignoring extra bitmap file: '%s'"), buf.buf);
                close(fd);
                strbuf_release(&buf);
                return -1;
@@ -348,8 +371,10 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
        if (load_bitmap_header(bitmap_git) < 0)
                goto cleanup;
 
-       if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum))
+       if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum)) {
+               error(_("checksum doesn't match in MIDX and bitmap"));
                goto cleanup;
+       }
 
        if (load_midx_revindex(bitmap_git->midx) < 0) {
                warning(_("multi-pack bitmap is missing required reverse index"));
@@ -384,26 +409,31 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
 {
        int fd;
        struct stat st;
-       char *idx_name;
+       char *bitmap_name;
 
        if (open_pack_index(packfile))
                return -1;
 
-       idx_name = pack_bitmap_filename(packfile);
-       fd = git_open(idx_name);
-       free(idx_name);
+       bitmap_name = pack_bitmap_filename(packfile);
+       fd = git_open(bitmap_name);
 
-       if (fd < 0)
+       if (fd < 0) {
+               if (errno != ENOENT)
+                       warning_errno("cannot open '%s'", bitmap_name);
+               free(bitmap_name);
                return -1;
+       }
+       free(bitmap_name);
 
        if (fstat(fd, &st)) {
+               error_errno(_("cannot fstat bitmap file"));
                close(fd);
                return -1;
        }
 
        if (bitmap_git->pack || bitmap_git->midx) {
                /* ignore extra bitmap file; we can only handle one */
-               warning("ignoring extra bitmap file: %s", packfile->pack_name);
+               warning(_("ignoring extra bitmap file: '%s'"), packfile->pack_name);
                close(fd);
                return -1;
        }
@@ -470,7 +500,7 @@ static int load_bitmap(struct bitmap_index *bitmap_git)
                !(bitmap_git->tags = read_bitmap_1(bitmap_git)))
                goto failed;
 
-       if (load_bitmap_entries_v1(bitmap_git) < 0)
+       if (!bitmap_git->table_lookup && load_bitmap_entries_v1(bitmap_git) < 0)
                goto failed;
 
        return 0;
@@ -508,15 +538,16 @@ static int open_pack_bitmap(struct repository *r,
 static int open_midx_bitmap(struct repository *r,
                            struct bitmap_index *bitmap_git)
 {
+       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))
-                       return 0;
+                       ret = 0;
        }
-       return -1;
+       return ret;
 }
 
 static int open_bitmap(struct repository *r,
@@ -557,13 +588,255 @@ struct include_data {
        struct bitmap *seen;
 };
 
+struct bitmap_lookup_table_triplet {
+       uint32_t commit_pos;
+       uint64_t offset;
+       uint32_t xor_row;
+};
+
+struct bitmap_lookup_table_xor_item {
+       struct object_id oid;
+       uint64_t offset;
+};
+
+/*
+ * Given a `triplet` struct pointer and pointer `p`, this
+ * function reads the triplet beginning at `p` into the struct.
+ * Note that this function assumes that there is enough memory
+ * left for filling the `triplet` struct from `p`.
+ */
+static int bitmap_lookup_table_get_triplet_by_pointer(struct bitmap_lookup_table_triplet *triplet,
+                                                     const unsigned char *p)
+{
+       if (!triplet)
+               return -1;
+
+       triplet->commit_pos = get_be32(p);
+       p += sizeof(uint32_t);
+       triplet->offset = get_be64(p);
+       p += sizeof(uint64_t);
+       triplet->xor_row = get_be32(p);
+       return 0;
+}
+
+/*
+ * This function gets the raw triplet from `row`'th row in the
+ * lookup table and fills that data to the `triplet`.
+ */
+static int bitmap_lookup_table_get_triplet(struct bitmap_index *bitmap_git,
+                                          uint32_t pos,
+                                          struct bitmap_lookup_table_triplet *triplet)
+{
+       unsigned char *p = NULL;
+       if (pos >= bitmap_git->entry_count)
+               return error(_("corrupt bitmap lookup table: triplet position out of index"));
+
+       p = bitmap_git->table_lookup + st_mult(pos, BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH);
+
+       return bitmap_lookup_table_get_triplet_by_pointer(triplet, p);
+}
+
+/*
+ * Searches for a matching triplet. `commit_pos` is a pointer
+ * to the wanted commit position value. `table_entry` points to
+ * a triplet in lookup table. The first 4 bytes of each
+ * triplet (pointed by `table_entry`) are compared with `*commit_pos`.
+ */
+static int triplet_cmp(const void *commit_pos, const void *table_entry)
+{
+
+       uint32_t a = *(uint32_t *)commit_pos;
+       uint32_t b = get_be32(table_entry);
+       if (a > b)
+               return 1;
+       else if (a < b)
+               return -1;
+
+       return 0;
+}
+
+static uint32_t bitmap_bsearch_pos(struct bitmap_index *bitmap_git,
+                           struct object_id *oid,
+                           uint32_t *result)
+{
+       int found;
+
+       if (bitmap_is_midx(bitmap_git))
+               found = bsearch_midx(oid, bitmap_git->midx, result);
+       else
+               found = bsearch_pack(oid, bitmap_git->pack, result);
+
+       return found;
+}
+
+/*
+ * `bsearch_triplet_by_pos` function searches for the raw triplet
+ * having commit position same as `commit_pos` and fills `triplet`
+ * object from the raw triplet. Returns 1 on success and 0 on
+ * failure.
+ */
+static int bitmap_bsearch_triplet_by_pos(uint32_t commit_pos,
+                                 struct bitmap_index *bitmap_git,
+                                 struct bitmap_lookup_table_triplet *triplet)
+{
+       unsigned char *p = bsearch(&commit_pos, bitmap_git->table_lookup, bitmap_git->entry_count,
+                                  BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH, triplet_cmp);
+
+       if (!p)
+               return -1;
+
+       return bitmap_lookup_table_get_triplet_by_pointer(triplet, p);
+}
+
+static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_git,
+                                                   struct commit *commit)
+{
+       uint32_t commit_pos, xor_row;
+       uint64_t offset;
+       int flags;
+       struct bitmap_lookup_table_triplet triplet;
+       struct object_id *oid = &commit->object.oid;
+       struct ewah_bitmap *bitmap;
+       struct stored_bitmap *xor_bitmap = NULL;
+       const int bitmap_header_size = 6;
+       static struct bitmap_lookup_table_xor_item *xor_items = NULL;
+       static size_t xor_items_nr = 0, xor_items_alloc = 0;
+       static int is_corrupt = 0;
+       int xor_flags;
+       khiter_t hash_pos;
+       struct bitmap_lookup_table_xor_item *xor_item;
+
+       if (is_corrupt)
+               return NULL;
+
+       if (!bitmap_bsearch_pos(bitmap_git, oid, &commit_pos))
+               return NULL;
+
+       if (bitmap_bsearch_triplet_by_pos(commit_pos, bitmap_git, &triplet) < 0)
+               return NULL;
+
+       xor_items_nr = 0;
+       offset = triplet.offset;
+       xor_row = triplet.xor_row;
+
+       while (xor_row != 0xffffffff) {
+               ALLOC_GROW(xor_items, xor_items_nr + 1, xor_items_alloc);
+
+               if (xor_items_nr + 1 >= bitmap_git->entry_count) {
+                       error(_("corrupt bitmap lookup table: xor chain exceeds entry count"));
+                       goto corrupt;
+               }
+
+               if (bitmap_lookup_table_get_triplet(bitmap_git, xor_row, &triplet) < 0)
+                       goto corrupt;
+
+               xor_item = &xor_items[xor_items_nr];
+               xor_item->offset = triplet.offset;
+
+               if (nth_bitmap_object_oid(bitmap_git, &xor_item->oid, triplet.commit_pos) < 0) {
+                       error(_("corrupt bitmap lookup table: commit index %u out of range"),
+                               triplet.commit_pos);
+                       goto corrupt;
+               }
+
+               hash_pos = kh_get_oid_map(bitmap_git->bitmaps, xor_item->oid);
+
+               /*
+                * If desired bitmap is already stored, we don't need
+                * to iterate further. Because we know that bitmaps
+                * that are needed to be parsed to parse this bitmap
+                * has already been stored. So, assign this stored bitmap
+                * to the xor_bitmap.
+                */
+               if (hash_pos < kh_end(bitmap_git->bitmaps) &&
+                       (xor_bitmap = kh_value(bitmap_git->bitmaps, hash_pos)))
+                       break;
+               xor_items_nr++;
+               xor_row = triplet.xor_row;
+       }
+
+       while (xor_items_nr) {
+               xor_item = &xor_items[xor_items_nr - 1];
+               bitmap_git->map_pos = xor_item->offset;
+               if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) {
+                       error(_("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""),
+                               oid_to_hex(&xor_item->oid));
+                       goto corrupt;
+               }
+
+               bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
+               xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
+               bitmap = read_bitmap_1(bitmap_git);
+
+               if (!bitmap)
+                       goto corrupt;
+
+               xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags);
+               xor_items_nr--;
+       }
+
+       bitmap_git->map_pos = offset;
+       if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) {
+               error(_("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""),
+                       oid_to_hex(oid));
+               goto corrupt;
+       }
+
+       /*
+        * Don't bother reading the commit's index position or its xor
+        * offset:
+        *
+        *   - The commit's index position is irrelevant to us, since
+        *     load_bitmap_entries_v1 only uses it to learn the object
+        *     id which is used to compute the hashmap's key. We already
+        *     have an object id, so no need to look it up again.
+        *
+        *   - The xor_offset is unusable for us, since it specifies how
+        *     many entries previous to ours we should look at. This
+        *     makes sense when reading the bitmaps sequentially (as in
+        *     load_bitmap_entries_v1()), since we can keep track of
+        *     each bitmap as we read them.
+        *
+        *     But it can't work for us, since the bitmap's don't have a
+        *     fixed size. So we learn the position of the xor'd bitmap
+        *     from the commit table (and resolve it to a bitmap in the
+        *     above if-statement).
+        *
+        * Instead, we can skip ahead and immediately read the flags and
+        * ewah bitmap.
+        */
+       bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
+       flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
+       bitmap = read_bitmap_1(bitmap_git);
+
+       if (!bitmap)
+               goto corrupt;
+
+       return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags);
+
+corrupt:
+       free(xor_items);
+       is_corrupt = 1;
+       return NULL;
+}
+
 struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git,
                                      struct commit *commit)
 {
        khiter_t hash_pos = kh_get_oid_map(bitmap_git->bitmaps,
                                           commit->object.oid);
-       if (hash_pos >= kh_end(bitmap_git->bitmaps))
-               return NULL;
+       if (hash_pos >= kh_end(bitmap_git->bitmaps)) {
+               struct stored_bitmap *bitmap = NULL;
+               if (!bitmap_git->table_lookup)
+                       return NULL;
+
+               /* this is a fairly hot codepath - no trace2_region please */
+               /* NEEDSWORK: cache misses aren't recorded */
+               bitmap = lazy_bitmap_for_commit(bitmap_git, commit);
+               if (!bitmap)
+                       return NULL;
+               return lookup_stored_bitmap(bitmap);
+       }
        return lookup_stored_bitmap(kh_value(bitmap_git->bitmaps, hash_pos));
 }
 
@@ -831,7 +1104,7 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
                revs->include_check_data = &incdata;
 
                if (prepare_revision_walk(revs))
-                       die("revision walk setup failed");
+                       die(_("revision walk setup failed"));
 
                show_data.bitmap_git = bitmap_git;
                show_data.base = base;
@@ -1640,15 +1913,15 @@ static void test_bitmap_type(struct bitmap_test_data *tdata,
        }
 
        if (bitmap_type == OBJ_NONE)
-               die("object %s not found in type bitmaps",
+               die(_("object '%s' not found in type bitmaps"),
                    oid_to_hex(&obj->oid));
 
        if (bitmaps_nr > 1)
-               die("object %s does not have a unique type",
+               die(_("object '%s' does not have a unique type"),
                    oid_to_hex(&obj->oid));
 
        if (bitmap_type != obj->type)
-               die("object %s: real type %s, expected: %s",
+               die(_("object '%s': real type '%s', expected: '%s'"),
                    oid_to_hex(&obj->oid),
                    type_name(obj->type),
                    type_name(bitmap_type));
@@ -1662,7 +1935,7 @@ static void test_show_object(struct object *object, const char *name,
 
        bitmap_pos = bitmap_position(tdata->bitmap_git, &object->oid);
        if (bitmap_pos < 0)
-               die("Object not in bitmap: %s\n", oid_to_hex(&object->oid));
+               die(_("object not in bitmap: '%s'"), oid_to_hex(&object->oid));
        test_bitmap_type(tdata, object, bitmap_pos);
 
        bitmap_set(tdata->base, bitmap_pos);
@@ -1677,7 +1950,7 @@ static void test_show_commit(struct commit *commit, void *data)
        bitmap_pos = bitmap_position(tdata->bitmap_git,
                                     &commit->object.oid);
        if (bitmap_pos < 0)
-               die("Object not in bitmap: %s\n", oid_to_hex(&commit->object.oid));
+               die(_("object not in bitmap: '%s'"), oid_to_hex(&commit->object.oid));
        test_bitmap_type(tdata, &commit->object, bitmap_pos);
 
        bitmap_set(tdata->base, bitmap_pos);
@@ -1694,26 +1967,28 @@ void test_bitmap_walk(struct rev_info *revs)
        struct ewah_bitmap *bm;
 
        if (!(bitmap_git = prepare_bitmap_git(revs->repo)))
-               die("failed to load bitmap indexes");
+               die(_("failed to load bitmap indexes"));
 
        if (revs->pending.nr != 1)
-               die("you must specify exactly one commit to test");
+               die(_("you must specify exactly one commit to test"));
 
-       fprintf(stderr, "Bitmap v%d test (%d entries loaded)\n",
-               bitmap_git->version, bitmap_git->entry_count);
+       fprintf_ln(stderr, "Bitmap v%d test (%d entries%s)",
+               bitmap_git->version,
+               bitmap_git->entry_count,
+               bitmap_git->table_lookup ? "" : " loaded");
 
        root = revs->pending.objects[0].item;
        bm = bitmap_for_commit(bitmap_git, (struct commit *)root);
 
        if (bm) {
-               fprintf(stderr, "Found bitmap for %s. %d bits / %08x checksum\n",
+               fprintf_ln(stderr, "Found bitmap for '%s'. %d bits / %08x checksum",
                        oid_to_hex(&root->oid), (int)bm->bit_size, ewah_checksum(bm));
 
                result = ewah_to_bitmap(bm);
        }
 
        if (!result)
-               die("Commit %s doesn't have an indexed bitmap", oid_to_hex(&root->oid));
+               die(_("commit '%s' doesn't have an indexed bitmap"), oid_to_hex(&root->oid));
 
        revs->tag_objects = 1;
        revs->tree_objects = 1;
@@ -1722,7 +1997,7 @@ void test_bitmap_walk(struct rev_info *revs)
        result_popcnt = bitmap_popcount(result);
 
        if (prepare_revision_walk(revs))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
 
        tdata.bitmap_git = bitmap_git;
        tdata.base = bitmap_new();
@@ -1738,9 +2013,9 @@ void test_bitmap_walk(struct rev_info *revs)
        stop_progress(&tdata.prg);
 
        if (bitmap_equals(result, tdata.base))
-               fprintf(stderr, "OK!\n");
+               fprintf_ln(stderr, "OK!");
        else
-               die("mismatch in bitmap results");
+               die(_("mismatch in bitmap results"));
 
        bitmap_free(result);
        bitmap_free(tdata.base);
@@ -1753,15 +2028,24 @@ void test_bitmap_walk(struct rev_info *revs)
 
 int test_bitmap_commits(struct repository *r)
 {
-       struct bitmap_index *bitmap_git = prepare_bitmap_git(r);
        struct object_id oid;
        MAYBE_UNUSED void *value;
+       struct bitmap_index *bitmap_git = prepare_bitmap_git(r);
 
        if (!bitmap_git)
-               die("failed to load bitmap indexes");
+               die(_("failed to load bitmap indexes"));
+
+       /*
+        * As this function is only used to print bitmap selected
+        * commits, we don't have to read the commit table.
+        */
+       if (bitmap_git->table_lookup) {
+               if (load_bitmap_entries_v1(bitmap_git) < 0)
+                       die(_("failed to load bitmap indexes"));
+       }
 
        kh_foreach(bitmap_git->bitmaps, oid, value, {
-               printf("%s\n", oid_to_hex(&oid));
+               printf_ln("%s", oid_to_hex(&oid));
        });
 
        free_bitmap_index(bitmap_git);
@@ -1786,7 +2070,7 @@ int test_bitmap_hashes(struct repository *r)
 
                nth_bitmap_object_oid(bitmap_git, &oid, index_pos);
 
-               printf("%s %"PRIu32"\n",
+               printf_ln("%s %"PRIu32"",
                       oid_to_hex(&oid), get_be32(bitmap_git->hashes + index_pos));
        }
 
@@ -1948,7 +2232,7 @@ static off_t get_disk_usage_for_type(struct bitmap_index *bitmap_git,
                                        struct object_id oid;
                                        nth_midxed_object_oid(&oid, bitmap_git->midx, midx_pos);
 
-                                       die(_("could not find %s in pack %s at offset %"PRIuMAX),
+                                       die(_("could not find '%s' in pack '%s' at offset %"PRIuMAX),
                                            oid_to_hex(&oid),
                                            pack->pack_name,
                                            (uintmax_t)offset);
@@ -1984,7 +2268,7 @@ static off_t get_disk_usage_for_extended(struct bitmap_index *bitmap_git)
                        continue;
 
                if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
-                       die(_("unable to get disk usage of %s"),
+                       die(_("unable to get disk usage of '%s'"),
                            oid_to_hex(&obj->oid));
 
                total += object_size;
index 3d3ddd77345002f3075047b1f0bf545a4e229157..f0180b5276b15d6567eda9984637333811fa851b 100644 (file)
@@ -23,9 +23,19 @@ struct bitmap_disk_header {
 
 #define NEEDS_BITMAP (1u<<22)
 
+/*
+ * The width in bytes of a single triplet in the lookup table
+ * extension:
+ *     (commit_pos, offset, xor_row)
+ *
+ * whose fields ar 32-, 64-, 32- bits wide, respectively.
+ */
+#define BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH (16)
+
 enum pack_bitmap_opts {
-       BITMAP_OPT_FULL_DAG = 1,
-       BITMAP_OPT_HASH_CACHE = 4,
+       BITMAP_OPT_FULL_DAG = 0x1,
+       BITMAP_OPT_HASH_CACHE = 0x4,
+       BITMAP_OPT_LOOKUP_TABLE = 0x10,
 };
 
 enum pack_bitmap_flags {
@@ -75,7 +85,7 @@ int bitmap_has_oid_in_uninteresting(struct bitmap_index *, const struct object_i
 off_t get_disk_usage_from_bitmap(struct bitmap_index *, struct rev_info *);
 
 void bitmap_writer_show_progress(int show);
-void bitmap_writer_set_checksum(unsigned char *sha1);
+void bitmap_writer_set_checksum(const unsigned char *sha1);
 void bitmap_writer_build_type_index(struct packing_data *to_pack,
                                    struct pack_idx_entry **index,
                                    uint32_t index_nr);
index 74f4eae668d5555f99fa4d6af0f486ddc94b5447..4974e75eb4d0e9d002fc70a87e5bb4526e1e49f7 100644 (file)
@@ -22,7 +22,7 @@
  *
  *   - pack position refers to an object's position within a non-existent pack
  *     described by the MIDX. The pack structure is described in
- *     Documentation/technical/pack-format.txt.
+ *     gitformat-pack(5).
  *
  *     It is effectively a concatanation of all packs in the MIDX (ordered by
  *     their numeric ID within the MIDX) in their original order within each
index 75c254e0e0cbdb00cb7f41056060d3c7e91021aa..c0d7dd93f46dfbc07ea0f17839d4a2d1a9d43622 100644 (file)
@@ -941,20 +941,10 @@ unsigned long repo_approximate_object_count(struct repository *r)
        return r->objects->approximate_object_count;
 }
 
-static void *get_next_packed_git(const void *p)
-{
-       return ((const struct packed_git *)p)->next;
-}
-
-static void set_next_packed_git(void *p, void *next)
-{
-       ((struct packed_git *)p)->next = next;
-}
+DEFINE_LIST_SORT(static, sort_packs, struct packed_git, next);
 
-static int sort_pack(const void *a_, const void *b_)
+static int sort_pack(const struct packed_git *a, const struct packed_git *b)
 {
-       const struct packed_git *a = a_;
-       const struct packed_git *b = b_;
        int st;
 
        /*
@@ -981,9 +971,7 @@ static int sort_pack(const void *a_, const void *b_)
 
 static void rearrange_packed_git(struct repository *r)
 {
-       r->objects->packed_git = llist_mergesort(
-               r->objects->packed_git, get_next_packed_git,
-               set_next_packed_git, sort_pack);
+       sort_packs(&r->objects->packed_git, sort_pack);
 }
 
 static void prepare_packed_git_mru(struct repository *r)
@@ -1404,7 +1392,7 @@ static int delta_base_cache_key_eq(const struct delta_base_cache_key *a,
        return a->p == b->p && a->base_offset == b->base_offset;
 }
 
-static int delta_base_cache_hash_cmp(const void *unused_cmp_data,
+static int delta_base_cache_hash_cmp(const void *cmp_data UNUSED,
                                     const struct hashmap_entry *va,
                                     const struct hashmap_entry *vb,
                                     const void *vkey)
@@ -2286,7 +2274,8 @@ int is_promisor_object(const struct object_id *oid)
                if (has_promisor_remote()) {
                        for_each_packed_object(add_promisor_object,
                                               &promisor_objects,
-                                              FOR_EACH_OBJECT_PROMISOR_ONLY);
+                                              FOR_EACH_OBJECT_PROMISOR_ONLY |
+                                              FOR_EACH_OBJECT_PACK_ORDER);
                }
                promisor_objects_prepared = 1;
        }
diff --git a/pager.c b/pager.c
index 5cfe23b025c77b08715591c3893017111c2a697d..b66bbff2785cb6ed032edb4f0d9cd68f6a841c36 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -38,7 +38,8 @@ static void wait_for_pager_signal(int signo)
        raise(signo);
 }
 
-static int core_pager_config(const char *var, const char *value, void *data)
+static int core_pager_config(const char *var, const char *value,
+                            void *data UNUSED)
 {
        if (!strcmp(var, "core.pager"))
                return git_config_string(&pager_program, var, value);
index edf55d3ef5d7428b68e793d6d684c0299710c628..a1ec932f0f9ff32e82223735dfd927473051fd3b 100644 (file)
@@ -324,6 +324,8 @@ static enum parse_opt_result parse_long_opt(
                const char *rest, *long_name = options->long_name;
                enum opt_parsed flags = OPT_LONG, opt_flags = OPT_LONG;
 
+               if (options->type == OPTION_SUBCOMMAND)
+                       continue;
                if (!long_name)
                        continue;
 
@@ -332,7 +334,7 @@ again:
                        rest = NULL;
                if (!rest) {
                        /* abbreviated? */
-                       if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) &&
+                       if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT) &&
                            !strncmp(long_name, arg, arg_end - arg)) {
 is_abbreviated:
                                if (abbrev_option &&
@@ -419,6 +421,19 @@ static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p,
        return PARSE_OPT_ERROR;
 }
 
+static enum parse_opt_result parse_subcommand(const char *arg,
+                                             const struct option *options)
+{
+       for (; options->type != OPTION_END; options++)
+               if (options->type == OPTION_SUBCOMMAND &&
+                   !strcmp(options->long_name, arg)) {
+                       *(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;
+                       return PARSE_OPT_SUBCOMMAND;
+               }
+
+       return PARSE_OPT_UNKNOWN;
+}
+
 static void check_typos(const char *arg, const struct option *options)
 {
        if (strlen(arg) < 3)
@@ -442,6 +457,7 @@ static void check_typos(const char *arg, const struct option *options)
 static void parse_options_check(const struct option *opts)
 {
        char short_opts[128];
+       void *subcommand_value = NULL;
 
        memset(short_opts, '\0', sizeof(short_opts));
        for (; opts->type != OPTION_END; opts++) {
@@ -489,6 +505,14 @@ static void parse_options_check(const struct option *opts)
                               "Are you using parse_options_step() directly?\n"
                               "That case is not supported yet.");
                        break;
+               case OPTION_SUBCOMMAND:
+                       if (!opts->value || !opts->subcommand_fn)
+                               optbug(opts, "OPTION_SUBCOMMAND needs a value and a subcommand function");
+                       if (!subcommand_value)
+                               subcommand_value = opts->value;
+                       else if (subcommand_value != opts->value)
+                               optbug(opts, "all OPTION_SUBCOMMANDs need the same value");
+                       break;
                default:
                        ; /* ok. (usually accepts an argument) */
                }
@@ -499,6 +523,14 @@ static void parse_options_check(const struct option *opts)
        BUG_if_bug("invalid 'struct option'");
 }
 
+static int has_subcommands(const struct option *options)
+{
+       for (; options->type != OPTION_END; options++)
+               if (options->type == OPTION_SUBCOMMAND)
+                       return 1;
+       return 0;
+}
+
 static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
                                  int argc, const char **argv, const char *prefix,
                                  const struct option *options,
@@ -515,7 +547,20 @@ static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
        ctx->prefix = prefix;
        ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
        ctx->flags = flags;
-       if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+       ctx->has_subcommands = has_subcommands(options);
+       if (!ctx->has_subcommands && (flags & PARSE_OPT_SUBCOMMAND_OPTIONAL))
+               BUG("Using PARSE_OPT_SUBCOMMAND_OPTIONAL without subcommands");
+       if (ctx->has_subcommands) {
+               if (flags & PARSE_OPT_STOP_AT_NON_OPTION)
+                       BUG("subcommands are incompatible with PARSE_OPT_STOP_AT_NON_OPTION");
+               if (!(flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) {
+                       if (flags & PARSE_OPT_KEEP_UNKNOWN_OPT)
+                               BUG("subcommands are incompatible with PARSE_OPT_KEEP_UNKNOWN_OPT unless in combination with PARSE_OPT_SUBCOMMAND_OPTIONAL");
+                       if (flags & PARSE_OPT_KEEP_DASHDASH)
+                               BUG("subcommands are incompatible with PARSE_OPT_KEEP_DASHDASH unless in combination with PARSE_OPT_SUBCOMMAND_OPTIONAL");
+               }
+       }
+       if ((flags & PARSE_OPT_KEEP_UNKNOWN_OPT) &&
            (flags & PARSE_OPT_STOP_AT_NON_OPTION) &&
            !(flags & PARSE_OPT_ONE_SHOT))
                BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
@@ -589,6 +634,7 @@ static int show_gitcomp(const struct option *opts, int show_all)
        int nr_noopts = 0;
 
        for (; opts->type != OPTION_END; opts++) {
+               const char *prefix = "--";
                const char *suffix = "";
 
                if (!opts->long_name)
@@ -598,6 +644,9 @@ static int show_gitcomp(const struct option *opts, int show_all)
                        continue;
 
                switch (opts->type) {
+               case OPTION_SUBCOMMAND:
+                       prefix = "";
+                       break;
                case OPTION_GROUP:
                        continue;
                case OPTION_STRING:
@@ -620,7 +669,8 @@ static int show_gitcomp(const struct option *opts, int show_all)
                        suffix = "=";
                if (starts_with(opts->long_name, "no-"))
                        nr_noopts++;
-               printf(" --%s%s", opts->long_name, suffix);
+               printf("%s%s%s%s", opts == original_opts ? "" : " ",
+                      prefix, opts->long_name, suffix);
        }
        show_negated_gitcomp(original_opts, show_all, -1);
        show_negated_gitcomp(original_opts, show_all, nr_noopts);
@@ -743,10 +793,38 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
                if (*arg != '-' || !arg[1]) {
                        if (parse_nodash_opt(ctx, arg, options) == 0)
                                continue;
-                       if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
-                               return PARSE_OPT_NON_OPTION;
-                       ctx->out[ctx->cpidx++] = ctx->argv[0];
-                       continue;
+                       if (!ctx->has_subcommands) {
+                               if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
+                                       return PARSE_OPT_NON_OPTION;
+                               ctx->out[ctx->cpidx++] = ctx->argv[0];
+                               continue;
+                       }
+                       switch (parse_subcommand(arg, options)) {
+                       case PARSE_OPT_SUBCOMMAND:
+                               return PARSE_OPT_SUBCOMMAND;
+                       case PARSE_OPT_UNKNOWN:
+                               if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
+                                       /*
+                                        * arg is neither a short or long
+                                        * option nor a subcommand.  Since
+                                        * this command has a default
+                                        * operation mode, we have to treat
+                                        * this arg and all remaining args
+                                        * as args meant to that default
+                                        * operation mode.
+                                        * So we are done parsing.
+                                        */
+                                       return PARSE_OPT_DONE;
+                               error(_("unknown subcommand: `%s'"), arg);
+                               usage_with_options(usagestr, options);
+                       case PARSE_OPT_COMPLETE:
+                       case PARSE_OPT_HELP:
+                       case PARSE_OPT_ERROR:
+                       case PARSE_OPT_DONE:
+                       case PARSE_OPT_NON_OPTION:
+                               /* Impossible. */
+                               BUG("parse_subcommand() cannot return these");
+                       }
                }
 
                /* lone -h asks for help */
@@ -774,6 +852,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
                                        goto show_usage;
                                goto unknown;
                        case PARSE_OPT_NON_OPTION:
+                       case PARSE_OPT_SUBCOMMAND:
                        case PARSE_OPT_HELP:
                        case PARSE_OPT_COMPLETE:
                                BUG("parse_short_opt() cannot return these");
@@ -799,6 +878,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
                                        *(char *)ctx->argv[0] = '-';
                                        goto unknown;
                                case PARSE_OPT_NON_OPTION:
+                               case PARSE_OPT_SUBCOMMAND:
                                case PARSE_OPT_COMPLETE:
                                case PARSE_OPT_HELP:
                                        BUG("parse_short_opt() cannot return these");
@@ -830,6 +910,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
                case PARSE_OPT_HELP:
                        goto show_usage;
                case PARSE_OPT_NON_OPTION:
+               case PARSE_OPT_SUBCOMMAND:
                case PARSE_OPT_COMPLETE:
                        BUG("parse_long_opt() cannot return these");
                case PARSE_OPT_DONE:
@@ -839,7 +920,19 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
 unknown:
                if (ctx->flags & PARSE_OPT_ONE_SHOT)
                        break;
-               if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+               if (ctx->has_subcommands &&
+                   (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL) &&
+                   (ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) {
+                       /*
+                        * Found an unknown option given to a command with
+                        * subcommands that has a default operation mode:
+                        * we treat this option and all remaining args as
+                        * arguments meant to that default operation mode.
+                        * So we are done parsing.
+                        */
+                       return PARSE_OPT_DONE;
+               }
+               if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT))
                        return PARSE_OPT_UNKNOWN;
                ctx->out[ctx->cpidx++] = ctx->argv[0];
                ctx->opt = NULL;
@@ -884,7 +977,14 @@ int parse_options(int argc, const char **argv,
        case PARSE_OPT_COMPLETE:
                exit(0);
        case PARSE_OPT_NON_OPTION:
+       case PARSE_OPT_SUBCOMMAND:
+               break;
        case PARSE_OPT_DONE:
+               if (ctx.has_subcommands &&
+                   !(flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) {
+                       error(_("need a subcommand"));
+                       usage_with_options(usagestr, options);
+               }
                break;
        case PARSE_OPT_UNKNOWN:
                if (ctx.argv[0][1] == '-') {
@@ -1009,6 +1109,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
                size_t pos;
                int pad;
 
+               if (opts->type == OPTION_SUBCOMMAND)
+                       continue;
                if (opts->type == OPTION_GROUP) {
                        fputc('\n', outfile);
                        need_newline = 0;
index 685fccac137fc23884f0e816d53b7be549506441..b6ef86e0d15e3dc36364977dd3515fa118dee165 100644 (file)
@@ -11,6 +11,7 @@ enum parse_opt_type {
        OPTION_GROUP,
        OPTION_NUMBER,
        OPTION_ALIAS,
+       OPTION_SUBCOMMAND,
        /* options with no arguments */
        OPTION_BIT,
        OPTION_NEGBIT,
@@ -30,10 +31,11 @@ enum parse_opt_flags {
        PARSE_OPT_KEEP_DASHDASH = 1 << 0,
        PARSE_OPT_STOP_AT_NON_OPTION = 1 << 1,
        PARSE_OPT_KEEP_ARGV0 = 1 << 2,
-       PARSE_OPT_KEEP_UNKNOWN = 1 << 3,
+       PARSE_OPT_KEEP_UNKNOWN_OPT = 1 << 3,
        PARSE_OPT_NO_INTERNAL_HELP = 1 << 4,
        PARSE_OPT_ONE_SHOT = 1 << 5,
        PARSE_OPT_SHELL_EVAL = 1 << 6,
+       PARSE_OPT_SUBCOMMAND_OPTIONAL = 1 << 7,
 };
 
 enum parse_opt_option_flags {
@@ -56,6 +58,7 @@ enum parse_opt_result {
        PARSE_OPT_ERROR = -1,   /* must be the same as error() */
        PARSE_OPT_DONE = 0,     /* fixed so that "return 0" works */
        PARSE_OPT_NON_OPTION,
+       PARSE_OPT_SUBCOMMAND,
        PARSE_OPT_UNKNOWN
 };
 
@@ -67,6 +70,9 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
                                              const struct option *opt,
                                              const char *arg, int unset);
 
+typedef int parse_opt_subcommand_fn(int argc, const char **argv,
+                                   const char *prefix);
+
 /*
  * `type`::
  *   holds the type of the option, you must have an OPTION_END last in your
@@ -76,7 +82,8 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
  *   the character to use as a short option name, '\0' if none.
  *
  * `long_name`::
- *   the long option name, without the leading dashes, NULL if none.
+ *   the long option (without the leading dashes) or subcommand name,
+ *   NULL if none.
  *
  * `value`::
  *   stores pointers to the values to be filled.
@@ -93,7 +100,7 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
  *
  * `help`::
  *   the short help associated to what the option does.
- *   Must never be NULL (except for OPTION_END).
+ *   Must never be NULL (except for OPTION_END and OPTION_SUBCOMMAND).
  *   OPTION_GROUP uses this pointer to store the group header.
  *   Should be wrapped by N_() for translation.
  *
@@ -109,7 +116,8 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
  *                             is last on the command line. If the option is
  *                             not last it will require an argument.
  *                             Should not be used with PARSE_OPT_OPTARG.
- *   PARSE_OPT_NODASH: this option doesn't start with a dash.
+ *   PARSE_OPT_NODASH: this option doesn't start with a dash; can only be a
+ *                    short option and can't accept arguments.
  *   PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
  *                             (i.e. '<argh>') in the help message.
  *                             Useful for options with multiple parameters.
@@ -130,6 +138,9 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
  * `ll_callback`::
  *   pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
  *
+ * `subcommand_fn`::
+ *   pointer to a function to use for OPTION_SUBCOMMAND.
+ *   It will be put in value when the subcommand is given on the command line.
  */
 struct option {
        enum parse_opt_type type;
@@ -144,6 +155,7 @@ struct option {
        intptr_t defval;
        parse_opt_ll_cb *ll_callback;
        intptr_t extra;
+       parse_opt_subcommand_fn *subcommand_fn;
 };
 
 #define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
@@ -205,6 +217,14 @@ struct option {
 #define OPT_ALIAS(s, l, source_long_name) \
        { OPTION_ALIAS, (s), (l), (source_long_name) }
 
+#define OPT_SUBCOMMAND_F(l, v, fn, f) { \
+       .type = OPTION_SUBCOMMAND, \
+       .long_name = (l), \
+       .value = (v), \
+       .flags = (f), \
+       .subcommand_fn = (fn) }
+#define OPT_SUBCOMMAND(l, v, fn)    OPT_SUBCOMMAND_F((l), (v), (fn), 0)
+
 /*
  * parse_options() will filter out the processed options and leave the
  * non-option arguments in argv[]. argv0 is assumed program name and
@@ -294,6 +314,7 @@ struct parse_opt_ctx_t {
        int argc, cpidx, total;
        const char *opt;
        enum parse_opt_flags flags;
+       unsigned has_subcommands;
        const char *prefix;
        const char **alias_groups; /* must be in groups of 3 elements! */
        struct option *updated_options;
index 8bf425555de252f12935b4fae68f375f3a815987..46c6a8f3eab519c88c0732677c9d09703f5882a3 100644 (file)
@@ -38,7 +38,7 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
 static int patch_id_neq(const void *cmpfn_data,
                        const struct hashmap_entry *eptr,
                        const struct hashmap_entry *entry_or_key,
-                       const void *unused_keydata)
+                       const void *keydata UNUSED)
 {
        /* NEEDSWORK: const correctness? */
        struct diff_options *opt = (void *)cmpfn_data;
index 84ad9c73cfb50a9fd34eed3b5e68fae522c796fe..46e77a85fee9d86e6e16e9f466ecfc3db893fd16 100644 (file)
@@ -759,3 +759,92 @@ int match_pathspec_attrs(struct index_state *istate,
 
        return 1;
 }
+
+int pathspec_needs_expanded_index(struct index_state *istate,
+                                 const struct pathspec *pathspec)
+{
+       unsigned int i, pos;
+       int res = 0;
+       char *skip_worktree_seen = NULL;
+
+       /*
+        * If index is not sparse, no index expansion is needed.
+        */
+       if (!istate->sparse_index)
+               return 0;
+
+       /*
+        * When using a magic pathspec, assume for the sake of simplicity that
+        * the index needs to be expanded to match all matchable files.
+        */
+       if (pathspec->magic)
+               return 1;
+
+       for (i = 0; i < pathspec->nr; i++) {
+               struct pathspec_item item = pathspec->items[i];
+
+               /*
+                * If the pathspec item has a wildcard, the index should be expanded
+                * if the pathspec has the possibility of matching a subset of entries inside
+                * of a sparse directory (but not the entire directory).
+                *
+                * If the pathspec item is a literal path, the index only needs to be expanded
+                * if a) the pathspec isn't in the sparse checkout cone (to make sure we don't
+                * expand for in-cone files) and b) it doesn't match any sparse directories
+                * (since we can reset whole sparse directories without expanding them).
+                */
+               if (item.nowildcard_len < item.len) {
+                       /*
+                        * Special case: if the pattern is a path inside the cone
+                        * followed by only wildcards, the pattern cannot match
+                        * partial sparse directories, so we know we don't need to
+                        * expand the index.
+                        *
+                        * Examples:
+                        * - in-cone/foo***: doesn't need expanded index
+                        * - not-in-cone/bar*: may need expanded index
+                        * - **.c: may need expanded index
+                        */
+                       if (strspn(item.original + item.nowildcard_len, "*") == item.len - item.nowildcard_len &&
+                           path_in_cone_mode_sparse_checkout(item.original, istate))
+                               continue;
+
+                       for (pos = 0; pos < istate->cache_nr; pos++) {
+                               struct cache_entry *ce = istate->cache[pos];
+
+                               if (!S_ISSPARSEDIR(ce->ce_mode))
+                                       continue;
+
+                               /*
+                                * If the pre-wildcard length is longer than the sparse
+                                * directory name and the sparse directory is the first
+                                * component of the pathspec, need to expand the index.
+                                */
+                               if (item.nowildcard_len > ce_namelen(ce) &&
+                                   !strncmp(item.original, ce->name, ce_namelen(ce))) {
+                                       res = 1;
+                                       break;
+                               }
+
+                               /*
+                                * If the pre-wildcard length is shorter than the sparse
+                                * directory and the pathspec does not match the whole
+                                * directory, need to expand the index.
+                                */
+                               if (!strncmp(item.original, ce->name, item.nowildcard_len) &&
+                                   wildmatch(item.original, ce->name, 0)) {
+                                       res = 1;
+                                       break;
+                               }
+                       }
+               } else if (!path_in_cone_mode_sparse_checkout(item.original, istate) &&
+                          !matches_skip_worktree(pathspec, i, &skip_worktree_seen))
+                       res = 1;
+
+               if (res > 0)
+                       break;
+       }
+
+       free(skip_worktree_seen);
+       return res;
+}
index 402ebb808081e386da46786fe1d5a1521e3cc4ac..41f6adfbb421fee745e3717ffd57ff92acfc82b1 100644 (file)
@@ -171,4 +171,16 @@ int match_pathspec_attrs(struct index_state *istate,
                         const char *name, int namelen,
                         const struct pathspec_item *item);
 
+/*
+ * Determine whether a pathspec will match only entire index entries (non-sparse
+ * files and/or entire sparse directories). If the pathspec has the potential to
+ * match partial contents of a sparse directory, return 1 to indicate the index
+ * should be expanded to match the  appropriate index entries.
+ *
+ * For the sake of simplicity, always return 1 if using a more complex "magic"
+ * pathspec.
+ */
+int pathspec_needs_expanded_index(struct index_state *istate,
+                                 const struct pathspec *pathspec);
+
 #endif /* PATHSPEC_H */
index 8e43c2def4ca4fa470b7a318ffa8a060b5c39838..ce4e73b6833a48119dfc5f36b64daa8e962dc9c4 100644 (file)
@@ -309,7 +309,8 @@ int write_packetized_from_fd_no_flush(int fd_in, int fd_out)
        return err;
 }
 
-int write_packetized_from_buf_no_flush(const char *src_in, size_t len, int fd_out)
+int write_packetized_from_buf_no_flush_count(const char *src_in, size_t len,
+                                            int fd_out, int *packet_counter)
 {
        int err = 0;
        size_t bytes_written = 0;
@@ -324,6 +325,8 @@ int write_packetized_from_buf_no_flush(const char *src_in, size_t len, int fd_ou
                        break;
                err = packet_write_gently(fd_out, src_in + bytes_written, bytes_to_write);
                bytes_written += bytes_to_write;
+               if (packet_counter)
+                       (*packet_counter)++;
        }
        return err;
 }
index 1f623de60a856944b8c1b3e844228e36c8c07162..79c538b99e477660fb8819d7fd0175daf4520cc5 100644 (file)
@@ -32,7 +32,13 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((f
 int packet_flush_gently(int fd);
 int packet_write_fmt_gently(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 int write_packetized_from_fd_no_flush(int fd_in, int fd_out);
-int write_packetized_from_buf_no_flush(const char *src_in, size_t len, int fd_out);
+int write_packetized_from_buf_no_flush_count(const char *src_in, size_t len,
+                                            int fd_out, int *packet_counter);
+static inline int write_packetized_from_buf_no_flush(const char *src_in,
+                                                    size_t len, int fd_out)
+{
+       return write_packetized_from_buf_no_flush_count(src_in, len, fd_out, NULL);
+}
 
 /*
  * Stdio versions of packet_write functions. When mixing these with fd
index 934784fe523711b39ef72d495c07c101526b85e0..8b2a936ba0d082a86c80f6e6aee2b3ce917bc9c9 100644 (file)
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,8 +1,7 @@
 # Bulgarian translation of git po-file.
-# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Alexander Shopov <ash@kambanaria.org>.
 # This file is distributed under the same license as the git package.
 # Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022.
-#
 # ========================
 # DICTIONARY TO MERGE IN GIT GUI
 # ------------------------
@@ -64,6 +63,8 @@
 # pathspec magic опция за магически пътища
 # bitmap index индекс на база битови маски
 # multi-pack bitmap многопакетната битова маска
+# ewah bitmap битова маска във формат EWAH
+# type bitmap битова маска на видовете
 # mark маркер
 # plumbing команди от системно ниво
 # porcelain команди от потребителско ниво
 # scheduler планиращ модул
 # snapshot снимка
 # enlistment зачислена директория
+# remove enlistment отчислявам директория
 # zealous merge засилено сливане
 # unregister отчислявам
 # marked counting изброяване
 # traverse обхождам
 # timestamp времево клеймо
 # bare repository голо хранилище
-#
+# resolve-undo отмяна на разрешените подавания
+# maintenance задачи по поддръжка
+# GLE последна грешка в нишката - от GetLatError: https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
+# lookup table таблица със съответствия
+# out of range извън диапазона
+# checksum сума за проверка
+# superproject обхващащ проект
 # ------------------------
 # „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
 # ------------------------
 # msgcat todo1.po todo2.po > todo.po
 # grep '^#: ' todo.po | sed 's/^#: //' | tr ' ' '\n' | sed 's/:[0-9]*$//' > FILES
 # for i in `sort -u FILES`; do cnt=`grep $i FILES | wc -l`; echo $cnt $i ;done | sort -n
-#
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.37\n"
+"Project-Id-Version: git 2.38\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-22 15:43+0200\n"
-"PO-Revision-Date: 2022-06-22 15:44+0200\n"
+"POT-Creation-Date: 2022-09-28 10:59+0200\n"
+"PO-Revision-Date: 2022-09-28 10:59+0200\n"
 "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
 "Language-Team: Bulgarian <dict@fsa-bg.org>\n"
 "Language: bg\n"
@@ -363,7 +370,6 @@ msgstr "път"
 msgid "could not refresh index"
 msgstr "индексът не може да бъде обновен"
 
-#
 #, c-format
 msgid "Bye.\n"
 msgstr "Изход.\n"
@@ -625,6 +631,24 @@ msgstr ""
 "d — без прилагане на това и всички следващи парчета от файла от индекса и "
 "работното дърво\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+"Прилагане на промяната в правата за достъп към работното дърво [y,n,q,a,d"
+"%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Прилагане на изтриването към работното дърво [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Прилагане на добавянето към работното дърво [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Прилагане на парчето към работното дърво [y,n,q,a,d%s,?]? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -642,10 +666,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "заглавната част на парчето „%.*s“ не може да се анализира"
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "заглавната част на оцветеното парче „%.*s“ не може да се анализира"
-
 msgid "could not parse diff"
 msgstr "разликата не може да се анализира"
 
@@ -936,6 +956,29 @@ msgstr ""
 "detachedHead“\n"
 "да е „false“ (лъжа̀).\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Следните пътища са преместени извън дефинициите за частично\n"
+"изтегляне, но вече не са частични заради локални промени.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Ако искате да ги обновите, пробвайте едно от следните:\n"
+"  ⁃ обновете индекса с командата:\n"
+"\n"
+"    git add --sparse ПЪТ…\n"
+"\n"
+"  ⁃ приложете правилата за частичност с командата:\n"
+"\n"
+"    git sparse-checkout reapply"
+
 msgid "cmdline ends with \\"
 msgstr "командният ред завършва с „/“"
 
@@ -1460,6 +1503,10 @@ msgstr "обектът-BLOB „%s“ не може да бъде обработ
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "неподдържани права за достъп до файл: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "грешка при декомпресиране с „deflate“ (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "филтърът „%s“ не може да бъде стартиран"
@@ -1479,10 +1526,6 @@ msgstr "пътят не е правилно кодиран в UTF-8: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "твърде дълъг път (%d знака, SHA1: %s): %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "грешка при декомпресиране с „deflate“ (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "времевото клеймо е твърде голямо за тази система: %<PRIuMAX>"
@@ -3315,8 +3358,13 @@ msgstr "библиотека на C: "
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "командата е стартирана извън хранилище на Git, затова няма куки\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory ФАЙЛ] [-s|--suffix ФОРМАТ]"
+# FIXME
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory ФАЙЛ] [-s|--suffix ФОРМАТ] [--"
+"diagnose[=РЕЖИМ]]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3353,16 +3401,29 @@ msgstr ""
 "Разгледайте останалата част от доклада за грешка по-долу.\n"
 "Може да изтриете редовете, които не искате да споделите.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "укажете файла, в който да се запази докладът за грешка"
+msgid "mode"
+msgstr "РЕЖИМ"
 
-msgid "specify a strftime format suffix for the filename"
-msgstr "укажете суфикса на файла във формат за „strftime“"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"създаване на допълнителен архив във формат zip с подробни диагностични "
+"съобщения (стандартно е „stats“ — статистика)"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "укажете местоположение, в което да се запазят докладите за грешка"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "укажете суфикса на файловете във формат за „strftime“"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "родителските директории на „%s“ не може да бъдат създадени"
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "не може да се създаде архив за диагностичните съобщения: %s"
+
 msgid "System Info"
 msgstr "Информация за системата"
 
@@ -3421,10 +3482,6 @@ msgstr "За приемането на пратка е необходимо хр
 msgid "Unbundling objects"
 msgstr "Разпакетиране на пратки от обекти"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Непозната подкоманда: %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "обектът „%s“ (%s) не може да бъде прочетен"
@@ -3504,6 +3561,11 @@ msgstr "извеждане на размера на обект"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "позволяване на опциите „-s“ и „-t“ да работят с повредени обекти"
 
+msgid "use mail map file"
+msgstr ""
+"използване на файл за съответствията на имената и адресите на е-поща („."
+"mailmap“)"
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr ""
 "Пакетно извеждане на заявените обекти на стандартния изход (или „--batch-all-"
@@ -3515,6 +3577,9 @@ msgstr "извеждане на пълното съдържание на ОБЕ
 msgid "like --batch, but don't emit <contents>"
 msgstr "като „--batch“, но без извеждане на съдържанието"
 
+msgid "stdin is NUL-terminated"
+msgstr "стандартният вход да ползва нулевия знак „NUL“ за разделител"
+
 msgid "read commands from stdin"
 msgstr "изчитане на командите от стандартния вход"
 
@@ -4403,6 +4468,13 @@ msgstr ""
 "инициализиране на файла за частично изтегляне („.git/info/sparse-checkout“) "
 "да съдържа само файловете в основната директория"
 
+msgid "uri"
+msgstr "АДРЕС"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"АДРЕС за доставяне на пратки на git преди доставяне от отдалеченото хранилище"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr ""
@@ -4468,10 +4540,10 @@ msgstr "обектът „%s“ не може да бъде обновен"
 msgid "failed to initialize sparse-checkout"
 msgstr "частичното изтегляне не може да се инициализира"
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr ""
-"указателят „HEAD“ от отдалеченото хранилище сочи към нещо,\n"
-"което не съществува.  Не може да се изтегли определен клон.\n"
+"указателят „HEAD“ от отдалеченото хранилище сочи към нещо, което не "
+"съществува.  Изтегляне не може да се извърши"
 
 msgid "unable to checkout working tree"
 msgstr "работното дърво не може да бъде подготвено"
@@ -4495,6 +4567,13 @@ msgstr "Трябва да укажете кое хранилище искате
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "опциите „%s“ и „%s %s“ са несъвместими"
 
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"опцията „--bundle-uri“ е несъвместима с „--depth“, „--shallow-since“ и „--"
+"shallow-exclude“"
+
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "не съществува хранилище „%s“"
@@ -4574,6 +4653,14 @@ msgstr "опцията „--local“ се прескача"
 msgid "cannot clone from filtered bundle"
 msgstr "не може да се клонира от филтрирана пратка"
 
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr ""
+"хранилището не може да се инициализира, адресът на пратката се прескача"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "неуспешно доставяне на обекти от пратка на адрес „%s“"
+
 msgid "remote transport reported error"
 msgstr "отдалеченият транспорт върна грешка"
 
@@ -4694,10 +4781,6 @@ msgstr ""
 msgid "Collecting commits from input"
 msgstr "Получаване на подаванията от входа"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "непозната подкоманда: %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -5066,9 +5149,6 @@ msgstr "подробна информация за състоянието (ст
 msgid "terminate entries with NUL"
 msgstr "разделяне на елементите с нулевия знак „NUL“"
 
-msgid "mode"
-msgstr "РЕЖИМ"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "извеждане на неследените файлове.  Възможните РЕЖИМи са „all“ (подробна "
@@ -5685,6 +5765,22 @@ msgstr "Не са открити имена — нищо не може да бъ
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "опциите „%s“ и указателите към обекти са несъвместими"
 
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory ФАЙЛ] [-s|--suffix ФОРМАТ] [--"
+"diagnose[=РЕЖИМ]]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "укажете местоположение на архива с диагностичната информация"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "укажете суфикса на файла във формат за „strftime“"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "указване на съдържанието на диагностичния архив"
+
 msgid "--merge-base only works with two commits"
 msgstr "опцията „--merge-base“ изисква точно две подавания"
 
@@ -6066,12 +6162,9 @@ msgstr "[актуален]"
 msgid "[rejected]"
 msgstr "[отхвърлен]"
 
-msgid "can't fetch in current branch"
+msgid "can't fetch into checked-out branch"
 msgstr "в текущия клон не може да се доставя"
 
-msgid "checked out in another worktree"
-msgstr "изтеглен в друго работно дърво"
-
 msgid "[tag update]"
 msgstr "[обновяване на етикетите]"
 
@@ -6487,7 +6580,6 @@ msgstr "Проверка на директориите с обекти"
 msgid "Checking %s link"
 msgstr "Проверка на връзките на „%s“"
 
-#
 #, c-format
 msgid "invalid %s"
 msgstr "неправилен указател „%s“"
@@ -6514,6 +6606,10 @@ msgstr "„%s“: неправилен указател за SHA1 в дърво
 msgid "non-tree in cache-tree"
 msgstr "в дървото на кеша има нещо, което не е дърво"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "„%s“: неправилен указател за отмяна на разрешените подавания"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [ОПЦИЯ…] [ОБЕКТ…]"
 
@@ -6578,7 +6674,7 @@ msgstr "git fsmonitor--daemon status"
 
 #, c-format
 msgid "value of '%s' out of range: %d"
-msgstr "дÑ\8aлжинаÑ\82а Ð½Ð° â\80\9e%sâ\80\9c e Ð¸Ð·Ð²Ñ\8aн Ð¸Ð½Ñ\82еÑ\80вала: %d"
+msgstr "дÑ\8aлжинаÑ\82а Ð½Ð° â\80\9e%sâ\80\9c e Ð¸Ð·Ð²Ñ\8aн Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½а: %d"
 
 #, c-format
 msgid "value of '%s' not bool or int: %d"
@@ -6856,13 +6952,16 @@ msgstr ""
 "неуспешно изпълнение на „crontab -l“.  Системата ви може да не поддържа "
 "„cron“"
 
+msgid "failed to create crontab temporary file"
+msgstr "не може да се създаде временен файл за crontab"
+
+msgid "failed to open temporary file"
+msgstr "временният файл не може да се отвори"
+
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "неуспешно изпълнение на „crontab“.  Системата ви може да не поддържа „cron“"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "стандартният вход на „crontab“ не може да се отвори"
-
 msgid "'crontab' died"
 msgstr "процесът на „crontab“ умря"
 
@@ -6909,10 +7008,6 @@ msgstr "неуспешно добавяне на хранилище към фа
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance ПОДКОМАНДА [ОПЦИЯ…]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "неправилна подкоманда: „%s“"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [ОПЦИЯ…] [-e] ШАБЛОН [ВЕРСИЯ…] [[--] ПЪТ…]"
 
@@ -7094,6 +7189,9 @@ msgstr ""
 "позволяване на стартирането на grep(1) (текущият компилат пренебрегва тази "
 "опция)"
 
+msgid "maximum number of results per file"
+msgstr "максимален брой резултати във файл"
+
 msgid "no pattern given"
 msgstr "не сте задали шаблон"
 
@@ -7178,16 +7276,22 @@ msgid "show info page"
 msgstr "показване на информационна страница"
 
 msgid "print command description"
-msgstr "извеждане на описанието на команда"
+msgstr "показване на описанието на команда"
 
 msgid "print list of useful guides"
 msgstr "показване на списък с въведения"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr "показване на списък с командите за файлове и хранилища за потребители"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr "показване на списък с файлови формати, протоколи и др. за програмисти"
+
 msgid "print all configuration variable names"
 msgstr "показване на имената на всички конфигуриращи променливи"
 
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [КОМАНДА]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [КОМАНДА|ДОКУМЕНТ]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -7403,7 +7507,7 @@ msgstr[1] "действието завърши с %d локални обекта
 #, c-format
 msgid "Unexpected tail checksum for %s (disk corruption?)"
 msgstr ""
-"Ð\9dеоÑ\87аквана Ð¿Ð¾Ñ\81ледваÑ\89а Ñ\81Ñ\83ма Ð·Ð° Ð³Ñ\80еÑ\88ки Ð·а „%s“ (причината може да е грешка в "
+"Ð\9dеоÑ\87аквана Ð¿Ð¾Ñ\81ледваÑ\89а Ñ\81Ñ\83ма Ð·Ð° Ð¿Ñ\80овеÑ\80ка Ð½а „%s“ (причината може да е грешка в "
 "диска)"
 
 #, c-format
@@ -7666,10 +7770,8 @@ msgstr "без извеждане на разликите"
 msgid "show source"
 msgstr "извеждане на изходния код"
 
-msgid "use mail map file"
-msgstr ""
-"използване на файл за съответствията на имената и адресите на е-поща („."
-"mailmap“)"
+msgid "clear all previously-defined decoration filters"
+msgstr "изчистване на зададените филтри за форма̀та на извежданата информация"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "специален формат само на указателите напасващи на ШАБЛОНа"
@@ -7936,6 +8038,11 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr "процент за претегляне при оценка на създаването"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr ""
+"показване на заглавната част „From:“ в тялото на писмото дори и да е същата "
+"като тази на плика на писмото"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "грешна идентичност: %s"
@@ -7998,6 +8105,18 @@ msgstr ""
 "Следеният отдалечен клон не бе открит, затова изрично задайте "
 "ОТДАЛЕЧЕН_КЛОН.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "неправилен формат за „ls-tree“: елементът „%s“ не започва с „(“"
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "неправилен формат за „ls-tree“: елементът „%s“ не завършва с „)“"
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "неправилен формат за „ls-tree“: %%%.*s"
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [ОПЦИЯ…] [ФАЙЛ…]"
 
@@ -8085,6 +8204,13 @@ msgid "show sparse directories in the presence of a sparse index"
 msgstr ""
 "указване на частично изтеглените директории при наличието на частичен индекс"
 
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"опцията „--format“ е несъвместима с „-s“/„-o“/„-k“/„-t“/„--resolve-undo“/„--"
+"deduplicate“/„--eol“"
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url]\n"
@@ -8310,6 +8436,40 @@ msgstr "указателят „%s“ не може да бъде изтрит"
 msgid "Merging %s with %s\n"
 msgstr "Сливане на „%s“ с „%s“\n"
 
+msgid "not something we can merge"
+msgstr "не може да се слее"
+
+msgid "refusing to merge unrelated histories"
+msgstr "независими истории не може да се слеят"
+
+msgid "failure to merge"
+msgstr "неуспешно сливане"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [ОПЦИЯ…] КЛОН_1 КЛОН_2"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] БАЗОВО_ДЪРВО КЛОН_1 КЛОН_2"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "същинско, а не тривиално сливане"
+
+msgid "do a trivial merge only"
+msgstr "само тривиално сливане"
+
+msgid "also show informational/conflict messages"
+msgstr "показване и информационните съобщения, и тези при конфликт"
+
+msgid "list filenames without modes/oids/stages"
+msgstr ""
+"извеждане на имената на файлове без режими/идентификатори на обекти/етапи"
+
+msgid "allow merging unrelated histories"
+msgstr "позволяване на сливане на независими истории"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "„--trivial-merge“ е несъвместима с другите опции"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [ОПЦИЯ…] [ПОДАВАНЕ…]"
 
@@ -8391,9 +8551,6 @@ msgstr "преустановяване (--abort) без промяна на ин
 msgid "continue the current in-progress merge"
 msgstr "продължаване на текущото сливане"
 
-msgid "allow merging unrelated histories"
-msgstr "позволяване на сливане на независими истории"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr ""
 "без изпълнение на куките преди подаване и сливане и при промяна на "
@@ -8516,9 +8673,6 @@ msgstr "„%s“ не може да се затвори"
 msgid "not something we can merge in %s: %s"
 msgstr "не може да се слее в „%s“: %s"
 
-msgid "not something we can merge"
-msgstr "не може да се слее"
-
 msgid "--abort expects no arguments"
 msgstr "опцията „--abort“ не приема аргументи"
 
@@ -8573,13 +8727,18 @@ msgstr "„%s“ — не е нещо, което може да се слее"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Може да слеете точно едно подаване във връх без история"
 
-msgid "refusing to merge unrelated histories"
-msgstr "независими истории не може да се слеят"
-
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Обновяване „%s..%s“\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Сливането ще презапише локалните промѐни на тези файлове:\n"
+"    %s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Проба със сливане в рамките на индекса…\n"
@@ -8615,6 +8774,10 @@ msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Автоматичното сливане завърши успешно.  Самото подаване не е извършено\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "При завършване скатаните промени да се приложат с „git stash pop“\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "ПРЕДУПРЕЖДЕНИЕ: аргументът-етикет не минава проверка с „fsck“: %s"
@@ -8738,6 +8901,9 @@ msgstr "Проверка на преименуването на обект от
 msgid "bad source"
 msgstr "неправилен обект"
 
+msgid "destination exists"
+msgstr "целта съществува"
+
 msgid "can not move directory into itself"
 msgstr "директория не може да се премести в себе си"
 
@@ -8753,9 +8919,6 @@ msgstr "не е под контрола на Git"
 msgid "conflicted"
 msgstr "конфликт"
 
-msgid "destination exists"
-msgstr "целта съществува"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "презаписване на „%s“"
@@ -8769,6 +8932,9 @@ msgstr "множество източници за една цел"
 msgid "destination directory does not exist"
 msgstr "целевата директория не съществува"
 
+msgid "destination exists in the index"
+msgstr "целта съществува в индекса"
+
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, обект: „%s“, цел: „%s“"
@@ -9136,8 +9302,8 @@ msgid "use notes from <notes-ref>"
 msgstr "да се използва бележката сочена от този УКАЗАТЕЛ_ЗА_БЕЛЕЖКА"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "непозната подкоманда: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "непозната подкоманда: „%s“"
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -10065,12 +10231,17 @@ msgstr "извеждане само на информацията за първ
 msgid "only emit output related to the second range"
 msgstr "извеждане само на информацията за втория диапазон"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "„%s“ не е версия"
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "не е диапазон с подавания: „%s“"
 
-msgid "single arg format must be symmetric range"
-msgstr "вариантът с единствен аргумент изисква симетричен диапазон"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "не е симетричен диапазон: „%s“"
 
 msgid "need two commit ranges"
 msgstr "необходими са два диапазона с подавания"
@@ -10344,6 +10515,9 @@ msgid "move commits that begin with squash!/fixup! under -i"
 msgstr ""
 "преместване на подаванията, които започват със „squash!“/“fixup!“ при „-i“"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr "обновяване на клоните, които сочат към пребазирани подавания"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr ""
 "добавяне на редове с команди за изпълнение след всяко подаване в "
@@ -10895,6 +11069,9 @@ msgstr " нов (следващото доставяне ще го разпол
 msgid " tracked"
 msgstr " следен"
 
+msgid " skipped"
+msgstr " прескочен"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " стар (изтрийте чрез „git remote prune“)"
 
@@ -11587,6 +11764,10 @@ msgstr "Новият индекс не може да бъде записан."
 msgid "unable to get disk usage of %s"
 msgstr "използваното място за „%s“ не може да бъде получено"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "неправилна стойност за „%s“: „%s“, единственият позволен формат е „%s“"
+
 msgid "rev-list does not support display of notes"
 msgstr "командата „rev-list“ не поддържа извеждането на бележки"
 
@@ -11612,6 +11793,9 @@ msgstr "неочакван край на входа"
 msgid "no usage string given before the `--' separator"
 msgstr "липсва низ преди разделителя „--“"
 
+msgid "missing opt-spec before option flags"
+msgstr "липсват опции пред флаговете за опции"
+
 msgid "Needed a single revision"
 msgstr "Изисква точно една версия"
 
@@ -12391,6 +12575,10 @@ msgstr "добавяне на „# “ в началото на всеки ре
 msgid "Expecting a full ref name, got %s"
 msgstr "Очаква се пълно име на указател, а не „%s“"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "не може да се получи връзка към хранилище за подмодула „%s“"
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -12399,12 +12587,6 @@ msgstr ""
 "настройката „%s“ липсва.  Приема се, че това хранилище е правилният източник "
 "за себе си."
 
-msgid "alternative anchor for relative paths"
-msgstr "директория за определянето на относителните пътища"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=ПЪТ] [ПЪТ…]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "Във файла „.gitmodules“ не е открит адрес за пътя към подмодул „%s“"
@@ -12437,8 +12619,8 @@ msgstr "без извеждане на изход при въвеждането
 msgid "recurse into nested submodules"
 msgstr "рекурсивно обхождане на подмодулите"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] КОМАНДА"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] КОМАНДА"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -12460,8 +12642,8 @@ msgstr ""
 msgid "suppress output for initializing a submodule"
 msgstr "без извеждане на информация при инициализирането на подмодул"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [ОПЦИЯ…] [ПЪТ]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [ОПЦИЯ…] [ПЪТ]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -12488,9 +12670,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [ПЪТ…]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name ПЪТ"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "● %s %s(обект-BLOB)→%s(подмодул)"
@@ -12527,8 +12706,8 @@ msgstr "прескачане на подмодули, чиято настрой
 msgid "limit the summary size"
 msgstr "ограничаване на размера на обобщението"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [ОПЦИЯ…] [ПОДАВАНЕ] [--] [ПЪТ]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [ОПЦИЯ…] [ПОДАВАНЕ] [--] [ПЪТ]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "не може да се достави версия за „HEAD“"
@@ -12541,10 +12720,6 @@ msgstr "Синхронизиране на адреса на подмодул з
 msgid "failed to register url for submodule path '%s'"
 msgstr "неуспешно регистриране на адрес за пътя към подмодул „%s“"
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "отдалеченият адрес на подмодула „%s“ не може да бъде получен"
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "отдалеченият адрес на подмодула „%s“ не може да бъде променен"
@@ -12552,8 +12727,8 @@ msgstr "отдалеченият адрес на подмодула „%s“ н
 msgid "suppress output of synchronizing submodule url"
 msgstr "без извеждане на информация при синхронизирането на подмодул"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [ПЪТ]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [ПЪТ]"
 
 #, c-format
 msgid ""
@@ -12615,6 +12790,10 @@ msgstr ""
 "задайте настройката „submodule.alternateErrorStrategy“ да е „info“ или\n"
 "при клониране ползвайте опцията „--reference-if-able“ вместо „--reference“."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "не може да се получи връзка към хранилище за директорията на git „%s“"
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "към подмодула „%s“ не може да се добави алтернативен източник: %s"
@@ -12646,6 +12825,9 @@ msgstr "директорията не е празна: „%s“"
 msgid "could not get submodule directory for '%s'"
 msgstr "директорията на подмодула „%s“ не може да бъде получена"
 
+msgid "alternative anchor for relative paths"
+msgstr "директория за определянето на относителните пътища"
+
 msgid "where the new submodule will be cloned to"
 msgstr "къде да се клонира новият подмодул"
 
@@ -12673,10 +12855,6 @@ msgstr ""
 "[--name ИМЕ] [--depth ДЪЛБОЧИНА] [--single-branch] [--filter ФИЛТЪР] --url "
 "АДРЕС --path ПЪТ"
 
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Неправилен режим на обновяване „%s“ за пътя към подмодул „%s“"
-
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr ""
@@ -12752,6 +12930,10 @@ msgstr ""
 "Подмодулът в пътя „%s“ е доставен, но не съдържа обекта със сума\n"
 "„%s“.  Директното доставяне на това подаване е неуспешно."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "подмодулът в „%s“ не може да се инициализира"
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12760,10 +12942,6 @@ msgstr ""
 "Клонът на подмодула „%s“ е настроен да наследява клона от обхващащия проект, "
 "но той не е на никой клон"
 
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "не може да се получи връзка към хранилище за подмодула „%s“"
-
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr "Текущата версия за подмодула в „%s“ липсва"
@@ -12798,13 +12976,15 @@ msgstr "без доставяне на новите обекти от отдал
 msgid "path into the working tree"
 msgstr "път към работното дърво"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "път към работното дърво, през границите на вложените подмодули"
-
-msgid "rebase, merge, checkout or none"
+msgid "use the 'checkout' update strategy (default)"
 msgstr ""
-"„rebase“ (пребазиране), „merge“ (сливане), „checkout“ (изтегляне) или "
-"„none“ (нищо да не се прави)"
+"използване на стратегията за обновяване „checkout“ (изтегляне — стандартно)"
+
+msgid "use the 'merge' update strategy"
+msgstr "използване на стратегията за обновяване „merge“ (сливане)"
+
+msgid "use the 'rebase' update strategy"
+msgstr "използване на стратегията за обновяване „rebase“ (пребазиране)"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "извършване на плитко клониране, отрязано до указания брой версии"
@@ -12818,6 +12998,9 @@ msgstr "дали първоначалното клониране да е пли
 msgid "don't print cloning progress"
 msgstr "без извеждане на напредъка на клонирането"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "предотвратяване на клониране в непразна история, включва „--init“"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12829,14 +13012,11 @@ msgstr ""
 "shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
 "[--] [ПЪТ…]"
 
-msgid "bad value for update parameter"
-msgstr "неправилен параметър към опцията „--update“"
-
 msgid "recurse into submodules"
 msgstr "рекурсивно обхождане подмодулите"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [ОПЦИЯ…] [ПЪТ…]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [ОПЦИЯ…] [ПЪТ…]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr "проверка дали писането във файла „.gitmodules“ е безопасно"
@@ -12856,8 +13036,8 @@ msgstr "файлът „.gitmodules“ трябва да е в работнот
 msgid "suppress output for setting url of a submodule"
 msgstr "без извеждане на информация при задаването на адреса на подмодул"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] [ПЪТ] [НОВ_ПЪТ]"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] [ПЪТ] [НОВ_ПЪТ]"
 
 msgid "set the default tracking branch to master"
 msgstr "задаване на стандартния следящ клон да е „master“"
@@ -12865,12 +13045,11 @@ msgstr "задаване на стандартния следящ клон да
 msgid "set the default tracking branch"
 msgstr "задаване на стандартния следящ клон"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) ПЪТ"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) ПЪТ"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-b|--branch) КЛОН ПЪТ"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) КЛОН ПЪТ"
 
 msgid "--branch or --default required"
 msgstr "необходимо е една от опциите „--branch“ и „--default“"
@@ -12968,8 +13147,8 @@ msgid ""
 msgstr ""
 "името на подмодула да е указаното, а не да е автоматично същото като пътя"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ПЪТ]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ПЪТ]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
@@ -13178,6 +13357,16 @@ msgstr "Обновен етикет „%s“ (бе „%s“)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "пакетният файл надвишава максималния възможен размер"
 
+msgid "failed to write object in stream"
+msgstr "някой обект не може да се запише в потока"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "декомпресирането с „inflate“ завърши (%d)"
+
+msgid "invalid blob object from stream"
+msgstr "неправилен обект-BLOB от потока"
+
 msgid "Unpacking objects"
 msgstr "Разпакетиране на обектите"
 
@@ -13726,6 +13915,27 @@ msgstr "запис на обект-дърво за поддиректорият
 msgid "only useful for debugging"
 msgstr "само за изчистване на грешки"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "„core.fsyncMethod = batch“ не се поддържа на тази платформа"
+
+msgid "failed to create temporary file"
+msgstr "не може да се създаде временен файл"
+
+msgid "insufficient capabilities"
+msgstr "недостатъчно възможности"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "неуспешно изтегляне на пратка от адрес: „%s“"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "файлът на адрес „%s“ не е пратка"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "неуспешно разпакетиране на пратка от адрес „%s“"
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "непознат алгоритъм за контролни суми за пратки „%s“"
@@ -13939,6 +14149,9 @@ msgstr ""
 "Задаване на име удобно за потребителите на обект въз основа на наличен "
 "указател"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Създаване на архив във формат zip с диагностична информация"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "Извеждане на разликите между подаванията, версиите, работното дърво"
 
@@ -14070,8 +14283,8 @@ msgstr "Сливане на файловете, които се нуждаят 
 msgid "The standard helper program to use with git-merge-index"
 msgstr "Стандартната помощна програма за „git-merge-index“"
 
-msgid "Show three-way merge without touching index"
-msgstr "Извеждане на тройно сливане без промяна на индекса"
+msgid "Perform merge without touching index or working tree"
+msgstr "Извършване на сливането без промени по индекса или работното време"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr "Изпълнение на програмите за коригиране на конфликтите при сливане"
@@ -14266,6 +14479,9 @@ msgstr "Проверка на пакетираните архивни файло
 msgid "Check the GPG signature of tags"
 msgstr "Проверка на подписите GPG върху етикетите"
 
+msgid "Display version information about Git"
+msgstr "Извеждане на версията на Git"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Извеждане на журнал с разликите, въведени с всяко подаване"
 
@@ -14299,6 +14515,24 @@ msgstr "Полезен минимален набор от команди за е
 msgid "Frequently asked questions about using Git"
 msgstr "Често задавани въпроси за употребата на Git"
 
+msgid "The bundle file format"
+msgstr "Формат на пратките"
+
+msgid "Chunk-based file formats"
+msgstr "Формати на откъсите"
+
+msgid "Git commit graph format"
+msgstr "Формат на гра̀фа с подаванията"
+
+msgid "Git index format"
+msgstr "Формат на индекса"
+
+msgid "Git pack format"
+msgstr "Формат на пакетите"
+
+msgid "Git cryptographic signature formats"
+msgstr "Формати на криптографските подписи"
+
 msgid "A Git Glossary"
 msgstr "Речник с термините на Git"
 
@@ -14320,6 +14554,21 @@ msgstr "Дефиниране на свойствата на подмодулит
 msgid "Git namespaces"
 msgstr "Пространства от имена на Git"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Възможности на протоколи, версия 1 и 2"
+
+msgid "Things common to various protocols"
+msgstr "Общи за различните протоколи възможности"
+
+msgid "Git HTTP-based protocols"
+msgstr "Протоколи на Git на основа на HTTP"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Как пакетите се пренасят по мрежата"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Мрежов протокол на Git, версия 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Помощни програми за работа с отдалечените хранилища"
 
@@ -14344,6 +14593,9 @@ msgstr "Уеб интерфейс на Git"
 msgid "An overview of recommended workflows with Git"
 msgstr "Общ преглед на препоръчваните начини за работа с Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Инструмент за управление на големи хранилища на Git "
+
 msgid "commit-graph file is too small"
 msgstr "файлът за гра̀фа с подаванията е твърде малък"
 
@@ -14601,6 +14853,14 @@ msgstr "липсва информация за компилатора\n"
 msgid "no libc information available\n"
 msgstr "липсва информация за библиотеката на C\n"
 
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "не може да се определи свободното дисково пространство за „%s“"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "не може да се получи информацията за „%s“"
+
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
 msgstr ""
@@ -14672,6 +14932,18 @@ msgstr ""
 "промѐните по директориите не може да бъдат прочетени [последна грешка в "
 "нишката: GLE=%ld]"
 
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr ""
+"файлът „%2$ls“ не може да бъде отворен за четене [последна грешка в нишката: "
+"GLE=%1$ld]"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr ""
+"информацията за протокола на „%2$ls“ не може да се получи [последна грешка в "
+"нишката: GLE=%1$ld]"
+
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr "идентификаторът за сигурност (SID=%ld) не може да бъде копиран"
@@ -14942,7 +15214,7 @@ msgstr "„%s“ не е правилна стойност за време за
 
 #, c-format
 msgid "abbrev length out of range: %d"
-msgstr "дÑ\8aлжинаÑ\82а Ð½Ð° Ñ\81Ñ\8aкÑ\80аÑ\89аване Ðµ Ð¸Ð·Ð²Ñ\8aн Ð¸Ð½Ñ\82еÑ\80вала ([4; 40]): %d"
+msgstr "дÑ\8aлжинаÑ\82а Ð½Ð° Ñ\81Ñ\8aкÑ\80аÑ\89аване Ðµ Ð¸Ð·Ð²Ñ\8aн Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½а ([4; 40]): %d"
 
 #, c-format
 msgid "bad zlib compression level %d"
@@ -15225,196 +15497,20 @@ msgid "failed to close rev-list's stdin"
 msgstr "стандартният вход на списъка с версиите не може да бъде затворен"
 
 #, c-format
-msgid "'%s' does not exist"
-msgstr "„%s“ не съществува."
-
-msgid "need a working directory"
-msgstr "необходима е работна директория"
+msgid "illegal crlf_action %d"
+msgstr "неправилно действие за край на ред (crlf_action): %d"
 
-msgid "could not find enlistment root"
-msgstr "началната зачислена директория не може да бъде открита"
+#, c-format
+msgid "CRLF would be replaced by LF in %s"
+msgstr "всяка последователност от знаци „CRLF“ ще бъдe заменена с „LF“ в „%s“."
 
 #, c-format
-msgid "could not switch to '%s'"
-msgstr "не може да се премине към „%s“"
-
-#, c-format
-msgid "could not configure %s=%s"
-msgstr "настройката „%s=%s“ не може да се зададе"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "„log.excludeDecoration“ не може да се настрои"
-
-msgid "Scalar enlistments require a worktree"
-msgstr "Зачисляването на директории чрез „scalar“ изисква работно дърво"
-
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "директорията „%s“ не може да бъде отворена"
-
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "„%s“ се прескача, защото не е нито файл, нито директория"
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "не може да се определи свободното дисково пространство за „%s“"
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "не може да се получи информацията за „%s“"
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "отдалеченият указател „HEAD“ не сочи към клон: „%.*s“"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-"името на стандартния клон на отдалеченото хранилище не може да се получи, "
-"затова ще се ползва локално настроеното име на стандартния клон"
-
-msgid "failed to get default branch name"
-msgstr "неуспешно получаване на името на стандартния клон"
-
-msgid "failed to unregister repository"
-msgstr "хранилището не може да бъде отчислено"
-
-msgid "failed to delete enlistment directory"
-msgstr "зачислената директория не може да бъде изтрита"
-
-msgid "branch to checkout after clone"
-msgstr "към кой клон да се премине след клониране"
-
-msgid "when cloning, create full working directory"
-msgstr "при клониране да се създава пълна работна директория"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "да се свалят метаданните само за изтегляния клон"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "името на работното дърво не може да се извлече от „%s“"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "директорията „%s“ вече съществува"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "основният клон на „%s“ не може да бъде получен"
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "отдалеченото хранилище в „%s“ не може да се настрои"
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "„%s“ не може да се настрои"
-
-msgid "partial clone failed; attempting full clone"
-msgstr "неуспешно създаване на непълно хранилище, ще се опита пълно хранилище"
-
-msgid "could not configure for full clone"
-msgstr "не може да се настрои пълно клониране"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "директорията за „%s“ не може да се създадe"
-
-msgid "could not duplicate stdout"
-msgstr "стандартният изход не може да се дублира"
-
-msgid "failed to write archive"
-msgstr "неуспешен запис на архива"
-
-msgid "`scalar list` does not take arguments"
-msgstr "„scalar list“ не приема аргументи"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "пренастройване на всички зачислени директории"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "опцията „--all“ и указването на зачислена директория не са съвместими"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "вече няма хранилище на git в „%s“"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run ЗАДАЧА [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]\n"
-"Задачи:\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "няма задача с име „%s“"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
-
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete ЗАЧИСЛЕНА_ДИРЕКТОРИЯ"
-
-msgid "refusing to delete current working directory"
-msgstr "текущата работна директория няма да бъде изтрита"
-
-msgid "include Git version"
-msgstr "включване и на версията на git"
-
-msgid "include Git's build options"
-msgstr "включване и на опциите за компилиране на git"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "„-C“ изисква ДИРЕКТОРИЯ"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "не може да се влезе в директорията „%s“"
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "опцията „-c“ изисква аргумент във вид КЛЮЧ=СТОЙНОСТ"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C ДИРЕКТОРИЯ] [-c КЛЮЧ=СТОЙНОСТ] КОМАНДА [ОПЦИЯ…]<\n"
-"\n"
-"Команди:\n"
-
-#, c-format
-msgid "illegal crlf_action %d"
-msgstr "неправилно действие за край на ред (crlf_action): %d"
-
-#, c-format
-msgid "CRLF would be replaced by LF in %s"
-msgstr "всяка последователност от знаци „CRLF“ ще бъдe заменена с „LF“ в „%s“."
-
-#, c-format
-msgid ""
-"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
-"touches it"
-msgstr ""
-"следващия път, когато git работи в работното копие на „%s“, всяка "
-"последователност от знаци „CRLF“ ще бъдe заменена с „LF“"
+msgid ""
+"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
+"touches it"
+msgstr ""
+"следващия път, когато git работи в работното копие на „%s“, всяка "
+"последователност от знаци „CRLF“ ще бъдe заменена с „LF“"
 
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
@@ -15613,6 +15709,32 @@ msgstr ""
 msgid "Marked %d islands, done.\n"
 msgstr "Отбелязани са %d групи, работата приключи.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "неправилна стойност за „--%s“: „%s“"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "директорията „%s“ липсва и не може да се архивира"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "директорията „%s“ не може да бъде отворена"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "„%s“ се прескача, защото не е нито файл, нито директория"
+
+msgid "could not duplicate stdout"
+msgstr "стандартният изход не може да се дублира"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "директорията „%s“ не може да бъде добавена към архива"
+
+msgid "failed to write archive"
+msgstr "неуспешен запис на архива"
+
 msgid "--merge-base does not work with ranges"
 msgstr "опцията „--merge-base“ не работи с диапазони"
 
@@ -16242,6 +16364,9 @@ msgstr "git fetch-pack: очаква се „ACK“/„NAK“, а бе полу
 msgid "unable to write to remote"
 msgstr "невъзможно писане към отдалечено хранилище"
 
+msgid "Server supports filter"
+msgstr "Сървърът поддържа филтри"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "неправилен плитък ред: „%s“"
@@ -16352,9 +16477,6 @@ msgstr "сървърът не поддържа алгоритъм „%s“"
 msgid "Server does not support shallow requests"
 msgstr "Сървърът не поддържа плитки заявки"
 
-msgid "Server supports filter"
-msgstr "Сървърът поддържа филтри"
-
 msgid "unable to write request to remote"
 msgstr "невъзможно писане към отдалечено хранилище"
 
@@ -16710,6 +16832,12 @@ msgstr "Команди от ниско ниво / Синхронизация н
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Команди от ниско ниво / Допълнителни инструменти"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "Команди за хранилища, файлове и др. интерфейси за потребители:"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Файлови формати, протоколи и др. интерфейси за програмисти:"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "налични команди на git от „%s“"
@@ -16723,6 +16851,12 @@ msgstr "Това са най-често използваните команди
 msgid "The Git concept guides are:"
 msgstr "Ръководствата за концепциите в Git са:"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Команди за хранилища, файлове и др. за потребители:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Файлови формати, протоколи и др. за програмисти:"
+
 msgid "External commands"
 msgstr "Външни команди"
 
@@ -16810,10 +16944,6 @@ msgstr ""
 "За да изключите това предупреждение, изпълнете:\n"
 "    git config advice.ignoredHook false"
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "Куката „%s“ не може да се стартира\n"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "опцията „--packfile“ изисква валидна контролна сума (а не „%s“)"
@@ -17005,18 +17135,14 @@ msgstr "след аргументите към „ls-refs“ се очаква 
 msgid "quoted CRLF detected"
 msgstr "цитирани знаци CRLF"
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Сливането ще презапише локалните промѐни на тези файлове:\n"
-"    %s"
-
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "Неуспешно сливане на подмодула „%s“ (не е изтеглен)"
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Неуспешно сливане на подмодула „%s“ (няма база за сливане)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "Неуспешно сливане на подмодула „%s“ (няма подавания)"
@@ -17037,26 +17163,8 @@ msgstr "Неуспешно сливане на подмодула „%s“"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"Неуспешно сливане на подмодула „%s“, но е открито възможно решение:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"Ако това е така, добавете го към индекса с команда като следната:\n"
-"\n"
-"    git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"Това приема предложеното.\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
+msgstr "Неуспешно сливане на подмодула „%s“, но е открито възможно решение: %s"
 
 #, c-format
 msgid ""
@@ -17219,13 +17327,45 @@ msgstr ""
 "КОНФЛИКТ (промяна/изтриване): „%s“ е изтрит в %s, а е променен в %s.  Версия "
 "%s на „%s“ е оставена в дървото."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
 msgstr ""
-"Бележка: „%s“ не е актуален и пречи за преминаването към версията с "
-"конфликт.  Старият вариант е преименуван на „%s“"
+" ⁃ преминаване към подмодула (%s), след които или де се слее подаването\n"
+"   „%s“, или да се обновяви към съществуващо подаване, в които\n"
+"   тези промени са слети\n"
+
+#, c-format
+msgid ""
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
+msgstr ""
+"В момента рекурсивното сливане с модули поддържа само тривиалните случаи.\n"
+"Ще трябва ръчно да разрешавате конфликтите във всеки модул, в който се "
+"появят.\n"
+"Това може да се постигне чрез следните стъпки:\n"
+"%s — върнете се към обхващащия проект и изпълнете:\n"
+"\n"
+"    git add %s\n"
+"\n"
+"   за да отбележите сливането или обновяването\n"
+" ⁃ решете конфликтите в обхващащия проект\n"
+" ⁃ подайте индекса в обхващащия проект\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -17305,6 +17445,21 @@ msgstr ""
 "Открито е сливане, което може да решава проблема със сливането на "
 "подмодула:\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Ако това е така, добавете го към индекса с команда като следната:\n"
+"\n"
+"    git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"Това приема предложеното.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr "Неуспешно сливане на подмодула „%s“ (открити са множество сливания)"
@@ -17546,7 +17701,8 @@ msgstr "неправилен ред: „%s“."
 
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr ""
-"индексът за множество пакети се прескача, защото контролната сума не съвпада"
+"индексът за множество пакети се прескача, защото сумата за проверка не "
+"съвпада"
 
 msgid "could not load pack"
 msgstr "пакетът не може да се зареди"
@@ -17596,7 +17752,7 @@ msgid "multi-pack-index file exists, but failed to parse"
 msgstr "файлът с индекса за множество пакети, но не може да бъде анализиран"
 
 msgid "incorrect checksum"
-msgstr "неправилна контролна сума"
+msgstr "неправилна сума за проверка"
 
 msgid "Looking for referenced packfiles"
 msgstr "Търсене на указаните пакетни файлове"
@@ -17851,6 +18007,22 @@ msgstr "неуспешно приключване на „deflate“ върху
 msgid "confused by unstable object source data for %s"
 msgstr "грешка поради нестабилния източник данни за обектите „%s“"
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "при записа на обект в потока: %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "новият обект не може да се компресира поточно с „deflate“ (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "неуспешно изпълнение на „deflateEnd“ върху поточния обект: %d"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "директорията „%s“ не може да бъде създадена"
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr "обектът за „%s“ не може да се прочете"
@@ -18037,63 +18209,178 @@ msgid ""
 "path '%s' is in the index, but not '%s'\n"
 "hint: Did you mean ':%d:%s' aka ':%d:./%s'?"
 msgstr ""
-"пътят „%s“ е в индекса, но не в „%s“\n"
-"Пробвайте с „%d:%s“, което е същото като „%d:./%s“."
+"пътят „%s“ е в индекса, но не в „%s“\n"
+"Пробвайте с „%d:%s“, което е същото като „%d:./%s“."
+
+#, c-format
+msgid "path '%s' exists on disk, but not in the index"
+msgstr "пътят „%s“ съществува на диска, но не е в индекса"
+
+#, c-format
+msgid "path '%s' does not exist (neither on disk nor in the index)"
+msgstr "пътят „%s“ не съществува нито на диска, нито в индекса"
+
+msgid "relative path syntax can't be used outside working tree"
+msgstr "относителен път не може да се ползва извън работното дърво"
+
+#, c-format
+msgid "<object>:<path> required, only <object> '%s' given"
+msgstr "необходими са и двете — ОБЕКТ:ПЪТ, а е даден само ОБЕКТът „%s“"
+
+#, c-format
+msgid "invalid object name '%.*s'."
+msgstr "неправилно име на обект: „%.*s“"
+
+#, c-format
+msgid "invalid object type \"%s\""
+msgstr "неправилен вид обект: „%s“"
+
+#, c-format
+msgid "object %s is a %s, not a %s"
+msgstr "обектът „%s“ е %s, а не %s"
+
+#, c-format
+msgid "object %s has unknown type id %d"
+msgstr "обектът „%s“ е непознат вид: %d"
+
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "обектът „%s“ не може да бъде анализиран"
+
+#, c-format
+msgid "hash mismatch %s"
+msgstr "разлика в контролната сума: „%s“"
+
+msgid "trying to write commit not in index"
+msgstr "опит за записване на обект за подаване извън индекса"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr ""
+"индексът на база битови маски не може да се зареди (възможно е да е повреден)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "повреден индекс на база битови маски (прекалено малък)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "повреден индекс на база битови маски (неправилна заглавна част)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "версия „%d“ на файла за индекса на база битови маски не се поддържа"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"повреден индекс на база битови маски (прекалено малък, за да напасне на кеша "
+"за контролните суми)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"повреден файл за индекс на база битови маски (прекалено е малък дори и за "
+"таблицата със съответствия)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "повтарящ се запис в индекс на база битови маски: „%s“"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr ""
+"повредена битова маска във формат EWAH: отрязана заглавна част за запис %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr ""
+"повредена битова маска във формат EWAH: индексът на подаването %u е извън "
+"диапазона"
+
+msgid "corrupted bitmap pack index"
+msgstr "повреден пакетен индекс на база битови маски"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "неправилно отместване по XOR в пакетен индекс на база битови маски"
+
+msgid "cannot fstat bitmap file"
+msgstr "не може да се получи информация за файла с битови маски с „fstat“"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "игнориране на излишния файл с битови маски: „%s“"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr ""
+"сумата за проверка се различава във файла с индекса за множество пакети и "
+"битовата маска"
+
+msgid "multi-pack bitmap is missing required reverse index"
+msgstr "задължителният обратен индекс липсва в многопакетната битова маска"
 
 #, c-format
-msgid "path '%s' exists on disk, but not in the index"
-msgstr "пътят „%s“ съществува на диска, но не е в индекса"
+msgid "could not open pack %s"
+msgstr "пакетът „%s“ не може да се отвори"
 
 #, c-format
-msgid "path '%s' does not exist (neither on disk nor in the index)"
-msgstr "пÑ\8aÑ\82Ñ\8fÑ\82 â\80\9e%sâ\80\9c Ð½Ðµ Ñ\81Ñ\8aÑ\89еÑ\81Ñ\82вÑ\83ва Ð½Ð¸Ñ\82о Ð½Ð° Ð´Ð¸Ñ\81ка, Ð½Ð¸Ñ\82о Ð² Ð¸Ð½Ð´ÐµÐºÑ\81а"
+msgid "preferred pack (%s) is invalid"
+msgstr "пÑ\80едпоÑ\87иÑ\82аниÑ\8fÑ\82 Ð¿Ð°ÐºÐµÑ\82 â\80\9e%sâ\80\9c Ðµ Ð½ÐµÐ¿Ñ\80авилен"
 
-msgid "relative path syntax can't be used outside working tree"
-msgstr "относителен път не може да се ползва извън работното дърво"
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr ""
+"повредена таблица със съответствия: местоположението на тройката е извън "
+"индекса"
 
-#, c-format
-msgid "<object>:<path> required, only <object> '%s' given"
-msgstr "необходими са и двете — ОБЕКТ:ПЪТ, а е даден само ОБЕКТът „%s“"
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr ""
+"повредена таблица със съответствия: веригата за XOR е по-дълга от броя на "
+"записите"
 
 #, c-format
-msgid "invalid object name '%.*s'."
-msgstr "неправилно име на обект: „%.*s“"
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr ""
+"повредена таблица със съответствия: индексът на подаването %u е извън "
+"диапазона"
 
 #, c-format
-msgid "invalid object type \"%s\""
-msgstr "неправилен вид обект: „%s“"
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr ""
+"повредена битова маска във формат EWAH: отрязана заглавна част за битовата "
+"маска на подаване „%s“"
 
 #, c-format
-msgid "object %s is a %s, not a %s"
-msgstr "обекÑ\82Ñ\8aÑ\82 â\80\9e%sâ\80\9c Ðµ %s, Ð° Ð½Ðµ %s"
+msgid "object '%s' not found in type bitmaps"
+msgstr "обекÑ\82Ñ\8aÑ\82 â\80\9e%sâ\80\9c Ð»Ð¸Ð¿Ñ\81ва Ð² Ð±Ð¸Ñ\82оваÑ\82а Ð¼Ð°Ñ\81ка Ð½Ð° Ð²Ð¸Ð´Ð¾Ð²ÐµÑ\82е"
 
 #, c-format
-msgid "object %s has unknown type id %d"
-msgstr "обекÑ\82Ñ\8aÑ\82 â\80\9e%sâ\80\9c Ðµ Ð½ÐµÐ¿Ð¾Ð·Ð½Ð°Ñ\82 Ð²Ð¸Ð´: %d"
+msgid "object '%s' does not have a unique type"
+msgstr "обекÑ\82Ñ\8aÑ\82 â\80\9e%sâ\80\9c Ð½Ñ\8fма Ñ\83никален Ð²Ð¸Ð´"
 
 #, c-format
-msgid "unable to parse object: %s"
-msgstr "обектът „%s“ не може да бъде анализиран"
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "обект „%s“: истинският му вид е „%s“, а се очакваше „%s“"
 
 #, c-format
-msgid "hash mismatch %s"
-msgstr "разлика в контролната сума: „%s“"
+msgid "object not in bitmap: '%s'"
+msgstr "обектът „%s“ липсва в индекса на база битови маски"
 
-msgid "multi-pack bitmap is missing required reverse index"
-msgstr "задÑ\8aлжиÑ\82елниÑ\8fÑ\82 Ð¾Ð±Ñ\80аÑ\82ен Ð¸Ð½Ð´ÐµÐºÑ\81 Ð»Ð¸Ð¿Ñ\81ва Ð² Ð¼Ð½Ð¾Ð³Ð¾Ð¿Ð°ÐºÐµÑ\82наÑ\82а Ð±Ð¸Ñ\82ова Ð¼Ð°Ñ\81ка"
+msgid "failed to load bitmap indexes"
+msgstr "неÑ\83Ñ\81пеÑ\88но Ð·Ð°Ñ\80еждане Ð½Ð° Ð¸Ð½Ð´ÐµÐºÑ\81и Ð½Ð° Ð±Ð°Ð·Ð° Ð±Ð¸Ñ\82ови Ð¼Ð°Ñ\81ки"
 
-#, c-format
-msgid "could not open pack %s"
-msgstr "пакетът „%s“ не може да се отвори"
+msgid "you must specify exactly one commit to test"
+msgstr "трябва да укажете точно едно подаване за тестване"
 
 #, c-format
-msgid "preferred pack (%s) is invalid"
-msgstr "предпочитаният пакет „%s“ е неправилен"
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "подаването „%s“ няма индекс на база битови маски"
+
+msgid "mismatch in bitmap results"
+msgstr "различие в резултатите от битовите маски"
 
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
 msgstr "„%s“ липсва в пакет „%s“ при отместване %<PRIuMAX>"
 
+#, c-format
+msgid "unable to get disk usage of '%s'"
+msgstr "използваното място за съхранение на „%s“ не може да бъде получено"
+
 #, c-format
 msgid "mtimes file %s is too small"
 msgstr "файлът с времето на промяна (mtime) „%s“ е твърде малък"
@@ -18230,6 +18517,9 @@ msgstr "„--%s“ (с 2 тирета) ли имахте предвид?"
 msgid "alias of --%s"
 msgstr "псевдоним на „--%s“"
 
+msgid "need a subcommand"
+msgstr "необходима е подкоманда"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "непозната опция: „%s“"
@@ -18683,9 +18973,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -18712,7 +19005,12 @@ msgstr ""
 "                    — създаване на подаване със сливане със съобщението от\n"
 "                      първоначалното подаване (или съобщението от ЕДИН_РЕД,\n"
 "                      ако не е зададено подаване със сливане.  С опцията\n"
-"                      „-c ПОДАВАНЕ“, може да смените съобщението.\n"
+"                      „-c ПОДАВАНЕ“, може да смените съобщението\n"
+"u, update-ref УКАЗАТЕЛ\n"
+"                    — проследяване на заместител на УКАЗАТЕЛя, който трябва\n"
+"                      да се обнови до това положение в новите подавания.\n"
+"                      УКАЗАТЕЛят се обновява в края на пребазирането\n"
+"\n"
 "\n"
 "Може да променяте последователността на редовете — те се изпълняват\n"
 "последователно отгоре-надолу.\n"
@@ -19188,6 +19486,13 @@ msgstr "протоколна грешка: очаква се SHA1 или ука
 msgid "http transport does not support %s"
 msgstr "транспортът по http не поддържа „%s“"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "протоколна грешка: очаква се „АДРЕС ПЪТ“, липсва интервал"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "файлът на адрес „%s“ не може да се свали"
+
 msgid "git-http-push failed"
 msgstr "неуспешно изпълнение на „git-http-push“"
 
@@ -19532,6 +19837,16 @@ msgstr "не може да се определи към какво да сочи
 msgid "failed to find tree of %s"
 msgstr "дървото, сочено от „%s“, не може да бъде открито"
 
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr ""
+"в информацията за отмяна на разрешените подавания присъства „%s“, който "
+"липсва"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "подаването „%s“ към опцията „--ancestry-path“ не може да бъде получено"
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "опцията „--unpacked=ПАКЕТЕН_ФАЙЛ“ вече не се поддържа"
 
@@ -19554,6 +19869,174 @@ msgstr ""
 msgid "cannot create async thread: %s"
 msgstr "не може да се създаде асинхронна нишка: %s"
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "„%s“ не съществува."
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "не може да се премине към „%s“"
+
+msgid "need a working directory"
+msgstr "необходима е работна директория"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Зачисляването на директории чрез „scalar“ изисква работно дърво"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "настройката „%s=%s“ не може да се зададе"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "„log.excludeDecoration“ не може да се настрои"
+
+msgid "could not add enlistment"
+msgstr "директория не може да се зачисли"
+
+msgid "could not set recommended config"
+msgstr "препоръчаните настройки не може да се зададат"
+
+msgid "could not turn on maintenance"
+msgstr "задачите по поддръжка не може да се включат"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "фоновият процес на FSMonitor не може да бъде спрян"
+
+msgid "could not turn off maintenance"
+msgstr "задачите по поддръжка не може да се изключат"
+
+msgid "could not remove enlistment"
+msgstr "директорията не може да се отчисли"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "отдалеченият указател „HEAD“ не сочи към клон: „%.*s“"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"името на стандартния клон на отдалеченото хранилище не може да се получи, "
+"затова ще се ползва локално настроеното име на стандартния клон"
+
+msgid "failed to get default branch name"
+msgstr "неуспешно получаване на името на стандартния клон"
+
+msgid "failed to unregister repository"
+msgstr "хранилището не може да бъде отчислено"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "фоновият процес FSMonitor не може да бъде спрян"
+
+msgid "failed to delete enlistment directory"
+msgstr "зачислената директория не може да бъде изтрита"
+
+msgid "branch to checkout after clone"
+msgstr "към кой клон да се премине след клониране"
+
+msgid "when cloning, create full working directory"
+msgstr "при клониране да се създава пълна работна директория"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "да се свалят метаданните само за изтегляния клон"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "името на работното дърво не може да се извлече от „%s“"
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "директорията „%s“ вече съществува"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "основният клон на „%s“ не може да бъде получен"
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "отдалеченото хранилище в „%s“ не може да се настрои"
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "„%s“ не може да се настрои"
+
+msgid "partial clone failed; attempting full clone"
+msgstr "неуспешно създаване на непълно хранилище, ще се опита пълно хранилище"
+
+msgid "could not configure for full clone"
+msgstr "не може да се настрои пълно клониране"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "„scalar list“ не приема аргументи"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "пренастройване на всички зачислени директории"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "опцията „--all“ и указването на зачислена директория не са съвместими"
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "вече няма хранилище на git в „%s“"
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run ЗАДАЧА [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]\n"
+"Задачи:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "няма задача с име „%s“"
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [ЗАЧИСЛЕНА_ДИРЕКТОРИЯ]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete ЗАЧИСЛЕНА_ДИРЕКТОРИЯ"
+
+msgid "refusing to delete current working directory"
+msgstr "текущата работна директория няма да бъде изтрита"
+
+msgid "include Git version"
+msgstr "включване и на версията на git"
+
+msgid "include Git's build options"
+msgstr "включване и на опциите за компилиране на git"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "„-C“ изисква ДИРЕКТОРИЯ"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "не може да се влезе в директорията „%s“"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "опцията „-c“ изисква аргумент във вид КЛЮЧ=СТОЙНОСТ"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C ДИРЕКТОРИЯ] [-c КЛЮЧ=СТОЙНОСТ] КОМАНДА [ОПЦИЯ…]<\n"
+"\n"
+"Команди:\n"
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr ""
 "неочакван изчистващ пакет „flush“ при изчитане на състоянието от "
@@ -19703,10 +20186,6 @@ msgstr "локалните промѐни ще бъдат презаписан
 msgid "commit your changes or stash them to proceed."
 msgstr "подайте или скатайте промѐните, за да продължите"
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: превъртане"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -20208,6 +20687,29 @@ msgstr "сливането на „%.*s“ не може даже да запо
 msgid "merge: Unable to write new index file"
 msgstr "сливане: новият индекс не може да бъде запазен"
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr ""
+"изглежда в момента тече друг процес за пребазиране; файлът „%s.lock“ вече "
+"съществува"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Следните указатели са обновени с %s:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Неуспешно обновяване на следните указатели с %s:\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "Не може да се скатае автоматично"
 
@@ -20377,6 +20879,10 @@ msgstr "излишните команди за отбиране не бяха п
 msgid "the script was already rearranged."
 msgstr "скриптът вече е преподреден."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "файлът за обновяване на указателите „%s“ е неправилен"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "„%s“ е извън хранилището при „%s“"
@@ -20504,16 +21010,21 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"хранилището не е безопасно („%s“ се притежава от някой друг)\n"
-"За да зададете изключение за тази директория, изпълнете:\n"
+"засечено е проблемно притежание на хранилището „%s“\n"
+"%sЗа да зададете изключение за тази директория, изпълнете:\n"
 "\n"
 "    git config --global --add safe.directory %s"
 
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr ""
+"голото хранилище „%s“ не може да се ползва („safe.bareRepository“ е „%s“)"
+
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -21388,6 +21899,18 @@ msgstr "неправилен номер на порт"
 msgid "invalid '..' path segment"
 msgstr "неправилна част от пътя „..“"
 
+msgid "usage: "
+msgstr "употреба: "
+
+msgid "fatal: "
+msgstr "фатална грешка: "
+
+msgid "error: "
+msgstr "грешка: "
+
+msgid "warning: "
+msgstr "предупреждение: "
+
 msgid "Fetching objects"
 msgstr "Доставяне на обектите"
 
@@ -22220,24 +22743,6 @@ msgstr "Избраните парчета не може да се добавят
 msgid "ignoring unmerged: %s\n"
 msgstr "пренебрегване на неслятото: „%s“\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Прилагане на промяната в правата за достъп към работното дърво [y,n,q,a,d"
-"%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Прилагане на изтриването към работното дърво [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Прилагане на добавянето към работното дърво [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "Прилагане на парчето към работното дърво [y,n,q,a,d%s,?]? "
-
 msgid "No other hunks to goto\n"
 msgstr "Няма други парчета\n"
 
index 80c430df4540bf329e4b4a0f92f43f6c3bcc3fa6..7a17ed5936046a55c612ad06f34ceba660a3b0f1 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -13,6 +13,7 @@
 #   bundle           |  farcell
 #   chunk            |  fragment
 #   cover letter     |  carta de presentació
+#   cruft            |  superflu
 #   delta            |  diferència
 #   deprecated       |  en desús
 #   detached         |  separat
 #   fetch            |  obtenir
 #   flush            |  buidar / buidatge
 #   graph            |  graf
+#   hash             |  resum
 #   hint             |  consell
 #   hook             |  lligam
 #   hunk             |  tros
 #   not supported    |  no està admès
 #   pull             |  baixar
 #   push             |  pujar
+#   quote            |  cometes (ortogràfiques)
 #   repository       |  repositori
 #   setting          |  paràmetre
 #   shallow          |  superficial
@@ -65,8 +68,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-24 13:30+0200\n"
-"PO-Revision-Date: 2022-06-03 19:00-0600\n"
+"POT-Creation-Date: 2022-09-28 18:55+0200\n"
+"PO-Revision-Date: 2022-09-28 19:00-0600\n"
 "Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
 "Language-Team: Catalan\n"
 "Language: ca\n"
@@ -472,6 +475,22 @@ msgstr ""
 "a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Aplica el canvi de mode a l'arbre de treball [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Aplica la supressió a l'arbre de treball [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Aplica l'addició a l'arbre de treball [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Aplica aquest tros a l'arbre de treball [y,n,q,a,d%s,?]? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -489,10 +508,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "no s'ha pogut analitzar la capçalera del tros «%.*s»"
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "no s'ha pogut analitzar la capçalera del tros acolorida «%.*s»"
-
 msgid "could not parse diff"
 msgstr "no s'ha pogut analitzar el diff"
 
@@ -780,11 +795,30 @@ msgstr ""
 "«false»\n"
 "\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Els camins següents s'han mogut fora de la\n"
+"definició de sparse-checkout però no són dispersos\n"
+"a causa de modificacions en local.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Per a corregir la dispersió d'aquests camins, feu el següent:\n"
+"* Useu «git add --sparse <paths>» per a actualitzar l'índex\n"
+"* Useu «git sparse-checkout reapply» per a aplicar les regles de dispersió"
+
 msgid "cmdline ends with \\"
 msgstr "la línia d'ordres acaba amb \\"
 
 msgid "unclosed quote"
-msgstr "cita no tancada"
+msgstr "commetes no tancades"
 
 #, c-format
 msgid "unrecognized whitespace option '%s'"
@@ -1219,7 +1253,7 @@ msgid "instead of applying the patch, output a summary for the input"
 msgstr "en lloc d'aplicar el pedaç, emet un resum de l'entrada"
 
 msgid "instead of applying the patch, see if the patch is applicable"
-msgstr "en lloc d'aplicar el pedaç, veges si el pedaç és aplicable"
+msgstr "en lloc d'aplicar el pedaç, determina si el pedaç és aplicable"
 
 msgid "make sure the patch is applicable to the current index"
 msgstr "assegura que el pedaç sigui aplicable a l'índex actual"
@@ -1294,6 +1328,10 @@ msgstr "no es pot transmetre el blob %s"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "mode de fitxer no compatible: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "error de deflació (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "no s'ha pogut iniciar el filtre «%s»"
@@ -1313,10 +1351,6 @@ msgstr "el camí no és vàlid en UTF-8: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "el camí és massa llarg (%d caràcters, SHA1: %s): %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "error de deflació (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "marca de temps massa gran per a aquest sistema: %<PRIuMAX>"
@@ -1364,17 +1398,17 @@ msgstr "Fitxer no trobat: %s"
 msgid "Not a regular file: %s"
 msgstr "No és un fitxer normal: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unclosed quote: '%s'"
-msgstr "cita no tancada"
+msgstr "cometes no tancades: «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "missing colon: '%s'"
-msgstr "falta el valor per «%s»"
+msgstr "falten els dos punts: «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "empty file name: '%s'"
-msgstr "mbox buit: «%s»"
+msgstr "nom de fitxer buit: «%s»"
 
 msgid "fmt"
 msgstr "format"
@@ -1394,9 +1428,8 @@ msgstr "fitxer"
 msgid "add untracked file to archive"
 msgstr "inclou els fitxers no seguits a l'arxiu"
 
-#, fuzzy
 msgid "path:content"
-msgstr "contingut"
+msgstr "camí: contingut"
 
 msgid "write the archive to this file"
 msgstr "escriu l'arxiu a aquest fitxer"
@@ -2423,16 +2456,20 @@ msgid "Are you sure [Y/n]? "
 msgstr "N'esteu segur [Y/n]? "
 
 msgid "status: waiting for both good and bad commits\n"
-msgstr ""
+msgstr "estat: s'estan esperant les comissions bones i dolentes\n"
 
 #, c-format
 msgid "status: waiting for bad commit, %d good commit known\n"
 msgid_plural "status: waiting for bad commit, %d good commits known\n"
 msgstr[0] ""
+"estat: s'està esperant una comissió incorrecta, es coneix %d comissió bona\n"
 msgstr[1] ""
+"estat: s'està esperant una comissió incorrecta, es coneixen %d comissions "
+"bones\n"
 
 msgid "status: waiting for good commit(s), bad commit known\n"
 msgstr ""
+"estat: s'està esperant comissions bones, es coneix una comissió incorrecta\n"
 
 msgid "no terms defined"
 msgstr "cap terme definit"
@@ -2472,7 +2509,7 @@ msgid "'%s' does not appear to be a valid revision"
 msgstr "«%s» no sembla ser una revisió vàlida"
 
 msgid "bad HEAD - I need a HEAD"
-msgstr "HEAD incorrecte - cal un HEAD"
+msgstr "HEAD incorrecte - cal una HEAD"
 
 #, c-format
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
@@ -2650,7 +2687,7 @@ msgstr ""
 "no tractis les comissions arrel com de frontera (per defecte: desactivat)"
 
 msgid "show work cost statistics"
-msgstr "mostra les estadístiques de preu de treball"
+msgstr "mostra les estadístiques del cost de treball"
 
 msgid "force progress reporting"
 msgstr "força l'informe de progrés"
@@ -2912,7 +2949,7 @@ msgid "Generic options"
 msgstr "Opcions genèriques"
 
 msgid "show hash and subject, give twice for upstream branch"
-msgstr "mostra el hash i l'assumpte, doneu dues vegades per a la branca font"
+msgstr "mostra el hash i l'assumpte, useu-lo dues vegades per a la branca font"
 
 msgid "suppress informational messages"
 msgstr "omet els missatges informatius"
@@ -2999,7 +3036,7 @@ msgid "print only branches of the object"
 msgstr "imprimeix només les branques de l'objecte"
 
 msgid "sorting and filtering are case insensitive"
-msgstr "l'ordenació i el filtratge distingeixen entre majúscules i minúscules"
+msgstr "ordenació i filtratge distingeixen entre majúscules i minúscules"
 
 msgid "recurse through submodules"
 msgstr "inclou recursivament als submòduls"
@@ -3027,7 +3064,7 @@ msgid "branch name required"
 msgstr "cal el nom de branca"
 
 msgid "Cannot give description to detached HEAD"
-msgstr "No es pot donar descripció a un HEAD separat"
+msgstr "No es pot donar descripció a una HEAD separada"
 
 msgid "cannot edit description of more than one branch"
 msgstr "no es pot editar la descripció de més d'una branca"
@@ -3105,8 +3142,12 @@ msgid "not run from a git repository - no hooks to show\n"
 msgstr ""
 "no s'està executant en un repositori de git - no hi ha lligams a mostrar\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3141,16 +3182,28 @@ msgstr ""
 "Reviseu la resta de l'informe d'error de sota.\n"
 "Podeu eliminar qualsevol línia que vulgueu.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "especifiqueu una destinació per al fitxer d'informe d'error"
+msgid "mode"
+msgstr "mode"
+
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"crea un arxiu zip addicional amb diagnòstics detallats (per defecte «stats»)"
 
-msgid "specify a strftime format suffix for the filename"
+msgid "specify a destination for the bugreport file(s)"
+msgstr "especifiqueu una destinació per al fitxer de l'informe d'error"
+
+msgid "specify a strftime format suffix for the filename(s)"
 msgstr "especifiqueu un sufix en format strftime per al nom de fitxer"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "no s'han pogut crear els directoris principals de «%s»"
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "no s'ha pogut crear l'arxiu de diagnòstic %s"
+
 msgid "System Info"
 msgstr "Informació del sistema"
 
@@ -3208,10 +3261,6 @@ msgstr "Cal un repositori per a desfer un farcell."
 msgid "Unbundling objects"
 msgstr "S'estan desagrupant objectes"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Subordre desconeguda: %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "no es pot llegir l'objecte %s «%s»"
@@ -3274,17 +3323,16 @@ msgstr "Comprova l'existència de l'objecte o emet el contingut de l'objecte"
 msgid "check if <object> exists"
 msgstr "comprova si <object> existeix"
 
-#, fuzzy
 msgid "pretty-print <object> content"
-msgstr "empremta de <object> contingut"
+msgstr "impressió embellida del contingut de l'<objecte>"
 
-#, fuzzy
 msgid "Emit [broken] object attributes"
-msgstr "Emet els atributs de l'objecte  objectbroken]"
+msgstr "Emet els atributs [broken] de l'objecte"
 
-#, fuzzy
 msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
-msgstr "mostra el tipus d'objecte (un de 'blob', 'tree', 'commit', 'tag', ...)"
+msgstr ""
+"mostra el tipus d'objecte (un dels següents: «blob», «tree», «commit», "
+"«tag», ...)"
 
 msgid "show object size"
 msgstr "mostra la mida de l'objecte"
@@ -3292,62 +3340,57 @@ msgstr "mostra la mida de l'objecte"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "permet que -s i -t funcionin amb objectes trencats/malmesos"
 
-#, fuzzy
+msgid "use mail map file"
+msgstr "usa el fitxer de mapa de correu"
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
-msgstr "Objectes lots sol·licitats a stdin (o --batch-all-objects)"
+msgstr "Objectes de lots sol·licitats a stdin (o --batch-all-objects)"
 
-#, fuzzy
 msgid "show full <object> or <rev> contents"
-msgstr "mostra el contingut complet de <object> o <rev>"
+msgstr "mostra el contingut complet de <objecte> o <rev>"
 
-#, fuzzy
 msgid "like --batch, but don't emit <contents>"
-msgstr "com --batch, però no emeti <contents>"
+msgstr "com a --batch, però no emetis <contents>"
+
+msgid "stdin is NUL-terminated"
+msgstr "l'entrada és acabada amb NUL"
 
-#, fuzzy
 msgid "read commands from stdin"
 msgstr "llegeix les ordres de stdin"
 
-#, fuzzy
 msgid "with --batch[-check]: ignores stdin, batches all known objects"
-msgstr "amb --batch--check:: ignora stdin, bateja tots els objectes coneguts"
+msgstr ""
+"amb --batch[-check]: ignora stdin, posa en lots tots els objectes coneguts"
 
-#, fuzzy
 msgid "Change or optimize batch output"
 msgstr "Canvia o optimitza la sortida per lots"
 
 msgid "buffer --batch output"
 msgstr "posa la sortida de --batch en memòria intermèdia"
 
-#, fuzzy
 msgid "follow in-tree symlinks"
 msgstr "segueix els enllaços simbòlics en l'arbre"
 
-#, fuzzy
 msgid "do not order objects before emitting them"
-msgstr "no ordena objectes abans d'emetre'ls"
+msgstr "no ordenis els objectes abans d'emetre'ls"
 
-#, fuzzy
 msgid ""
 "Emit object (blob or tree) with conversion or filter (stand-alone, or with "
 "batch)"
 msgstr ""
 "Emet l'objecte (blob o arbre) amb conversió o filtre (stand-alone, o amb lot)"
 
-#, fuzzy
 msgid "run textconv on object's content"
 msgstr "executar textconv al contingut de l'objecte"
 
-#, fuzzy
 msgid "run filters on object's content"
 msgstr "executa els filtres al contingut de l'objecte"
 
 msgid "blob|tree"
 msgstr "blob|tree"
 
-#, fuzzy
 msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
-msgstr "useu un <path> per a (--textconv | --filters); No amb 'batch'"
+msgstr "useu un <path> per a (--textconv | --filters); no amb «batch»"
 
 #, c-format
 msgid "'%s=<%s>' needs '%s' or '%s'"
@@ -3358,7 +3401,7 @@ msgstr "path|tree-ish"
 
 #, c-format
 msgid "'%s' requires a batch mode"
-msgstr "%s requereix un mode batch"
+msgstr "«%s» requereix un mode batch"
 
 #, c-format
 msgid "'-%c' is incompatible with batch mode"
@@ -3378,11 +3421,9 @@ msgstr "<object> requerit amb «-%c»"
 msgid "too many arguments"
 msgstr "hi ha massa arguments"
 
-#, fuzzy, c-format
+#, c-format
 msgid "only two arguments allowed in <type> <object> mode, not %d"
-msgstr ""
-"només es permeten dos arguments en el mode <type> <object>, no en un "
-"percentatge"
+msgstr "només es permeten dos arguments en el mode <type> <object>, no %d"
 
 msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
 msgstr "git check-attr [-a | --all | <atribut>...] [--] <nom-de-camí>..."
@@ -3460,9 +3501,8 @@ msgstr "«stage» ha de ser entre 1 i 3 o all"
 msgid "check out all files in the index"
 msgstr "agafa tots els fitxers en l'índex"
 
-#, fuzzy
 msgid "do not skip files with skip-worktree set"
-msgstr "no ometis els fitxers amb el conjunt d'arbres de salt"
+msgstr "no ometis els fitxers amb skip-worktree establert"
 
 msgid "force overwrite of existing files"
 msgstr "força la sobreescriptura de fitxers existents"
@@ -4016,7 +4056,7 @@ msgstr ""
 "ask each            - confirma cada supressió (com «rm -i»)\n"
 "quit                - deixa de netejar\n"
 "help                - aquesta pantalla\n"
-"?                   - ajuda de selecció de l'avís"
+"?                   - ajuda de selecció manual"
 
 msgid "Would remove the following item:"
 msgid_plural "Would remove the following items:"
@@ -4176,9 +4216,8 @@ msgstr "usa només adreces IPv4"
 msgid "use IPv6 addresses only"
 msgstr "usa només adreces IPv6"
 
-#, fuzzy
 msgid "apply partial clone filters to submodules"
-msgstr "Aplica els filtres de clonatge parcial als submòduls"
+msgstr "aplica els filtres de clonatge parcial als submòduls"
 
 msgid "any cloned submodules will use their remote-tracking branch"
 msgstr "qualsevol submòdul clonat utilitzarà la seva branca de seguiment remot"
@@ -4188,6 +4227,12 @@ msgstr ""
 "inicialitza el fitxer «sparse-checkout» per a incloure només els fitxers a "
 "l'arrel"
 
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "un URI per a baixar paquets abans d'obtenir des del remot origen"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: No s'ha pogut afegir un alternatiu per a «%s»: %s\n"
@@ -4247,10 +4292,10 @@ msgstr "no s'ha pogut actualitzar %s"
 msgid "failed to initialize sparse-checkout"
 msgstr "no s'ha pogut inicialitzar «sparse-checkout»"
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr ""
-"la HEAD remot es refereix a una referència que no existeix; no s'ha pogut "
-"agafar.\n"
+"la HEAD remot es refereix a una referència que no existeix, no s'ha pogut "
+"agafar"
 
 msgid "unable to checkout working tree"
 msgstr "no s'ha pogut agafar l'arbre de treball"
@@ -4274,6 +4319,12 @@ msgstr "Heu d'especificar un repositori per a clonar."
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "les opcions «%s» i «%s %s» no es poden usar juntes"
 
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri és incompatible amb --depth, --shallow-since i --shallow-exclude"
+
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "el repositori «%s» no existeix"
@@ -4347,6 +4398,13 @@ msgstr "--local s'ignora"
 msgid "cannot clone from filtered bundle"
 msgstr "no es pot clonar des del farell filtrat"
 
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "no s'ha pogut inicialitzar el repositori, s'omet l'URI del paquet"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "no s'han pogut obtenir els objectes de l'URI del paquet «%s»"
+
 msgid "remote transport reported error"
 msgstr "el transport remot ha informat d'un error"
 
@@ -4462,10 +4520,6 @@ msgstr "usa com a màxim un --reachable, --stdin-commits, o --stdin-packs"
 msgid "Collecting commits from input"
 msgstr "S'estan recollint les comissions de l'entrada"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "subordre no reconeguda: %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -4821,9 +4875,6 @@ msgstr "mostra l'estat en format llarg (per defecte)"
 msgid "terminate entries with NUL"
 msgstr "acaba les entrades amb NUL"
 
-msgid "mode"
-msgstr "mode"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "mostra els fitxers no seguits, modes opcionals: all, normal, no. (Per "
@@ -4869,7 +4920,7 @@ msgid "Commit message options"
 msgstr "Opcions de missatge de comissió"
 
 msgid "read message from file"
-msgstr "llegiu el missatge des d'un fitxer"
+msgstr "llegeix el missatge des d'un fitxer"
 
 msgid "author"
 msgstr "autor"
@@ -5095,7 +5146,7 @@ msgid "type"
 msgstr "tipus"
 
 msgid "value is given this type"
-msgstr "el valor té donat aquest tipus"
+msgstr "el valor és d'aquest tipus que s'ha donat"
 
 msgid "value is \"true\" or \"false\""
 msgstr "el valor és «true» o «false»"
@@ -5356,7 +5407,7 @@ msgstr ""
 
 #, c-format
 msgid "traversed %lu commits\n"
-msgstr "%lu comissions travessades\n"
+msgstr "%lu comissions recorregudes\n"
 
 #, c-format
 msgid ""
@@ -5427,6 +5478,22 @@ msgstr "No s'ha trobat cap nom, no es pot descriure res."
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "les opcions «%s» i de comissió no es poden usar juntes"
 
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "especifiqueu una destinació per a l'arxiu de diagnòstic"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "especifiqueu un sufix en format strftime per al nom de fitxer"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "especifica el contingut de l'arxiu de diagnòstic"
+
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base només funciona amb dues comissions"
 
@@ -5695,7 +5762,7 @@ msgid "set upstream for git pull/fetch"
 msgstr "estableix la font per a git pull/fetch"
 
 msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "annexa a .git/FETCH_HEAD en lloc de sobreescriure"
+msgstr "annexa a .git/FETCH_HEAD en lloc de sobreescriure'l"
 
 msgid "use atomic transaction to update references"
 msgstr "usa una transacció atòmica per a actualitzar les referències"
@@ -5755,9 +5822,8 @@ msgstr "aprofundeix la història d'un clon superficial basat en una data"
 msgid "convert to a complete repository"
 msgstr "converteix en un repositori complet"
 
-#, fuzzy
 msgid "re-fetch without negotiating common commits"
-msgstr "tornar a capturar sense negociar comissions comunes"
+msgstr "tornar a obtenir sense negociar comissions comunes"
 
 msgid "prepend this to submodule path output"
 msgstr "anteposa això a la sortida de camí del submòdul"
@@ -5812,12 +5878,9 @@ msgstr "[al dia]"
 msgid "[rejected]"
 msgstr "[rebutjat]"
 
-msgid "can't fetch in current branch"
+msgid "can't fetch into checked-out branch"
 msgstr "no es pot obtenir en la branca actual"
 
-msgid "checked out in another worktree"
-msgstr "s'ha agafat en un altre arbre de treball"
-
 msgid "[tag update]"
 msgstr "[actualització d'etiqueta]"
 
@@ -5974,7 +6037,6 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr "necessiteu especificar un nom d'etiqueta"
 
-#, fuzzy
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
 msgstr "--negotiate-only necessita un o més --negotiation-tip=*"
 
@@ -6025,7 +6087,7 @@ msgid "populate log with at most <n> entries from shortlog"
 msgstr "emplena el registre amb <n> entrades del registre curt com a màxim"
 
 msgid "alias for --log (deprecated)"
-msgstr "àlies per --log (en desús)"
+msgstr "àlies per --log (en desús)"
 
 msgid "text"
 msgstr "text"
@@ -6054,7 +6116,8 @@ msgstr ""
 
 msgid "quote placeholders suitably for shells"
 msgstr ""
-"posa els marcadors de posició de forma adequada per a intèrprets d'ordres"
+"posa els marcadors de posició entre cometes adequades per a intèrprets "
+"d'ordres"
 
 msgid "quote placeholders suitably for perl"
 msgstr "posa els marcadors de posició entre cometes adequades per al perl"
@@ -6131,15 +6194,15 @@ msgstr "S'està comprovant la connectivitat"
 
 #, c-format
 msgid "missing %s %s"
-msgstr "manca %s %s"
+msgstr "%s %s manca"
 
 #, c-format
 msgid "unreachable %s %s"
-msgstr "inabastable %s %s"
+msgstr "%s %s inabastable"
 
 #, c-format
 msgid "dangling %s %s"
-msgstr "sense assignació %s %s"
+msgstr "%s %s sense assignació"
 
 msgid "could not create lost-found"
 msgstr "no s'ha pogut crear el trobat-perdut"
@@ -6238,7 +6301,7 @@ msgstr "%s apunta a una cosa estranya (%s)"
 
 #, c-format
 msgid "%s: detached HEAD points at nothing"
-msgstr "%s: el HEAD separat no apunta a res"
+msgstr "%s: la HEAD separada no apunta a res"
 
 #, c-format
 msgid "notice: %s points to an unborn branch (%s)"
@@ -6254,6 +6317,10 @@ msgstr "%s: apuntador sha1 no vàlid a l'arbre de la memòria cau"
 msgid "non-tree in cache-tree"
 msgstr "un no arbre en l'arbre de la memòria cau"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s: el punter sha1 no és vàlid a «resolve-undo»"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<opcions>] [<objecte>...]"
 
@@ -6320,49 +6387,45 @@ msgstr "git fsmonitor--daemon status"
 msgid "value of '%s' out of range: %d"
 msgstr "el valor de «%s» està fora de rang: %d"
 
-#, fuzzy, c-format
+#, c-format
 msgid "value of '%s' not bool or int: %d"
-msgstr "valor de \"%s\" no bool ni int: el percentatge"
+msgstr "valor de «%s» no és booleà ni enter: %d"
 
 #, c-format
 msgid "fsmonitor-daemon is watching '%s'\n"
-msgstr "fsmonitor-daemon està veient '%s'\n"
+msgstr "fsmonitor-daemon està veient «%s»\n"
 
 #, c-format
 msgid "fsmonitor-daemon is not watching '%s'\n"
 msgstr "fsmonitor-daemon no està vigilant «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not create fsmonitor cookie '%s'"
-msgstr "no s'ha pogut crear la galeta fsmonitor '%s'"
+msgstr "no s'ha pogut crear la galeta fsmonitor «%s»"
 
 #, c-format
 msgid "fsmonitor: cookie_result '%d' != SEEN"
-msgstr "fsmonitor: cookie_result '%d' != SEEN"
+msgstr "fsmonitor: cookie_result «%d» != SEEN"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not start IPC thread pool on '%s'"
 msgstr "no s'ha pogut iniciar el grup de fils IPC a «%s»"
 
-#, fuzzy
 msgid "could not start fsmonitor listener thread"
-msgstr "no s'ha pogut iniciar el fil d'oient del fsmonitor"
+msgstr "no s'ha pogut iniciar el fil receptor del fsmonitor"
 
-#, fuzzy
 msgid "could not start fsmonitor health thread"
-msgstr "no s'ha pogut iniciar el fil d'oient del fsmonitor"
+msgstr "no s'ha pogut iniciar el fil de salut del fsmonitor"
 
-#, fuzzy
 msgid "could not initialize listener thread"
-msgstr "no s'ha pogut inicialitzar el fil d'oient"
+msgstr "no s'ha pogut inicialitzar el fil receptor"
 
-#, fuzzy
 msgid "could not initialize health thread"
-msgstr "no s'ha pogut inicialitzar el fil d'oient"
+msgstr "no s'ha pogut inicialitzar el fil de salut"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not cd home '%s'"
-msgstr "no s'ha pogut tancar «%s»"
+msgstr "no s'ha pogut fer cd home «%s»"
 
 #, c-format
 msgid "fsmonitor--daemon is already running '%s'"
@@ -6372,15 +6435,13 @@ msgstr "fsmonitor--daemon is already running «%s»"
 msgid "running fsmonitor-daemon in '%s'\n"
 msgstr "s'està executant fsmonitor-daemon en «%s»\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "starting fsmonitor-daemon in '%s'\n"
-msgstr "s'està iniciant fsmonitor-daemon a «%s»"
+msgstr "s'està iniciant fsmonitor-daemon a «%s»\n"
 
-#, fuzzy
 msgid "daemon failed to start"
 msgstr "el dimoni ha fallat en iniciar"
 
-#, fuzzy
 msgid "daemon not online yet"
 msgstr "el dimoni encara no està en línia"
 
@@ -6393,19 +6454,17 @@ msgstr "separat de la consola"
 msgid "use <n> ipc worker threads"
 msgstr "usa <n> fils de treball ipc"
 
-#, fuzzy
 msgid "max seconds to wait for background daemon startup"
-msgstr "màxim de segons a esperar a l'inici del dimoni de fons"
+msgstr "màxim de segons a esperar a l'inici del dimoni en segon pla"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid 'ipc-threads' value (%d)"
-msgstr "valor «ipc-threads» no vàlid (%)"
+msgstr "valor «ipc-threads» no vàlid (%d)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Unhandled subcommand '%s'"
-msgstr "Subordre no gestionada '%s'"
+msgstr "Subordre no gestionada «%s»"
 
-#, fuzzy
 msgid "fsmonitor--daemon not supported on this platform"
 msgstr "fsmonitor--daemon no és compatible amb aquesta plataforma"
 
@@ -6441,9 +6500,8 @@ msgstr ""
 msgid "prune unreferenced objects"
 msgstr "poda objectes sense referència"
 
-#, fuzzy
 msgid "pack unreferenced objects separately"
-msgstr "poda objectes sense referència"
+msgstr "empaqueta els objectes no referenciats de forma separada"
 
 msgid "be more thorough (increased runtime)"
 msgstr "sigues més exhaustiu (el temps d'execució augmenta)"
@@ -6458,9 +6516,9 @@ msgstr ""
 msgid "repack all other packs except the largest pack"
 msgstr "reempaqueta tots els altres paquets excepte el paquet més gran"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to parse gc.logExpiry value %s"
-msgstr "no s'ha pogut analitzar el valor %s de gc.logexpiry"
+msgstr "no s'ha pogut analitzar el valor %s de gc.logExpiry"
 
 #, c-format
 msgid "failed to parse prune expiry value %s"
@@ -6598,13 +6656,16 @@ msgstr ""
 "no s'ha pogut executar «crontab -l»; el vostre sistema podria no admetre "
 "«cron»"
 
+msgid "failed to create crontab temporary file"
+msgstr "no s'ha pogut crear un fitxer temporal crontab"
+
+msgid "failed to open temporary file"
+msgstr "no s'ha pogut obrir el fitxer temporal"
+
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "no s'ha pogut executar «crontab»; el vostre sistema podria no admetre «cron»"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "s'ha produït un error en obrir stdin de «crontab»"
-
 msgid "'crontab' died"
 msgstr "«crontab» ha mort"
 
@@ -6651,10 +6712,6 @@ msgstr "no s'ha pogut afegir un repositori a la configuració global"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <subcommand> [<options>]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "subordre no vàlida: %s"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<opcions>] [-e] <patró> [<revisió>...] [[--] <camí>...]"
 
@@ -6715,7 +6772,7 @@ msgid "process binary files as text"
 msgstr "processa els fitxers binaris com a text"
 
 msgid "don't match patterns in binary files"
-msgstr "no coincideixis amb els patrons en els fitxers binaris"
+msgstr "no cerquis els patrons en els fitxers binaris"
 
 msgid "process binary files with textconv filters"
 msgstr "processa els fitxers binaris amb filtres de textconv"
@@ -6829,6 +6886,9 @@ msgstr "mostra els fitxers coincidents en el paginador"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "permet la invocació de grep(1) (ignorat per aquesta compilació)"
 
+msgid "maximum number of results per file"
+msgstr "nombre màxim de resultats per fitxer"
+
 msgid "no pattern given"
 msgstr "no s'ha donat cap patró"
 
@@ -6892,11 +6952,9 @@ msgstr "processa el fitxer com si fos d'aquest camí"
 msgid "print all available commands"
 msgstr "imprimeix totes les ordres disponibles"
 
-#, fuzzy
 msgid "show external commands in --all"
 msgstr "mostra les ordres externes a --all"
 
-#, fuzzy
 msgid "show aliases in --all"
 msgstr "mostra els àlies a --all"
 
@@ -6918,11 +6976,21 @@ msgstr "imprimeix la descripció de l'ordre"
 msgid "print list of useful guides"
 msgstr "imprimeix la llista de guies útils"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr ""
+"imprimeix la llista de repositoris, ordres i interfícies de fitxers que veu "
+"l'usuari"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr ""
+"mostra la llista de formats de fitxer, protocols i altres interfícies de "
+"desenvolupador"
+
 msgid "print all configuration variable names"
 msgstr "imprimeix tots els noms de les variables de configuració"
 
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -6976,16 +7044,15 @@ msgstr "«%s» és un àlies de «%s»"
 msgid "bad alias.%s string: %s"
 msgstr "cadena «alias.%s» incorrecte: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "the '%s' option doesn't take any non-option arguments"
 msgstr "l'opció «%s» no pren cap argument que no sigui una opció"
 
-#, fuzzy
 msgid ""
 "the '--no-[external-commands|aliases]' options can only be used with '--all'"
 msgstr ""
-"les opcions «--no-exexternal-commands|aliases with» només es poden utilitzar "
-"amb «--all»"
+"les opcions «--no-[external-commands|aliases]» només es poden utilitzar amb "
+"«--all»"
 
 #, c-format
 msgid "usage: %s%s"
@@ -7144,8 +7211,8 @@ msgstr "Suma de verificació final no esperada per a %s (corrupció de disc?)"
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
-msgstr[0] "El paquet té %d diferència no resolta"
-msgstr[1] "El paquet té %d diferències no resoltes"
+msgstr[0] "el paquet té %d diferència no resolta"
+msgstr[1] "el paquet té %d diferències no resoltes"
 
 #, c-format
 msgid "unable to deflate appended object (%d)"
@@ -7174,9 +7241,9 @@ msgstr "no s'ha pogut canviar el nom del fitxer temporal «*.%s» a «%s»"
 msgid "error while closing pack file"
 msgstr "error en tancar el fitxer empaquetat"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad pack.indexVersion=%<PRIu32>"
-msgstr "pack.indexversion=%<PRIu32> incorrecte"
+msgstr "bad pack.indexVersion=%<PRIu32>"
 
 #, c-format
 msgid "Cannot open existing pack file '%s'"
@@ -7207,7 +7274,7 @@ msgstr "%s incorrecte"
 
 #, c-format
 msgid "unknown hash algorithm '%s'"
-msgstr "algorisme hash desconegut «%s»"
+msgstr "algorisme de resum desconegut «%s»"
 
 msgid "--stdin requires a git repository"
 msgstr "--stdin requereix un repositori git"
@@ -7263,7 +7330,7 @@ msgid "unable to move %s to %s"
 msgstr "no s'ha pogut moure %s a %s"
 
 msgid "attempt to reinitialize repository with different hash"
-msgstr "s'ha intentat reinicialitzar el repositori amb un hash diferent"
+msgstr "s'ha intentat reinicialitzar el repositori amb un resum diferent"
 
 #, c-format
 msgid "%s already exists"
@@ -7307,7 +7374,7 @@ msgid "override the name of the initial branch"
 msgstr "sobreescriu el nom de la branca inicial"
 
 msgid "hash"
-msgstr "hash"
+msgstr "resum"
 
 msgid "specify the hash algorithm to use"
 msgstr "especifiqueu l'algorisme de resum a usar"
@@ -7397,8 +7464,8 @@ msgstr "omet la sortida de diferències"
 msgid "show source"
 msgstr "mostra la font"
 
-msgid "use mail map file"
-msgstr "usa el fitxer de mapa de correu"
+msgid "clear all previously-defined decoration filters"
+msgstr "neteja tots els filtres de decoració prèviament definits"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "només decora les referències que coincideixin amb <patró>"
@@ -7427,7 +7494,6 @@ msgstr "-L<range>:<file> no es pot usar amb una especificació de camí"
 msgid "Final output: %d %s\n"
 msgstr "Sortida final: %d %s\n"
 
-#, fuzzy
 msgid "unable to create temporary object directory"
 msgstr "no s'ha pogut crear el directori temporal de l'objecte"
 
@@ -7494,7 +7560,7 @@ msgid ""
 msgstr ""
 "no s'ha pogut obtenir la font, si voleu registrar la comissió base\n"
 "automàticament, useu git branch --set-upstream-to per a seguir una\n"
-"una branca remota. També podeu especificar la comissió base amb --base=<base-"
+"branca remota. També podeu especificar la comissió base amb --base=<base-"
 "commit-id> manualment"
 
 msgid "failed to find exact merge base"
@@ -7574,7 +7640,7 @@ msgid "don't output binary diffs"
 msgstr "no emetis diferències binàries"
 
 msgid "output all-zero hash in From header"
-msgstr "emet un hash de tots zeros en la capçalera From"
+msgstr "emet un resum de tots zeros en la capçalera From"
 
 msgid "don't include a patch matching a commit upstream"
 msgstr "no incloguis pedaços que coincideixin amb comissions a la font"
@@ -7658,6 +7724,11 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr "percentatge pel qual la creació és ponderada"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr ""
+"mostra en el cos el remitent: encara que sigui idèntic a la capçalera del "
+"correu electrònic"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "línia d'identitat no vàlida: %s"
@@ -7718,6 +7789,18 @@ msgstr ""
 "No s'ha pogut trobar una branca remota seguida. Especifiqueu <font> "
 "manualment.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "format incorrecte del ls-files: l'element «%s» no comença amb «(»"
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "format incorrecte del ls-files: l'element «%s» no acaba amb «)»"
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "format incorrecte de ls-files: %%%.*s"
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<opcions>] [<fitxer>...]"
 
@@ -7804,6 +7887,13 @@ msgstr "suprimeix les entrades duplicades"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "mostra els directoris dispersos en presència d'un índex dispers"
 
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format no es pot usar amb -s, -o, -k, -t, --resolve-undo, --deduplicate, --"
+"eol"
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url]\n"
@@ -7826,7 +7916,7 @@ msgid "limit to tags"
 msgstr "limita a etiquetes"
 
 msgid "limit to heads"
-msgstr "limita a caps"
+msgstr "limita a «heads»"
 
 msgid "do not show peeled tags"
 msgstr "no mostris les etiquetes pelades"
@@ -7843,21 +7933,21 @@ msgstr "mostra la referència subjacent a més de l'objecte que assenyali"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<opcions>] <arbre> [<camí>...]"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not get object info about '%s'"
-msgstr "no s'ha pogut obtenir la informació de l'objecte sobre «%s»"
+msgstr "no s'ha pogut obtenir la informació sobre l'objecte «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "format ls-tree dolent: l'element '%s' no comença amb '('"
+msgstr "format incorrecte del ls-tree: l'element '%s' no comença amb «(»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "format ls-tree dolent: l'element '%s' no acaba en ')'"
+msgstr "format incorrecte del ls-tree: l'element '%s' no acaba en «(»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad ls-tree format: %%%.*s"
-msgstr "format incorrecte de ls-tree:%%.*s"
+msgstr "format incorrecte de ls-tree: %%%.*s"
 
 msgid "only show trees"
 msgstr "mostra només els arbres"
@@ -7877,7 +7967,6 @@ msgstr "mida de l'objecte d'inclusió"
 msgid "list only filenames"
 msgstr "llista només els noms de fitxer"
 
-#, fuzzy
 msgid "list only objects"
 msgstr "llista només els objectes"
 
@@ -7888,7 +7977,6 @@ msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
 "llista l'arbre sencer; no només el directori actual (implica --full-name)"
 
-#, fuzzy
 msgid "--format can't be combined with other format-altering options"
 msgstr "--format no es pot combinar amb altres opcions d'alteració de format"
 
@@ -7924,14 +8012,13 @@ msgid "<action>"
 msgstr "<acció>"
 
 msgid "action when quoted CR is found"
-msgstr "acció quan es troba un CR en una cita"
+msgstr "acció quan es troba un CR entre cometes"
 
 msgid "use headers in message's body"
 msgstr "utilitza les capçaleres en el cos del missatge"
 
-#, fuzzy
 msgid "reading patches from stdin/tty..."
-msgstr "llegir pedaços de stdin/tty..."
+msgstr "s'estan llegint pedaços de stdin/tty..."
 
 #, c-format
 msgid "empty mbox: '%s'"
@@ -8027,6 +8114,39 @@ msgstr "no s'ha pogut resoldre la referència «%s»"
 msgid "Merging %s with %s\n"
 msgstr "S'està fusionant %s amb %s\n"
 
+msgid "not something we can merge"
+msgstr "no és quelcom que puguem fusionar"
+
+msgid "refusing to merge unrelated histories"
+msgstr "s'està refusant fusionar històries no relacionades"
+
+msgid "failure to merge"
+msgstr "s'ha produït un error en fusionar"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "fes una fusió real en lloc d'una fusió trivial"
+
+msgid "do a trivial merge only"
+msgstr "fes només una fusió trivial"
+
+msgid "also show informational/conflict messages"
+msgstr "també mostra missatges informatius i de conflictes"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "llista els noms de fitxer sense modes/oids/stages"
+
+msgid "allow merging unrelated histories"
+msgstr "permet fusionar històries no relacionades"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge és incompatible amb totes les altres opcions"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<opcions>] [<comissió>...]"
 
@@ -8106,10 +8226,7 @@ msgid "--abort but leave index and working tree alone"
 msgstr "--abort però deixa l'índex i l'arbre de treball intactes"
 
 msgid "continue the current in-progress merge"
-msgstr "continua la fusió en curs actual"
-
-msgid "allow merging unrelated histories"
-msgstr "permet fusionar històries no relacionades"
+msgstr "continua la fusió actual en curs"
 
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "evita els lligams pre-merge-commit i commit-msg"
@@ -8230,9 +8347,6 @@ msgstr "no s'ha pogut tancar «%s»"
 msgid "not something we can merge in %s: %s"
 msgstr "no és quelcom que puguem fusionar en %s: %s"
 
-msgid "not something we can merge"
-msgstr "no és quelcom que puguem fusionar"
-
 msgid "--abort expects no arguments"
 msgstr "--abort no espera cap argument"
 
@@ -8271,25 +8385,30 @@ msgstr ""
 "establert."
 
 msgid "Squash commit into empty head not supported yet"
-msgstr "Una comissió «squash» a un HEAD buit encara no es permet"
+msgstr "Una comissió «squash» a una HEAD buida encara no es permet"
 
 msgid "Non-fast-forward commit does not make sense into an empty head"
-msgstr "Una comissió no d'avanç ràpid no té sentit a un HEAD buit"
+msgstr "Una comissió no d'avanç ràpid no té sentit a una HEAD buida"
 
 #, c-format
 msgid "%s - not something we can merge"
 msgstr "%s - no és una cosa que puguem fusionar"
 
 msgid "Can merge only exactly one commit into empty head"
-msgstr "Es pot fusionar només una comissió a un HEAD buit"
-
-msgid "refusing to merge unrelated histories"
-msgstr "s'està refusant fusionar històries no relacionades"
+msgstr "Es pot fusionar només una comissió a una HEAD buida"
 
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "S'estan actualitzant %s..%s\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Els canvis locals als fitxers següents se sobreescriuran per la fusió:\n"
+"  %s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "S'està intentant una fusió molt trivial en l'índex...\n"
@@ -8324,6 +8443,10 @@ msgstr ""
 "La fusió automàtica ha sortit bé; s'ha aturat abans de cometre com s'havia "
 "demanat\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "Quan acabi, aplica els canvis «stashed» amb «git stash pop»\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "avís: l'entrada d'etiqueta no passa fsck: %s"
@@ -8381,9 +8504,8 @@ msgstr "git multi-pack-index [<opcions>] expire"
 msgid "git multi-pack-index [<options>] repack [--batch-size=<size>]"
 msgstr "git multi-pack-index [<opcions>] repack [--batch-size=<mida>]"
 
-#, fuzzy
 msgid "directory"
-msgstr "fitxer/directori"
+msgstr "directori"
 
 msgid "object directory containing set of packfile and pack-index pairs"
 msgstr ""
@@ -8447,6 +8569,9 @@ msgstr "S'està comprovant el canvi de nom de «%s» a «%s»\n"
 msgid "bad source"
 msgstr "origen incorrecte"
 
+msgid "destination exists"
+msgstr "el destí existeix"
+
 msgid "can not move directory into itself"
 msgstr "no es pot moure un directori a dins d'ell mateix"
 
@@ -8462,9 +8587,6 @@ msgstr "no està sota control de versions"
 msgid "conflicted"
 msgstr "en conflicte"
 
-msgid "destination exists"
-msgstr "el destí existeix"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "s'està sobreescrivint «%s»"
@@ -8478,6 +8600,9 @@ msgstr "múltiples orígens per al mateix destí"
 msgid "destination directory does not exist"
 msgstr "el directori destí no existeix"
 
+msgid "destination exists in the index"
+msgstr "el destí existeix a l'índex"
+
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, origen=%s, destí=%s"
@@ -8514,11 +8639,9 @@ msgstr "ignora les referències que coincideixin amb <patró>"
 msgid "list all commits reachable from all refs"
 msgstr "llista totes les comissions abastables de totes les referències"
 
-#, fuzzy
 msgid "deprecated: use --annotate-stdin instead"
-msgstr "obsolet: useu annotate-stdin"
+msgstr "obsolet: useu en comptes --annotate-stdin"
 
-#, fuzzy
 msgid "annotate text from stdin"
 msgstr "anota el text de stdin"
 
@@ -8842,8 +8965,8 @@ msgid "use notes from <notes-ref>"
 msgstr "usa les notes de <referència-de-notes>"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "subordre desconeguda: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "subordre desconeguda: «%s»"
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -8986,21 +9109,18 @@ msgstr "no s'ha pogut obtenir el tipus de l'objecte %s al paquet %s"
 msgid "could not find pack '%s'"
 msgstr "no s'ha pogut trobar el paquet «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "packfile %s cannot be accessed"
-msgstr "el fitxer de paquet %s no es pot mapar%s"
+msgstr "no es pot accedir al fitxer de paquet %s"
 
-#, fuzzy
 msgid "Enumerating cruft objects"
-msgstr "S'estan enumerant els objectes"
+msgstr "S'estan enumerant els objectes superflus"
 
-#, fuzzy
 msgid "unable to add cruft objects"
-msgstr "no s'han pogut afegir els objectes recents"
+msgstr "no s'han pogut afegir els objectes superflus"
 
-#, fuzzy
 msgid "Traversing cruft objects"
-msgstr "S'estan comprimint els objectes"
+msgstr "S'estan recorrent els objectes superflus"
 
 #, c-format
 msgid ""
@@ -9018,9 +9138,8 @@ msgstr ""
 "s'esperava un identificador d'objecte, s'ha rebut brossa:\n"
 " %s"
 
-#, fuzzy
 msgid "could not load cruft pack .mtimes"
-msgstr "no s'ha pogut carregar el paquet"
+msgstr "no s'ha pogut carregar superflus del paquet superflu"
 
 msgid "cannot open pack index"
 msgstr "no s'ha pogut obrir l'índex del paquet"
@@ -9090,16 +9209,16 @@ msgid "use OFS_DELTA objects"
 msgstr "usa objectes OFS_DELTA"
 
 msgid "use threads when searching for best delta matches"
-msgstr "usa fils en cercar les millores coincidències de diferències"
+msgstr "usa fils en cercar les millors coincidències de diferències"
 
 msgid "do not create an empty pack output"
-msgstr "no creïs una emissió de paquet buida"
+msgstr "no creïs una emissió de paquet buit"
 
 msgid "read revision arguments from standard input"
 msgstr "llegeix els arguments de revisió des de l'entrada estàndard"
 
 msgid "limit the objects to those that are not yet packed"
-msgstr "limita els objectes als quals encara no s'hagin empaquetat"
+msgstr "limita els objectes a aquells que encara no estan empaquetats"
 
 msgid "include objects reachable from any reference"
 msgstr "inclou els objectes abastables de qualsevol referència"
@@ -9131,13 +9250,11 @@ msgstr "empaqueta els objectes inabastables solts"
 msgid "unpack unreachable objects newer than <time>"
 msgstr "desempaqueta els objectes inabastables més nous que <data>"
 
-#, fuzzy
 msgid "create a cruft pack"
-msgstr "crea paquets prims"
+msgstr "crea un paquet superflu"
 
-#, fuzzy
 msgid "expire cruft objects older than <time>"
-msgstr "fes caducar els objectes més antics que <data>"
+msgstr "fes caducar els objectes superflus més antics que <data>"
 
 msgid "use the sparse reachability algorithm"
 msgstr "utilitza l'algorisme d'accessibilitat dispers"
@@ -9175,7 +9292,7 @@ msgid "handling for missing objects"
 msgstr "gestió dels objectes absents"
 
 msgid "do not pack objects in promisor packfiles"
-msgstr "empaquetis els objectes als fitxers de paquet «promisor»"
+msgstr "no empaquetis els objectes als fitxers de paquet «promisor»"
 
 msgid "respect islands during delta compression"
 msgstr "respecta les illes durant la compressió delta"
@@ -9219,17 +9336,14 @@ msgstr "no es pot utilitzar --filter sense --stdin-packs"
 msgid "cannot use internal rev list with --stdin-packs"
 msgstr "no es pot utilitzar la llista de revisió interna amb --stdin-packs"
 
-#, fuzzy
 msgid "cannot use internal rev list with --cruft"
-msgstr "no es pot utilitzar la llista de revisió interna amb --stdin-packs"
+msgstr "no es pot utilitzar la llista de revisió interna amb --cruft"
 
-#, fuzzy
 msgid "cannot use --stdin-packs with --cruft"
-msgstr "no es pot usar -a amb -d"
+msgstr "no es pot --stdin-packs amb --cruft"
 
-#, fuzzy
 msgid "cannot use --max-pack-size with --cruft"
-msgstr "no es pot usar -a amb -d"
+msgstr "no es pot usar --max-pack-size amb --cruft"
 
 msgid "Enumerating objects"
 msgstr "S'estan enumerant els objectes"
@@ -9408,7 +9522,7 @@ msgstr ""
 "preferència per defecte per a tots els repositoris. Podeu també usar --"
 "rebase,\n"
 "--no-rebase o --ff-only en la línia d'ordres per a sobreescriure el valor\n"
-"per defecte configuració en aquesta execució.\n"
+"per defecte de la configuració en aquesta execució.\n"
 
 msgid "Updating an unborn branch with changes added to the index."
 msgstr ""
@@ -9448,7 +9562,7 @@ msgstr ""
 "per a recuperar."
 
 msgid "Cannot merge multiple branches into empty head."
-msgstr "No es poden fusionar múltiples branques a un HEAD buit."
+msgstr "No es poden fusionar múltiples branques a una HEAD buida."
 
 msgid "Cannot rebase onto multiple branches."
 msgstr "No es pot fer «rebase» sobre múltiples branques."
@@ -9473,14 +9587,13 @@ msgstr "abreviatura d'etiqueta sense <tag>"
 msgid "--delete only accepts plain target ref names"
 msgstr "--delete només accepta noms de referència de destí senzills"
 
-#, fuzzy
 msgid ""
 "\n"
 "To choose either option permanently, see push.default in 'git help config'.\n"
 msgstr ""
 "\n"
-"Per a triar qualsevol opció permanentment, vegeu push.default a «git help "
-"config»."
+"Per a triar qualsevol de les opcions permanentment, vegeu push.default a "
+"«git help config».\n"
 
 msgid ""
 "\n"
@@ -9489,8 +9602,13 @@ msgid ""
 "autoSetupMerge\n"
 "in 'git help config'.\n"
 msgstr ""
+"\n"
+"Per a evitar configurar automàticament les branques font quan el seu nom\n"
+"no coincideix amb el de la branca local, vegeu l'opció «simple» de «branch."
+"autoSetupMerge»\n"
+"a «git help config».\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The upstream branch of your current branch does not match\n"
 "the name of your current branch.  To push to the upstream branch\n"
@@ -9512,7 +9630,7 @@ msgstr ""
 "Per a pujar a la branca del mateix nom en el remot, useu\n"
 "\n"
 "    git push %s HEAD\n"
-"%s"
+"%s%s"
 
 #, c-format
 msgid ""
@@ -9533,8 +9651,12 @@ msgid ""
 "To have this happen automatically for branches without a tracking\n"
 "upstream, see 'push.autoSetupRemote' in 'git help config'.\n"
 msgstr ""
+"\n"
+"Per fer que això succeeixi automàticament per a les branques sense "
+"seguiment\n"
+"font, vegeu «push.autoSetupRemote» a «git help config».\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The current branch %s has no upstream branch.\n"
 "To push the current branch and set the remote as upstream, use\n"
@@ -9546,6 +9668,7 @@ msgstr ""
 "Per a pujar la branca actual i establir el remot com a font, useu\n"
 "\n"
 "    git push --set-upstream %s %s\n"
+"%s"
 
 #, c-format
 msgid "The current branch %s has multiple upstream branches, refusing to push."
@@ -9760,12 +9883,17 @@ msgstr "emet només la sortida relacionada amb el primer interval"
 msgid "only emit output related to the second range"
 msgstr "emet només la sortida relacionada amb el segon interval"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "«%s» no és una revisió"
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "no és un rang de comissions: «%s»"
 
-msgid "single arg format must be symmetric range"
-msgstr "el format de l'argument únic ha de ser de rang simètric"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "no és un rang simètric: «%s»"
 
 msgid "need two commit ranges"
 msgstr "calen dos rangs de comissió"
@@ -9804,7 +9932,7 @@ msgid "<subdirectory>/"
 msgstr "<subdirectori>/"
 
 msgid "read the tree into the index under <subdirectory>/"
-msgstr "llegiu l'arbre a l'índex sota <subdirectori>/"
+msgstr "llegeix l'arbre a l'índex sota <subdirectori>/"
 
 msgid "update working tree with merge result"
 msgstr "actualitza l'arbre de treball amb el resultat de fusió"
@@ -9983,7 +10111,7 @@ msgid "add a Signed-off-by trailer to each commit"
 msgstr "afegeix un «trailer» tipus «Signed-off-by» a cada comissió"
 
 msgid "make committer date match author date"
-msgstr "fes que la data del «comitter» coincideixi amb la data de l'autor"
+msgstr "fes que la data del «committer» coincideixi amb la data de l'autor"
 
 msgid "ignore author date and use current date"
 msgstr "ignora la data de l'autor i utilitza la data actual"
@@ -10027,9 +10155,8 @@ msgstr "utilitza estratègies de fusió per a fer «rebase»"
 msgid "let the user edit the list of commits to rebase"
 msgstr "permet a l'usuari editar la llista de comissions a fer «rebase»"
 
-#, fuzzy
 msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
-msgstr "(EN DESÚS) intenta recrear fusions en lloc d'ignorar-les"
+msgstr "(SUPRIMIT) era: intenta recrear fusions en lloc d'ignorar-les"
 
 msgid "how to handle commits that become empty"
 msgstr "com gestionar les comissions que queden buides"
@@ -10040,6 +10167,11 @@ msgstr "manté les comissions que comencen en blanc"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "mou les comissions que comencen amb squash!/fixup! sota -i"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr ""
+"actualitza les branques que apunten a comissions a les quals se'ls està fent "
+"«rebase»"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr "afegeix línies d'exec després de cada comissió de la llista editable"
 
@@ -10078,12 +10210,18 @@ msgid ""
 "Use `git rebase --abort` to terminate current rebase.\n"
 "Or downgrade to v2.33, or earlier, to complete the rebase."
 msgstr ""
+"«rebase --preserve-merges» (-p) ja no és admès.\n"
+"Utilitzeu «git rebase --abort» per a finalitzar el «rebase» actual.\n"
+"O bé baixeu a la versió v2.33, o anterior, per a completar el «rebase»."
 
 msgid ""
 "--preserve-merges was replaced by --rebase-merges\n"
 "Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
 "which is no longer supported; use 'merges' instead"
 msgstr ""
+"--preserve-merges s'ha substituït per --rebase-merges\n"
+"Nota: la configuració «pull.rebase» també podria estar establerta a\n"
+"+-«preserve», que ja no s'admet; utilitzeu «merge» en el seu lloc"
 
 msgid "No rebase in progress?"
 msgstr "No hi ha un «rebase» en curs?"
@@ -10195,7 +10333,7 @@ msgid "Current branch %s is up to date, rebase forced.\n"
 msgstr "La branca actual %s està al dia; «rebase» forçat.\n"
 
 msgid "The pre-rebase hook refused to rebase."
-msgstr "El lligam pre-«rebase» ha refusat a fer «rebase»."
+msgstr "El lligam pre-rebase ha refusat a fer «rebase»."
 
 #, c-format
 msgid "Changes to %s:\n"
@@ -10302,13 +10440,12 @@ msgstr ""
 msgid "git reflog exists <ref>"
 msgstr "git reflog exists <referència>"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid timestamp '%s' given to '--%s'"
-msgstr "el codi de temps «%s» no és vàlid donat a «--%s»"
+msgstr "marca de temps «%s» donada a «--%s» no és vàlida"
 
-#, fuzzy
 msgid "do not actually prune any entries"
-msgstr "no practiquis cap entrada"
+msgstr "no eliminis cap entrada"
 
 msgid ""
 "rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"
@@ -10317,34 +10454,28 @@ msgstr "reescriu l'antic SHA1 amb el nou SHA1 de l'entrada que ara precedeix"
 msgid "update the reference to the value of the top reflog entry"
 msgstr "actualitza la referència al valor de l'entrada de reflog superior"
 
-#, fuzzy
 msgid "print extra information on screen"
 msgstr "imprimeix informació extra a la pantalla"
 
 msgid "timestamp"
 msgstr "marca de temps"
 
-#, fuzzy
 msgid "prune entries older than the specified time"
 msgstr "poda les entrades més antigues que el temps especificat"
 
-#, fuzzy
 msgid ""
 "prune entries older than <time> that are not reachable from the current tip "
 "of the branch"
 msgstr ""
-"poda les entrades més antigues de <time> que no es poden accedir des de la "
+"poda les entrades més antigues de <data> que no es poden accedir des de la "
 "punta actual de la branca"
 
-#, fuzzy
 msgid "prune any reflog entries that point to broken commits"
 msgstr "poda qualsevol entrada de reflog que apunti a comissions trencades"
 
-#, fuzzy
 msgid "process the reflogs of all references"
 msgstr "processa els reflogs de totes les referències"
 
-#, fuzzy
 msgid "limits processing to reflogs from the current worktree only"
 msgstr "limita el processament a reflogs només de l'arbre de treball actual"
 
@@ -10532,9 +10663,8 @@ msgstr ""
 "\t%s\n"
 "\tActualitzeu la configuració manualment si és necessari."
 
-#, fuzzy
 msgid "Renaming remote references"
-msgstr "Canviant el nom de les referències remotes"
+msgstr "S'està canviant el nom de les referències remotes"
 
 #, c-format
 msgid "deleting '%s' failed"
@@ -10569,6 +10699,9 @@ msgstr " nou (la pròxima obtenció emmagatzemarà a remotes/%s)"
 msgid " tracked"
 msgstr " seguit"
 
+msgid " skipped"
+msgstr " omès"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " estancat (useu «git remote prune» per a eliminar)"
 
@@ -10795,7 +10928,6 @@ msgstr "sigues detallat; s'ha de col·locar abans d'una subordre"
 msgid "git repack [<options>]"
 msgstr "git repack [<opcions>]"
 
-#, fuzzy
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
 "--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
@@ -10803,7 +10935,7 @@ msgstr ""
 "Els reempaquetaments incrementals són incompatibles amb els índexs de mapes "
 "de bits.  Useu\n"
 "--no-write-bitmap-index o inhabiliteu el paràmetre de configuració pack."
-"writebitmaps."
+"writeBitmaps."
 
 msgid "could not start pack-objects to repack promisor objects"
 msgstr ""
@@ -10847,16 +10979,16 @@ msgstr "empaqueta-ho tot en un únic paquet"
 msgid "same as -a, and turn unreachable objects loose"
 msgstr "el mateix que -a, i solta els objectes inabastables"
 
-#, fuzzy
 msgid "same as -a, pack unreachable cruft objects separately"
-msgstr "el mateix que -a, i solta els objectes inabastables"
+msgstr ""
+"el mateix que -a, empaqueta els objectes superflus inabastables de forma "
+"separada"
 
 msgid "approxidate"
 msgstr "data aproximada"
 
-#, fuzzy
 msgid "with -C, expire objects older than this"
-msgstr "fes caducar els objectes més antics que <data>"
+msgstr "amb -C, venç els objectes més antics que aquest"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "elimina els paquets redundants, i executeu git-prune-packed"
@@ -10923,9 +11055,9 @@ msgstr "no es poden suprimir paquets en un repositori d'objectes preciosos"
 msgid "Nothing new to pack."
 msgstr "Res nou a empaquetar."
 
-#, fuzzy, c-format
+#, c-format
 msgid "pack prefix %s does not begin with objdir %s"
-msgstr "el nom del fitxer de paquet «%s» no acaba amb «.%s»"
+msgstr "el prefix de paquet %s no comença amb objdir %s"
 
 #, c-format
 msgid "missing required file: %s"
@@ -11168,7 +11300,7 @@ msgid "keep"
 msgstr "reteniment"
 
 msgid "You do not have a valid HEAD."
-msgstr "No teniu un HEAD vàlid."
+msgstr "No teniu una HEAD vàlida."
 
 msgid "Failed to find tree of HEAD."
 msgstr "S'ha produït un error en trobar l'arbre de HEAD."
@@ -11230,14 +11362,14 @@ msgstr "el restabliment de %s no es permet en un repositori nu"
 msgid "Unstaged changes after reset:"
 msgstr "Canvis «unstaged» després del restabliment:"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "It took %.2f seconds to refresh the index after reset.  You can use\n"
 "'--no-refresh' to avoid this."
 msgstr ""
-"Es van trigar un temps de,2f segons a actualitzar l'índex després de "
-"reiniciar.  Pots utilitzar\n"
-".--no-refresh' per evitar això."
+"Es van trigar %.2f segons a actualitzar l'índex després de reiniciar.  Podeu "
+"usar\n"
+".--no-refresh' per evitar això."
 
 #, c-format
 msgid "Could not reset index file to revision '%s'."
@@ -11250,6 +11382,10 @@ msgstr "No s'ha pogut escriure el fitxer d'índex nou."
 msgid "unable to get disk usage of %s"
 msgstr "no s'ha pogut obtenir l'ús del disc de %s"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "valor no vàlid per a «%s»: «%s», l'únic format permès és «%s»"
+
 msgid "rev-list does not support display of notes"
 msgstr "el rev-list no permet mostrar notes"
 
@@ -11275,6 +11411,9 @@ msgstr "final prematur de l'entrada"
 msgid "no usage string given before the `--' separator"
 msgstr "no s'ha indicat cap cadena d'ús abans del separador «--»"
 
+msgid "missing opt-spec before option flags"
+msgstr "manca l'opció opt-spec abans de les altres opcions"
+
 msgid "Needed a single revision"
 msgstr "Cal una sola revisió"
 
@@ -11392,7 +11531,7 @@ msgid "keep redundant, empty commits"
 msgstr "retén les comissions redundants i buides"
 
 msgid "use the 'reference' format to refer to commits"
-msgstr ""
+msgstr "useu el format «referència» per a referir-vos a les comissions"
 
 msgid "revert failed"
 msgstr "la reversió ha fallat"
@@ -11511,7 +11650,7 @@ msgid "unknown group type: %s"
 msgstr "tipus de grup desconegut: %s"
 
 msgid "group by committer rather than author"
-msgstr "agrupa per «comitter» en comptes de per autor"
+msgstr "agrupa per «committer» en comptes de per autor"
 
 msgid "sort output according to the number of commits per author"
 msgstr "ordena la sortida segons el nombre de comissions per autor"
@@ -11675,7 +11814,7 @@ msgid "dereference tags into object IDs"
 msgstr "desreferencia les etiquetes a ID d'objecte"
 
 msgid "only show SHA1 hash using <n> digits"
-msgstr "mostra el hash SHA1 usant només <n> xifres"
+msgstr "mostra el resum SHA1 usant només <n> xifres"
 
 msgid "do not print results to stdout (useful with --verify)"
 msgstr "no imprimeixis els resultats a stdout (útil amb --verify)"
@@ -11709,9 +11848,8 @@ msgstr "s'ha produït un error en suprimir el directori «%s»"
 msgid "failed to create directory for sparse-checkout file"
 msgstr "no s'ha pogut crear el directori per al fitxer sparse-checkout"
 
-#, fuzzy
 msgid "failed to initialize worktree config"
-msgstr "no s'ha pogut inicialitzar l'arbre de treball to"
+msgstr "no s'ha pogut inicialitzar la configuració de l'arbre de treball"
 
 msgid "failed to modify sparse-index config"
 msgstr "no s'ha pogut modificar la configuració de l'índex dispers"
@@ -11736,7 +11874,7 @@ msgstr "no s'ha pogut normalitzar el camí %s"
 
 #, c-format
 msgid "unable to unquote C-style string '%s'"
-msgstr "no s'ha pogut treure la cita a la cadena amb estil C «%s»"
+msgstr "no s'han pogut treure les cometes a la cadena amb estil C «%s»"
 
 msgid "unable to load existing sparse-checkout patterns"
 msgstr "no s'han pogut carregar els patrons de «sparse-checkout» existents"
@@ -11744,51 +11882,45 @@ msgstr "no s'han pogut carregar els patrons de «sparse-checkout» existents"
 msgid "existing sparse-checkout patterns do not use cone mode"
 msgstr "els patrons de «sparse-checkout» existents no usen el mode con"
 
-#, fuzzy
 msgid "please run from the toplevel directory in non-cone mode"
-msgstr ""
-"executeu des del directori de nivell superior en mode que no sigui compatible"
+msgstr "executeu des del directori de nivell superior en mode que no sigui con"
 
-#, fuzzy
 msgid "specify directories rather than patterns (no leading slash)"
 msgstr "especifica els directoris en lloc dels patrons (sense barra inclinada)"
 
-#, fuzzy
 msgid ""
 "specify directories rather than patterns.  If your directory starts with a "
 "'!', pass --skip-checks"
 msgstr ""
 "especifica els directoris en lloc dels patrons.  Si el vostre directori "
-"comença amb un '!', passeu --skip-checks"
+"comença amb un «!», passeu --skip-checks"
 
-#, fuzzy
 msgid ""
 "specify directories rather than patterns.  If your directory really has any "
 "of '*?[]\\' in it, pass --skip-checks"
 msgstr ""
 "especifica els directoris en lloc dels patrons.  Si el vostre directori "
-"realment té alguna de '*?\\\\', passeu --skip-checks"
+"realment té alguna de «*?[]\\», useu --skip-checks"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "'%s' is not a directory; to treat it as a directory anyway, rerun with --"
 "skip-checks"
 msgstr ""
-"%%s' no és un directori; per tractar-lo com un directori de totes maneres, "
-"torneu a executar amb --skip-checks"
+"«%s» no és un directori; per a tractar-lo com un directori, torneu a "
+"executar amb --skip-checks"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "pass a leading slash before paths such as '%s' if you want a single file "
 "(see NON-CONE PROBLEMS in the git-sparse-checkout manual)."
 msgstr ""
 "passa una barra d'inici abans dels camins com ara «%s» si voleu un sol "
-"fitxer (vegeu els problemes NO CONE al manual de git-sparse-checkout)."
+"fitxer (vegeu «NON-CONE PROBLEMS» al manual de git-sparse-checkout)."
 
 msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
 msgstr "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
 
-#, fuzzy
 msgid ""
 "skip some sanity checks on the given paths that might give false positives"
 msgstr ""
@@ -12049,6 +12181,10 @@ msgstr "anteposa el caràcter de comentari i un espai a cada línia"
 msgid "Expecting a full ref name, got %s"
 msgstr "S'espera un nom de referència ple, s'ha rebut %s"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "no s'ha pogut obtenir el gestor del repositori pel submòdul «%s»"
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -12057,12 +12193,6 @@ msgstr ""
 "no s'ha pogut trobar la configuració «%s». S'assumeix que aquest repositori "
 "és el seu repositori font autoritzat."
 
-msgid "alternative anchor for relative paths"
-msgstr "àncora alternativa per als camins relatius"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<camí>] [<camí>...]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "No s'ha trobat cap url per al camí de submòdul «%s» a .gitmodules"
@@ -12095,8 +12225,8 @@ msgstr "omet la sortida en entrar a cada ordre del submòdul"
 msgid "recurse into nested submodules"
 msgstr "inclou recursivament els submòduls imbricats"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <ordre>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <ordre>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -12121,8 +12251,8 @@ msgstr ""
 msgid "suppress output for initializing a submodule"
 msgstr "omet la sortida en inicialitzar un submòdul"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<opcions>] [<camí>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<opcions>] [<camí>]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -12149,9 +12279,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<camí>...]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <camí>"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(blob)->%s(submòdul)"
@@ -12188,8 +12315,8 @@ msgstr "omet els submòduls amb el valor «ignore_config» establert a «all»"
 msgid "limit the summary size"
 msgstr "limita la mida del resum"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<options>] [<commit>] [--] [<path>]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "no s'ha pogut obtenir una revisió per a HEAD"
@@ -12202,11 +12329,6 @@ msgstr "S'està sincronitzant l'url del submòdul per a «%s»\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "s'ha produït un error en registrar l'url per al camí del submòdul «%s»"
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr ""
-"s'ha produït un error en obtenir el remot per defecte pel submòdul «%s»"
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "s'ha produït un error en actualitzar el remot pel submòdul «%s»"
@@ -12214,8 +12336,8 @@ msgstr "s'ha produït un error en actualitzar el remot pel submòdul «%s»"
 msgid "suppress output of synchronizing submodule url"
 msgstr "omet la sortida de la sincronització de l'URL del submòdul"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<camí>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<path>]"
 
 #, c-format
 msgid ""
@@ -12277,6 +12399,10 @@ msgstr ""
 "submodule.alternateErrorStrategy a «info» o bé cloneu amb\n"
 "«--reference-if-able' en comptes de «--reference»."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "no s'ha pogut obtenir el gestor del repositori per al gitdir «%s»"
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "el submòdul «%s» no pot afegir un alternatiu: %s"
@@ -12305,6 +12431,9 @@ msgstr "directori no buit: «%s»"
 msgid "could not get submodule directory for '%s'"
 msgstr "no s'ha pogut obtenir el directori de submòdul per a «%s»"
 
+msgid "alternative anchor for relative paths"
+msgstr "àncora alternativa per als camins relatius"
+
 msgid "where the new submodule will be cloned to"
 msgstr "a on es clonarà el submòdul nou"
 
@@ -12323,7 +12452,6 @@ msgstr "força el progrés del clonatge"
 msgid "disallow cloning into non-empty directory"
 msgstr "no permetis clonar en un directori no buit"
 
-#, fuzzy
 msgid ""
 "git submodule--helper clone [--prefix=<path>] [--quiet] [--reference "
 "<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
@@ -12331,11 +12459,7 @@ msgid ""
 msgstr ""
 "git submodule--helper clone [--prefix=<path>] [--quiet] [--reference "
 "<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
-"<filter-spec>]--url <url> --path <path>"
-
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Mode d'actualització «%s» no vàlid per al camí de submòdul «%s»"
+"<filter-spec>] --url <url> --path <path>"
 
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
@@ -12411,6 +12535,10 @@ msgstr ""
 "S'ha obtingut en un camí de submòdul «%s», però no contenia %s. L'obtenció "
 "directa d'aquesta comissió ha fallat."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "no s'ha pogut inicialitzar el submòdul al camí «%s»"
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12420,25 +12548,21 @@ msgstr ""
 "superprojecte, però el superprojecte no és en cap branca"
 
 #, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "no s'ha pogut obtenir el gestor del repositori pel submòdul «%s»"
-
-#, fuzzy, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr "No s'ha pogut trobar la revisió actual al camí del submòdul «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Unable to fetch in submodule path '%s'"
-msgstr "No s'ha pogut recuperar el camí del submòdul «%s»"
+msgstr "No s'ha pogut obtenir el camí del submòdul «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Unable to find %s revision in submodule path '%s'"
-msgstr ""
-"No s'ha pogut trobar la revisió de percentatges en el camí del submòdul «%s»"
+msgstr "No s'ha pogut trobar la revisió %s en el camí del submòdul «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to recurse into submodule path '%s'"
-msgstr "No s'ha pogut tornar a repetir al camí del submòdul «%s»"
+msgstr ""
+"s'ha produït un error en cercar recursivament al camí del submòdul «%s»"
 
 msgid "force checkout updates"
 msgstr "força les actualitzacions"
@@ -12446,13 +12570,11 @@ msgstr "força les actualitzacions"
 msgid "initialize uninitialized submodules before update"
 msgstr "inicialitza els submòduls sense inicialitzar abans d'actualitzar"
 
-#, fuzzy
 msgid "use SHA-1 of submodule's remote tracking branch"
-msgstr "utilitza SHA-1 de la branca de seguiment remota del submòdul"
+msgstr "usa el SHA-1 de la branca de seguiment remota del submòdul"
 
-#, fuzzy
 msgid "traverse submodules recursively"
-msgstr "traverteix els submòduls recursivament"
+msgstr "recorre els submòduls recursivament"
 
 msgid "don't fetch new objects from the remote site"
 msgstr "no obtinguis els objectes nous del lloc remot"
@@ -12460,11 +12582,14 @@ msgstr "no obtinguis els objectes nous del lloc remot"
 msgid "path into the working tree"
 msgstr "camí a l'arbre de treball"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "camí a l'arbre de treball, a través de fronteres de submòduls niats"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "utilitza l'estratègia d'actualització «checkout» (predeterminada)"
+
+msgid "use the 'merge' update strategy"
+msgstr "utilitza l'estratègia d'actualització de «merge»"
 
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout o none"
+msgid "use the 'rebase' update strategy"
+msgstr "utilitza l'estratègia d'actualització de «rebase»"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "crea un clon superficial truncat al nombre de revisions especificat"
@@ -12478,6 +12603,9 @@ msgstr "si el clonatge inicial ha de seguir la recomanació de superficialitat"
 msgid "don't print cloning progress"
 msgstr "no imprimeixis el progrés del clonatge"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "no permetis clonar en un directori no buit, implica --init"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12489,14 +12617,11 @@ msgstr ""
 "shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
 "[--] [<path>...]"
 
-msgid "bad value for update parameter"
-msgstr "valor incorrecte per al paràmetre update"
-
 msgid "recurse into submodules"
 msgstr "inclou recursivament als submòduls"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<opcions>] [<camí>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<options>] [<path>...]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr "comprova si és segur escriure al fitxer .gitmodules"
@@ -12516,8 +12641,8 @@ msgstr "assegureu-vos que el fitxer .gitmodules és a l'arbre de treball"
 msgid "suppress output for setting url of a submodule"
 msgstr "omet la sortida en configurar un URL d'un submòdul"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <path> <newurl>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <path> <newurl>"
 
 msgid "set the default tracking branch to master"
 msgstr "estableix la branca de seguiment per defecte a «master»"
@@ -12525,13 +12650,11 @@ msgstr "estableix la branca de seguiment per defecte a «master»"
 msgid "set the default tracking branch"
 msgstr "estableix la branca de seguiment per defecte"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
 
 msgid "--branch or --default required"
 msgstr "cal --branch o --default"
@@ -12542,17 +12665,15 @@ msgstr "mostra només els missatges d'error"
 msgid "force creation"
 msgstr "força la creació"
 
-#, fuzzy
 msgid "show whether the branch would be created"
 msgstr "mostra si es crearà la branca"
 
-#, fuzzy
 msgid ""
 "git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
 "quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
 msgstr ""
 "git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
-"quiet] [-t|--track] [-n|--dry-run] <name> <start_oid> <start_name>"
+"quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
 
 #, c-format
 msgid "creating branch '%s'"
@@ -12624,7 +12745,6 @@ msgstr "permet afegir un camí de submòdul que si no s'hagués ignorat"
 msgid "borrow the objects from reference repositories"
 msgstr "manlleva els objectes dels repositoris de referències"
 
-#, fuzzy
 msgid ""
 "sets the submodule's name to the given string instead of defaulting to its "
 "path"
@@ -12632,8 +12752,8 @@ msgstr ""
 "estableix el nom del submòdul a la cadena donada en lloc de per defecte al "
 "seu camí"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<opcions>] [--] <repositori> [<camí>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<options>] [--] <repository> [<path>]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
@@ -12841,6 +12961,16 @@ msgstr "Etiqueta «%s» actualitzada (era %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "el paquet supera la mida màxima permesa"
 
+msgid "failed to write object in stream"
+msgstr "no s'ha pogut escriure l'objecte al flux"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "inflate ha retornat (%d)"
+
+msgid "invalid blob object from stream"
+msgstr "l'objecte blob del flux no és vàlid"
+
 msgid "Unpacking objects"
 msgstr "S'estan desempaquetant els objectes"
 
@@ -13353,7 +13483,7 @@ msgstr ""
 
 #, c-format
 msgid "validation failed, cannot remove working tree: %s"
-msgstr "la validació ha fallat, no es pot suprmir l'arbre de treball: %s"
+msgstr "la validació ha fallat, no es pot suprimir l'arbre de treball: %s"
 
 #, c-format
 msgid "repair: %s: %s"
@@ -13375,9 +13505,30 @@ msgstr "escriu l'objecte d'arbre per a un subdirectori <prefix>"
 msgid "only useful for debugging"
 msgstr "només útil per a la depuració"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch no és compatible amb aquesta plataforma"
+
+msgid "failed to create temporary file"
+msgstr "no s'ha pogut crear un fitxer temporal"
+
+msgid "insufficient capabilities"
+msgstr "capacitats insuficients"
+
 #, c-format
-msgid "unrecognized bundle hash algorithm: %s"
-msgstr "algoritme de hash del farcell desconegut: %s"
+msgid "failed to download bundle from URI '%s'"
+msgstr "no s'ha pogut baixar el paquet de l'URI «%s»"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "el fitxer a l'URI «%s» no és farcell"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "s'ha produït un error en desempaquetar el farcell de l'URI «%s»"
+
+#, c-format
+msgid "unrecognized bundle hash algorithm: %s"
+msgstr "algoritme de resum del farcell desconegut: %s"
 
 #, c-format
 msgid "unknown capability '%s'"
@@ -13460,7 +13611,7 @@ msgid "final chunk has non-zero id %<PRIx32>"
 msgstr "el fragment final té un id %<PRIx32> que no és zero"
 
 msgid "invalid hash version"
-msgstr "especificació de hash no vàlida"
+msgstr "especificació de resum no vàlida"
 
 #, c-format
 msgid "invalid color value: %.*s"
@@ -13582,6 +13733,9 @@ msgid "Give an object a human readable name based on an available ref"
 msgstr ""
 "Dona un nom llegible per a humans basant-se en les referències disponibles"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Genera un arxiu zip d'informació de diagnòstic"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr ""
 "Mostra els canvis entre comissions, la comissió i l'arbre de treball, etc"
@@ -13714,8 +13868,8 @@ msgstr "Executa una fusió per als fitxers que cal fusionar"
 msgid "The standard helper program to use with git-merge-index"
 msgstr "El programa d'ajuda estàndard a utilitzar amb git-merge-index"
 
-msgid "Show three-way merge without touching index"
-msgstr "Mostra la fusió de tres vies sense tocar l'índex"
+msgid "Perform merge without touching index or working tree"
+msgstr "Realitza la fusió sense tocar l'índex o l'arbre de treball"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
@@ -13916,6 +14070,9 @@ msgstr "Valida els fitxers d'arxius Git empaquetats"
 msgid "Check the GPG signature of tags"
 msgstr "Verifica la signatura GPG de les etiquetes"
 
+msgid "Display version information about Git"
+msgstr "Mostra informació de la versió del Git"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Mostra registres amb la diferència introduïda per cada comissió"
 
@@ -13949,6 +14106,24 @@ msgstr "Un conjunt mínim útil d'ordres diàries del Git"
 msgid "Frequently asked questions about using Git"
 msgstr "Preguntes freqüents sobre l'ús del Git"
 
+msgid "The bundle file format"
+msgstr "El format del fitxer de farcell"
+
+msgid "Chunk-based file formats"
+msgstr "Formats de fitxer basats en blocs"
+
+msgid "Git commit graph format"
+msgstr "Format de graf de comissions del Git"
+
+msgid "Git index format"
+msgstr "Format de l'índex del Git"
+
+msgid "Git pack format"
+msgstr "format de paquet del Git"
+
+msgid "Git cryptographic signature formats"
+msgstr "Formats de signatura criptogràfica del Git"
+
 msgid "A Git Glossary"
 msgstr "Un glossari de Git"
 
@@ -13970,6 +14145,21 @@ msgstr "La definició de les propietats de submòduls"
 msgid "Git namespaces"
 msgstr "Espais de noms del Git"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Capacitats de protocol v0 i v1"
+
+msgid "Things common to various protocols"
+msgstr "Coses comunes en  diversos protocols"
+
+msgid "Git HTTP-based protocols"
+msgstr "Protocols basats en HTTP del Git"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Com es transfereixen els paquets en la xarxa"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Protocol Git Wire, versió 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Programes d'ajuda per a interactuar amb repositoris remots"
 
@@ -13994,6 +14184,9 @@ msgstr "Interfície web del Git (interfície web pels repositoris Git)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Una visió de conjunt de fluxos de treball recomanats amb Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Una eina per a gestionar dipòsits Git grans"
+
 msgid "commit-graph file is too small"
 msgstr "el fitxer del graf de comissions és massa petit"
 
@@ -14009,7 +14202,7 @@ msgstr "la versió del graf de comissions %X no coincideix amb la versió %X"
 #, c-format
 msgid "commit-graph hash version %X does not match version %X"
 msgstr ""
-"la versió del hash del graf de comissions %X no coincideix amb la versió %X"
+"la versió del resum del graf de comissions %X no coincideix amb la versió %X"
 
 #, c-format
 msgid "commit-graph file is too small to hold %u chunks"
@@ -14244,13 +14437,12 @@ msgstr "La comissió %s no té signatura GPG."
 msgid "Commit %s has a good GPG signature by %s\n"
 msgstr "La comissió %s té una signatura GPG bona de %s\n"
 
-#, fuzzy
 msgid ""
 "Warning: commit message did not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitEncoding to the encoding your project uses.\n"
 msgstr ""
-"Advertència: el missatge de comissió no és compatible amb UTF-8.\n"
+"Avís: el missatge de comissió no és compatible amb UTF-8.\n"
 "Potser voleu esmenar-lo després de corregir el missatge, o establir\n"
 "la variable de configuració i18n.commitencoding a la codificació que\n"
 "usi el vostre projecte.\n"
@@ -14261,31 +14453,37 @@ msgstr "no hi ha informació disponible del compilador\n"
 msgid "no libc information available\n"
 msgstr "no hi ha informació disponible de libc\n"
 
-#, fuzzy, c-format
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "no s'ha pogut determinar l'espai de disc lliure per a «%s»"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "no s'ha pogut obtenir la informació per a «%s»"
+
+#, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
-msgstr "no s'ha pogut commutar a «%s»"
+msgstr "[GLE %ld] el fil de salut no ha pogut obrir «%ls»"
 
 #, c-format
 msgid "[GLE %ld] health thread getting BHFI for '%ls'"
-msgstr ""
+msgstr "[GLE %ld] s'està obtenint BHFI del fil de salut per a «%ls»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not convert to wide characters: '%s'"
-msgstr ""
-"no s'han pogut convertir els següents «grafts»:\n"
-"%s"
+msgstr "no s'ha pogut convertir a caràcters amples: «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "BHFI changed '%ls'"
-msgstr "no es pot canviar a «%s»"
+msgstr "S'ha canviat BHFI «%ls»"
 
 #, c-format
 msgid "unhandled case in 'has_worktree_moved': %d"
-msgstr ""
+msgstr "cas no gestionat a «has_worktree_moved»: %d"
 
 #, c-format
 msgid "health thread wait failed [GLE %ld]"
-msgstr ""
+msgstr "ha fallat l'espera del fil de salut [GLE %ld]"
 
 msgid "Unable to create FSEventStream."
 msgstr "No s'ha pogut crear el FSEventStream."
@@ -14295,102 +14493,100 @@ msgstr "No s'ha pogut iniciar el FSEventStream"
 
 #, c-format
 msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
-msgstr ""
+msgstr "[GLE %ld] no s'ha pogut convertir el camí a UTF-8: «%.*ls»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "[GLE %ld] could not watch '%s'"
-msgstr "no s'ha pogut commutar a «%s»"
+msgstr "[GLE %ld] no s'ha pogut vigilar «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "[GLE %ld] could not get longname of '%s'"
-msgstr "no s'ha pogut commutar a «%s»"
+msgstr "[GLE %ld] no s'ha pogut obtenir el nom llarg de «%s»"
 
 #, c-format
 msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "Ha fallat ReadDirectoryChangedW a «%s» [GLE %ld]"
 
 #, c-format
 msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "Ha fallat GetOverlappedResult a «%s» [GLE %ld]"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not read directory changes [GLE %ld]"
-msgstr "no s'han pogut crear directoris per %s"
+msgstr "no s'han pogut llegir els canvis de directori [GLE %ld]"
+
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] no s'ha pogut obrir per a llegir «%ls»"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] no s'ha pogut obtenir la informació del protocol per a «%ls»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to copy SID (%ld)"
-msgstr "s'ha produït un error en copiar el fitxer a «%s»"
+msgstr "no s'ha pogut copiar el SID (%ld)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to get owner for '%s' (%ld)"
-msgstr "s'ha produït un error en obtenir la branca per defecte per a «%s»"
+msgstr "no s'ha pogut obtenir el propietari de «%s» (%ld)"
 
 msgid "memory exhausted"
 msgstr "memòria esgotada"
 
 msgid "Success"
-msgstr ""
+msgstr "Èxit"
 
 msgid "No match"
-msgstr ""
+msgstr "Cap coincidència"
 
-#, fuzzy
 msgid "Invalid regular expression"
-msgstr "usa les expressions regulars POSIX ampliades"
+msgstr "Expressió regular no vàlida"
 
-#, fuzzy
 msgid "Invalid collation character"
-msgstr "caràcter de llast"
+msgstr "El caràcter de col·lació no és vàlid"
 
-#, fuzzy
 msgid "Invalid character class name"
-msgstr "hi ha caràcters no vàlids en el nom de màquina"
+msgstr "Nom de la classe del caràcter no vàlid"
 
 msgid "Trailing backslash"
-msgstr ""
+msgstr "Barra inversa del final"
 
-#, fuzzy
 msgid "Invalid back reference"
-msgstr "referència no vàlida: %s"
+msgstr "Referència anterior no vàlida"
 
 msgid "Unmatched [ or [^"
-msgstr ""
+msgstr "[ or [^ no emparellat"
 
 msgid "Unmatched ( or \\("
-msgstr ""
+msgstr "( o \\( no emparellat"
 
 msgid "Unmatched \\{"
-msgstr ""
+msgstr "\\{ no emparellat"
 
-#, fuzzy
 msgid "Invalid content of \\{\\}"
-msgstr "contingut no vàlid: «%s»"
+msgstr "Contingut no vàlid de \\{\\}"
 
-#, fuzzy
 msgid "Invalid range end"
-msgstr "codificació de transferència no vàlida"
+msgstr "Fi d'interval no vàlid"
 
-#, fuzzy
 msgid "Memory exhausted"
-msgstr "memòria esgotada"
+msgstr "Memòria esgotada"
 
-#, fuzzy
 msgid "Invalid preceding regular expression"
-msgstr "usa les expressions regulars POSIX ampliades"
+msgstr "Expressió regular anterior no vàlida"
 
-#, fuzzy
 msgid "Premature end of regular expression"
-msgstr "usa les expressions regulars POSIX ampliades"
+msgstr "Fi prematur d'expressió regular"
 
 msgid "Regular expression too big"
-msgstr ""
+msgstr "Expressió regular és massa gran"
 
 msgid "Unmatched ) or \\)"
-msgstr ""
+msgstr ") o \\) no no emparellat"
 
-#, fuzzy
 msgid "No previous regular expression"
-msgstr "usa les expressions regulars compatibles amb Perl"
+msgstr "No hi ha expressió regular anterior"
 
 msgid "could not send IPC command"
 msgstr "no s'ha pogut enviar l'ordre IPC"
@@ -14406,21 +14602,21 @@ msgstr "no s'ha pogut començar un fil «accept_thread» «%s»"
 msgid "could not start worker[0] for '%s'"
 msgstr "no s'ha pogut iniciar el fil[0] per a «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "ConnectNamedPipe failed for '%s' (%lu)"
-msgstr "uname() ha fallat amb l'error «%s» (%d)\n"
+msgstr "Ha fallat ConnectNamedPipe per a «%s» (%lu)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not create fd from pipe for '%s'"
-msgstr "no s'han pogut crear directoris per %s"
+msgstr "no s'ha pogut crear un fd a partir de la canonada per a «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not start thread[0] for '%s'"
 msgstr "no s'ha pogut iniciar el fil[0] per a «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "wait for hEvent failed for '%s'"
-msgstr "S'ha produït un error en autenticar per «%s»"
+msgstr "ha fallat l'espera de hEvent per a «%s»"
 
 msgid "cannot resume in the background, please use 'fg' to resume"
 msgstr "no es pot reprendre en segon pla, si us plau useu «fg» per a reprendre"
@@ -14876,185 +15072,6 @@ msgstr "escriptura fallada al rev-list"
 msgid "failed to close rev-list's stdin"
 msgstr "s'ha produït un error en tancar l'stdin del rev-list"
 
-#, c-format
-msgid "'%s' does not exist"
-msgstr "«%s» no existeix"
-
-msgid "need a working directory"
-msgstr "cal un directori de treball"
-
-msgid "could not find enlistment root"
-msgstr "no s'ha pogut trobar un arrel d'allistament"
-
-#, c-format
-msgid "could not switch to '%s'"
-msgstr "no s'ha pogut commutar a «%s»"
-
-#, c-format
-msgid "could not configure %s=%s"
-msgstr "no s'ha pogut configurar %s=%s"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "no s'ha pogut configurar log.excludeDecoration"
-
-msgid "Scalar enlistments require a worktree"
-msgstr "Els allistaments escalars requereixen un arbre de treball"
-
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "no s'ha pogut obrir el directori «%s»"
-
-#, fuzzy, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "el destí «%s» no és un directori"
-
-#, fuzzy, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "no s'ha pogut crear el directori d'arbre de treball «%s»"
-
-#, fuzzy, c-format
-msgid "could not get info for '%s'"
-msgstr "no s'ha pogut llegir el fitxer de registre per a «%s»"
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "el HEAD remot no és una branca: «%.*s»"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-"no s'ha pogut obtenir el nom de la branca per defecte del remot; s'usa ela "
-"predeterminada localment"
-
-msgid "failed to get default branch name"
-msgstr "s'ha produït un error en obtenir el nom de branca predeterminada"
-
-msgid "failed to unregister repository"
-msgstr "s'ha produït un error en desregistrar el repositori"
-
-msgid "failed to delete enlistment directory"
-msgstr "s'ha produït un error en suprimir l'allistament del directori"
-
-msgid "branch to checkout after clone"
-msgstr "branca a agafar després de clonar"
-
-msgid "when cloning, create full working directory"
-msgstr "quan es clona, crear un directori de treball complet"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "només baixa les metadades per a la branca que s'agafarà"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<opcions>] [--] <repo> [<dir>]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "no es pot deduir el nom de l'arbre de treball de «%s»"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "el directori «%s» ja existeix"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "s'ha produït un error en obtenir la branca per defecte per a «%s»"
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "no s'ha pogut configurar el remot a «%s»"
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "no s'ha pogut configurar «%s»"
-
-msgid "partial clone failed; attempting full clone"
-msgstr "ha fallat la clonació parcial; s'està intentant la clonació completa"
-
-msgid "could not configure for full clone"
-msgstr "no s'ha pogut configurar per a una clonació completa"
-
-#, fuzzy
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar register [<enlistment>]"
-
-#, fuzzy, c-format
-msgid "could not create directory for '%s'"
-msgstr "No s'ha pogut crear el directori per a «%s»"
-
-#, fuzzy
-msgid "could not duplicate stdout"
-msgstr "no s'ha pogut actualitzar %s"
-
-#, fuzzy
-msgid "failed to write archive"
-msgstr "s'ha produït un error en llegir la memòria cau"
-
-msgid "`scalar list` does not take arguments"
-msgstr "«scalar list» no accepta arguments"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<enlistment>]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "reconfigura tots els allistaments registrats"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <enlistment>]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "--all o <enlistment>, però no ambdós"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "no existeix un repositori de git a: «%s»"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <task>  {<enlistment>]\n"
-"Tasques:\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "no existeix la tasca: «%s»"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<enlistment>]"
-
-msgid "scalar delete <enlistment>"
-msgstr "supressió de l'escalar <enlistment>"
-
-msgid "refusing to delete current working directory"
-msgstr "s'ha rebutjat suprimir el directori de treball actual"
-
-msgid "include Git version"
-msgstr "inclou la versió del Git"
-
-msgid "include Git's build options"
-msgstr "inclou les opcions de construcció del Git"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "-C requereix un <directory>"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "no s'ha pogut canviar a «%s»"
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c requereix un argument <key>=<value>"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Ordres:\n"
-
 #, c-format
 msgid "illegal crlf_action %d"
 msgstr "crlf_action %d il·legal"
@@ -15068,6 +15085,8 @@ msgid ""
 "in the working copy of '%s', CRLF will be replaced by LF the next time Git "
 "touches it"
 msgstr ""
+"a la còpia de treball de «%s», CRLF serà substituït per LF, la propera "
+"vegada que el Git ho modifiqui"
 
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
@@ -15078,6 +15097,8 @@ msgid ""
 "in the working copy of '%s', LF will be replaced by CRLF the next time Git "
 "touches it"
 msgstr ""
+"a la còpia de treball de «%s», LF serà substituït per CRLF la propera vegada "
+"que Git ho modifiqui"
 
 #, c-format
 msgid "BOM is prohibited in '%s' if encoded as %s"
@@ -15260,6 +15281,32 @@ msgstr ""
 msgid "Marked %d islands, done.\n"
 msgstr "Marcades %d illes, fet.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "no és vàlid --%s amb valor «%s»"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "no s'ha pogut arxivar el directori que falta «%s»"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "no s'ha pogut obrir el directori «%s»"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "s'omet «%s», que no és ni fitxer ni directori"
+
+msgid "could not duplicate stdout"
+msgstr "no s'ha pogut duplicar stdout"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "no s'ha pogut afegir el directori «%s» a l'arxivador"
+
+msgid "failed to write archive"
+msgstr "s'ha produït un error en escriure arxiu"
+
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base no funciona amb intervals"
 
@@ -15441,7 +15488,7 @@ msgid "synonym for '-p --stat'"
 msgstr "sinònim de «-p --stat»"
 
 msgid "machine friendly --stat"
-msgstr "llegible per màquina --stat"
+msgstr "llegible per una màquina --stat"
 
 msgid "output only the last line of --stat"
 msgstr "mostra només l'última línia de --stat"
@@ -15666,7 +15713,7 @@ msgid "equivalent to --word-diff=color --word-diff-regex=<regex>"
 msgstr "equivalent a --word-diff=color --word-diff-regex=<regex>"
 
 msgid "moved lines of code are colored differently"
-msgstr "les línies de codi que s'ha mogut s'acoloreixen diferent"
+msgstr "les línies de codi que s'han mogut s'acoloreixen diferent"
 
 msgid "how white spaces are ignored in --color-moved"
 msgstr "com s'ignoren els espais en blanc a --color-moved"
@@ -15887,6 +15934,9 @@ msgstr "git fetch-pack: s'esperava ACK/NAK, s'ha rebut «%s»"
 msgid "unable to write to remote"
 msgstr "no s'ha pogut escriure al remot"
 
+msgid "Server supports filter"
+msgstr "El servidor accepta filtratge"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "línia de shallow no vàlida: %s"
@@ -15998,9 +16048,6 @@ msgstr "el servidor no és compatible amb l'algorisme «%s»"
 msgid "Server does not support shallow requests"
 msgstr "El servidor no permet sol·licituds superficials"
 
-msgid "Server supports filter"
-msgstr "El servidor accepta filtratge"
-
 msgid "unable to write request to remote"
 msgstr "no s'ha pogut escriure la sol·licitud al remot"
 
@@ -16008,9 +16055,9 @@ msgstr "no s'ha pogut escriure la sol·licitud al remot"
 msgid "expected '%s', received '%s'"
 msgstr "s'esperava «%s», s'ha rebut «%s»"
 
-#, fuzzy, c-format
+#, c-format
 msgid "expected '%s'"
-msgstr "línia inesperada: «%s»"
+msgstr "s'esperava «%s»"
 
 #, c-format
 msgid "unexpected acknowledgment line: '%s'"
@@ -16082,28 +16129,29 @@ msgstr "fsmonitor--daemon no s'està executant"
 msgid "could not send '%s' command to fsmonitor--daemon"
 msgstr "no s'ha pogut enviar l'ordre «%s» a fsmonitor--daemon"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr "%s és incompatible amb %s"
+msgstr "el repositori nu «%s» és incompatible amb fsmonitor"
 
 #, c-format
 msgid "repository '%s' is incompatible with fsmonitor due to errors"
-msgstr ""
+msgstr "el repositori «%s» és incompatible amb fsmonitor a causa d'errors"
 
-#, fuzzy, c-format
+#, c-format
 msgid "remote repository '%s' is incompatible with fsmonitor"
-msgstr "%s és incompatible amb %s"
+msgstr "el repositori remot «%s» no és compatible amb fsmonitor"
 
-#, fuzzy, c-format
+#, c-format
 msgid "virtual repository '%s' is incompatible with fsmonitor"
-msgstr "%s és incompatible amb %s"
+msgstr "el repositori virtual «%s» és incompatible amb fsmonitor"
 
 #, c-format
 msgid ""
 "repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"
 msgstr ""
+"el repositori «%s» és incompatible amb fsmonitor a causa de la manca de "
+"sòcols Unix"
 
-#, fuzzy
 msgid ""
 "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
@@ -16113,7 +16161,7 @@ msgid ""
 "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
 "           <command> [<args>]"
 msgstr ""
-"git [--version] [--help] [-C <path>] [-c <name>=<value>]\n"
+"git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
@@ -16263,9 +16311,8 @@ msgstr "gpg.ssh.defaultKeyCommand ha fallat: %s %s"
 msgid "gpg failed to sign the data"
 msgstr "gpg ha fallat en signar les dades"
 
-#, fuzzy
 msgid "user.signingKey needs to be set for ssh signing"
-msgstr "user.signingkey s'ha d'establir per a signar amb ssh"
+msgstr "user.signingKey s'ha d'establir per a signar amb ssh"
 
 #, c-format
 msgid "failed writing ssh signing key to '%s'"
@@ -16344,6 +16391,12 @@ msgstr "Ordres de baix nivell / Sincronització de repositoris"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Ordres de baix nivell / Ajudants interns"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "Repositori, ordre i interfície de fitxers que veu l'usuari"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Formats de fitxers, protocols i interfícies que veu el desenvolupador"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "ordres de git disponibles en «%s»"
@@ -16357,6 +16410,12 @@ msgstr "Aquestes són ordres habituals del Git usades en diverses situacions:"
 msgid "The Git concept guides are:"
 msgstr "Les guies de Git de conceptes són:"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Repositori, ordre i interfície de fitxers que veu l'usuari:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Formats de fitxer, protocols i altres interfícies de desenvolupador:"
+
 msgid "External commands"
 msgstr "Ordres externes"
 
@@ -16440,10 +16499,6 @@ msgstr ""
 "El lligam «%s» s'ha ignorat perquè no s'ha establert com a executable.\n"
 "Podeu desactivar aquest avís amb «git config advice.ignoredHook false»."
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "No s'ha pogut iniciar el lligam «%s»'\n"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "l'argument a --packfile ha de ser un resum vàlid (s'ha obtingut «%s»)"
@@ -16451,9 +16506,9 @@ msgstr "l'argument a --packfile ha de ser un resum vàlid (s'ha obtingut «%s»)
 msgid "not a git repository"
 msgstr "no és un repositori de git"
 
-#, fuzzy, c-format
+#, c-format
 msgid "negative value for http.postBuffer; defaulting to %d"
-msgstr "valor negatiu per http.postbuffer; utilitzant el valor %d"
+msgstr "valor negatiu per http.postBuffer; utilitzant el valor %d"
 
 msgid "Delegation control is not supported with cURL < 7.22.0"
 msgstr "No s'admet el control de delegació amb el cURL < 7.22.0"
@@ -16631,20 +16686,16 @@ msgid "expected flush after ls-refs arguments"
 msgstr "s'esperava una neteja després dels arguments ls-refs"
 
 msgid "quoted CRLF detected"
-msgstr "CRLF citat detectat"
-
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Els canvis locals als fitxers següents se sobreescriuran per la fusió:\n"
-"  %s"
+msgstr "CRLF entre cometes detectat"
 
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "S'ha produït un error en fusionar el submòdul %s (no està agafat)"
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "S'ha produït un error en fusionar el submòdul %s (no hi ha fusió base)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "S'ha produït un error en fusionar el submòdul %s (no hi ha comissions)"
@@ -16665,28 +16716,10 @@ msgstr "S'ha produït un error en fusionar el submòdul «%s»"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
 msgstr ""
-"S'ha produït un error en fusionar el submòdul %s, però existeix una solució "
-"possible:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"Si això és correcte simplement afegiu-ho a l'índex per exemple\n"
-"utilitzant:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s «%s»\n"
-"\n"
-"que acceptarà aquest suggeriment.\n"
+"S'ha produït un error en fusionar el submòdul %s, però existeix una solució "
+"possible: %s"
 
 #, c-format
 msgid ""
@@ -16852,13 +16885,43 @@ msgstr ""
 "CONFLICTE: (modificació/supressió): %s suprimit a %s i modificat a %s. La "
 "versió %s de %s s'ha deixat en l'arbre."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - aneu al submòdul (%s), i fusioneu la comissió %s\n"
+"   o actualitzeu-la a una comissió existent que ha fusionat aquests canvis\n"
+
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
 msgstr ""
-"Nota: %s no està actualitzat i en forma de comprovar la versió en conflicte; "
-"còpia antiga reanomenada a %s"
+"La fusió recursiva amb submòduls actualment només admet casos trivials.\n"
+"Si us plau, manegeu manualment la fusió de cada submòdul en conflicte.\n"
+"Això es pot aconseguir amb els passos següents:\n"
+"%s - torneu al superprojecte i executeu:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   per a enregistrar la fusió o actualització de dalt\n"
+" - resoleu qualsevol altre conflicte al superprojecte\n"
+" - publiqueu l'índex resultant al superprojecte\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -16932,6 +16995,22 @@ msgstr ""
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "S'ha trobat una possible resolució de fusió pel submòdul:\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Si això és correcte simplement afegiu-ho a l'índex per exemple\n"
+"utilitzant:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s «%s»\n"
+"\n"
+"que acceptarà aquest suggeriment.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr ""
@@ -17123,7 +17202,8 @@ msgstr "no es reconeix la versió %d de l'índex multipaquet"
 
 #, c-format
 msgid "multi-pack-index hash version %u does not match version %u"
-msgstr "la versió del hash índex multipaquet %u no coincideix amb la versió %u"
+msgstr ""
+"la versió del resum índex multipaquet %u no coincideix amb la versió %u"
 
 msgid "multi-pack-index missing required pack-name chunk"
 msgstr "falta un fragment de nom de paquet necessari al multi-index"
@@ -17471,6 +17551,22 @@ msgstr "ha fallat deflateEnd a l'objecte %s(%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "confós per la font de dades inestable de l'objecte per a %s"
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "escriu l'objecte de flux %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "no s'ha pogut desinflar l'object nou (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "ha fallat deflateEnd a l'objecte del flux (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "s'ha produït un error en crear el directori %s"
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr "no es pot llegir l'objecte per a %s"
@@ -17507,7 +17603,7 @@ msgstr "no s'ha pogut obrir %s"
 
 #, c-format
 msgid "hash mismatch for %s (expected %s)"
-msgstr "no coincideix la suma per a %s (s'esperava %s)"
+msgstr "no coincideix el resum per a %s (s'esperava %s)"
 
 #, c-format
 msgid "unable to mmap %s"
@@ -17700,40 +17796,149 @@ msgstr "no s'ha pogut analitzar l'objecte: %s"
 msgid "hash mismatch %s"
 msgstr "el resum no coincideix %s"
 
+msgid "trying to write commit not in index"
+msgstr "s'està intentant no escriure la publicació a l'índex"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr ""
+"s'ha produït un error en carregar l'índex de mapa de bits (està malmès?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "índex de mapa de bits malmès (massa petit)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "fitxer d'índex de mapa de bits malmès (capçalera incorrecta)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "versió «%d» no admesa per al fitxer d'índex de mapa de bits"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se a la "
+"memòria cau de hash)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"fitxer d'índex de mapa de bits malmès (massa curt per a ajustar-se a la "
+"taula de cerca)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "entrada duplicada a l'índex del mapa de bits: «%s»"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "mapa de bits ewah malmès: capçalera truncada per a l'entrada %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "mapa de bits ewah malmès: l'índex de comissió %u està fora de rang"
+
+msgid "corrupted bitmap pack index"
+msgstr "índex de paquets de mapa de bits malmès"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "el desplaçament XOR a l'índex de mapa de bits no és vàlid"
+
+msgid "cannot fstat bitmap file"
+msgstr "no es pot fer fstat en el fitxer de mapa de bits"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "s'ignorarà el fitxer extra de mapa de bits: «%s»"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "la suma de verificació no coincideix amb el MIDX i el mapa de bits"
+
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "falta l'índex invers necessari al mapa de bits multipaquet"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not open pack %s"
-msgstr "no s'ha pogut obrir «%s»"
+msgstr "no s'ha pogut obrir el paquet %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "preferred pack (%s) is invalid"
-msgstr "el paquet preferit «%s» ha caducat"
+msgstr "el paquet preferit (%s) no és vàlid"
+
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr ""
+"taula de cerca de mapa de bits malmesa: posició la tripleta fora de l'índex"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr ""
+"taula de cerca de mapa de bits malmesa: la cadena xor excedeix el nombre "
+"d'entrades"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr ""
+"taula de cerca de mapa de bits malmesa: l'índex de comissió %u està fora de "
+"rang"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr ""
+"mapa de bits ewah malmès: capçalera truncada per al mapa de bits de la "
+"comissió «%s»"
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "no s'ha trobat l'objecte «%s» als tipus de mapes de bits"
+
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "l'objecte «%s» no té un tipus únic"
+
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "objecte «%s»: tipus real «%s», s'esperava: «%s»"
 
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "no s'ha pogut trobar %s al paquet %s al desplaçament %<PRIuMAX>"
+msgid "object not in bitmap: '%s'"
+msgstr "objecte no trobat al mapa de bits: «%s»"
 
-#, fuzzy, c-format
+msgid "failed to load bitmap indexes"
+msgstr "s'ha produït un error en carregar l'índex de mapa de bits"
+
+msgid "you must specify exactly one commit to test"
+msgstr "heu d'especificar exactament una comissió a provar"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "la comissió «%s» no té un mapa de bits indexat"
+
+msgid "mismatch in bitmap results"
+msgstr "no coincideix en els resultats del mapa de bits"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "no s'ha pogut trobar «%s» al paquet «%s» al desplaçament %<PRIuMAX>"
+
+#, c-format
+msgid "unable to get disk usage of '%s'"
+msgstr "no s'ha pogut obtenir l'ús del disc de «%s»"
+
+#, c-format
 msgid "mtimes file %s is too small"
-msgstr "el fitxer de l'índex multipaquet %s és massa petit"
+msgstr "el fitxer mtimes %s és massa petit"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s has unknown signature"
-msgstr "el fitxer d'índex invers %s té una signatura desconeguda"
+msgstr "el fitxer mtimes %s té una signatura desconeguda"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s has unsupported version %<PRIu32>"
-msgstr "el fitxer d'índex invers %s té la versió %<PRIu32> no admesa"
+msgstr "el fitxer mtimes %s té la versió %<PRIu32> no admesa"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s has unsupported hash id %<PRIu32>"
-msgstr "el fitxer d'índex invers %s té un ID de resum %<PRIu32> no admès"
+msgstr "el fitxer mtimes %s té un ID de resum %<PRIu32> no admès"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s is corrupt"
-msgstr "el fitxer d'índex invers %s està malmès"
+msgstr "el fitxer mtimes %s està malmès"
 
 #, c-format
 msgid "reverse-index file %s is too small"
@@ -17839,6 +18044,9 @@ msgstr "voleu dir «--%s» (amb dos guionets)?"
 msgid "alias of --%s"
 msgstr "àlies de --%s"
 
+msgid "need a subcommand"
+msgstr "cal una subordre"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "opció desconeguda «%s»"
@@ -17991,7 +18199,7 @@ msgstr "l'especificació de camí «%s» és més enllà d'un enllaç simbòlic"
 
 #, c-format
 msgid "line is badly quoted: %s"
-msgstr "la línia està mal citada: %s"
+msgstr "la línia no està ben envoltada per cometes: %s"
 
 msgid "unable to write flush packet"
 msgstr "no s'ha pogut escriure el paquet de buidatge"
@@ -18280,9 +18488,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -18293,7 +18504,8 @@ msgstr ""
 "e, edit <comissió> = usa la comissió, però atura't per a esmenar-la\n"
 "s, squash <comissió> = usa la comissió, però fusiona-la a la comissió "
 "prèvia\n"
-"f, fixup [-C | -c] <commit> = com a «squash», però manté només el missatge\n"
+"f, fixup [-C | -c] <comissió> = com a «squash», però manté només el "
+"missatge\n"
 "                   de comissió previ, a menys que s'usi -C, en aquest cas\n"
 "                   manté només el missatge d'aquesta comissió; -c és el "
 "mateix\n"
@@ -18306,11 +18518,16 @@ msgstr ""
 "l, label <etiqueta> = etiqueta la HEAD actual amb un nom\n"
 "t, reset <etiqueta> = reinicia HEAD a una etiqueta\n"
 "m, merge [-C <comissió> | -c <comissió>] <etiqueta> [# <oneline>]\n"
-".       crea una comissió de fusió usant el missatge de la comissió\n"
-".       de fusió original (o línia única, si no hi ha cap comissió de fusió "
+"        crea una comissió de fusió usant el missatge de la comissió de fusió "
 "original\n"
-".       especificada). Useu -c <comissió> per a reescriure el missatge de la "
-"comissió.\n"
+"        (o línia única, si no hi ha cap comissió de fusió original "
+"especificada).\n"
+"        Useu -c <comissió> per a reescriure el missatge de la comissió.\n"
+"u, update-ref <ref> = segueix un marcador de posició per a actualitzar "
+"<ref>\n"
+"                      a aquesta posició en les comissions noves. La <ref> "
+"s'actualitza\n"
+"                      al final del «rebase»\n"
 "\n"
 "Es pot canviar l'ordre d'aquestes línies; s'executen de dalt a baix.\n"
 
@@ -18786,6 +19003,14 @@ msgstr "error de protocol: s'esperava sha/ref, s'ha obtingut «%s»"
 msgid "http transport does not support %s"
 msgstr "El transport http no admet %s"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr ""
+"s'ha produït un error de protocol: s'esperava «<url> <path>», falta espai"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "no s'ha pogut baixar el fitxer a l'URL «%s»"
+
 msgid "git-http-push failed"
 msgstr "git-http-push ha fallat"
 
@@ -18796,7 +19021,7 @@ msgid "remote-curl: error reading command stream from git"
 msgstr "remote-curl: error en llegir el flux d'ordres del git"
 
 msgid "remote-curl: fetch attempted without a local repo"
-msgstr "remote-curl: s'ha intentat l'obtenció sense un dipòsit local"
+msgstr "remote-curl: s'ha intentat l'obtenció sense un repositori local"
 
 #, c-format
 msgid "remote-curl: unknown command '%s' from git"
@@ -18813,13 +19038,13 @@ msgstr "més d'un paquet de recepció donat, usant el primer"
 msgid "more than one uploadpack given, using the first"
 msgstr "més d'un paquet de càrrega donat, usant el primer"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unrecognized value transfer.credentialsInUrl: '%s'"
-msgstr "patró no reconegut: «%s»"
+msgstr "valor no conegut per a transfer.credentialsInUrl: «%s»"
 
 #, c-format
 msgid "URL '%s' uses plaintext credentials"
-msgstr ""
+msgstr "L'URL «%s» utilitza credencials en text pla"
 
 #, c-format
 msgid "Cannot fetch both %s and %s to %s"
@@ -18843,12 +19068,12 @@ msgstr "el valor «%s» del patró no té «*»"
 
 #, c-format
 msgid "src refspec %s does not match any"
-msgstr "l'especificació de referència src %s no coincideix amb cap referència"
+msgstr "l'especificació de referència font %s no coincideix amb cap referència"
 
 #, c-format
 msgid "src refspec %s matches more than one"
 msgstr ""
-"l'especificació de referència de src %s coincideix amb més d'una referència"
+"l'especificació de referència de font %s coincideix amb més d'una referència"
 
 #. TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
 #. <remote> <src>:<dst>" push, and "being pushed ('%s')" is
@@ -19059,95 +19284,271 @@ msgstr "MERGE_RR corrupte"
 msgid "unable to write rerere record"
 msgstr "no s'ha pogut escriure el registre «rerere»"
 
-#, c-format
-msgid "there were errors while writing '%s' (%s)"
-msgstr "s'han produït errors en escriure «%s» (%s)"
+#, c-format
+msgid "there were errors while writing '%s' (%s)"
+msgstr "s'han produït errors en escriure «%s» (%s)"
+
+#, c-format
+msgid "could not parse conflict hunks in '%s'"
+msgstr "no s'han pogut analitzar els pedaços en conflicte a «%s»"
+
+#, c-format
+msgid "failed utime() on '%s'"
+msgstr "s'ha produït un error en fer «failed utime()» a «%s»"
+
+#, c-format
+msgid "writing '%s' failed"
+msgstr "s'ha produït un error en escriure «%s»"
+
+#, c-format
+msgid "Staged '%s' using previous resolution."
+msgstr "«Staged» «%s» utilitzant una resolució anterior."
+
+#, c-format
+msgid "Recorded resolution for '%s'."
+msgstr "Es recorda la resolució per a «%s»."
+
+#, c-format
+msgid "Resolved '%s' using previous resolution."
+msgstr "S'ha resolt «%s» usant una resolució anterior."
+
+#, c-format
+msgid "cannot unlink stray '%s'"
+msgstr "no es pot desenllaçar «%s» (extraviat)"
+
+#, c-format
+msgid "Recorded preimage for '%s'"
+msgstr "Imatge prèvia registrada per a «%s»"
+
+#, c-format
+msgid "failed to update conflicted state in '%s'"
+msgstr "ha fallat en actualitzar l'estat en conflicte a «%s»"
+
+#, c-format
+msgid "no remembered resolution for '%s'"
+msgstr "no hi ha cap resolució recordada per a «%s»"
+
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "no es pot fer «unlink» de «%s»"
+
+#, c-format
+msgid "Updated preimage for '%s'"
+msgstr "Imatge prèvia actualitzada per a «%s»"
+
+#, c-format
+msgid "Forgot resolution for '%s'\n"
+msgstr "S'ha oblidat la resolució per a «%s»\n"
+
+msgid "unable to open rr-cache directory"
+msgstr "no s'ha pogut obrir el directori rr-cache"
+
+msgid "update the index with reused conflict resolution if possible"
+msgstr ""
+"actualitza l'índex amb la resolució de conflictes reusada si és possible"
+
+msgid "could not determine HEAD revision"
+msgstr "no s'ha pogut determinar la revisió de HEAD"
+
+#, c-format
+msgid "failed to find tree of %s"
+msgstr "s'ha produït un error en cercar l'arbre de %s"
+
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo indica «%s» que manquen"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "no s'ha pogut obtenir la comissió per a l'argument d'ancestry-path %s"
+
+msgid "--unpacked=<packfile> no longer supported"
+msgstr "--unpacked=<packfile> ja no s'admet"
+
+msgid "your current branch appears to be broken"
+msgstr "la vostra branca actual sembla malmesa"
+
+#, c-format
+msgid "your current branch '%s' does not have any commits yet"
+msgstr "la branca actual «%s» encara no té cap comissió"
+
+msgid "object filtering requires --objects"
+msgstr "el filtratge d'objectes requereix --objects"
+
+msgid "-L does not yet support diff formats besides -p and -s"
+msgstr "-L no és encara compatible amb formats que no siguin «-p» o «-s»"
+
+#, c-format
+msgid "cannot create async thread: %s"
+msgstr "no s'ha pogut crear fil «async»: %s"
+
+#, c-format
+msgid "'%s' does not exist"
+msgstr "«%s» no existeix"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "no s'ha pogut commutar a «%s»"
+
+msgid "need a working directory"
+msgstr "cal un directori de treball"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Els allistaments escalars requereixen un arbre de treball"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "no s'ha pogut configurar %s=%s"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "no s'ha pogut configurar log.excludeDecoration"
+
+msgid "could not add enlistment"
+msgstr "no s'ha afegit a l'allistament"
+
+msgid "could not set recommended config"
+msgstr "no s'ha pogut establir la configuració recomanada"
+
+msgid "could not turn on maintenance"
+msgstr "no s'ha pogut activar el manteniment"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "no s'ha pogut iniciar el dimoni del fsmonitor"
+
+msgid "could not turn off maintenance"
+msgstr "no s'ha pogut desactivar el manteniment"
+
+msgid "could not remove enlistment"
+msgstr "no s'ha pogut eliminar l'allistament"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "la HEAD remota no és una branca: «%.*s»"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"no s'ha pogut obtenir el nom de la branca per defecte del remot; s'usa ela "
+"predeterminada localment"
+
+msgid "failed to get default branch name"
+msgstr "s'ha produït un error en obtenir el nom de branca predeterminada"
+
+msgid "failed to unregister repository"
+msgstr "s'ha produït un error en desregistrar el repositori"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "no s'ha pogut aturar el dimoni del FSMonitor"
+
+msgid "failed to delete enlistment directory"
+msgstr "s'ha produït un error en suprimir l'allistament del directori"
+
+msgid "branch to checkout after clone"
+msgstr "branca a agafar després de clonar"
+
+msgid "when cloning, create full working directory"
+msgstr "quan es clona, crear un directori de treball complet"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "només baixa les metadades per a la branca que s'agafarà"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<opcions>] [--] <repo> [<dir>]"
 
 #, c-format
-msgid "could not parse conflict hunks in '%s'"
-msgstr "no s'han pogut analitzar els pedaços en conflicte a «%s»"
+msgid "cannot deduce worktree name from '%s'"
+msgstr "no es pot deduir el nom de l'arbre de treball de «%s»"
 
 #, c-format
-msgid "failed utime() on '%s'"
-msgstr "s'ha produït un error en fer «failed utime()» a «%s»"
+msgid "directory '%s' exists already"
+msgstr "el directori «%s» ja existeix"
 
 #, c-format
-msgid "writing '%s' failed"
-msgstr "s'ha produït un error en escriure «%s»"
+msgid "failed to get default branch for '%s'"
+msgstr "s'ha produït un error en obtenir la branca per defecte per a «%s»"
 
 #, c-format
-msgid "Staged '%s' using previous resolution."
-msgstr "«Staged» «%s» utilitzant una resolució anterior."
+msgid "could not configure remote in '%s'"
+msgstr "no s'ha pogut configurar el remot a «%s»"
 
 #, c-format
-msgid "Recorded resolution for '%s'."
-msgstr "Es recorda la resolució per a «%s»."
+msgid "could not configure '%s'"
+msgstr "no s'ha pogut configurar «%s»"
 
-#, c-format
-msgid "Resolved '%s' using previous resolution."
-msgstr "S'ha resolt «%s» usant una resolució anterior."
+msgid "partial clone failed; attempting full clone"
+msgstr "ha fallat la clonació parcial; s'està intentant la clonació completa"
 
-#, c-format
-msgid "cannot unlink stray '%s'"
-msgstr "no es pot desenllaçar «%s» (extraviat)"
+msgid "could not configure for full clone"
+msgstr "no s'ha pogut configurar per a una clonació completa"
 
-#, c-format
-msgid "Recorded preimage for '%s'"
-msgstr "Imatge prèvia registrada per a «%s»"
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<enlistment>]"
 
-#, c-format
-msgid "failed to update conflicted state in '%s'"
-msgstr "ha fallat en actualitzar l'estat en conflicte a «%s»"
+msgid "`scalar list` does not take arguments"
+msgstr "«scalar list» no accepta arguments"
 
-#, c-format
-msgid "no remembered resolution for '%s'"
-msgstr "no hi ha cap resolució recordada per a «%s»"
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<enlistment>]"
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "no es pot fer «unlink» de «%s»"
+msgid "reconfigure all registered enlistments"
+msgstr "reconfigura tots els allistaments registrats"
 
-#, c-format
-msgid "Updated preimage for '%s'"
-msgstr "Imatge prèvia actualitzada per a «%s»"
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <enlistment>]"
 
-#, c-format
-msgid "Forgot resolution for '%s'\n"
-msgstr "S'ha oblidat la resolució per a «%s»\n"
+msgid "--all or <enlistment>, but not both"
+msgstr "--all o <enlistment>, però no ambdós"
 
-msgid "unable to open rr-cache directory"
-msgstr "no s'ha pogut obrir el directori rr-cache"
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "no existeix un repositori de git a: «%s»"
 
-msgid "update the index with reused conflict resolution if possible"
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
 msgstr ""
-"actualitza l'índex amb la resolució de conflictes reusada si és possible"
-
-msgid "could not determine HEAD revision"
-msgstr "no s'ha pogut determinar la revisió de HEAD"
+"scalar run <task>  {<enlistment>]\n"
+"Tasques:\n"
 
 #, c-format
-msgid "failed to find tree of %s"
-msgstr "s'ha produït un error en cercar l'arbre de %s"
+msgid "no such task: '%s'"
+msgstr "no existeix la tasca: «%s»"
 
-msgid "--unpacked=<packfile> no longer supported"
-msgstr "--unpacked=<packfile> ja no s'admet"
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<enlistment>]"
 
-msgid "your current branch appears to be broken"
-msgstr "la vostra branca actual sembla malmesa"
+msgid "scalar delete <enlistment>"
+msgstr "supressió de l'escalar <enlistment>"
 
-#, c-format
-msgid "your current branch '%s' does not have any commits yet"
-msgstr "la branca actual «%s» encara no té cap comissió"
+msgid "refusing to delete current working directory"
+msgstr "s'ha rebutjat suprimir el directori de treball actual"
 
-msgid "object filtering requires --objects"
-msgstr "el filtratge d'objectes requereix --objects"
+msgid "include Git version"
+msgstr "inclou la versió del Git"
 
-msgid "-L does not yet support diff formats besides -p and -s"
-msgstr "-L no és encara compatible amb formats que no siguin «-p» o «-s»"
+msgid "include Git's build options"
+msgstr "inclou les opcions de construcció del Git"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C requereix un <directory>"
 
 #, c-format
-msgid "cannot create async thread: %s"
-msgstr "no s'ha pogut crear fil «async»: %s"
+msgid "could not change to '%s'"
+msgstr "no s'ha pogut canviar a «%s»"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c requereix un argument <key>=<value>"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Ordres:\n"
 
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr ""
@@ -19174,7 +19575,7 @@ msgstr ""
 "l'empenta"
 
 msgid "the receiving end does not support this repository's hash algorithm"
-msgstr "el receptor de destí no admet l'algorisme de hash del repositori"
+msgstr "el receptor de destí no admet l'algorisme de resum del repositori"
 
 msgid "the receiving end does not support --signed push"
 msgstr "el destí receptor no admet pujar --signed"
@@ -19273,10 +19674,6 @@ msgstr "els vostres canvis locals se sobreescriurien per %s."
 msgid "commit your changes or stash them to proceed."
 msgstr "cometeu els vostres canvis o feu un «stash» per a procedir."
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: avanç ràpid"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -19366,7 +19763,7 @@ msgid ""
 "    git commit --amend --reset-author\n"
 msgstr ""
 "S'han configurat el vostre nom i adreça electrònica\n"
-"automàticament basant-se en el vostre nom d'usuari i nom de màquina. \n"
+"automàticament basant-se en el vostre nom d'usuari i nom de màquina.\n"
 "Comproveu que siguin correctes. Podeu suprimir aquest\n"
 "missatge establint-los explícitament. Executeu l'ordre següent i\n"
 "seguiu les instruccions en l'editor per a editar el vostre\n"
@@ -19391,7 +19788,7 @@ msgid ""
 "    git commit --amend --reset-author\n"
 msgstr ""
 "S'han configurat el vostre nom i adreça electrònica\n"
-"automàticament basats en el vostre nom d'usuari i nom de màquina. \n"
+"automàticament basats en el vostre nom d'usuari i nom de màquina.\n"
 "Comproveu que siguin correctes. Podeu suprimir aquest\n"
 "missatge establint-los explícitament:\n"
 "\n"
@@ -19763,6 +20160,28 @@ msgstr "no s'ha pogut fusionar «%.*s»"
 msgid "merge: Unable to write new index file"
 msgstr "fusió: no s'ha pogut escriure un fitxer d'índex nou"
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr ""
+"sembla que s'està executant un altre procés «rebase»: «%s.lock» ja existeix"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"S'han actualitzat els següents refs amb %s:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"No s'han pogut actualitzar les referències següents amb %s:\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "No es pot fer un «stash» automàticament"
 
@@ -19929,6 +20348,10 @@ msgstr "no s'han pogut ometre les ordres «picks» no necessàries"
 msgid "the script was already rearranged."
 msgstr "l'script ja estava endreçat."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "el fitxer update-refs a «%s» no és vàlid"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "«%s» està fora del repositori a «%s»"
@@ -20051,11 +20474,19 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
+"s'ha detectat una propietat dubtosa al repositori a «%s»\n"
+"%sPer a afegir una excepció per a aquest directori, executeu:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "no es pot utilitzar el dipòsit nu «%s» (safe.bareRepository és «%s»)"
 
 #, c-format
 msgid ""
@@ -20132,9 +20563,8 @@ msgstr "no s'ha pogut editar «%s»"
 msgid "ignoring suspicious submodule name: %s"
 msgstr "s'està ignorant el nom de submòdul sospitós %s"
 
-#, fuzzy
 msgid "negative values not allowed for submodule.fetchJobs"
-msgstr "no es permeten els valors negatius a submodule.fetchjobs"
+msgstr "no es permeten els valors negatius a submodule.fetchJobs"
 
 #, c-format
 msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
@@ -20936,6 +21366,18 @@ msgstr "número de port no vàlid"
 msgid "invalid '..' path segment"
 msgstr "segment de camí «..» no vàlid"
 
+msgid "usage: "
+msgstr "ús: "
+
+msgid "fatal: "
+msgstr "fatal: "
+
+msgid "error: "
+msgstr "error: "
+
+msgid "warning: "
+msgstr "avís: "
+
 msgid "Fetching objects"
 msgstr "S'estan obtenint objectes"
 
@@ -20966,7 +21408,7 @@ msgid ".git file broken"
 msgstr "fitxer .git malmès"
 
 msgid ".git file incorrect"
-msgstr "fitxer .git malmès"
+msgstr "fitxer .git incorrecte"
 
 msgid "not a valid path"
 msgstr "no és un camí vàlid"
@@ -21668,7 +22110,7 @@ msgid ""
 msgstr ""
 "y - descarta aquest tros de l'arbre de treball\n"
 "n - no descartis aquest tros des de l'arbre de treball\n"
-"q - surt; no apliquis aquest tros ni cap dels pendents\n"
+"q - surt; no descartis aquest tros ni cap dels pendents\n"
 "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
 
@@ -21681,7 +22123,7 @@ msgid ""
 msgstr ""
 "y - descarta aquest tros de l'índex i de l'arbre de treball\n"
 "n - no descartis aquest tros des de l'índex i de l'arbre de treball\n"
-"q - surt; no apliquis aquest tros ni cap dels pendents\n"
+"q - surt; no descartis aquest tros ni cap dels pendents\n"
 "a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
 "d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer"
 
@@ -21739,22 +22181,6 @@ msgstr "Els trossos seleccionats no apliquen a l'índex\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "s'està ignorant %s no fusionat\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "Aplica el canvi de mode a l'arbre de treball [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Aplica la supressió a l'arbre de treball [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Aplica l'addició a l'arbre de treball [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "Aplica aquest tros a l'arbre de treball [y,n,q,a,d%s,?]? "
-
 msgid "No other hunks to goto\n"
 msgstr "No hi ha altres trossos on anar-hi\n"
 
@@ -22120,13 +22546,13 @@ msgstr "no es pot enviar el missatge en 7 bits"
 msgid "invalid transfer encoding"
 msgstr "codificació de transferència no vàlida"
 
-#, fuzzy, perl-format
+#, perl-format
 msgid ""
 "fatal: %s: rejected by %s hook\n"
 "%s\n"
 "warning: no patches were sent\n"
 msgstr ""
-"fatal: %s: rebutjat pel lligam sendemail-validate\n"
+"fatal: %s: rebutjat pel lligam %s\n"
 "%s\n"
 "avís: no s'ha enviat cap pedaç\n"
 
@@ -22151,302 +22577,83 @@ msgstr "S'està ometent %s amb el sufix de còpia de seguretat «%s».\n"
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Esteu segur que voleu enviar %s? [y|N]: "
 
-#~ msgid "--preserve-merges was replaced by --rebase-merges"
-#~ msgstr "--preserve-merges ha estat substituït per --rebase-merges"
-
-#, c-format
-#~ msgid ""
-#~ "CRLF will be replaced by LF in %s.\n"
-#~ "The file will have its original line endings in your working directory"
-#~ msgstr ""
-#~ "CRLF serà reemplaçat per LF en %s.\n"
-#~ "El fitxer tindrà els seus terminadors de línia originals en el vostre "
-#~ "directori de treball"
-
-#, c-format
-#~ msgid ""
-#~ "LF will be replaced by CRLF in %s.\n"
-#~ "The file will have its original line endings in your working directory"
-#~ msgstr ""
-#~ "LF serà reemplaçat per CRLF en %s.\n"
-#~ "El fitxer tindrà els seus terminadors de línia originals en el vostre "
-#~ "directori de treball"
-
-#, c-format
-#~ msgid "error reading section header '%s'"
-#~ msgstr "error en llegir la capçalera de la secció «%s»"
+#~ msgid "(stats|all)"
+#~ msgstr "(stats|all)"
 
-#~ msgid "load_reverse_index: could not open pack"
-#~ msgstr "load_reverse_index: no s'ha pogut obrir el paquet"
+#~ msgid "git maintenance register"
+#~ msgstr "git maintenance register"
 
-#, perl-format
-#~ msgid "fatal: %s: rejected by %s hook\n"
-#~ msgstr "fatal: %s: rebutjat pel lligam %s\n"
+#~ msgid "git maintenance unregister"
+#~ msgstr "git maintenance unregister"
 
-#~ msgid "git archive --list"
-#~ msgstr "git archive --list"
+#~ msgid "git maintenance stop"
+#~ msgstr "git maintenance stop"
 
 #, c-format
-#~ msgid "unknown value for --diff-merges: %s"
-#~ msgstr "valor desconegut per a --diff-merges: %s"
+#~ msgid "could not parse colored hunk header '%.*s'"
+#~ msgstr "no s'ha pogut analitzar la capçalera del tros acolorida «%.*s»"
 
 #, c-format
-#~ msgid "invalid value '%s' for lsrefs.unborn"
-#~ msgstr "valor «%s» no vàlid per a «lsrefs.unborn»"
-
-#~ msgid "backend for `git stash -p`"
-#~ msgstr "rerefons per a «git stash -p»"
+#~ msgid "Unknown subcommand: %s"
+#~ msgstr "Subordre desconeguda: %s"
 
-#, c-format
-#~ msgid "Invalid value for --empty: %s"
-#~ msgstr "Valor no vàlid per a --empty: %s"
+#~ msgid "checked out in another worktree"
+#~ msgstr "s'ha agafat en un altre arbre de treball"
 
-#, c-format
-#~ msgid "Invalid value for --patch-format: %s"
-#~ msgstr "Valor no vàlid per a --patch-format: %s"
+#~ msgid "failed to open stdin of 'crontab'"
+#~ msgstr "s'ha produït un error en obrir stdin de «crontab»"
 
 #, c-format
-#~ msgid "Invalid value for --show-current-patch: %s"
-#~ msgstr "Valor no vàlid per --show-current-patch: %s"
+#~ msgid "invalid subcommand: %s"
+#~ msgstr "subordre no vàlida: %s"
 
-#~ msgid ""
-#~ "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad "
-#~ "| --term-new]"
-#~ msgstr ""
-#~ "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad "
-#~ "| --term-new]"
+#~ msgid "single arg format must be symmetric range"
+#~ msgstr "el format de l'argument únic ha de ser de rang simètric"
 
-#~ msgid "git bisect--helper --bisect-next"
-#~ msgstr "git bisect--helper --bisect-next"
+#~ msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
+#~ msgstr "git submodule--helper list [--prefix=<camí>] [<camí>...]"
 
-#~ msgid "git bisect--helper --bisect-visualize"
-#~ msgstr "git bisect--helper --bisect-visualize"
+#~ msgid "git submodule--helper name <path>"
+#~ msgstr "git submodule--helper name <camí>"
 
 #, c-format
-#~ msgid "invalid color '%s' in color.blame.repeatedLines"
-#~ msgstr "color «%s» no vàlid en «color.blame.repeatedLines»"
-
-#~ msgid "invalid value for blame.coloring"
-#~ msgstr "valor no vàlid per a «blame.coloring»"
-
-#~ msgid ""
-#~ "git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e "
-#~ "| -p | <type> | --textconv | --filters) [--path=<path>] <object>"
-#~ msgstr ""
-#~ "git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e "
-#~ "| -p | <tipus> | --textconv | --filters [--path=<camí>]) <objecte>"
-
-#~ msgid "show object type"
-#~ msgstr "mostra el tipus de l'objecte"
-
-#~ msgid "exit with zero when there's no error"
-#~ msgstr "surt amb zero quan no hi ha error"
-
-#~ msgid "show info and content of objects fed from the standard input"
-#~ msgstr ""
-#~ "mostra la informació i contingut dels objectes rebuts de l'entrada "
-#~ "estàndard"
-
-#~ msgid "show info about objects fed from the standard input"
-#~ msgstr "mostra informació sobre els objectes rebuts de l'entrada estàndard"
-
-#~ msgid "follow in-tree symlinks (used with --batch or --batch-check)"
-#~ msgstr ""
-#~ "segueix els enllaços simbòlics en l'arbre (s'usa amb --batch o --batch-"
-#~ "check)"
-
-#~ msgid "show all objects with --batch or --batch-check"
-#~ msgstr "mostra tots els objectes amb --batch o --batch-check"
-
-#~ msgid "do not order --batch-all-objects output"
-#~ msgstr "no ordenar la sortida de --batch-all-objects"
-
-#~ msgid "set up tracking mode (see git-pull(1))"
-#~ msgstr "configura el mode de seguiment (vegeu git-pull(1))"
-
-#~ msgid "Using both --reset-author and --author does not make sense"
-#~ msgstr "Usar ambdós --reset-author i --author no té sentit"
-
-#~ msgid "Options --squash and --fixup cannot be used together"
-#~ msgstr "Les opcions --squash i --fixup no es poden usar juntes"
-
-#~ msgid "Only one of -c/-C/-F/--fixup can be used."
-#~ msgstr "Només un de -c/-C/-F/--fixup es pot usar."
-
-#~ msgid "Option -m cannot be combined with -c/-C/-F."
-#~ msgstr "l'opció -m no es pot combinar amb -c/-C/-F/."
-
-#~ msgid ""
-#~ "Only one of --include/--only/--all/--interactive/--patch can be used."
+#~ msgid "failed to get the default remote for submodule '%s'"
 #~ msgstr ""
-#~ "Només un de --include/--only/--all/--interactive/--patch es pot usar."
-
-#~ msgid "git count-objects [-v] [-H | --human-readable]"
-#~ msgstr "git count-objects [-v] [-H | --human-readable]"
+#~ "s'ha produït un error en obtenir el remot per defecte pel submòdul «%s»"
 
 #, c-format
-#~ msgid "configuration fetch.output contains invalid value %s"
-#~ msgstr "la configuració fetch.output conté un valor no vàlid %s"
-
-#~ msgid "--cached or --untracked cannot be used with --no-index"
-#~ msgstr "--cached o --untracked no es pot usar amb --no-index"
-
-#~ msgid "--untracked cannot be used with --cached"
-#~ msgstr "--untracked no es pot usar amb --cached"
-
-#~ msgid "git hash-object  --stdin-paths"
-#~ msgstr "git hash-object  --stdin-paths"
-
-#~ msgid "git help [-g|--guides]"
-#~ msgstr "git help [-g|--guides]"
-
-#~ msgid "git help [-c|--config]"
-#~ msgstr "git help [-c|--config]"
+#~ msgid "Invalid update mode '%s' for submodule path '%s'"
+#~ msgstr "Mode d'actualització «%s» no vàlid per al camí de submòdul «%s»"
 
-#~ msgid "git mktag"
-#~ msgstr "git mktag"
+#~ msgid "path into the working tree, across nested submodule boundaries"
+#~ msgstr "camí a l'arbre de treball, a través de fronteres de submòduls niats"
 
-#~ msgid "git mktree [-z] [--missing] [--batch]"
-#~ msgstr "git mktree [-z] [--missing] [--batch]"
+#~ msgid "rebase, merge, checkout or none"
+#~ msgstr "rebase, merge, checkout o none"
 
-#~ msgid "read from stdin"
-#~ msgstr "llegeix de stdin"
+#~ msgid "bad value for update parameter"
+#~ msgstr "valor incorrecte per al paràmetre update"
 
-#~ msgid "git notes merge --commit [-v | -q]"
-#~ msgstr "git notes merge --commit [-v | -q]"
-
-#~ msgid "git notes merge --abort [-v | -q]"
-#~ msgstr "git notes merge --abort [-v | -q]"
-
-#~ msgid "git notes get-ref"
-#~ msgstr "git notes get-ref"
-
-#~ msgid "invalid value for --missing"
-#~ msgstr "valor no vàlid per a --missing"
-
-#~ msgid "git prune-packed [-n | --dry-run] [-q | --quiet]"
-#~ msgstr "git prune-packed [-n | --dry-run] [-q | --quiet]"
+#~ msgid "Show three-way merge without touching index"
+#~ msgstr "Mostra la fusió de tres vies sense tocar l'índex"
 
+# c-format
 #, c-format
-#~ msgid "Invalid value for %s: %s"
-#~ msgstr "Valor no vàlid per a %s: %s"
+#~ msgid "could not create directory for '%s'"
+#~ msgstr "no s'ha pogut crear el directori per a «%s»"
 
 #, c-format
-#~ msgid "Invalid value for pull.ff: %s"
-#~ msgstr "Valor no vàlid per a pull.ff: %s"
-
-#~ msgid "git rebase --continue | --abort | --skip | --edit-todo"
-#~ msgstr "git rebase --continue | --abort | --skip | --edit-todo"
-
-#, c-format
-#~ msgid "'%s' is not a valid timestamp"
-#~ msgstr "«%s» no és una marca de temps vàlida"
-
-#~ msgid "git reflog [ show | expire | delete | exists ]"
-#~ msgstr "git reflog [ show | expire | delete | exists ]"
-
-#~ msgid "git remote [-v | --verbose]"
-#~ msgstr "git remote [-v | --verbose]"
-
-#~ msgid "git replace [-f] --convert-graft-file"
-#~ msgstr "git replace [-f] --convert-graft-file"
+#~ msgid "Couldn't start hook '%s'\n"
+#~ msgstr "No s'ha pogut iniciar el lligam «%s»'\n"
 
 #, c-format
 #~ msgid ""
-#~ "\n"
-#~ "It took %.2f seconds to enumerate unstaged changes after reset.  You can\n"
-#~ "use '--quiet' to avoid this.  Set the config setting reset.quiet to true\n"
-#~ "to make this the default.\n"
-#~ msgstr ""
-#~ "\n"
-#~ "S'ha trigat %.2f segons a enumerar els canvis «unstaged» després del "
-#~ "reinici.\n"
-#~ "Podeu utilitzar «--quiet» per a evitar-ho. Establiu el paràmetre de "
-#~ "configuració\n"
-#~ "reset.quiet a true per a fer que aquesta configuració sigui "
-#~ "predeterminada.\n"
-
-#~ msgid "git sparse-checkout list"
-#~ msgstr "git sparse-checkout list"
-
-#~ msgid "unable to upgrade repository format to enable worktreeConfig"
-#~ msgstr ""
-#~ "no s'ha pogut actualitzar el format del repositori per a habilitar "
-#~ "worktreeConfig"
-
-#~ msgid "git sparse-checkout init [--cone] [--[no-]sparse-index]"
-#~ msgstr "git sparse-checkout init [--cone] [--[no-]sparse-index]"
-
-#~ msgid "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]"
-#~ msgstr "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]"
-
-#~ msgid "git sparse-checkout disable"
-#~ msgstr "git sparse-checkout disable"
-
-#~ msgid ""
-#~ "the stash.useBuiltin support has been removed!\n"
-#~ "See its entry in 'git help config' for details."
-#~ msgstr ""
-#~ "s'ha eliminat l'opció stash.useBuiltin.\n"
-#~ "Per a més detalls vegeu la seva entrada a «git help config»."
-
-#~ msgid "git stripspace [-s | --strip-comments]"
-#~ msgstr "git stripspace [-s | --strip-comments]"
-
-#~ msgid "git stripspace [-c | --comment-lines]"
-#~ msgstr "git stripspace [-c | --comment-lines]"
-
-#~ msgid "submodule--helper print-default-remote takes no arguments"
-#~ msgstr "submodule--helper print-default-remote no pren cap argument"
-
-#~ msgid "git submodule--helper update-clone [--prefix=<path>] [<path>...]"
-#~ msgstr "git submodule--helper update-clone [--prefix=<camí>] [<camí>...]"
-
-#~ msgid "suppress output for update by rebase or merge"
-#~ msgstr "omet la sortida per les actualitzacions per «rebase» o fusió"
-
-#~ msgid "overrides update mode in case the repository is a fresh clone"
-#~ msgstr ""
-#~ "sobreescriu el mode d'actualització en cas que el repositori sigui un "
-#~ "clon nou"
-
-#~ msgid "depth for shallow fetch"
-#~ msgstr "profunditat per a les obtencions superficials"
-
-#~ msgid "sha1"
-#~ msgstr "sha1"
-
-#~ msgid "SHA1 expected by superproject"
-#~ msgstr "SHA1 esperat per superproject"
-
-#~ msgid "subsha1"
-#~ msgstr "subsha1"
-
-#~ msgid "SHA1 of submodule's HEAD"
-#~ msgstr "SHA1 del HEAD del submòdul"
-
-#~ msgid "git submodule--helper run-update-procedure [<options>] <path>"
-#~ msgstr "git submodule--helper run-update-procedure [<options>] <path>"
-
-#~ msgid "git submodule--helper config --check-writeable"
-#~ msgstr "git submodule--helper config --check-writeable"
-
-#~ msgid "git update-server-info [--force]"
-#~ msgstr "git update-server-info [--force]"
-
-#~ msgid "Initialize and modify the sparse-checkout"
-#~ msgstr "Inicialitza i modifica el «sparse-checkout»"
-
-#, sh-format
-#~ msgid ""
-#~ "Unable to find current ${remote_name}/${branch} revision in submodule "
-#~ "path '$sm_path'"
+#~ "Note: %s not up to date and in way of checking out conflicted version; "
+#~ "old copy renamed to %s"
 #~ msgstr ""
-#~ "No s'ha pogut trobar la revisió actual de ${remote_name}/${branch} en el "
-#~ "camí de submòdul «$sm_path»"
+#~ "Nota: %s no està actualitzat i en forma de comprovar la versió en "
+#~ "conflicte; còpia antiga reanomenada a %s"
 
-#, sh-format
-#~ msgid "Failed to recurse into submodule path '$displaypath'"
-#~ msgstr ""
-#~ "S'ha produït un error en recórrer recursivament dins del camí de submòdul "
-#~ "«$displaypath»"
+#, c-format
+#~ msgid "%s: fast-forward"
+#~ msgstr "%s: avanç ràpid"
index 76d6d3bea7c51af906dd60c160f491578e073e21..f5c9c29e0b2af13eff5f02313cddc7c14dee4531 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -8,16 +8,16 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-21 19:57+0000\n"
-"PO-Revision-Date: 2022-06-20 21:17+0200\n"
-"Last-Translator: Matthias Rüster <matthias.ruester@gmail.com>\n"
-"Language-Team: Matthias Rüster <matthias.ruester@gmail.com>\n"
+"POT-Creation-Date: 2022-09-28 17:09+0200\n"
+"PO-Revision-Date: 2022-09-28 17:10+0200\n"
+"Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
+"Language-Team: German\n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n!=1);\n"
-"X-Generator: Poedit 3.1\n"
+"X-Generator: Poedit 3.1.1\n"
 
 #, c-format
 msgid "Huh (%s)?"
@@ -379,8 +379,8 @@ msgstr "Ergänzung im Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 #, c-format, perl-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
-"Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,"
-"d%s,?]? "
+"Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d"
+"%s,?]? "
 
 msgid ""
 "y - discard this hunk from index and worktree\n"
@@ -411,8 +411,8 @@ msgstr "Ergänzung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 #, c-format, perl-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
-"Diesen Patch-Block auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,"
-"d%s,?]? "
+"Diesen Patch-Block auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d"
+"%s,?]? "
 
 msgid ""
 "y - apply this hunk to index and worktree\n"
@@ -428,6 +428,23 @@ msgstr ""
 "a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
 "d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht anwenden\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Modusänderung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Löschung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+"Diesen Patch-Block auf das Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -445,10 +462,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "Konnte Block-Header '%.*s' nicht parsen."
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "Konnte farbigen Block-Header '%.*s' nicht parsen."
-
 msgid "could not parse diff"
 msgstr "konnte Diff nicht parsen"
 
@@ -506,7 +519,6 @@ msgstr ""
 "Um '%c' Zeilen zu entfernen, löschen Sie diese.\n"
 "Zeilen, die mit %c beginnen, werden entfernt.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
 #. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
@@ -524,14 +536,12 @@ msgstr "konnte Block-Header nicht parsen"
 msgid "'git apply --cached' failed"
 msgstr "'git apply --cached' schlug fehl"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input
 #. at this point.
@@ -750,6 +760,26 @@ msgstr ""
 "'advice.detachedHead' auf 'false' setzen.\n"
 "\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Die folgenden Pfade wurden aus der partiellen Checkout-Definition\n"
+"verschoben, sind aber aufgrund lokaler Änderungen nicht partiell.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Um den partiellen Checkout dieser Pfade zu korrigieren, gehen Sie wie folgt "
+"vor:\n"
+"* Verwenden Sie \"git add --sparse <Pfade>\", um den Index zu aktualisieren\n"
+"* Verwenden Sie \"git sparse-checkout reapply\", um die Regeln für partielle "
+"Checkouts anzuwenden"
+
 msgid "cmdline ends with \\"
 msgstr "Befehlszeile endet mit \\"
 
@@ -1271,6 +1301,10 @@ msgstr "kann Blob %s nicht streamen"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "Nicht unterstützter Dateimodus: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "Fehler beim Komprimieren (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "konnte '%s' Filter nicht starten"
@@ -1290,10 +1324,6 @@ msgstr "Pfad ist kein gültiges UTF-8: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "Pfad zu lang (%d Zeichen, SHA1: %s): %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "Fehler beim Komprimieren (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "Timestamp zu groß für dieses System: %<PRIuMAX>"
@@ -1618,12 +1648,10 @@ msgstr ""
 msgid "not tracking: ambiguous information for ref '%s'"
 msgstr "kein Tracking: mehrdeutige Informationen für Referenz '%s'"
 
-#. #-#-#-#-#  branch.c.po  #-#-#-#-#
 #. TRANSLATORS: This is a line listing a remote with duplicate
 #. refspecs in the advice message below. For RTL languages you'll
 #. probably want to swap the "%s" and leading "  " space around.
 #.
-#. #-#-#-#-#  object-name.c.po  #-#-#-#-#
 #. TRANSLATORS: This is line item of ambiguous object output
 #. from describe_ambiguous_object() above. For RTL languages
 #. you'll probably want to swap the "%s" and leading " " space
@@ -1990,8 +2018,8 @@ msgstr ""
 #, c-format
 msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
 msgstr ""
-"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"%s --"
-"skip\" aus."
+"Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"%s --skip"
+"\" aus."
 
 #, c-format
 msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
@@ -3108,8 +3136,12 @@ msgstr "libc Info: "
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "nicht in einem Git-Repository ausgeführt - keine Hooks zum Anzeigen\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <Datei>] [-s|--suffix <Format>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <Datei>] [-s|--suffix <Format>] [--"
+"diagnose[=<Modus>]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3147,16 +3179,29 @@ msgstr ""
 "Bitte überprüfen Sie den restlichen Teil des Fehlerberichts unten.\n"
 "Sie können jede Zeile löschen, die Sie nicht mitteilen möchten.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "Speicherort für die Datei des Fehlerberichts angeben"
+msgid "mode"
+msgstr "Modus"
 
-msgid "specify a strftime format suffix for the filename"
-msgstr "Dateiendung im strftime-Format für den Dateinamen angeben"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"ein zusätzliches Zip-Archiv mit detaillierten Diagnosen erstellen (Standard "
+"'stats')"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "einen Zielort für die Fehlerberichtsdatei(en) angeben"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "ein Suffix im strftime-Format für den/die Dateinamen angeben"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "konnte vorangehende Verzeichnisse für '%s' nicht erstellen"
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "Diagnosearchiv %s kann nicht erstellt werden"
+
 msgid "System Info"
 msgstr "System Info"
 
@@ -3214,10 +3259,6 @@ msgstr "Zum Entpacken wird ein Repository benötigt."
 msgid "Unbundling objects"
 msgstr "Entpacken von Objekten"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Unbekannter Unterbefehl: %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "kann Objekt %s '%s' nicht lesen"
@@ -3296,6 +3337,9 @@ msgstr "Objektgröße anzeigen"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "-s und -t mit beschädigten Objekten erlauben"
 
+msgid "use mail map file"
+msgstr "\"mailmap\"-Datei verwenden"
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr ""
 "Batch-Objekte von Standard-Eingabe (oder --batch-all-objects) angefordert"
@@ -3306,6 +3350,9 @@ msgstr "vollständige Inhalte von <Objekt> oder <Commit> anzeigen"
 msgid "like --batch, but don't emit <contents>"
 msgstr "wie --batch, aber keine Ausgabe von <Inhalten>"
 
+msgid "stdin is NUL-terminated"
+msgstr "stdin endet mit NUL"
+
 msgid "read commands from stdin"
 msgstr "Befehle von der Standard-Eingabe lesen"
 
@@ -4198,6 +4245,14 @@ msgstr ""
 "Initialisiere Datei für partiellen Checkout, um nur Dateien im\n"
 "Root-Verzeichnis einzubeziehen"
 
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"eine URI für das Herunterladen von Bundles vor dem Abruf\n"
+"aus dem ursprünglichen Remote-Repository"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: Konnte Alternative für '%s' nicht hinzufügen: %s\n"
@@ -4257,10 +4312,10 @@ msgstr "kann %s nicht aktualisieren"
 msgid "failed to initialize sparse-checkout"
 msgstr "Fehler beim Initialisieren vom partiellen Checkout."
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr ""
-"Externer HEAD bezieht sich auf eine nicht existierende Referenz und kann "
-"nicht ausgecheckt werden.\n"
+"HEAD des Remote-Repositories verweist auf nicht existierende Referenz, kann "
+"nicht ausgecheckt werden"
 
 msgid "unable to checkout working tree"
 msgstr "Arbeitsverzeichnis konnte nicht ausgecheckt werden"
@@ -4284,6 +4339,13 @@ msgstr "Sie müssen ein Repository zum Klonen angeben."
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "die Optionen '%s' und '%s %s' können nicht gemeinsam verwendet werden"
 
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri ist inkompatibel mit --depth, --shallow-since und --shallow-"
+"exclude"
+
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "Repository '%s' existiert nicht"
@@ -4368,6 +4430,13 @@ msgstr "--local wird ignoriert"
 msgid "cannot clone from filtered bundle"
 msgstr "kann nicht von gefiltertem Bundle klonen"
 
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "konnte das Repository nicht initialisieren, überspringe Bundle-URI"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "Objekte aus Bundle-URI '%s' konnten nicht abgerufen werden"
+
 msgid "remote transport reported error"
 msgstr "Remoteübertragung meldete Fehler"
 
@@ -4489,10 +4558,6 @@ msgstr ""
 msgid "Collecting commits from input"
 msgstr "Sammle Commits von der Standard-Eingabe"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "Nicht erkannter Unterbefehl: %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -4856,9 +4921,6 @@ msgstr "Status im Langformat anzeigen (Standard)"
 msgid "terminate entries with NUL"
 msgstr "Einträge mit NUL-Zeichen abschließen"
 
-msgid "mode"
-msgstr "Modus"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "unversionierte Dateien anzeigen, optionale Modi: all, normal, no. (Standard: "
@@ -5449,8 +5511,8 @@ msgstr "Markierung"
 
 msgid "append <mark> on dirty working tree (default: \"-dirty\")"
 msgstr ""
-"<Markierung> bei geändertem Arbeitsverzeichnis anhängen (Standard: \"-"
-"dirty\")"
+"<Markierung> bei geändertem Arbeitsverzeichnis anhängen (Standard: \"-dirty"
+"\")"
 
 msgid "append <mark> on broken working tree (default: \"-broken\")"
 msgstr ""
@@ -5463,6 +5525,22 @@ msgstr "Keine Namen gefunden, kann nichts beschreiben."
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "Option '%s' und Commit-Angaben können nicht gemeinsam verwendet werden"
 
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <Pfad>] [-s|--suffix <Format>] [--"
+"mode=<Modus>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "einen Zielort für das Diagnosearchiv angeben"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "Dateiendung im strftime-Format für den Dateinamen angeben"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "den Inhalt des Diagnosearchivs angeben"
+
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base funktioniert nur mit zwei Commits"
 
@@ -5597,13 +5675,13 @@ msgstr "Ausgaben unterdrücken; nur git_env_*() Werte als Exit-Code verwenden"
 #, c-format
 msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
 msgstr ""
-"Option `--default' erwartet einen booleschen Wert bei `--type=bool`, nicht "
-"`%s`"
+"Option `--default' erwartet einen booleschen Wert bei `--type=bool`, nicht `"
+"%s`"
 
 #, c-format
 msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
+"option `--default' expects an unsigned long value with `--type=ulong`, not `"
+"%s`"
 msgstr ""
 "Option `--default' erwartet einen vorzeichenlosen Long-Wert bei `--"
 "type=ulong`, nicht `%s`"
@@ -5851,11 +5929,8 @@ msgstr "[aktuell]"
 msgid "[rejected]"
 msgstr "[zurückgewiesen]"
 
-msgid "can't fetch in current branch"
-msgstr "kann \"fetch\" im aktuellen Branch nicht ausführen"
-
-msgid "checked out in another worktree"
-msgstr "in einem anderen Arbeitsverzeichnis ausgecheckt"
+msgid "can't fetch into checked-out branch"
+msgstr "fetch kann in den ausgecheckten Branch nicht durchgeführt werden"
 
 msgid "[tag update]"
 msgstr "[Tag Aktualisierung]"
@@ -6299,6 +6374,10 @@ msgstr "%s: Ungültiger SHA1-Zeiger in Cache-Verzeichnis"
 msgid "non-tree in cache-tree"
 msgstr "non-tree in Cache-Verzeichnis"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s: Ungültiger sha1-Zeiger in resolve-undo"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<Optionen>] [<Objekt>...]"
 
@@ -6639,14 +6718,17 @@ msgstr ""
 "Fehler beim Ausführen von 'crontab -l'; Ihr System unterstützt eventuell "
 "'cron' nicht"
 
+msgid "failed to create crontab temporary file"
+msgstr "temporäre crontab Datei konnte nicht erstellt werden"
+
+msgid "failed to open temporary file"
+msgstr "temporäre Datei kann nicht geöffnet werden"
+
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "Fehler beim Ausführen von 'crontab'; Ihr System unterstützt eventuell 'cron' "
 "nicht"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "Fehler beim Öffnen der Standard-Eingabe von 'crontab'"
-
 msgid "'crontab' died"
 msgstr "'crontab' abgebrochen"
 
@@ -6693,10 +6775,6 @@ msgstr "Repository konnte nicht zur globalen Konfiguration hinzugefügt werden"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <Unterbefehl> [<Optionen>]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "ungültiger Unterbefehl: %s"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<Optionen>] [-e] <Muster> [<Commit>...] [[--] <Pfad>...]"
 
@@ -6708,7 +6786,6 @@ msgstr "grep: Fehler beim Erzeugen eines Thread: %s"
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "ungültige Anzahl von Threads (%d) für %s angegeben"
 
-#. #-#-#-#-#  grep.c.po  #-#-#-#-#
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
@@ -6871,6 +6948,9 @@ msgstr "Dateien mit Übereinstimmungen im Anzeigeprogramm anzeigen"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "den Aufruf von grep(1) erlauben (von dieser Programmversion ignoriert)"
 
+msgid "maximum number of results per file"
+msgstr "maximale Anzahl von Ergebnissen pro Datei"
+
 msgid "no pattern given"
 msgstr "Kein Muster angegeben."
 
@@ -6962,11 +7042,21 @@ msgstr "Beschreibung des Befehls ausgeben"
 msgid "print list of useful guides"
 msgstr "Liste von allgemein verwendeten Anleitungen anzeigen"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr ""
+"Liste der benutzerseitigen Repository-, Befehls- und Dateischnittstellen "
+"ausgeben"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr ""
+"Liste von Dateiformaten, Protokollen und anderen Entwicklerschnittstellen "
+"ausgeben"
+
 msgid "print all configuration variable names"
 msgstr "alle Namen der Konfigurationsvariablen ausgeben"
 
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<Befehl>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<Befehl>|<Dokument>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -7438,8 +7528,8 @@ msgstr "Ausgabe der Unterschiede unterdrücken"
 msgid "show source"
 msgstr "Quelle anzeigen"
 
-msgid "use mail map file"
-msgstr "\"mailmap\"-Datei verwenden"
+msgid "clear all previously-defined decoration filters"
+msgstr "alle zuvor definierten Dekorationsfilter löschen"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "\"decorate\" nur bei Referenzen anwenden, die <Muster> entsprechen"
@@ -7698,6 +7788,11 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr "Prozentsatz mit welchem Erzeugung gewichtet wird"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr ""
+"From: aus E-Mail Text anzeigen, auch wenn es mit der Kopfzeile der E-Mail "
+"identisch ist"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "Ungültige Identifikationszeile: %s"
@@ -7758,6 +7853,18 @@ msgstr ""
 "Konnte gefolgten Remote-Branch nicht finden, bitte geben Sie <Upstream> "
 "manuell an.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "ungültiges ls-files-Format: Element '%s' fängt nicht mit '(' an"
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "ungültiges ls-files-Format: Element '%s' endet nicht auf ')'"
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "ungültiges ls-files-Format: %%%.*s"
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<Optionen>] [<Datei>...]"
 
@@ -7847,6 +7954,13 @@ msgstr "doppelte Einträge unterdrücken"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "zeige partielle Verzeichnisse, wenn ein partieller Index vorhanden ist"
 
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format kann nicht mit -s, -o, -k, -t, --resolve-undo, --deduplicate, --eol "
+"verwendet werden"
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url]\n"
@@ -8070,6 +8184,40 @@ msgstr "Konnte Referenz '%s' nicht auflösen"
 msgid "Merging %s with %s\n"
 msgstr "Führe %s mit %s zusammen\n"
 
+msgid "not something we can merge"
+msgstr "nichts was wir zusammenführen können"
+
+msgid "refusing to merge unrelated histories"
+msgstr "verweigere den Merge von nicht zusammenhängenden Historien"
+
+msgid "failure to merge"
+msgstr "Fehler beim Merge"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<Optionen>] <Branch1> <Branch2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr ""
+"git merge-tree [--trivial-merge] <Basis-Tree-Objekt> <Branch1> <Branch2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "einen echten Merge anstelle eines trivialen Merge durchführen"
+
+msgid "do a trivial merge only"
+msgstr "nur einen trivialen Merge durchführen"
+
+msgid "also show informational/conflict messages"
+msgstr "auch Informations-/Konfliktmeldungen anzeigen"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "Dateinamen ohne Modi/Oids/Stufen auflisten"
+
+msgid "allow merging unrelated histories"
+msgstr "erlaube das Zusammenführen von nicht zusammenhängenden Historien"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge ist mit allen anderen Optionen inkompatibel"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<Optionen>] [<Commit>...]"
 
@@ -8152,9 +8300,6 @@ msgstr "--abort, aber Index und Arbeitsverzeichnis unverändert lassen"
 msgid "continue the current in-progress merge"
 msgstr "den sich im Gange befindlichen Merge fortsetzen"
 
-msgid "allow merging unrelated histories"
-msgstr "erlaube das Zusammenführen von nicht zusammenhängenden Historien"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "Hooks pre-merge-commit und commit-msg umgehen"
 
@@ -8277,9 +8422,6 @@ msgstr "Konnte '%s' nicht schließen."
 msgid "not something we can merge in %s: %s"
 msgstr "nichts was wir in %s zusammenführen können: %s"
 
-msgid "not something we can merge"
-msgstr "nichts was wir zusammenführen können"
-
 msgid "--abort expects no arguments"
 msgstr "--abort akzeptiert keine Argumente"
 
@@ -8331,13 +8473,19 @@ msgstr "%s - nichts was wir zusammenführen können"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Kann nur exakt einen Commit in einem leeren Branch zusammenführen"
 
-msgid "refusing to merge unrelated histories"
-msgstr "verweigere den Merge von nicht zusammenhängenden Historien"
-
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Aktualisiere %s..%s\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
+"überschrieben werden:\n"
+"  %s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Probiere wirklich trivialen \"in-index\"-Merge...\n"
@@ -8371,6 +8519,12 @@ msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Automatischer Merge abgeschlossen; halte, wie gewünscht, vor dem Commit an\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr ""
+"Wenn Sie fertig sind, wenden Sie die Änderungen aus dem Stash mit `git stash "
+"pop` an\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "Warnung: Tag-Eingabe ungültig für fsck: %s"
@@ -8493,6 +8647,9 @@ msgstr "Prüfe Umbenennung von '%s' nach '%s'\n"
 msgid "bad source"
 msgstr "ungültige Quelle"
 
+msgid "destination exists"
+msgstr "Ziel existiert bereits"
+
 msgid "can not move directory into itself"
 msgstr "kann Verzeichnis nicht in sich selbst verschieben"
 
@@ -8508,9 +8665,6 @@ msgstr "nicht unter Versionskontrolle"
 msgid "conflicted"
 msgstr "in Konflikt"
 
-msgid "destination exists"
-msgstr "Ziel existiert bereits"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "überschreibe '%s'"
@@ -8524,6 +8678,9 @@ msgstr "mehrere Quellen für dasselbe Ziel"
 msgid "destination directory does not exist"
 msgstr "Zielverzeichnis existiert nicht"
 
+msgid "destination exists in the index"
+msgstr "Ziel existiert im Index"
+
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, Quelle=%s, Ziel=%s"
@@ -8889,8 +9046,8 @@ msgid "use notes from <notes-ref>"
 msgstr "Notizen von <Notiz-Referenz> verwenden"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "Unbekannter Unterbefehl: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "unbekannter Unterbefehl: `%s'"
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -9825,12 +9982,17 @@ msgstr "nur Ausgaben anzeigen, die sich auf den ersten Bereich beziehen"
 msgid "only emit output related to the second range"
 msgstr "nur Ausgaben anzeigen, die sich auf den zweiten Bereich beziehen"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "kein Commit: '%s'"
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "kein Commit-Bereich: '%s'"
 
-msgid "single arg format must be symmetric range"
-msgstr "Format mit einfachem Argument muss symmetrischer Bereich sein."
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "kein symmetrischer Bereich: '%s'"
 
 msgid "need two commit ranges"
 msgstr "Benötige zwei Commit-Bereiche."
@@ -9988,8 +10150,8 @@ msgstr "Konnte nicht zu %s wechseln."
 
 #, c-format
 msgid ""
-"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
-"\"ask\"."
+"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask"
+"\"."
 msgstr ""
 "nicht erkannter leerer Typ '%s'; gültige Werte sind \"drop\", \"keep\", und "
 "\"ask\"."
@@ -10112,6 +10274,10 @@ msgstr "behalte Commits, die leer beginnen"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "bei -i Commits verschieben, die mit squash!/fixup! beginnen"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr ""
+"Branches aktualisieren, die auf Commits verweisen, die gerade rebased werden"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr "exec-Zeilen nach jedem Commit der editierbaren Liste hinzufügen"
 
@@ -10654,6 +10820,9 @@ msgstr " neu (wird bei nächstem \"fetch\" in remotes/%s gespeichert)"
 msgid " tracked"
 msgstr " gefolgt"
 
+msgid " skipped"
+msgstr " übersprungen"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " veraltet (benutzen Sie 'git remote prune' zum Löschen)"
 
@@ -11335,6 +11504,10 @@ msgstr "Konnte neue Index-Datei nicht schreiben."
 msgid "unable to get disk usage of %s"
 msgstr "konnte Festplattennutzung von %s nicht bekommen"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "ungültiger Wert für '%s': '%s', das einzig zulässige Format ist '%s'"
+
 msgid "rev-list does not support display of notes"
 msgstr "rev-list unterstützt keine Anzeige von Notizen"
 
@@ -11361,6 +11534,9 @@ msgstr "frühzeitiges Ende der Eingabe"
 msgid "no usage string given before the `--' separator"
 msgstr "kein Verwendungstext vor dem `--' Separator angegeben"
 
+msgid "missing opt-spec before option flags"
+msgstr "fehlende opt-spec vor Optionsflags"
+
 msgid "Needed a single revision"
 msgstr "Benötigte einen einzelnen Commit"
 
@@ -12147,6 +12323,10 @@ msgstr "Kommentarzeichen mit Leerzeichen an jede Zeile voranstellen"
 msgid "Expecting a full ref name, got %s"
 msgstr "Vollständiger Referenzname erwartet, %s erhalten"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "Konnte kein Repository-Handle für Submodul '%s' erhalten."
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -12155,12 +12335,6 @@ msgstr ""
 "Konnte Konfiguration '%s' nicht nachschlagen. Nehme an, dass dieses\n"
 "Repository sein eigenes verbindliches Upstream-Repository ist."
 
-msgid "alternative anchor for relative paths"
-msgstr "Alternativer Anker für relative Pfade"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<Pfad>] [<Pfad>...]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "Keine URL für Submodul-Pfad '%s' in .gitmodules gefunden"
@@ -12194,8 +12368,8 @@ msgstr "Ausgaben beim Betreten eines Submodul-Befehls unterdrücken"
 msgid "recurse into nested submodules"
 msgstr "Rekursion in verschachtelte Submodule durchführen"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <Befehl>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <Befehl>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -12219,8 +12393,8 @@ msgstr ""
 msgid "suppress output for initializing a submodule"
 msgstr "Ausgaben bei Initialisierung eines Submoduls unterdrücken"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<Optionen>] [<Pfad>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<Optionen>] [<Pfad>]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -12246,9 +12420,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<Pfad>...]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <Pfad>"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(blob)->%s(submodule)"
@@ -12283,8 +12454,8 @@ msgstr ""
 msgid "limit the summary size"
 msgstr "Größe der Zusammenfassung begrenzen"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<Optionen>] [<Commit>] [--] [<Pfad>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<Optionen>] [<Commit>] [--] [<Pfad>]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "konnte keinen Commit für HEAD holen"
@@ -12297,10 +12468,6 @@ msgstr "Synchronisiere Submodul-URL für '%s'\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "Fehler beim Registrieren der URL für Submodul-Pfad '%s'"
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "Fehler beim Lesen des Standard-Remote-Repositories für Submodul '%s'"
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "Fehler beim Aktualisieren des Remote-Repositories für Submodul '%s'"
@@ -12308,8 +12475,8 @@ msgstr "Fehler beim Aktualisieren des Remote-Repositories für Submodul '%s'"
 msgid "suppress output of synchronizing submodule url"
 msgstr "Ausgaben bei der Synchronisierung der Submodul-URLs unterdrücken"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<Pfad>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<Pfad>]"
 
 #, c-format
 msgid ""
@@ -12373,6 +12540,10 @@ msgstr ""
 "submodule.alternateErrorStrategy auf 'info' oder klone mit der Option\n"
 "'--reference-if-able' statt '--reference'."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "konnte kein Repository-Handle für gitdir '%s' erhalten"
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "Submodul '%s' kann Alternative nicht hinzufügen: %s"
@@ -12403,6 +12574,9 @@ msgstr "Verzeichnis ist nicht leer: '%s'"
 msgid "could not get submodule directory for '%s'"
 msgstr "Konnte Submodul-Verzeichnis '%s' nicht finden."
 
+msgid "alternative anchor for relative paths"
+msgstr "Alternativer Anker für relative Pfade"
+
 msgid "where the new submodule will be cloned to"
 msgstr "Pfad für neues Submodul"
 
@@ -12430,10 +12604,6 @@ msgstr ""
 "<Repository>] [--name <Name>] [--depth <Tiefe>] [--single-branch] [--filter "
 "<filter-spec>] --url <URL> --path <Pfad>"
 
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Ungültiger Aktualisierungsmodus '%s' für Submodul-Pfad '%s'."
-
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr ""
@@ -12508,6 +12678,10 @@ msgstr ""
 "\"fetch\" in Submodul-Pfad '%s' ausgeführt, aber enthielt nicht %s. Direktes "
 "Anfordern dieses Commits ist fehlgeschlagen."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "konnte das Submodul unter dem Pfad '%s' nicht initialisieren"
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12516,10 +12690,6 @@ msgstr ""
 "Branch von Submodul (%s) ist konfiguriert, den Branch des Hauptprojektes\n"
 "zu erben, aber das Hauptprojekt befindet sich auf keinem Branch."
 
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "Konnte kein Repository-Handle für Submodul '%s' erhalten."
-
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr "Konnte aktuellen Commit nicht in Submodul-Pfad '%s' finden"
@@ -12554,12 +12724,14 @@ msgstr "keine neuen Objekte von Remote abrufen"
 msgid "path into the working tree"
 msgstr "Pfad zum Arbeitsverzeichnis"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr ""
-"Pfad zum Arbeitsverzeichnis, über verschachtelte Submodul-Grenzen hinweg"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "die Aktualisierungsstrategie \"checkout\" verwenden (Standard)"
+
+msgid "use the 'merge' update strategy"
+msgstr "die Aktualisierungsstrategie 'merge' verwenden"
 
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout oder none"
+msgid "use the 'rebase' update strategy"
+msgstr "die Aktualisierungsstrategie 'rebase' verwenden"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr ""
@@ -12577,6 +12749,10 @@ msgstr ""
 msgid "don't print cloning progress"
 msgstr "keine Fortschrittsanzeige beim Klonen"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr ""
+"klonen in ein nicht leeres Verzeichnis nicht zulassen, impliziert --init"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12588,14 +12764,11 @@ msgstr ""
 "shallow] [--reference <Repository>] [--recursive] [--[no-]single-branch] "
 "[--] [<Pfad>...]"
 
-msgid "bad value for update parameter"
-msgstr "Fehlerhafter Wert für update Parameter"
-
 msgid "recurse into submodules"
 msgstr "Rekursion in Submodule durchführen"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<Optionen>] [<Pfad>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<Optionen>] [<Pfad>...]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr "prüfen, ob es sicher ist, in die Datei .gitmodules zu schreiben"
@@ -12617,8 +12790,8 @@ msgstr ""
 msgid "suppress output for setting url of a submodule"
 msgstr "Ausgaben beim Setzen der URL eines Submoduls unterdrücken"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <Pfad> <neue URL>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <Pfad> <neue URL>"
 
 msgid "set the default tracking branch to master"
 msgstr "Standard-Tracking-Branch auf master setzen"
@@ -12626,13 +12799,11 @@ msgstr "Standard-Tracking-Branch auf master setzen"
 msgid "set the default tracking branch"
 msgstr "Standard-Tracking-Branch setzen"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) [<Pfad>]"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <Pfad>"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <Branch> <Pfad>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <Branch> <Pfad>"
 
 msgid "--branch or --default required"
 msgstr "Option --branch oder --default erforderlich"
@@ -12732,8 +12903,8 @@ msgstr ""
 "setzt den Namen des Submoduls auf die angegebene Zeichenkette fest, statt "
 "standardmäßig dessen Pfad zu nehmen"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<Optionen>] [--] <Repository> [<Pfad>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<Optionen>] [--] <Repository> [<Pfad>]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
@@ -12942,6 +13113,16 @@ msgstr "Tag '%s' aktualisiert (war %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "Paket überschreitet die maximal erlaubte Größe"
 
+msgid "failed to write object in stream"
+msgstr "Objekt kann nicht in Stream geschrieben werden"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "Dekomprimierung gab (%d) zurück"
+
+msgid "invalid blob object from stream"
+msgstr "ungültiges Blob-Objekt aus Stream"
+
 msgid "Unpacking objects"
 msgstr "Entpacke Objekte"
 
@@ -13497,6 +13678,27 @@ msgstr "das Tree-Objekt für ein Unterverzeichnis <Präfix> schreiben"
 msgid "only useful for debugging"
 msgstr "nur nützlich für Fehlersuche"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch wird auf dieser Plattform nicht unterstützt"
+
+msgid "failed to create temporary file"
+msgstr "temporäre Datei kann nicht erstellt werden"
+
+msgid "insufficient capabilities"
+msgstr "unzureichende Fähigkeiten"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "Download des Bundles von URI '%s' fehlgeschlagen"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "Datei unter URI '%s' ist kein Bundle"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "Bundle von URI '%s' konnte nicht entpackt werden"
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "unbekannter Paket-Hash-Algorithmus: %s"
@@ -13709,6 +13911,9 @@ msgstr ""
 "einem Objekt einen für Menschen lesbaren Namen basierend auf\n"
 "einer verfügbaren Referenz geben"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Erzeugen eines Zip-Archivs mit Diagnoseinformationen"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr ""
 "Änderungen zwischen Commits, Commit und Arbeitsverzeichnis, etc. anzeigen"
@@ -13846,8 +14051,8 @@ msgstr "einen Merge für zusammenzuführende Dateien ausführen"
 msgid "The standard helper program to use with git-merge-index"
 msgstr "das Standard-Hilfsprogramm für die Verwendung mit git-merge-index"
 
-msgid "Show three-way merge without touching index"
-msgstr "3-Wege-Merge anzeigen ohne den Index zu verändern"
+msgid "Perform merge without touching index or working tree"
+msgstr "Merge ohne Berührung von Index oder Arbeitsverzeichnis durchführen"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
@@ -14053,6 +14258,9 @@ msgstr "gepackte Git-Archivdateien validieren"
 msgid "Check the GPG signature of tags"
 msgstr "die GPG-Signatur von Tags prüfen"
 
+msgid "Display version information about Git"
+msgstr "Versionsinformationen über Git anzeigen"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Logs mit dem Unterschied, den jeder Commit einführt, anzeigen"
 
@@ -14087,6 +14295,24 @@ msgstr ""
 msgid "Frequently asked questions about using Git"
 msgstr "Häufig gestellte Fragen über die Nutzung von Git"
 
+msgid "The bundle file format"
+msgstr "Das Bundle-Dateiformat"
+
+msgid "Chunk-based file formats"
+msgstr "Chunk-basierte Dateiformate"
+
+msgid "Git commit graph format"
+msgstr "Git Commit Graph Format"
+
+msgid "Git index format"
+msgstr "Git-Index-Format"
+
+msgid "Git pack format"
+msgstr "Git-Pack-Format"
+
+msgid "Git cryptographic signature formats"
+msgstr "Git kryptographische Signaturformate"
+
 msgid "A Git Glossary"
 msgstr "ein Git-Glossar"
 
@@ -14108,6 +14334,21 @@ msgstr "Definition von Submodul-Eigenschaften"
 msgid "Git namespaces"
 msgstr "Git Namensbereiche"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Fähigkeiten des Protokolls v0 und v1"
+
+msgid "Things common to various protocols"
+msgstr "Gemeinsamkeiten zwischen verschiedenen Protokollen"
+
+msgid "Git HTTP-based protocols"
+msgstr "Git HTTP-basierte Protokolle"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Wie Pakete über die Leitung übertragen werden"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Git Wire Protokoll, Version 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Hilfsprogramme zur Interaktion mit Remote-Repositories"
 
@@ -14132,6 +14373,9 @@ msgstr "Git Web Interface (Web-Frontend für Git-Repositories)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Eine Übersicht über empfohlene Arbeitsabläufe mit Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Ein Werkzeug zur Verwaltung großer Git-Repositories"
+
 msgid "commit-graph file is too small"
 msgstr "Commit-Graph-Datei ist zu klein"
 
@@ -14377,6 +14621,14 @@ msgstr "keine Compiler-Information verfügbar\n"
 msgid "no libc information available\n"
 msgstr "keine libc Informationen verfügbar\n"
 
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "konnte freien Speicherplatz für '%s' nicht bestimmen"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "konnte keine Info für '%s' bekommen"
+
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
 msgstr "[GLE %ld] health Thread konnte '%ls' nicht öffnen"
@@ -14431,6 +14683,14 @@ msgstr "GetOverlappedResult fehlgeschlagen auf '%s' [GLE %ld]"
 msgid "could not read directory changes [GLE %ld]"
 msgstr "konnte Verzeichnisveränderungen nicht lesen [GLE %ld]"
 
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] '%ls' kann nicht zum Lesen geöffnet werden"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] kann keine Protokollinformationen für '%ls' erhalten"
+
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr "Fehler beim Kopieren von SID (%ld)"
@@ -14990,200 +15250,24 @@ msgid "failed to close rev-list's stdin"
 msgstr "Fehler beim Schließen von rev-lists Standard-Eingabe"
 
 #, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' existiert nicht."
-
-msgid "need a working directory"
-msgstr "Arbeitsverzeichnis benötigt"
-
-msgid "could not find enlistment root"
-msgstr "konnte Root-Verzeichnis für Eintragungen nicht finden"
+msgid "illegal crlf_action %d"
+msgstr "Unerlaubte crlf_action %d"
 
 #, c-format
-msgid "could not switch to '%s'"
-msgstr "konnte nicht zu '%s' wechseln"
+msgid "CRLF would be replaced by LF in %s"
+msgstr "CRLF würde in %s durch LF ersetzt werden"
 
 #, c-format
-msgid "could not configure %s=%s"
-msgstr "konnte %s=%s nicht konfigurieren"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "konnte log.excludeDecoration nicht konfigurieren"
+msgid ""
+"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
+"touches it"
+msgstr ""
+"in der Arbeitskopie von '%s', CRLF wird durch LF ersetzt, sobald es das "
+"nächste Mal von Git verarbeitet wird"
 
-msgid "Scalar enlistments require a worktree"
-msgstr "Skalare Eintragungen erfordern ein Arbeitsverzeichnis"
-
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "konnte Verzeichnis '%s' nicht öffnen"
-
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "überspringe '%s', das weder Datei noch Verzeichnis ist"
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "konnte freien Speicherplatz für '%s' nicht bestimmen"
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "konnte keine Info für '%s' bekommen"
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "externer HEAD ist kein Branch: '%.*s'"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-"Fehler beim Abfragen des Standard-Branchnamens vom Remote-Repository; nutze "
-"lokalen Standardwert"
-
-msgid "failed to get default branch name"
-msgstr "Fehler beim Abfragen des Standard-Branchnamens"
-
-msgid "failed to unregister repository"
-msgstr "Fehler beim Austragen des Repositories"
-
-msgid "failed to delete enlistment directory"
-msgstr "Fehler beim Löschen des Eintragungs-Verzeichnisses"
-
-msgid "branch to checkout after clone"
-msgstr "Branch, der nach dem Klonen ausgecheckt werden soll"
-
-msgid "when cloning, create full working directory"
-msgstr "vollständiges Arbeitsverzeichnis beim Klonen erstellen"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "lade nur Metadaten des Branches herunter, der ausgecheckt wird"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<Optionen>] [--] <Repository> [<Verzeichnis>]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "konnte Name für Arbeitsverzeichnis nicht von '%s' ableiten"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "Verzeichnis '%s' existiert bereits"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "Fehler beim Abfragen des Default-Branches für '%s'"
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "konnte Remote-Repository in '%s' nicht konfigurieren"
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "konnte '%s' nicht konfigurieren"
-
-msgid "partial clone failed; attempting full clone"
-msgstr "partielles Klonen fehlgeschlagen; versuche vollständiges Klonen"
-
-msgid "could not configure for full clone"
-msgstr "konnte nicht für vollständiges Klonen konfigurieren"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<Eintragung>]"
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "konnte Verzeichnis für '%s' nicht erstellen"
-
-msgid "could not duplicate stdout"
-msgstr "konnte Standard-Ausgabe nicht duplizieren"
-
-msgid "failed to write archive"
-msgstr "Schreiben des Archivs fehlgeschlagen"
-
-msgid "`scalar list` does not take arguments"
-msgstr "`scalar list` akzeptiert keine Argumente"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<Eintragung>]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "alle registrierten Eintragungen neu konfigurieren"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <Eintragung>]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "--all oder <Eintragung>, aber nicht beides"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "Git-Repository entfernt in '%s'"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <Aufgabe> [<Eintragung>]\n"
-"Aufgaben:\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "Aufgabe nicht gefunden: '%s'"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<Eintragung>]"
-
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <Eintragung>"
-
-msgid "refusing to delete current working directory"
-msgstr "Löschen des aktuellen Arbeitsverzeichnisses wurde verweigert"
-
-msgid "include Git version"
-msgstr "Git-Version einbeziehen"
-
-msgid "include Git's build options"
-msgstr "Build-Optionen von Git einbeziehen"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "-C erfordert ein <Verzeichnis>"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "konnte nicht zu '%s' wechseln"
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c benötigt ein <Schlüssel>=<Wert> Argument"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <Verzeichnis>] [-c <Schlüssel>=<Wert>] <Befehl> [<Optionen>]\n"
-"\n"
-"Befehle:\n"
-
-#, c-format
-msgid "illegal crlf_action %d"
-msgstr "Unerlaubte crlf_action %d"
-
-#, c-format
-msgid "CRLF would be replaced by LF in %s"
-msgstr "CRLF würde in %s durch LF ersetzt werden"
-
-#, c-format
-msgid ""
-"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
-"touches it"
-msgstr ""
-"in der Arbeitskopie von '%s', CRLF wird durch LF ersetzt, sobald es das "
-"nächste Mal von Git verarbeitet wird"
-
-#, c-format
-msgid "LF would be replaced by CRLF in %s"
-msgstr "LF würde in %s durch CRLF ersetzt werden"
+#, c-format
+msgid "LF would be replaced by CRLF in %s"
+msgstr "LF würde in %s durch CRLF ersetzt werden"
 
 #, c-format
 msgid ""
@@ -15373,6 +15457,32 @@ msgstr ""
 msgid "Marked %d islands, done.\n"
 msgstr "%d Delta-Islands markiert, fertig.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "ungültiger --%s Wert '%s'"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "fehlendes Verzeichnis '%s' konnte nicht archiviert werden"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "konnte Verzeichnis '%s' nicht öffnen"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "überspringe '%s', das weder Datei noch Verzeichnis ist"
+
+msgid "could not duplicate stdout"
+msgstr "konnte Standard-Ausgabe nicht duplizieren"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "konnte das Verzeichnis '%s' nicht zum Archivierungssystem hinzufügen"
+
+msgid "failed to write archive"
+msgstr "Schreiben des Archivs fehlgeschlagen"
+
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base funktioniert nicht mit Bereichen"
 
@@ -16004,6 +16114,9 @@ msgstr "git fetch-pack: ACK/NAK erwartet, '%s' bekommen"
 msgid "unable to write to remote"
 msgstr "konnte nicht zum Remote schreiben"
 
+msgid "Server supports filter"
+msgstr "Server unterstützt Filter"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "ungültige shallow-Zeile: %s"
@@ -16114,9 +16227,6 @@ msgstr "der Server unterstützt Algorithmus '%s' nicht"
 msgid "Server does not support shallow requests"
 msgstr "Server unterstützt keine shallow-Anfragen"
 
-msgid "Server supports filter"
-msgstr "Server unterstützt Filter"
-
 msgid "unable to write request to remote"
 msgstr "konnte Anfrage nicht zum Remote schreiben"
 
@@ -16462,6 +16572,12 @@ msgstr "Systembefehle / Repositories synchronisieren"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Systembefehle / Interne Hilfsbefehle"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "Benutzerseitige Repository-, Befehls- und Dateischnittstellen"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Dateiformate, Protokolle und andere Schnittstellen für Entwickler"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "Vorhandene Git-Befehle in '%s'"
@@ -16475,6 +16591,12 @@ msgstr "Allgemeine Git-Befehle, verwendet in verschiedenen Situationen:"
 msgid "The Git concept guides are:"
 msgstr "Die Git-Konzeptanleitungen sind:"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Benutzerseitige Repository-, Befehls- und Dateischnittstellen:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Dateiformate, Protokolle und andere Entwicklerschnittstellen:"
+
 msgid "External commands"
 msgstr "Externe Befehle"
 
@@ -16560,10 +16682,6 @@ msgstr ""
 "Sie können diese Warnung mit `git config advice.ignoredHook false` "
 "deaktivieren."
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "Konnte Hook '%s' nicht starten\n"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "Argument für --packfile muss ein gültiger Hash sein ('%s' erhalten)"
@@ -16751,19 +16869,14 @@ msgstr "erwartete Flush nach Argumenten für die Auflistung der Referenzen"
 msgid "quoted CRLF detected"
 msgstr "angeführtes CRLF entdeckt"
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
-"überschrieben werden:\n"
-"  %s"
-
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "Fehler beim Merge von Submodul %s (nicht ausgecheckt)."
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Merge von Submodul %s fehlgeschlagen (keine Merge-Basis)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "Fehler beim Merge von Submodul %s (Commits nicht vorhanden)."
@@ -16782,28 +16895,10 @@ msgstr "Fehler beim Zusammenführen von Submodul %s"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
 msgstr ""
-"Fehler beim Zusammenführen von Submodul %s, aber es ist eine mögliche "
-"Auflösung des Merges vorhanden:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"Falls das korrekt ist, fügen Sie es einfach der Staging-Area, zum Beispiel "
-"mit:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"hinzu, um diesen Vorschlag zu akzeptieren.\n"
+"Der Merge von Submodul %s ist fehlgeschlagen, aber es gibt eine mögliche "
+"Auflösung des Merges: %s"
 
 #, c-format
 msgid ""
@@ -16971,13 +17066,46 @@ msgstr ""
 "KONFLIKT (ändern/löschen): %s gelöscht in %s und geändert in %s. Stand %s "
 "von %s wurde im Arbeitsbereich gelassen."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#. - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - gehen Sie zu Submodul (%s) und mergen Sie entweder Commit %s\n"
+"   oder aktualisieren Sie zu einem bestehenden Commit, der diese Änderungen "
+"zusammengeführt hat\n"
+
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
 msgstr ""
-"Hinweis: %s nicht aktuell und konfliktbehaftete Version während des "
-"Auscheckens; alte Kopie zu %s umbenannt"
+"Das rekursive Zusammenführen mit Submodulen unterstützt derzeit nur triviale "
+"Fälle.\n"
+"Bitte führen Sie die Zusammenführung der einzelnen konfliktbehafteten "
+"Submodule manuell durch.\n"
+"Dies kann mit den folgenden Schritten erreicht werden:\n"
+"%s - zurück zum Hauptprojekt und dann ausführen:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   um die obige Zusammenführung oder Aktualisierung aufzuzeichnen\n"
+" - lösen Sie alle anderen Konflikte im Hauptprojekt\n"
+" - committen Sie den resultierenden Index in das Hauptprojekt\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -17052,6 +17180,22 @@ msgstr "Fehler beim Merge von Submodul %s (kein Vorspulen)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "Mögliche Auflösung des Merges für Submodul gefunden:\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Falls das korrekt ist, fügen Sie es einfach der Staging-Area, zum Beispiel "
+"mit:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"hinzu, um diesen Vorschlag zu akzeptieren.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr "Fehler beim Merge von Submodul %s (mehrere Merges gefunden)"
@@ -17128,8 +17272,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename "
-"\"%s\"->\"%s\" in \"%s\"%s"
+"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
+"\"->\"%s\" in \"%s\"%s"
 msgstr ""
 "KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Branch \"%s\" "
 "und \"%s\"->\"%s\" in Branch \"%s\"%s"
@@ -17589,8 +17733,24 @@ msgid "deflateEnd on object %s failed (%d)"
 msgstr "deflateEnd auf Objekt %s fehlgeschlagen (%d)"
 
 #, c-format
-msgid "confused by unstable object source data for %s"
-msgstr "Fehler wegen instabilen Objektquelldaten für %s"
+msgid "confused by unstable object source data for %s"
+msgstr "Fehler wegen instabilen Objektquelldaten für %s"
+
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "stream-Objekt schreiben %ld!= %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "neues Objekt kann nicht aus Stream entpackt werden (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "deflateEnd auf Stream-Objekt fehlgeschlagen (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "Verzeichnis %s kann nicht erstellt werden"
 
 #, c-format
 msgid "cannot read object for %s"
@@ -17657,7 +17817,7 @@ msgstr "%s [ungültiges Objekt]"
 #. TRANSLATORS: This is a line of ambiguous commit
 #. object output. E.g.:
 #. *
-#.    "deadbeef commit 2021-01-01 - Some Commit Message"
+#. "deadbeef commit 2021-01-01 - Some Commit Message"
 #.
 #, c-format
 msgid "%s commit %s - %s"
@@ -17666,7 +17826,7 @@ msgstr "%s Commit %s - %s"
 #. TRANSLATORS: This is a line of ambiguous
 #. tag object output. E.g.:
 #. *
-#.    "deadbeef tag 2022-01-01 - Some Tag Message"
+#. "deadbeef tag 2022-01-01 - Some Tag Message"
 #. *
 #. The second argument is the YYYY-MM-DD found
 #. in the tag.
@@ -17682,7 +17842,7 @@ msgstr "%s Tag %s - %s"
 #. tag object output where we couldn't parse
 #. the tag itself. E.g.:
 #. *
-#.    "deadbeef [bad tag, could not parse it]"
+#. "deadbeef [bad tag, could not parse it]"
 #.
 #, c-format
 msgid "%s [bad tag, could not parse it]"
@@ -17823,6 +17983,58 @@ msgstr "Konnte Objekt '%s' nicht parsen."
 msgid "hash mismatch %s"
 msgstr "Hash stimmt nicht mit %s überein."
 
+msgid "trying to write commit not in index"
+msgstr "Versuch, einen Commit zu schreiben, der nicht im Index steht"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "bitmap-Index kann nicht geladen werden (beschädigt?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "beschädigter Bitmap-Index (zu klein)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "beschädigte Bitmap-Indexdatei (falscher Header)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "nicht unterstützte Version '%d' für Bitmap-Indexdatei"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"beschädigte Bitmap-Indexdatei (zu kurz, um in den Hash-Cache zu passen)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"beschädigte Bitmap-Indexdatei (zu kurz, um in die Lookup-Tabelle zu passen)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "duplizierter Eintrag im Bitmap-Index: '%s'"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "fehlerhafte ewah-Bitmap: abgeschnittener Header für Eintrag %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "fehlerhafte ewah-Bitmap: Commit-Index %u außerhalb des Bereichs"
+
+msgid "corrupted bitmap pack index"
+msgstr "beschädigter Bitmap-Pack-Index"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "ungültiger XOR-Offset im Bitmap-Pack-Index"
+
+msgid "cannot fstat bitmap file"
+msgstr "kann Bitmap-Datei nicht lesen"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "ignoriere zusätzliche Bitmap-Datei: '%s'"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "Prüfsumme stimmt in MIDX und Bitmap nicht überein"
+
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "Multi-Pack-Bitmap fehlt erforderlicher Reverse-Index"
 
@@ -17834,9 +18046,60 @@ msgstr "konnte Paket '%s' nicht öffnen"
 msgid "preferred pack (%s) is invalid"
 msgstr "bevorzugtes Paket (%s) ist ungültig"
 
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "Bitmap-Lookup-Tabelle beschädigt: Triplet-Position außerhalb des Index"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr ""
+"fehlerhafte Bitmap-Lookup-Tabelle: XOR-Kette überschreitet die Anzahl der "
+"Einträge"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr ""
+"Bitmap-Lookup-Tabelle beschädigt: Commit-Index %u außerhalb des Bereichs"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr ""
+"fehlerhafte ewah-Bitmap: abgeschnittener Header für Bitmap des Commits \"%s\""
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "Objekt '%s' nicht im Typ Bitmaps gefunden"
+
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "das Objekt '%s' hat keinen eindeutigen Typ"
+
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "Objekt '%s': reeller Typ '%s', erwartet: '%s'"
+
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "Objekt nicht in Bitmap: '%s'"
+
+msgid "failed to load bitmap indexes"
+msgstr "Bitmap-Indizes konnten nicht geladen werden"
+
+msgid "you must specify exactly one commit to test"
+msgstr "Sie müssen genau einen Commit zum Testen angeben"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "Commit '%s' hat keine indizierte Bitmap"
+
+msgid "mismatch in bitmap results"
+msgstr "Unstimmigkeiten bei Bitmap-Ergebnissen"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "konnte '%s' in Paket '%s' bei Offset %<PRIuMAX> nicht finden"
+
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "konnte %s nicht in Paket %s bei Offset %<PRIuMAX> finden"
+msgid "unable to get disk usage of '%s'"
+msgstr "Festplattennutzung von '%s' kann nicht abgerufen werden"
 
 #, c-format
 msgid "mtimes file %s is too small"
@@ -17963,6 +18226,9 @@ msgstr "Meinten Sie `--%s` (mit zwei Strichen)?"
 msgid "alias of --%s"
 msgstr "Alias für --%s"
 
+msgid "need a subcommand"
+msgstr "benötige einen Unterbefehl"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "Unbekannte Option: `%s'"
@@ -18405,9 +18671,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -18429,11 +18698,16 @@ msgstr ""
 "l, label <Label> = aktuellen HEAD mit Label versehen\n"
 "t, reset <Label> = HEAD zu einem Label umsetzen\n"
 "m, merge [-C <Commit> | -c <Commit>] <Label> [# <eineZeile>]\n"
-".       Merge-Commit mit der originalen Merge-Commit-Beschreibung erstellen\n"
-".       (oder die eine Zeile, wenn keine originale Merge-Commit-"
+"        Merge-Commit mit der originalen Merge-Commit-Beschreibung erstellen\n"
+"        (oder die eine Zeile, wenn keine originale Merge-Commit-"
 "Beschreibung\n"
-".       spezifiziert ist). Benutzen Sie -c <Commit> zum Bearbeiten der\n"
-".       Commit-Beschreibung.\n"
+"        spezifiziert ist). Benutzen Sie -c <Commit> zum Bearbeiten der\n"
+"        Commit-Beschreibung.\n"
+"u, update-ref <Referenz>= einen Platzhalter für die zu aktualisierende "
+"<Referenz>\n"
+"                      zu dieser Position in den neuen Commits erstellen. Die "
+"<Referenz>wird\n"
+"                      am Ende des Rebase aktualisiert\n"
 "\n"
 "Diese Zeilen können umsortiert werden; sie werden von oben nach unten\n"
 "ausgeführt.\n"
@@ -18908,6 +19182,13 @@ msgstr "Protokollfehler: SHA-1/Referenz erwartet, '%s' bekommen"
 msgid "http transport does not support %s"
 msgstr "HTTP-Transport unterstützt nicht %s"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "Protokollfehler: erwartet '<url> <path>', fehlendes Leerzeichen"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "Datei unter URL '%s' konnte nicht heruntergeladen werden"
+
 msgid "git-http-push failed"
 msgstr "\"git-http-push\" fehlgeschlagen"
 
@@ -19258,6 +19539,14 @@ msgstr "Konnte HEAD-Commit nicht bestimmen."
 msgid "failed to find tree of %s"
 msgstr "Fehler beim Finden des \"Tree\"-Objektes von %s."
 
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo zeichnet `%s` auf, das fehlt"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "konnte kein Commit für das Argument ancestry-path %s erhalten"
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<Pack-Datei> wird nicht länger unterstützt"
 
@@ -19278,6 +19567,174 @@ msgstr "-L unterstützt noch keine anderen Diff-Formate außer -p und -s"
 msgid "cannot create async thread: %s"
 msgstr "Konnte Thread für async nicht erzeugen: %s"
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' existiert nicht."
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "konnte nicht zu '%s' wechseln"
+
+msgid "need a working directory"
+msgstr "Arbeitsverzeichnis benötigt"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Skalare Eintragungen erfordern ein Arbeitsverzeichnis"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "konnte %s=%s nicht konfigurieren"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "konnte log.excludeDecoration nicht konfigurieren"
+
+msgid "could not add enlistment"
+msgstr "konnte keine Eintragung hinzufügen"
+
+msgid "could not set recommended config"
+msgstr "konnte die empfohlene Konfiguration nicht setzen"
+
+msgid "could not turn on maintenance"
+msgstr "konnte die Wartung nicht einschalten"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "konnte den FSMonitor-Daemon nicht starten"
+
+msgid "could not turn off maintenance"
+msgstr "konnte die Wartung nicht abschalten"
+
+msgid "could not remove enlistment"
+msgstr "konnte die Eintragung nicht aufheben"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "externer HEAD ist kein Branch: '%.*s'"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"Fehler beim Abfragen des Standard-Branchnamens vom Remote-Repository; nutze "
+"lokalen Standardwert"
+
+msgid "failed to get default branch name"
+msgstr "Fehler beim Abfragen des Standard-Branchnamens"
+
+msgid "failed to unregister repository"
+msgstr "Fehler beim Austragen des Repositories"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "der FSMonitor-Daemon konnte nicht gestoppt werden"
+
+msgid "failed to delete enlistment directory"
+msgstr "Fehler beim Löschen des Eintragungs-Verzeichnisses"
+
+msgid "branch to checkout after clone"
+msgstr "Branch, der nach dem Klonen ausgecheckt werden soll"
+
+msgid "when cloning, create full working directory"
+msgstr "vollständiges Arbeitsverzeichnis beim Klonen erstellen"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "lade nur Metadaten des Branches herunter, der ausgecheckt wird"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<Optionen>] [--] <Repository> [<Verzeichnis>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "konnte Name für Arbeitsverzeichnis nicht von '%s' ableiten"
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "Verzeichnis '%s' existiert bereits"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "Fehler beim Abfragen des Default-Branches für '%s'"
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "konnte Remote-Repository in '%s' nicht konfigurieren"
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "konnte '%s' nicht konfigurieren"
+
+msgid "partial clone failed; attempting full clone"
+msgstr "partielles Klonen fehlgeschlagen; versuche vollständiges Klonen"
+
+msgid "could not configure for full clone"
+msgstr "konnte nicht für vollständiges Klonen konfigurieren"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<Eintragung>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` akzeptiert keine Argumente"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<Eintragung>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "alle registrierten Eintragungen neu konfigurieren"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <Eintragung>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all oder <Eintragung>, aber nicht beides"
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "Git-Repository entfernt in '%s'"
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <Aufgabe> [<Eintragung>]\n"
+"Aufgaben:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "Aufgabe nicht gefunden: '%s'"
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<Eintragung>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <Eintragung>"
+
+msgid "refusing to delete current working directory"
+msgstr "Löschen des aktuellen Arbeitsverzeichnisses wurde verweigert"
+
+msgid "include Git version"
+msgstr "Git-Version einbeziehen"
+
+msgid "include Git's build options"
+msgstr "Build-Optionen von Git einbeziehen"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C erfordert ein <Verzeichnis>"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "konnte nicht zu '%s' wechseln"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c benötigt ein <Schlüssel>=<Wert> Argument"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <Verzeichnis>] [-c <Schlüssel>=<Wert>] <Befehl> [<Optionen>]\n"
+"\n"
+"Befehle:\n"
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr "Unerwartetes Flush-Paket beim Lesen des Remote-Unpack-Status."
 
@@ -19403,10 +19860,6 @@ msgid "commit your changes or stash them to proceed."
 msgstr ""
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\", um fortzufahren."
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: Vorspulen"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -19900,6 +20353,28 @@ msgstr "konnte nicht einmal versuchen '%.*s' zu mergen"
 msgid "merge: Unable to write new index file"
 msgstr "merge: Konnte neue Index-Datei nicht schreiben."
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr ""
+"ein weiterer 'rebase'-Prozess scheint zu laufen; '%s.lock' existiert bereits"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Die folgenden Referenzen wurden mit %s aktualisiert:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Die Aktualisierung der folgenden Referenzen mit %s ist fehlgeschlagen:\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "Kann automatischen Stash nicht erzeugen"
 
@@ -20070,6 +20545,10 @@ msgstr "Konnte unnötige \"pick\"-Befehle nicht auslassen."
 msgid "the script was already rearranged."
 msgstr "Das Script wurde bereits umgeordnet."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "update-refs-Datei bei '%s' ist ungültig"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "'%s' liegt außerhalb des Repositories von '%s'"
@@ -20192,16 +20671,21 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"unsicheres Repository ('%s' gehört jemand anderem)\n"
-"Um eine Ausnahme für dieses Repository hinzuzufügen, führen Sie aus:\n"
+"dubiose Besitzverhältnisse im Repository bei '%s' entdeckt\n"
+"%sUm eine Ausnahme für dieses Verzeichnis hinzuzufügen, rufen Sie auf:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr ""
+"kann Bare-Repository '%s' nicht verwenden (safe.bareRepository ist '%s')"
+
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -21091,6 +21575,18 @@ msgstr "ungültige Portnummer"
 msgid "invalid '..' path segment"
 msgstr "ungültiges '..' Pfadsegment"
 
+msgid "usage: "
+msgstr "Verwendung: "
+
+msgid "fatal: "
+msgstr "Schwerwiegend: "
+
+msgid "error: "
+msgstr "Fehler: "
+
+msgid "warning: "
+msgstr "Warnung: "
+
 msgid "Fetching objects"
 msgstr "Anfordern der Objekte"
 
@@ -21474,8 +21970,8 @@ msgstr "Sie führen gerade \"cherry-pick\" von Commit %s aus."
 
 msgid "  (fix conflicts and run \"git cherry-pick --continue\")"
 msgstr ""
-"  (beheben Sie die Konflikte und führen Sie dann \"git cherry-pick --"
-"continue\" aus)"
+"  (beheben Sie die Konflikte und führen Sie dann \"git cherry-pick --continue"
+"\" aus)"
 
 msgid "  (run \"git cherry-pick --continue\" to continue)"
 msgstr "  (Führen Sie \"git cherry-pick --continue\" aus, um weiterzumachen)"
@@ -21948,23 +22444,6 @@ msgstr ""
 msgid "ignoring unmerged: %s\n"
 msgstr "ignoriere nicht zusammengeführte Datei: %s\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "Modusänderung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Löschung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Ergänzung auf Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Diesen Patch-Block auf das Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
-
 msgid "No other hunks to goto\n"
 msgstr "Keine anderen Patch-Blöcke verbleibend\n"
 
index b2190476799b17bc447be83aa7fee11b13dd8044..1ff5ff3911d05b08d4c21be46ce8572b22e6c1dd 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-16 08:28-0600\n"
-"PO-Revision-Date: 2021-11-07 18:53-0500\n"
+"POT-Creation-Date: 2022-09-27 21:02-0600\n"
+"PO-Revision-Date: 2022-09-27 22:56-0600\n"
 "Last-Translator: Alex Henrie <alexhenrie24@gmail.com>\n"
 "Language-Team: CodeLabora <codelabora@gmail.com>\n"
 "Language: es\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 3.0\n"
+"X-Generator: Poedit 3.1\n"
 
 #, c-format
 msgid "Huh (%s)?"
@@ -420,6 +420,22 @@ msgstr ""
 "a - aplicar este fragmento y todos los posteriores en el archivo\n"
 "d - no aplicar este fragmento ni ninguno de los siguientes en este archivo\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "¿Aplicar cambio de modo al árbol de trabajo [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "¿Aplicar eliminación al árbol de trabajo [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "¿Aplicar adición al árbol de trabajo [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "¿Aplicar este fragmento al árbol de trabajo [y,n,q,a,d,/%s,?]? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -437,10 +453,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "no se puede analizar hunk header '%.*s'"
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "no se puede analizar hunk header '%.*s'"
-
 msgid "could not parse diff"
 msgstr "no se puede analizar diff"
 
@@ -496,7 +508,6 @@ msgstr ""
 "Para eliminar '%c' líneas, bórrelas.\n"
 "Líneas comenzando con %c serán eliminadas.\n"
 
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
 #. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 msgid ""
 "If it does not apply cleanly, you will be given an opportunity to\n"
@@ -514,14 +525,12 @@ msgstr "no se puede analizar hunk header"
 msgid "'git apply --cached' failed"
 msgstr "falló 'git apply --cached'"
 
-#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
-#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input
 #. at this point.
@@ -731,6 +740,25 @@ msgstr ""
 "false\n"
 "\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Las rutas siguientes se han movido fuera de la definición\n"
+"de sparse-checkout pero no son escasas a causa de\n"
+"modificaciones locales.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Para corregir la escasez de estas rutas, haz lo siguiente:\n"
+"* Usa \"git add --sparse <rutas>\" para actualizar el índice\n"
+"* Usa \"git sparse-checkout reapply\" para aplicar las reglas de escasez"
+
 msgid "cmdline ends with \\"
 msgstr "cmdline termina en \\"
 
@@ -745,13 +773,13 @@ msgstr "opción de espacios en blanco no reconocida '%s'"
 msgid "unrecognized whitespace ignore option '%s'"
 msgstr "opción de ignorar espacios en blanco no reconocida '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s' and '%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '%s' y '%s' no pueden ser usados juntos"
 
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' outside a repository"
-msgstr "--3way está fuera de un repositorio"
+msgstr "'%s' fuera de un repositorio"
 
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
@@ -836,7 +864,7 @@ msgstr "parche corrupto en la línea %d"
 
 #, c-format
 msgid "new file %s depends on old contents"
-msgstr "nuevo archivo %s depende en contenidos viejos"
+msgstr "nuevo archivo %s depende de contenidos viejos"
 
 #, c-format
 msgid "deleted file %s still has contents"
@@ -844,7 +872,7 @@ msgstr "el archivo borrado %s todavía tiene contenido"
 
 #, c-format
 msgid "** warning: file %s becomes empty but is not deleted"
-msgstr "** peligro: el archivo %s está vacío pero no es borrado"
+msgstr "** advertencia: el archivo %s se volverá vacío pero no se borrará"
 
 #, c-format
 msgid "corrupt binary patch at line %d: %.*s"
@@ -1113,7 +1141,7 @@ msgid "Skipped patch '%s'."
 msgstr "Parche '%s' saltado."
 
 msgid "No valid patches in input (allow with \"--allow-empty\")"
-msgstr ""
+msgstr "No hay parches válidos en la entrada (permitir con \"--allow-empty\")"
 
 msgid "unable to read index file"
 msgstr "no es posible leer el archivo índice"
@@ -1240,7 +1268,7 @@ msgid "prepend <root> to all filenames"
 msgstr "anteponer <root> a todos los nombres de archivos"
 
 msgid "don't return error for empty patches"
-msgstr ""
+msgstr "no devolver error por parches vacíos"
 
 #, c-format
 msgid "cannot stream blob %s"
@@ -1250,6 +1278,10 @@ msgstr "no se puede transmitir el blob %s"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "modo de archivo no soportado: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "error al desinflar (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "no se puede comenzar filtro '%s'"
@@ -1269,22 +1301,18 @@ msgstr "ruta no válida UTF-8: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "ruta demasiada larga (%d chars, SHA1: %s): %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "error al desinflar (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "timestamp demasiado grande para este sistema: %<PRIuMAX>"
 
 msgid "git archive [<options>] <tree-ish> [<path>...]"
-msgstr "git archive [<opciones>] <parte-del-árbol> [<ruta>...]"
+msgstr "git archive [<opciones>] <árbol-ismo> [<ruta>...]"
 
 msgid ""
 "git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
 msgstr ""
-"git archive --remote <repo> [--exec <comando> ] [<opciones>] <parte-del-"
-"árbol> [<ruta>...]"
+"git archive --remote <repositorio> [--exec <comando> ] [<opciones>] <árbol-"
+"ismo> [<ruta>...]"
 
 msgid "git archive --remote <repo> [--exec <cmd>] --list"
 msgstr "git archive --remote <repo> [--exec <comando>] --list"
@@ -1320,17 +1348,17 @@ msgstr "Archivo no encontrado: %s"
 msgid "Not a regular file: %s"
 msgstr "No es un archivo regular: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unclosed quote: '%s'"
-msgstr "comillas incompletas"
+msgstr "comilla sin pareja: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "missing colon: '%s'"
-msgstr "valor faltante para '%s'"
+msgstr "falta un colon: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "empty file name: '%s'"
-msgstr "mbox vacío: '%s'"
+msgstr "nombre vacío de archivo: '%s'"
 
 msgid "fmt"
 msgstr "fmt"
@@ -1350,9 +1378,8 @@ msgstr "archivo"
 msgid "add untracked file to archive"
 msgstr "incluir archivos sin seguimiento a la crónica"
 
-#, fuzzy
 msgid "path:content"
-msgstr "contenido"
+msgstr "ruta:contenido"
 
 msgid "write the archive to this file"
 msgstr "escribe la crónica en este archivo"
@@ -1384,9 +1411,9 @@ msgstr "ruta para el comando git-upload-archive remoto"
 msgid "Unexpected option --remote"
 msgstr "Opción inesperada --remote"
 
-#, fuzzy, c-format
+#, c-format
 msgid "the option '%s' requires '%s'"
-msgstr "opción `%s' requiere un valor"
+msgstr "la opción `%s' requiere '%s'"
 
 msgid "Unexpected option --output"
 msgstr "Opción inesperada --output"
@@ -1548,68 +1575,64 @@ msgid ""
 "cannot inherit upstream tracking configuration of multiple refs when "
 "rebasing is requested"
 msgstr ""
+"no se puede heredar la configuración de rastreo upstream de múltiples "
+"referencias cuando se pide rebasar"
 
-#, fuzzy, c-format
+#, c-format
 msgid "not setting branch '%s' as its own upstream"
-msgstr "La rama %s no se configura como su propio upstream."
+msgstr "no configurando la rama %s como su propio upstream"
 
-#, fuzzy, c-format
+#, c-format
 msgid "branch '%s' set up to track '%s' by rebasing."
-msgstr ""
-"Rama '%s' configurada para hacer seguimiento a la referencia local '%s' por "
-"rebase."
+msgstr "rama '%s' configurada para rastrear '%s' por rebase."
 
-#, fuzzy, c-format
+#, c-format
 msgid "branch '%s' set up to track '%s'."
-msgstr ""
-"Rama '%s' configurada para hacer seguimiento a la referencia local '%s'."
+msgstr "rama '%s' configurada para rastrear '%s'."
 
-#, fuzzy, c-format
+#, c-format
 msgid "branch '%s' set up to track:"
-msgstr ""
-"Rama '%s' configurada para hacer seguimiento a la referencia local '%s'."
+msgstr "rama '%s' configurada para rastrear:"
 
-#, fuzzy
 msgid "unable to write upstream branch configuration"
-msgstr "No es posible escribir la configuración de la rama upstream"
+msgstr "no es posible escribir la configuración de la rama upstream"
 
-#, fuzzy
 msgid ""
 "\n"
 "After fixing the error cause you may try to fix up\n"
 "the remote tracking information by invoking:"
 msgstr ""
 "\n"
-"Tras arreglar la causa del error puedes intentar arreglar\n"
-"la información del rastreo remoto invocando\n"
-"\"git branch --set-upstream-to=%s%s%s\"."
+"Tras arreglar la causa del error puedes intentar\n"
+"arreglar la información de rastreo remoto invocando:"
 
 #, c-format
 msgid "asked to inherit tracking from '%s', but no remote is set"
 msgstr ""
+"se pidió heredar el rastreo de '%s', pero no se ha configurado ningún remoto"
 
 #, c-format
 msgid "asked to inherit tracking from '%s', but no merge configuration is set"
 msgstr ""
+"se pidió heredar el rastreo de '%s', pero no se ha configurado ninguna "
+"configuración de fusión"
 
-#, fuzzy, c-format
+#, c-format
 msgid "not tracking: ambiguous information for ref '%s'"
-msgstr "No rastreando: información ambigua para la referencia %s"
+msgstr "no rastreando: información ambigua para la referencia '%s'"
 
-#. #-#-#-#-#  branch.c.po  #-#-#-#-#
 #. TRANSLATORS: This is a line listing a remote with duplicate
 #. refspecs in the advice message below. For RTL languages you'll
 #. probably want to swap the "%s" and leading "  " space around.
 #.
-#. #-#-#-#-#  object-name.c.po  #-#-#-#-#
 #. TRANSLATORS: This is line item of ambiguous object output
 #. from describe_ambiguous_object() above. For RTL languages
 #. you'll probably want to swap the "%s" and leading " " space
 #. around.
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "  %s\n"
-msgstr "    %s"
+msgstr "  %s\n"
 
 #. TRANSLATORS: The second argument is a \n-delimited list of
 #. duplicate refspecs, composed above.
@@ -1625,24 +1648,34 @@ msgid ""
 "different remotes' fetch refspecs map into different\n"
 "tracking namespaces."
 msgstr ""
+"Hay múltiples remotos cuyas especificaciones de referencia de\n"
+"fetch corresponden a la referencia de rastreo remoto '%s':\n"
+"%s\n"
+"Esto es típicamente un error de configuración.\n"
+"\n"
+"Para soportar configuración de ramas que rastrean, asegura que\n"
+"las especificationes de referencia de fetch de remotos distintos\n"
+"mapeen a espacios de nombres de rastreo distintos."
 
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is not a valid branch name"
-msgstr "'%s' no es un nombre válido de rama."
+msgstr "'%s' no es un nombre válido de rama"
 
-#, fuzzy, c-format
+#, c-format
 msgid "a branch named '%s' already exists"
-msgstr "Una rama llamada '%s' ya existe."
+msgstr "una rama llamada '%s' ya existe"
 
-#, fuzzy, c-format
+#, c-format
 msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "No se puede borrar rama '%s' que cuenta con checkout en '%s'"
+msgstr ""
+"no se puede actualizar la rama '%s' a la fuerza que cuenta con checkout en "
+"'%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
 msgstr ""
-"No se puede configurar el rastreo de información; el punto de partida '%s' "
-"no es una rama."
+"no se puede configurar la información de rastreo; el punto de partida '%s' "
+"no es una rama"
 
 #, c-format
 msgid "the requested upstream branch '%s' does not exist"
@@ -1672,27 +1705,29 @@ msgstr ""
 msgid "not a valid object name: '%s'"
 msgstr "nombre de objeto no válido: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "ambiguous object name: '%s'"
-msgstr "Nombre de objeto ambiguo: '%s'."
+msgstr "nombre de objeto ambiguo: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "not a valid branch point: '%s'"
-msgstr "Punto de rama no válido: '%s'."
+msgstr "punto de bifurcación no válido: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "submodule '%s': unable to find submodule"
-msgstr "submódulo '%s' tiene un índice corrupto"
+msgstr "submódulo '%s': incapaz de encontrar el submódulo"
 
 #, c-format
 msgid ""
 "You may try updating the submodules using 'git checkout %s && git submodule "
 "update --init'"
 msgstr ""
+"Se puede intentar actualizar los submódulos usando 'git checkout %s && git "
+"submodule update --init'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "submodule '%s': cannot create branch '%s'"
-msgstr "submódulo '%s' no puede agregar alterno: %s"
+msgstr "submódulo '%s': no se puede crear la rama '%s'"
 
 #, c-format
 msgid "'%s' is already checked out at '%s'"
@@ -1850,9 +1885,10 @@ msgstr "falló al agregar archivos"
 msgid "--chmod param '%s' must be either -x or +x"
 msgstr "El parámetro '%s' para --chmod debe ser -x o +x"
 
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' and pathspec arguments cannot be used together"
-msgstr "-x y -X no pueden ser usadas juntas"
+msgstr ""
+"'%s' y los argumentos de especificación de ruta no pueden ser usados juntos"
 
 #, c-format
 msgid "Nothing specified, nothing added.\n"
@@ -1874,9 +1910,9 @@ msgstr "archivo índice corrompido"
 msgid "bad action '%s' for '%s'"
 msgstr "mala acción '%s' para '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid value for '%s': '%s'"
-msgstr "valor inválido para %s: %s"
+msgstr "valor inválido para '%s': '%s'"
 
 #, c-format
 msgid "could not read '%s'"
@@ -1946,10 +1982,11 @@ msgstr "Cuando hayas resuelto este problema, ejecuta \"%s --continue\"."
 msgid "If you prefer to skip this patch, run \"%s --skip\" instead."
 msgstr "Si prefieres saltar este parche, ejecuta \"%s --skip\"."
 
-#, fuzzy, c-format
+#, c-format
 msgid "To record the empty patch as an empty commit, run \"%s --allow-empty\"."
 msgstr ""
-"Para restaurar la rama original y detener el parcheo, ejecuta \"%s --abort\"."
+"Para registrar el parche vacío como un commit vacío, ejecuta \"%s --allow-"
+"empty\"."
 
 #, c-format
 msgid "To restore the original branch and stop patching, run \"%s --abort\"."
@@ -2025,13 +2062,13 @@ msgstr "no es posible escribir el archivo índice"
 msgid "Dirty index: cannot apply patches (dirty: %s)"
 msgstr "Índice sucio: no se puede aplicar parches (sucio: %s)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Skipping: %.*s"
-msgstr "Aplicando: %.*s"
+msgstr "Saltando: %.*s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Creating an empty commit: %.*s"
-msgstr "mantener commits redundantes, vacíos"
+msgstr "Creando un commit vacío: %.*s"
 
 msgid "Patch is empty."
 msgstr "El parche está vacío."
@@ -2050,9 +2087,8 @@ msgstr "El parche falló en %s %.*s"
 msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
 msgstr "Usa 'git am --show-current-patch=diff' para ver el parche fallido"
 
-#, fuzzy
 msgid "No changes - recorded it as an empty commit."
-msgstr "no se agregaron cambios al commit\n"
+msgstr "Sin cambios - se ha registrado como un commit vacío."
 
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
@@ -2096,9 +2132,9 @@ msgstr ""
 msgid "failed to read '%s'"
 msgstr "falló al leer '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s=%s' and '%s=%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '%s=%s' y '%s=%s' no pueden ser usadas juntas"
 
 msgid "git am [<options>] [(<mbox> | <Maildir>)...]"
 msgstr "git am [<opciones>] [(<mbox> | <Directorio-de-correo>)...]"
@@ -2180,7 +2216,7 @@ msgid "show the patch being applied"
 msgstr "mostrar el parche siendo aplicado"
 
 msgid "record the empty patch as an empty commit"
-msgstr ""
+msgstr "registrar el parche vacío como un commit vacío"
 
 msgid "lie about committer date"
 msgstr "mentir sobre la fecha del committer"
@@ -2194,9 +2230,8 @@ msgstr "key-id"
 msgid "GPG-sign commits"
 msgstr "firmar los commits con GPG"
 
-#, fuzzy
 msgid "how to handle empty patches"
-msgstr "mostrar el parche actual"
+msgstr "cómo manejar parches vacíos"
 
 msgid "(internal use for git-rebase)"
 msgstr "(uso interno para git-rebase)"
@@ -2366,16 +2401,16 @@ msgid "Are you sure [Y/n]? "
 msgstr "¿Estás seguro [Y/n]? "
 
 msgid "status: waiting for both good and bad commits\n"
-msgstr ""
+msgstr "estado: esperando ambos commits buenos y malos\n"
 
 #, c-format
 msgid "status: waiting for bad commit, %d good commit known\n"
 msgid_plural "status: waiting for bad commit, %d good commits known\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "estado: esperando commit malo, %d commit bueno conocido\n"
+msgstr[1] "estado: esperando commit malo, %d commits buenos conocidos\n"
 
 msgid "status: waiting for good commit(s), bad commit known\n"
-msgstr ""
+msgstr "estado: esperando commit bueno, commit malo conocido\n"
 
 msgid "no terms defined"
 msgstr "no hay términos definidos"
@@ -2475,13 +2510,13 @@ msgstr "ejecutando %s\n"
 msgid "bisect run failed: no command provided."
 msgstr "bisect falló: no se proveyó comando."
 
-#, fuzzy, c-format
+#, c-format
 msgid "unable to verify '%s' on good revision"
-msgstr "no es posible escribir el archivo '%s' modo %o"
+msgstr "no se puede verificar '%s' en la revisión buena"
 
 #, c-format
 msgid "bogus exit code %d for good revision"
-msgstr ""
+msgstr "código de salida malogrado %d de la revisión buena"
 
 #, c-format
 msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
@@ -2540,9 +2575,8 @@ msgstr "saltar algunos commits para checkout"
 msgid "visualize the bisection"
 msgstr "visualizar bisección"
 
-#, fuzzy
 msgid "use <cmd>... to automatically bisect"
-msgstr "use <cmd>... para aplicar bisección automática."
+msgstr "usa <cmd>... para bisecar automáticamente"
 
 msgid "no log for BISECT_WRITE"
 msgstr "no hay log para BISECT_WRITE"
@@ -2695,15 +2729,15 @@ msgstr "Blaming a líneas"
 msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
 msgstr "git branch [<opciones>] [-r | -a] [--merged] [--no-merged]"
 
-#, fuzzy
 msgid ""
 "git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
 "point>]"
-msgstr "git branch [<opciones>] [-l] [-f] <nombre-de-rama> [<punto-inicial>]"
+msgstr ""
+"git branch [<opciones>] [-l] [-f] [--recurse-submodules] <nombre-de-rama> "
+"[<punto-de-partida>]"
 
-#, fuzzy
 msgid "git branch [<options>] [-l] [<pattern>...]"
-msgstr "git for-each-ref [<opciones>] [<patrón>]"
+msgstr "git branch [<opciones>] [-l] [<patrón>...]"
 
 msgid "git branch [<options>] [-r] (-d | -D) <branch-name>..."
 msgstr "git branch [<opciones>] [-r] (-d | -D) <nombre-de-rama>..."
@@ -2852,9 +2886,8 @@ msgstr "mostrar hash y tema, dar dos veces para rama upstream"
 msgid "suppress informational messages"
 msgstr "suprimir mensajes informativos"
 
-#, fuzzy
 msgid "set branch tracking configuration"
-msgstr "mostrar información de la rama"
+msgstr "configurar rastreo de rama"
 
 msgid "do not use"
 msgstr "no usar"
@@ -2953,9 +2986,11 @@ msgid ""
 "branch with --recurse-submodules can only be used if submodule."
 "propagateBranches is enabled"
 msgstr ""
+"branch con --recurse-submodules solo se puede usar si submodule."
+"propagateBranches está habilitado"
 
 msgid "--recurse-submodules can only be used to create branches"
-msgstr ""
+msgstr "--recurse-submodules solo se puede usar para crear ramas"
 
 msgid "branch name required"
 msgstr "se necesita el nombre de la rama"
@@ -3040,9 +3075,12 @@ msgstr "información de libc: "
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "no ejecutado desde un repositorio git - no hay hooks para mostrar\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
 msgstr ""
-"git bugreport [-o|--output-directory <archivo>] [-s|--suffix <formato>]"
+"git bugreport [-o|--output-directory <archivo>] [-s|--suffix <formato>] [--"
+"diagnose[=<modo>]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3079,17 +3117,30 @@ msgstr ""
 "Por favor revisa el resto del reporte abajo.\n"
 "Puedes borrar cualquier línea que no desees compartir.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "especificar el destino para el archivo de reporte de bug"
+msgid "mode"
+msgstr "modo"
 
-msgid "specify a strftime format suffix for the filename"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
 msgstr ""
-"especificar el sufijo de formato de strftime para el nombre del archivo"
+"crear una crónica zip adicional con diagnósticos detallados (por defecto "
+"'stats')"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "especificar un destino para los archivos de reporte de bug"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr ""
+"especificar un sufijo de formato de strftime para los nombres de los archivos"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "no se pudo crear directorios principales para '%s'"
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "no se puede crear la crónica diagnóstica %s"
+
 msgid "System Info"
 msgstr "Información del sistema"
 
@@ -3147,84 +3198,77 @@ msgstr "Se necesita un repositorio para desagrupar."
 msgid "Unbundling objects"
 msgstr "Desagrupando objetos"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Sub-comando desconocido: %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "no se puede leer el objeto %s '%s'"
 
 msgid "flush is only for --buffer mode"
-msgstr ""
+msgstr "flush solo es para el modo --buffer"
 
-#, fuzzy
 msgid "empty command in input"
-msgstr "comando exec vacío"
+msgstr "comando vacío en la entrada"
 
-#, fuzzy, c-format
+#, c-format
 msgid "whitespace before command: '%s'"
-msgstr "editar mensaje antes de realizar commit"
+msgstr "espacio en blanco antes del comando: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s requires arguments"
-msgstr "-n requiere un argumento"
+msgstr "%s requiere argumentos"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s takes no arguments"
-msgstr "%s no toma valores"
+msgstr "%s no toma argumentos"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unknown command: '%s'"
-msgstr "comando desconocido: %d"
+msgstr "comando desconocido: '%s'"
 
 msgid "only one batch option may be specified"
 msgstr "solo se puede especificar una opción batch"
 
-#, fuzzy
 msgid "git cat-file <type> <object>"
-msgstr "git notes edit [<objeto>]"
+msgstr "git cat-file <tipo> <objeto>"
 
-#, fuzzy
 msgid "git cat-file (-e | -p) <object>"
-msgstr "git notes edit [<objeto>]"
+msgstr "git cat-file (-e | -p) <objeto>"
 
 msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
-msgstr ""
+msgstr "git cat-file (-t | -s) [--allow-unknown-type] <objeto>"
 
-#, fuzzy
 msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
 "             [--textconv | --filters]"
 msgstr ""
-"git cat-file (--batch[=<formato>] | --batch-check[=<formato>]) [--follow-"
-"symlinks] [--textconv | --filters]"
+"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
+"objects]\n"
+"             [--buffer] [--follow-symlinks] [--unordered]\n"
+"             [--textconv | --filters]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
 "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
 msgstr ""
+"git cat-file (--textconv | --filters)\n"
+"             [<revisión>:<ruta|árbol-ismo> | --path=<ruta|árbol-ismo> "
+"<revisión>]"
 
-#, fuzzy
 msgid "Check object existence or emit object contents"
-msgstr "para objetos blob, ejecuta textconv en el contenido del objeto"
+msgstr "Comprobar la existencia de un objeto o emitir el contenido del objeto"
 
-#, fuzzy
 msgid "check if <object> exists"
-msgstr "Revisando objetos"
+msgstr "comprobar si <objeto> existe"
 
-#, fuzzy
 msgid "pretty-print <object> content"
-msgstr "realizar pretty-print del contenido del objeto"
+msgstr "realizar pretty-print del contenido de <objeto>"
 
 msgid "Emit [broken] object attributes"
-msgstr ""
+msgstr "Emitir atributos de objeto [broken]"
 
-#, fuzzy
 msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
-msgstr "<tipo> puede ser: blob, tree, commit, tag"
+msgstr "mostrar tipo de objeto (uno de 'blob', 'tree', 'commit', 'tag' ...)"
 
 msgid "show object size"
 msgstr "mostrar el tamaño del objeto"
@@ -3232,91 +3276,91 @@ msgstr "mostrar el tamaño del objeto"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "permita que -s y -t funcionen con objetos rotos o corruptos"
 
+msgid "use mail map file"
+msgstr "usar archivo de mapa de correo"
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
-msgstr ""
+msgstr "Hacer batch a los objecos solicitados en stdin (o --batch-all-objects)"
 
 msgid "show full <object> or <rev> contents"
-msgstr ""
+msgstr "mostrar el contenido completo de <objeto> o <revisión>"
 
 msgid "like --batch, but don't emit <contents>"
-msgstr ""
+msgstr "como --batch, pero no emitir <contenido>"
+
+msgid "stdin is NUL-terminated"
+msgstr "stdin es terminada con NUL"
 
-#, fuzzy
 msgid "read commands from stdin"
-msgstr "leer packs de stdin"
+msgstr "leer comandos de stdin"
 
 msgid "with --batch[-check]: ignores stdin, batches all known objects"
 msgstr ""
+"con --batch[-check]: ignora stdin, hace batch a todos los objetos conocidos"
 
 msgid "Change or optimize batch output"
-msgstr ""
+msgstr "Cambia o optimiza la salida de batch"
 
 msgid "buffer --batch output"
 msgstr "salida buffer --batch"
 
-#, fuzzy
 msgid "follow in-tree symlinks"
-msgstr "no se pudo leer el symlink %s"
+msgstr "seguir symlinks en el árbol"
 
-#, fuzzy
 msgid "do not order objects before emitting them"
-msgstr "no se pudo leer el objeto %s para el symlink %s"
+msgstr "no ordenar objetos antes de emitirlos"
 
 msgid ""
 "Emit object (blob or tree) with conversion or filter (stand-alone, or with "
 "batch)"
 msgstr ""
+"Emitir objeto (blob o árbol) con conversión o filtro (independiente, o con "
+"batch)"
 
-#, fuzzy
 msgid "run textconv on object's content"
-msgstr "para objetos blob, ejecuta textconv en el contenido del objeto"
+msgstr "ejecuta textconv en el contenido del objeto"
 
-#, fuzzy
 msgid "run filters on object's content"
-msgstr "para objetos blob, ejecuta filters en el contenido del objeto"
+msgstr "ejecuta filtros en el contenido del objeto"
 
-#, fuzzy
 msgid "blob|tree"
-msgstr "blob"
+msgstr "blob|árbol"
 
-#, fuzzy
 msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
-msgstr "usar una ruta específica para --textconv/--filters"
+msgstr "usar una <ruta> para (--textconv | --filters); No con 'batch'"
 
 #, c-format
 msgid "'%s=<%s>' needs '%s' or '%s'"
-msgstr ""
+msgstr "'%s=<%s>' necesita '%s' o '%s'"
 
-#, fuzzy
 msgid "path|tree-ish"
-msgstr "árbol-ismo"
+msgstr "ruta|árbol-ismo"
 
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' requires a batch mode"
-msgstr "%s requiere un valor"
+msgstr "'%s' requiere un modo de batch"
 
-#, fuzzy, c-format
+#, c-format
 msgid "'-%c' is incompatible with batch mode"
-msgstr "%s es incompatible con %s"
+msgstr "'-%c' es incompatible con el modo de batch"
 
-#, fuzzy
 msgid "batch modes take no arguments"
-msgstr "esta opción no requiere argumentos"
+msgstr "los modos de batch no toman argumentos"
 
 #, c-format
 msgid "<rev> required with '%s'"
-msgstr ""
+msgstr "se requiere <revisión> con '%s'"
 
 #, c-format
 msgid "<object> required with '-%c'"
-msgstr ""
+msgstr "<objeto> requerido con '-%c'"
 
 msgid "too many arguments"
 msgstr "demasiados argumentos"
 
 #, c-format
 msgid "only two arguments allowed in <type> <object> mode, not %d"
-msgstr ""
+msgstr "solo se permiten dos argumentos en modo de <objeto> de <tipo>, no %d"
 
 msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
 msgstr "git check-attr [-a | --all | <attr>...] [--] <nombre-de-ruta>..."
@@ -3395,7 +3439,7 @@ msgid "check out all files in the index"
 msgstr "revisar todos los archivos en el índice"
 
 msgid "do not skip files with skip-worktree set"
-msgstr ""
+msgstr "no saltar archivos con skip-worktree configurado"
 
 msgid "force overwrite of existing files"
 msgstr "forzar sobreescritura de los archivos existentes"
@@ -3555,12 +3599,12 @@ msgid_plural ""
 "\n"
 "%s\n"
 msgstr[0] ""
-"Peligro: estás dejando %d commit atrás, no está conectado\n"
+"Advertencia: estás dejando %d commit atrás, no está conectado\n"
 "a ninguna rama:\n"
 "\n"
 "%s\n"
 msgstr[1] ""
-"Peligro: estás dejando %d commits atrás, no están conectados\n"
+"Advertencia: estás dejando %d commits atrás, no están conectados\n"
 "a ninguna rama:\n"
 "\n"
 "%s\n"
@@ -3618,7 +3662,7 @@ msgid ""
 "one remote, e.g. the 'origin' remote, consider setting\n"
 "checkout.defaultRemote=origin in your config."
 msgstr ""
-"Si querías hacer un check out a una rama rastreada remota, como 'origin',\n"
+"Si querías hacer un check out a una rama remota rastreada, como 'origin',\n"
 "puedes hacerlo proporcionando el nombre completo con la opción --track:\n"
 "\n"
 "    git checkout --track origin/<nombre>\n"
@@ -3665,6 +3709,8 @@ msgstr "se espera una rama, se obtuvo commit '%s'"
 msgid ""
 "If you want to detach HEAD at the commit, try again with the --detach option."
 msgstr ""
+"Si quieres desacoplar HEAD al commit, intenta de nuevo con la opción --"
+"detach."
 
 msgid ""
 "cannot switch branch while merging\n"
@@ -3732,9 +3778,8 @@ msgstr "realizar una fusión de tres vías con la rama nueva"
 msgid "style"
 msgstr "estilo"
 
-#, fuzzy
 msgid "conflict style (merge, diff3, or zdiff3)"
-msgstr "estilo de conflictos (merge o diff3)"
+msgstr "estilo de conflictos (merge, diff3 o zdiff3)"
 
 msgid "detach HEAD at named commit"
 msgstr "desacoplar HEAD en el commit nombrado"
@@ -3763,9 +3808,9 @@ msgstr "hacer checkout a su versión para los archivos sin fusionar"
 msgid "do not limit pathspecs to sparse entries only"
 msgstr "no limitar pathspecs a entradas escasas solamente"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '-%c', '-%c', and '%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '-%c', '-%c' y '%s' no pueden ser usadas juntas"
 
 msgid "--track needs a branch name"
 msgstr "--track necesita el nombre de una rama"
@@ -3873,13 +3918,11 @@ msgstr "falló al borrar %s"
 msgid "could not lstat %s\n"
 msgstr "no se pudo lstat %s\n"
 
-#, fuzzy
 msgid "Refusing to remove current working directory\n"
-msgstr "no es posible obtener el directorio de trabajo actual"
+msgstr "Rehusando eliminar el directorio de trabajo actual\n"
 
-#, fuzzy
 msgid "Would refuse to remove current working directory\n"
-msgstr "no es posible obtener el directorio de trabajo actual"
+msgstr "Se rehusaría eliminar el directorio de trabajo actual\n"
 
 #, c-format
 msgid ""
@@ -3923,7 +3966,7 @@ msgstr "Ingresa los patrones que ignorar>> "
 
 #, c-format
 msgid "WARNING: Cannot find items matched by: %s"
-msgstr "PELIGRO: No se puede encontrar objetos que concuerden con: %s"
+msgstr "ADVERTENCIA: No se puede encontrar objetos que concuerden con: %s"
 
 msgid "Select items to delete"
 msgstr "Seleccionar objetos para borrar"
@@ -4108,7 +4151,7 @@ msgid "use IPv6 addresses only"
 msgstr "solo usar direcciones IPv6"
 
 msgid "apply partial clone filters to submodules"
-msgstr ""
+msgstr "aplicar filtros de clonación parcial a los submódulos"
 
 msgid "any cloned submodules will use their remote-tracking branch"
 msgstr "cualquier submódulo clonado usará su branch de rastreo remoto"
@@ -4117,6 +4160,13 @@ msgid "initialize sparse-checkout file to include only files at root"
 msgstr ""
 "inicializar archivo sparse-checkout para incluir solo archivos en la raíz"
 
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"un URI para descargar bundles antes de hacer fetch del remoto de origen"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: No se pudo agregar un alterno para '%s': %s\n"
@@ -4176,9 +4226,10 @@ msgstr "incapaz de actualizar %s"
 msgid "failed to initialize sparse-checkout"
 msgstr "falló al inicializar sparse-checkout"
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr ""
-"remoto HEAD refiere a un ref inexistente, no se puede hacer checkout.\n"
+"la HEAD remota refiere a una referencia inexistente, no se puede hacer "
+"checkout"
 
 msgid "unable to checkout working tree"
 msgstr "no es posible realizar checkout en el árbol de trabajo"
@@ -4198,9 +4249,15 @@ msgstr "Demasiados argumentos."
 msgid "You must specify a repository to clone."
 msgstr "Tienes que especificar un repositorio para clonar."
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s' and '%s %s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '%s' y '%s %s' no pueden ser usadas juntas"
+
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri es incompatible con --depth, --shallow-since y --shallow-exclude"
 
 #, c-format
 msgid "repository '%s' does not exist"
@@ -4274,7 +4331,14 @@ msgid "--local is ignored"
 msgstr "--local es ignorado"
 
 msgid "cannot clone from filtered bundle"
-msgstr ""
+msgstr "no se puede clonar de un bundle filtrado"
+
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "falló al inicializar el repositorio, saltando el URI de bundle"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "falló al hacer fetch de objetos del URI de bundle '%s'"
 
 msgid "remote transport reported error"
 msgstr "transporte remoto reportó error"
@@ -4389,10 +4453,6 @@ msgstr "usa como máximo uno de --reachable, --stdin-commits, o --stdin-packs"
 msgid "Collecting commits from input"
 msgstr "Recolectando commits del input"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "subcomando desconocido: %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -4569,9 +4629,9 @@ msgstr "no se pudo leer log desde standard input"
 msgid "could not read log file '%s'"
 msgstr "no se pudo leer el log '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s' and '%s:%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '%s' y '%s:%s' no pueden ser usadas juntas"
 
 msgid "could not read SQUASH_MSG"
 msgstr "no se pudo leer SQUASH_MSG"
@@ -4694,13 +4754,13 @@ msgstr "Estás en medio de una fusión -- no se puede refrasear."
 msgid "You are in the middle of a cherry-pick -- cannot reword."
 msgstr "Estás en medio de un cherry-pick -- no se puede refrasear."
 
-#, fuzzy, c-format
+#, c-format
 msgid "reword option of '%s' and path '%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "la opción reword de '%s' y la ruta '%s' no pueden ser usadas juntas"
 
-#, fuzzy, c-format
+#, c-format
 msgid "reword option of '%s' and '%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "la opción reword de '%s' y '%s' no pueden ser usadas juntas"
 
 msgid "You have nothing to amend."
 msgstr "No tienes nada que enmendar."
@@ -4749,9 +4809,6 @@ msgstr "mostrar status en formato largo (default)"
 msgid "terminate entries with NUL"
 msgstr "terminar entradas con NUL"
 
-msgid "mode"
-msgstr "modo"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "mostrar archivos sin seguimiento, modos opcionales: all, normal, no. "
@@ -5342,9 +5399,26 @@ msgstr "adjuntar <marca> en un árbol de trabajo roto (default: \"-broken\")"
 msgid "No names found, cannot describe anything."
 msgstr "No se encontraron nombres, no se puede describir nada."
 
-#, fuzzy, c-format
+#, c-format
 msgid "option '%s' and commit-ishes cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "la opción '%s' y los commit-ismos no pueden ser usados juntos"
+
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <ruta>] [-s|--suffix <formato>] [--"
+"mode=<modo>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "especificar un destino para la crónica diagnóstica"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr ""
+"especificar el sufijo de formato de strftime para el nombre del archivo"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "especificar el contenido de la crónica diagnóstica"
 
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base solo funciona con dos commits"
@@ -5488,9 +5562,8 @@ msgid ""
 msgstr ""
 "opción `--default' espera un valor unsigned long con `--type=ulong`, no `%s`"
 
-#, fuzzy
 msgid "git fast-export [<rev-list-opts>]"
-msgstr "git fast-export [rev-list-opts]"
+msgstr "git fast-export [<opciones-de-rev-list>]"
 
 msgid "Error: Cannot export nested tags unless --mark-tags is specified."
 msgstr ""
@@ -5669,7 +5742,7 @@ msgid "convert to a complete repository"
 msgstr "convertir a un repositorio completo"
 
 msgid "re-fetch without negotiating common commits"
-msgstr ""
+msgstr "hacer fetch de nuevo sin negociar commits en común"
 
 msgid "prepend this to submodule path output"
 msgstr "anteponer esto a la salida de ruta del submódulo"
@@ -5688,15 +5761,15 @@ msgid "refmap"
 msgstr "refmap"
 
 msgid "specify fetch refmap"
-msgstr "especificar extracción de refmap"
+msgstr "especificar el mapa de referencias de fetch"
 
 msgid "report that we have only objects reachable from this object"
 msgstr "reportar que solo tenemos objetos alcanzables de este objeto"
 
 msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
 msgstr ""
-"no realizar fetch al packfile; en lugar de eso, mostrar los ancestros de las "
-"puntas de negociación"
+"no realizar fetch de un archivo de pack; en lugar de eso, mostrar los "
+"ancestros de las puntas de negociación"
 
 msgid "run 'maintenance --auto' after fetching"
 msgstr "ejecutar 'maintenance --auto' después de buscar"
@@ -5710,9 +5783,8 @@ msgstr "escribir commit-graph luego del fetch"
 msgid "accept refspecs from stdin"
 msgstr "aceptar refspecs de stdin"
 
-#, fuzzy
 msgid "couldn't find remote ref HEAD"
-msgstr "No se pudo encontrar ref remota HEAD"
+msgstr "no se pudo encontrar la referencia remota HEAD"
 
 #, c-format
 msgid "object %s not found"
@@ -5724,12 +5796,8 @@ msgstr "[actualizado]"
 msgid "[rejected]"
 msgstr "[rechazado]"
 
-msgid "can't fetch in current branch"
-msgstr "no se puede traer en la rama actual"
-
-#, fuzzy
-msgid "checked out in another worktree"
-msgstr "buscar en el índice en lugar del árbol de trabajo"
+msgid "can't fetch into checked-out branch"
+msgstr "no se puede hacer fetch a la rama actual"
 
 msgid "[tag update]"
 msgstr "[actualización de tag]"
@@ -5759,25 +5827,24 @@ msgstr "avance no rápido"
 msgid "cannot open '%s'"
 msgstr "no se puede abrir '%s'"
 
-#, fuzzy
 msgid ""
 "fetch normally indicates which branches had a forced update,\n"
 "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
 "flag or run 'git config fetch.showForcedUpdates true'"
 msgstr ""
-"Fetch normalmente incida qué branches han tenido un update forzado,\n"
+"fetch normalmente indica cuáles ramas han tenido una actualización forzada,\n"
 "pero esa validación ha sido deshabilitada. Para activarla de nuevo usa '--"
 "show-forced-updates'\n"
-"o ejecuta 'git config fetch.showForcedUpdates true'."
+"o ejecuta 'git config fetch.showForcedUpdates true'"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "it took %.2f seconds to check forced updates; you can use\n"
 "'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates "
 "false'\n"
 "to avoid this check\n"
 msgstr ""
-"Tomó %.2f segundos validar los updates forzados. Puedes usar\n"
+"tomó %.2f segundos validar las actualizaciones forzadas. Se puede usar\n"
 "'--no-show-forced-updates' o ejecutar 'git config fetch.showForcedUpdates "
 "false'\n"
 "para evitar esta validación.\n"
@@ -5816,17 +5883,17 @@ msgstr "[eliminado]"
 msgid "(none)"
 msgstr "(nada)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "refusing to fetch into branch '%s' checked out at '%s'"
-msgstr "No se puede borrar rama '%s' que cuenta con checkout en '%s'"
+msgstr "rehusando hacer fetch a la rama '%s' que cuenta con checkout en '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "option \"%s\" value \"%s\" is not valid for %s"
-msgstr "Valor \"%2$s\" de opción \"%1$s\" no es válido para %3$s"
+msgstr "el valor \"%2$s\" de la opción \"%1$s\" no es válido para %3$s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "option \"%s\" is ignored for %s\n"
-msgstr "Opción \"%s\" es ignorada por %s\n"
+msgstr "la opción \"%s\" es ignorada por %s\n"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -5839,13 +5906,13 @@ msgstr "el objeto %s no existe"
 msgid "multiple branches detected, incompatible with --set-upstream"
 msgstr "múltiples ramas detectadas, incompatible con --set-upstream"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "could not set upstream of HEAD to '%s' from '%s' when it does not point to "
 "any branch."
 msgstr ""
-"no se pudo configurar upstream de HEAD a %s cuando este no apunta a ninguna "
-"rama."
+"no se pudo cambiar el upstream de HEAD de '%s' a '%s' cuando este no apunta "
+"a ninguna rama."
 
 msgid "not setting upstream for a remote remote-tracking branch"
 msgstr "no configurar upstream para una rama de rastreo remoto"
@@ -5856,45 +5923,40 @@ msgstr "no configurar upstream para un tag remoto"
 msgid "unknown branch type"
 msgstr "tipo de branch desconocido"
 
-#, fuzzy
 msgid ""
 "no source branch found;\n"
 "you need to specify exactly one branch with the --set-upstream option"
 msgstr ""
 "no se encontró rama fuente.\n"
-"tienes que especificar exactamente una rama con la opción --set-upstream."
+"hay que especificar exactamente una rama con la opción --set-upstream"
 
 #, c-format
 msgid "Fetching %s\n"
 msgstr "Extrayendo %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not fetch %s"
-msgstr "No se pudo extraer %s"
+msgstr "no se pudo hacer fetch de %s"
 
 #, c-format
 msgid "could not fetch '%s' (exit code: %d)\n"
 msgstr "no se pudo hacer fetch a '%s' (código de salida: %d)\n"
 
-#, fuzzy
 msgid ""
 "no remote repository specified; please specify either a URL or a\n"
 "remote name from which new revisions should be fetched"
 msgstr ""
-"No hay repositorio remoto especificado. Por favor, especifica un URL o un\n"
-"nombre remoto del cual las nuevas revisiones deben ser extraídas."
+"no hay repositorio remoto especificado. Por favor, especifica un URL o un\n"
+"nombre remoto del cual hacer fetch de las nuevas revisiones"
 
-#, fuzzy
 msgid "you need to specify a tag name"
-msgstr "Tienes que especificar un nombre de tag."
+msgstr "hay que especificar un nombre de etiqueta"
 
-#, fuzzy
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
-msgstr "--negotiate-only necesita uno o más --negotiate-tip=*"
+msgstr "--negotiate-only necesita uno o más --negotiation-tip=*"
 
-#, fuzzy
 msgid "negative depth in --deepen is not supported"
-msgstr "Profundidad negativa en --deepen no soportada"
+msgstr "profundidad negativa en --deepen no es soportada"
 
 msgid "--unshallow on a complete repository does not make sense"
 msgstr "--unshallow no tiene sentido en un repositorio completo"
@@ -5905,20 +5967,20 @@ msgstr "fetch --all no toma un argumento de repositorio"
 msgid "fetch --all does not make sense with refspecs"
 msgstr "fetch --all no tiene sentido con refspecs"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no such remote or remote group: %s"
-msgstr "No existe el remoto o grupo remoto: %s"
+msgstr "no existe tal remoto o grupo remoto: %s"
 
-#, fuzzy
 msgid "fetching a group and specifying refspecs does not make sense"
-msgstr "Extraer un grupo y especificar refspecs no tiene sentido"
+msgstr ""
+"hacer fetch de un grupo y especificar especificaciones de referencia no "
+"tiene sentido"
 
 msgid "must supply remote when using --negotiate-only"
 msgstr "tiene que proveer un remoto cuando usa --negotiate-only"
 
-#, fuzzy
 msgid "protocol does not support --negotiate-only, exiting"
-msgstr "Protocolo no soporta --negotiate-only, saliendo."
+msgstr "el protocolo no soporta --negotiate-only, saliendo"
 
 msgid ""
 "--filter can only be used with the remote configured in extensions."
@@ -5950,9 +6012,8 @@ msgstr "texto"
 msgid "use <text> as start of message"
 msgstr "usar <text> como comienzo de mensaje"
 
-#, fuzzy
 msgid "use <name> instead of the real target branch"
-msgstr "usar <nombre> en lugar de 'origin' para rastrear upstream"
+msgstr "usar <nombre> en lugar de la rama de destino real"
 
 msgid "file to read from"
 msgstr "archivo del cual leer"
@@ -6025,7 +6086,7 @@ msgstr "error en %s %s: %s"
 #. TRANSLATORS: e.g. warning in tree 01bfda: <more explanation>
 #, c-format
 msgid "warning in %s %s: %s"
-msgstr "peligro en %s %s: %s"
+msgstr "advertencia en %s %s: %s"
 
 #, c-format
 msgid "broken link from %7s %s"
@@ -6093,11 +6154,11 @@ msgstr "tagged %s %s (%s) en %s"
 
 #, c-format
 msgid "%s: object corrupt or missing"
-msgstr "%s: objecto corrupto o faltante"
+msgstr "%s: objeto corrupto o faltante"
 
 #, c-format
 msgid "%s: invalid reflog entry %s"
-msgstr "%s: referencia inválida %s"
+msgstr "%s: entrada de log de referencias inválida %s"
 
 #, c-format
 msgid "Checking reflog %s->%s"
@@ -6170,6 +6231,10 @@ msgstr "%s: puntero inválido sha1 en cache-tree"
 msgid "non-tree in cache-tree"
 msgstr "non-tree en cache-tree"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s: puntero inválido sha1 en resolve-undo"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<opciones>] [<objeto>...]"
 
@@ -6220,79 +6285,73 @@ msgstr "%s: objeto faltante"
 msgid "invalid parameter: expected sha1, got '%s'"
 msgstr "parámetro inválido: sha1 esperado, se obtuvo '%s'"
 
-#, fuzzy
 msgid "git fsmonitor--daemon start [<options>]"
-msgstr "git stash list [<opciones>]"
+msgstr "git fsmonitor--daemon start [<opciones>]"
 
-#, fuzzy
 msgid "git fsmonitor--daemon run [<options>]"
-msgstr "git notes prune [<opciones>]"
+msgstr "git fsmonitor--daemon run [<opciones>]"
 
 msgid "git fsmonitor--daemon stop"
-msgstr ""
+msgstr "git fsmonitor--daemon stop"
 
 msgid "git fsmonitor--daemon status"
-msgstr ""
+msgstr "git fsmonitor--daemon status"
 
-#, fuzzy, c-format
+#, c-format
 msgid "value of '%s' out of range: %d"
-msgstr "largo de abreviatura fuera de rango: %d"
+msgstr "valor de '%s' fuera de rango: %d"
 
-#, fuzzy, c-format
+#, c-format
 msgid "value of '%s' not bool or int: %d"
-msgstr "valor es --bool o --int"
+msgstr "valor de '%s' no bool ni int: %d"
 
 #, c-format
 msgid "fsmonitor-daemon is watching '%s'\n"
-msgstr ""
+msgstr "fsmonitor-daemon está vigilando '%s'\n"
 
 #, c-format
 msgid "fsmonitor-daemon is not watching '%s'\n"
-msgstr ""
+msgstr "fsmonitor-daemon no está vigilando '%s'\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not create fsmonitor cookie '%s'"
-msgstr "no se pudo crear el archivo '%s'"
+msgstr "no se pudo crear la galleta de fsmonitor '%s'"
 
 #, c-format
 msgid "fsmonitor: cookie_result '%d' != SEEN"
-msgstr ""
+msgstr "fsmonitor: cookie_result '%d' != SEEN"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not start IPC thread pool on '%s'"
-msgstr "no se pudo iniciar el servidor en: '%s'"
+msgstr "no se pudo iniciar el pool de hilos IPC en '%s'"
 
-#, fuzzy
 msgid "could not start fsmonitor listener thread"
-msgstr "no se pudo comenzar ls-files en .."
+msgstr "no se pudo iniciar el hilo escuchante de fsmonitor"
 
-#, fuzzy
 msgid "could not start fsmonitor health thread"
-msgstr "no se pudo iniciar el accept_thread '%s'"
+msgstr "no se pudo iniciar el hilo de salud de fsmonitor"
 
-#, fuzzy
 msgid "could not initialize listener thread"
-msgstr "no se pudo guardar el árbol de índice"
+msgstr "no se pudo inicializar el hilo escuchante"
 
-#, fuzzy
 msgid "could not initialize health thread"
-msgstr "no se pudo normalizar la ruta %s"
+msgstr "no se pudo inicializar el hilo de salud"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not cd home '%s'"
-msgstr "no se pudo cerrar '%s'"
+msgstr "no se pudo cambiar al directorio personal '%s'"
 
 #, c-format
 msgid "fsmonitor--daemon is already running '%s'"
-msgstr ""
+msgstr "fsmonitor--daemon ya está ejecutando '%s'"
 
 #, c-format
 msgid "running fsmonitor-daemon in '%s'\n"
-msgstr ""
+msgstr "ejecutando fsmonitor-daemon en '%s'\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "starting fsmonitor-daemon in '%s'\n"
-msgstr "Probando mtime en '%s' "
+msgstr "iniciando fsmonitor-daemon en '%s'\n"
 
 msgid "daemon failed to start"
 msgstr "falló al iniciar demonio"
@@ -6300,32 +6359,28 @@ msgstr "falló al iniciar demonio"
 msgid "daemon not online yet"
 msgstr "demonio no está en línea todavía"
 
-#, fuzzy
 msgid "daemon terminated"
-msgstr "no hay términos definidos"
+msgstr "demonio terminado"
 
-#, fuzzy
 msgid "detach from console"
-msgstr "HEAD desacoplada de "
+msgstr "desacoplar de la consola"
 
-#, fuzzy
 msgid "use <n> ipc worker threads"
-msgstr "usar <n> hilos de trabajo"
+msgstr "usar <n> hilos de trabajo ipc"
 
-#, fuzzy
 msgid "max seconds to wait for background daemon startup"
-msgstr "segundos a esperar para que el dominio empiece o se detenga"
+msgstr "segundos máximos a esperar el inicio del demonio de fondo"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid 'ipc-threads' value (%d)"
-msgstr "valor --stat inválido: %s"
+msgstr "valor 'ipc-threads' inválido (%d)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Unhandled subcommand '%s'"
-msgstr "subcomando no válido: %s"
+msgstr "Subcomando no manejado '%s'"
 
 msgid "fsmonitor--daemon not supported on this platform"
-msgstr ""
+msgstr "fsmonitor--daemon no es soportado en este plataforma"
 
 msgid "git gc [<options>]"
 msgstr "git gc [<opciones>]"
@@ -6359,9 +6414,8 @@ msgstr ""
 msgid "prune unreferenced objects"
 msgstr "recortar objetos no referenciados"
 
-#, fuzzy
 msgid "pack unreferenced objects separately"
-msgstr "recortar objetos no referenciados"
+msgstr "empacar separadamente objetos no referenciados"
 
 msgid "be more thorough (increased runtime)"
 msgstr "ser más exhaustivo (aumentar runtime)"
@@ -6376,8 +6430,8 @@ msgid "repack all other packs except the largest pack"
 msgstr "reempaquetar todos los otros paquetes excepto el paquete más grande"
 
 #, c-format
-msgid "failed to parse gc.logexpiry value %s"
-msgstr "falló al analizar valor %s de gc.logexpiry"
+msgid "failed to parse gc.logExpiry value %s"
+msgstr "falló al analizar el valor %s de gc.logExpiry"
 
 #, c-format
 msgid "failed to parse prune expiry value %s"
@@ -6514,13 +6568,16 @@ msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr ""
 "no se pudo ejecutar 'crontab -l'; es posible que su sistema no soporte 'cron'"
 
+msgid "failed to create crontab temporary file"
+msgstr "falló al crear el archivo temporal de crontab"
+
+msgid "failed to open temporary file"
+msgstr "falló al abrir un archivo temporal"
+
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "no se pudo ejecutar 'crontab'; es posible que su sistema no soporte 'cron'"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "no se pudo abrir stdin de 'crontab'"
-
 msgid "'crontab' died"
 msgstr "'crontab' murió"
 
@@ -6567,10 +6624,6 @@ msgstr "no se pudo agregar el repositorio a la configuración global"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <subcomando> [<opciones>]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "subcomando no válido: %s"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<opciones>] [-e] <patrón> [<rev>...] [[--] <ruta>...]"
 
@@ -6582,7 +6635,6 @@ msgstr "grep: falló al crear el hilo: %s"
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "número inválido de hilos especificado (%d) para %s"
 
-#. #-#-#-#-#  grep.c.po  #-#-#-#-#
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
@@ -6745,6 +6797,9 @@ msgstr "mostrar archivos concordantes en el paginador"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "permitir el llamado de grep(1) (ignorado por esta build)"
 
+msgid "maximum number of results per file"
+msgstr "número máximo de resultados por archivo"
+
 msgid "no pattern given"
 msgstr "no se ha entregado ningún patrón"
 
@@ -6808,13 +6863,11 @@ msgstr "procesar el archivo como si fuera de esta ruta"
 msgid "print all available commands"
 msgstr "mostrar todos los comandos disponibles"
 
-#, fuzzy
 msgid "show external commands in --all"
-msgstr "Comandos externos"
+msgstr "mostrar comandos externos en --all"
 
-#, fuzzy
 msgid "show aliases in --all"
-msgstr "mostrar lista de tags en columnas"
+msgstr "mostrar aliases en --all"
 
 msgid "exclude guides"
 msgstr "excluir las guias"
@@ -6834,14 +6887,21 @@ msgstr "imprimir descripción del comando"
 msgid "print list of useful guides"
 msgstr "mostrar una lista de guías útiles"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr ""
+"imprimir lista de interfaces de repositorio, comando y archivo orientadas al "
+"usuario"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr ""
+"imprimir lista de formatos de archivos, protocolos y otras interfaces para "
+"el desarrollador"
+
 msgid "print all configuration variable names"
 msgstr "imprimir todos los nombres de variables de configuración"
 
-#, fuzzy
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr ""
-"git help [-a|--all] [--[no-]verbose]]\n"
-"         [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<comando>|<documento>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -6895,13 +6955,15 @@ msgstr "'%s' tiene el alias '%s'"
 msgid "bad alias.%s string: %s"
 msgstr "mal alias.%s string: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "the '%s' option doesn't take any non-option arguments"
-msgstr "esta opción no requiere argumentos"
+msgstr "la opción '%s' no toma ningún argumento aparte de opciones"
 
 msgid ""
 "the '--no-[external-commands|aliases]' options can only be used with '--all'"
 msgstr ""
+"las opciones '--no-[external-commands|aliases]' solo pueden ser usadas con "
+"'--all'"
 
 #, c-format
 msgid "usage: %s%s"
@@ -6912,9 +6974,10 @@ msgstr "'git help config' para más información"
 
 msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
 msgstr ""
+"git hook run [--ignore-missing] <nombre-de-hook> [-- <argumentos-de-hook>]"
 
 msgid "silently ignore missing requested <hook-name>"
-msgstr ""
+msgstr "ignorar silenciosamente <nombre-de-hook> solicitado y faltante"
 
 #, c-format
 msgid "object type mismatch at %s"
@@ -6946,9 +7009,9 @@ msgstr "se usaron más bytes de los disponibles"
 msgid "pack too large for current definition of off_t"
 msgstr "paquete demasiado grande para la definición actual de off_t"
 
-#, fuzzy, c-format
+#, c-format
 msgid "pack exceeds maximum allowed size (%s)"
-msgstr "paquete excede el máximo tamaño permitido"
+msgstr "el pack excede el tamaño máximo permitido (%s)"
 
 msgid "pack signature mismatch"
 msgstr "firma del paquete no concuerda"
@@ -6981,8 +7044,8 @@ msgstr "no se puede hacer pread en el paquete"
 #, c-format
 msgid "premature end of pack file, %<PRIuMAX> byte missing"
 msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
-msgstr[0] "final prematuro de archivo de paquete, %<PRIuMAX> byte faltante"
-msgstr[1] "final prematuro de archivo de paquete, %<PRIuMAX> bytes faltantes"
+msgstr[0] "fin prematuro de archivo de paquete, %<PRIuMAX> byte faltante"
+msgstr[1] "fin prematuro de archivo de paquete, %<PRIuMAX> bytes faltantes"
 
 msgid "serious inflate inconsistency"
 msgstr "inconsistencia seria en inflate"
@@ -7089,8 +7152,8 @@ msgid "error while closing pack file"
 msgstr "error mientras se cerraba el archivo paquete"
 
 #, c-format
-msgid "bad pack.indexversion=%<PRIu32>"
-msgstr "mal pack.indexversion=%<PRIu32>"
+msgid "bad pack.indexVersion=%<PRIu32>"
+msgstr "mal pack.indexVersion=%<PRIu32>"
 
 #, c-format
 msgid "Cannot open existing pack file '%s'"
@@ -7311,8 +7374,8 @@ msgstr "suprimir salida de diff"
 msgid "show source"
 msgstr "mostrar fuente"
 
-msgid "use mail map file"
-msgstr "usar archivo de mapa de mail"
+msgid "clear all previously-defined decoration filters"
+msgstr "limpiar todos los filtros de decoración previamente definidos"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "solo decorar refs que concuerden con <patrón>"
@@ -7341,9 +7404,8 @@ msgstr "-L<rango>:<archivo> no se puede usar con pathspec"
 msgid "Final output: %d %s\n"
 msgstr "Salida final: %d %s\n"
 
-#, fuzzy
 msgid "unable to create temporary object directory"
-msgstr "no es posible crear un archivo temporal"
+msgstr "incapaz de crear directorio temporal de objetos"
 
 #, c-format
 msgid "git show %s: bad file"
@@ -7572,6 +7634,9 @@ msgstr "mostrar cambios contra <refspec> en cover letter o en un solo parche"
 msgid "percentage by which creation is weighted"
 msgstr "porcentaje por el cual la creación es pesada"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "mostrar From: en el cuerpo aunque sea idéntico a la cabecera de e-mail"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "línea de identificación inválida: %s"
@@ -7585,9 +7650,8 @@ msgstr "--name-status no tiene sentido"
 msgid "--check does not make sense"
 msgstr "--check no tiene sentido"
 
-#, fuzzy
 msgid "--remerge-diff does not make sense"
-msgstr "--name-only no tiene sentido"
+msgstr "--remerge-diff no tiene sentido"
 
 #, c-format
 msgid "could not create directory '%s'"
@@ -7633,8 +7697,20 @@ msgstr ""
 "No se pudo encontrar una rama remota rastreada, por favor especifica "
 "<upstream> manualmente.\n"
 
-msgid "git ls-files [<options>] [<file>...]"
-msgstr "git ls-files [<opciones>] [<archivo>...]"
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "formato malo de ls-files: el elemento '%s' no comienza con '('"
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "formato malo de ls-files: el elemento '%s' no termina en ')'"
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "formato malo de ls-files: %%%.*s"
+
+msgid "git ls-files [<options>] [<file>...]"
+msgstr "git ls-files [<opciones>] [<archivo>...]"
 
 msgid "separate paths with the NUL character"
 msgstr "rutas están separadas con un carácter NULL"
@@ -7716,9 +7792,15 @@ msgstr "mostrar data de debug"
 msgid "suppress duplicate entries"
 msgstr "suprimir entradas duplicadas"
 
-#, fuzzy
 msgid "show sparse directories in the presence of a sparse index"
-msgstr "activar el uso de un índice sparse"
+msgstr "mostrar directorios escasos en la presencia de un índice escaso"
+
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format no puede ser usado con -s, -o, -k, -t, --resolve-undo, --"
+"deduplicate, --eol"
 
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
@@ -7759,21 +7841,21 @@ msgstr "mostrar ref subyacente en adición al objeto apuntado por él"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<opciones>] <árbol-ismo> [<ruta>...]"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not get object info about '%s'"
-msgstr "no se pudo analizar el objeto '%s'"
+msgstr "no se pudo averiguar información sobre el objeto '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "el nombre del archivo de paquete '%s' no termina con '.%s'"
+msgstr "formato malo de ls-tree: el elemento '%s' no comienza con '('"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "el nombre del archivo de paquete '%s' no termina con '.%s'"
+msgstr "formato malo de ls-tree: el elemento '%s' no termina en ')'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bad ls-tree format: %%%.*s"
-msgstr "formato inválido: %s"
+msgstr "formato malo de ls-tree: %%%.*s"
 
 msgid "only show trees"
 msgstr "solo mostrar árboles"
@@ -7793,9 +7875,8 @@ msgstr "incluir tamaño de objeto"
 msgid "list only filenames"
 msgstr "listar solo nombres de archivos"
 
-#, fuzzy
 msgid "list only objects"
-msgstr "Escribiendo objetos"
+msgstr "listar solo objetos"
 
 msgid "use full path names"
 msgstr "usar rutas completas"
@@ -7804,9 +7885,9 @@ msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
 "mostrar todo el árbol; no solo el directorio actual (implica --full-name)"
 
-#, fuzzy
 msgid "--format can't be combined with other format-altering options"
-msgstr "--mirror no puede ser combinado con refspecs"
+msgstr ""
+"--format no se puede combinar con otras opciones que alteren el formato"
 
 #. TRANSLATORS: keep <> in "<" mail ">" info.
 msgid "git mailinfo [<options>] <msg> <patch> < mail >info"
@@ -7845,9 +7926,8 @@ msgstr "actión cuando se encuentra un CR citado"
 msgid "use headers in message's body"
 msgstr "usar cabeceras en el cuerpo del mensaje"
 
-#, fuzzy
 msgid "reading patches from stdin/tty..."
-msgstr "leer actualizaciones de stdin"
+msgstr "leyendo parches de stdin/tty..."
 
 #, c-format
 msgid "empty mbox: '%s'"
@@ -7896,9 +7976,8 @@ msgstr "mandar resultados a standard output"
 msgid "use a diff3 based merge"
 msgstr "usar una fusión basada en diff3"
 
-#, fuzzy
 msgid "use a zealous diff3 based merge"
-msgstr "usar una fusión basada en diff3"
+msgstr "usar una fusión celosa basada en diff3"
 
 msgid "for conflicts, use our version"
 msgstr "por conflictos, usar nuestra versión"
@@ -7943,6 +8022,39 @@ msgstr "no se pudo resolver ref '%s'"
 msgid "Merging %s with %s\n"
 msgstr "Fusionando %s con %s\n"
 
+msgid "not something we can merge"
+msgstr "no es nada que se pueda fusionar"
+
+msgid "refusing to merge unrelated histories"
+msgstr "rehusando fusionar historias no relacionadas"
+
+msgid "failure to merge"
+msgstr "falló al fusionar"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<opciones>] <rama1> <rama2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <árbol-base> <rama1> <rama2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "hacer una fusión real en vez de una fusión trivial"
+
+msgid "do a trivial merge only"
+msgstr "hacer solo una fusión trivial"
+
+msgid "also show informational/conflict messages"
+msgstr "también mostrar mensajes informativos o de conflictos"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "listar nombres de archivo sin modos/oids/etapas"
+
+msgid "allow merging unrelated histories"
+msgstr "permitir fusionar historias no relacionadas"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge es incompatible con cualquier otra opción"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<opciones>] [<commit>...]"
 
@@ -8012,9 +8124,8 @@ msgstr "opción para la estrategia de fusión seleccionada"
 msgid "merge commit message (for a non-fast-forward merge)"
 msgstr "fusionar mensaje de commit (para una fusión no fast-forward)"
 
-#, fuzzy
 msgid "use <name> instead of the real target"
-msgstr "usar <nombre> en lugar de 'origin' para rastrear upstream"
+msgstr "usar <nombre> en lugar del destino real"
 
 msgid "abort the current in-progress merge"
 msgstr "abortar la fusión en progreso actual"
@@ -8025,9 +8136,6 @@ msgstr "--abort pero no tocar el índice ni el árbol de trabajo"
 msgid "continue the current in-progress merge"
 msgstr "continuar la fusión en progreso actual"
 
-msgid "allow merging unrelated histories"
-msgstr "permitir fusionar historias no relacionadas"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "hacer un bypass a hooks pre-merge-commit y commit-msg"
 
@@ -8149,9 +8257,6 @@ msgstr "no se pudo cerrar '%s'"
 msgid "not something we can merge in %s: %s"
 msgstr "nada que podamos fusionar en %s: %s"
 
-msgid "not something we can merge"
-msgstr "nada que podamos fusionar"
-
 msgid "--abort expects no arguments"
 msgstr "--abort no espera argumentos"
 
@@ -8201,13 +8306,19 @@ msgstr "%s - nada que podamos fusionar"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Solo se puede fusionar exactamente un commit en un head vacío"
 
-msgid "refusing to merge unrelated histories"
-msgstr "rehusando fusionar historias no relacionadas"
-
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Actualizando %s..%s\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Los cambios locales a los archivos siguientes serían sobreescritos al "
+"fusionar:\n"
+"  %s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Intentando fusión en índice realmente trivial...\n"
@@ -8241,9 +8352,14 @@ msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Fusión automática fue bien; detenida antes del commit como se solicitó\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr ""
+"Cuando esté terminado, aplica los cambios en stash con `git stash pop`\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
-msgstr "peligro: información de tag no pasa fsck: %s"
+msgstr "advertencia: la información de etiqueta no pasa fsck: %s"
 
 #, c-format
 msgid "error: tag input does not pass fsck: %s"
@@ -8298,9 +8414,8 @@ msgstr "git multi-pack-index [<opciones>] expire"
 msgid "git multi-pack-index [<options>] repack [--batch-size=<size>]"
 msgstr "git multi-pack-index [<opciones>] repack [--batch-size=<tamaño>]"
 
-#, fuzzy
 msgid "directory"
-msgstr "archivo/directorio"
+msgstr "directorio"
 
 msgid "object directory containing set of packfile and pack-index pairs"
 msgstr ""
@@ -8361,6 +8476,9 @@ msgstr "Revisando cambio de nombre de '%s' a '%s'\n"
 msgid "bad source"
 msgstr "mala fuente"
 
+msgid "destination exists"
+msgstr "el destino existe"
+
 msgid "can not move directory into itself"
 msgstr "no se puede mover un directorio en sí mismo"
 
@@ -8376,9 +8494,6 @@ msgstr "no se encuentra bajo control de versiones"
 msgid "conflicted"
 msgstr "en conflicto"
 
-msgid "destination exists"
-msgstr "destino existe"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "sobrescribiendo '%s'"
@@ -8392,6 +8507,9 @@ msgstr "múltiples fuentes para el mismo destino"
 msgid "destination directory does not exist"
 msgstr "el directorio de destino no existe"
 
+msgid "destination exists in the index"
+msgstr "el destino existe en el índice"
+
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, fuente=%s, destino=%s"
@@ -8410,9 +8528,8 @@ msgstr "git name-rev [<opciones>] <commit>..."
 msgid "git name-rev [<options>] --all"
 msgstr "git name-rev [<opciones>] --all"
 
-#, fuzzy
 msgid "git name-rev [<options>] --annotate-stdin"
-msgstr "git name-rev [<opciones>] --stdin"
+msgstr "git name-rev [<opciones>] --annotate-stdin"
 
 msgid "print only ref-based names (no object names)"
 msgstr "imprimir solo nombres basados en referencias (sin nombres de objetos)"
@@ -8429,12 +8546,11 @@ msgstr "ignorar refs que concuerden con <patrón>"
 msgid "list all commits reachable from all refs"
 msgstr "listar todos los commits alcanzables desde todas las referencias"
 
-msgid "deprecated: use annotate-stdin instead"
-msgstr ""
+msgid "deprecated: use --annotate-stdin instead"
+msgstr "deprecado: usa --annotate-stdin en su lugar"
 
-#, fuzzy
 msgid "annotate text from stdin"
-msgstr "leer el objeto de stdin"
+msgstr "anotar el texto de stdin"
 
 msgid "allow to print `undefined` names (default)"
 msgstr "permitir imprimir nombres `undefined` (predeterminado)"
@@ -8753,8 +8869,8 @@ msgid "use notes from <notes-ref>"
 msgstr "usar notas desde <referencia-de-notas>"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "subcomando desconocido: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "subcomando desconocido: '%s'"
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -8896,21 +9012,18 @@ msgstr "no se puede obtener el tipo de objeto %s en pack %s"
 msgid "could not find pack '%s'"
 msgstr "no se pudo encontrar pack '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "packfile %s cannot be accessed"
-msgstr "objeto %s no puede ser mapeado %s"
+msgstr "no se puede acceder al archivo de pack %s"
 
-#, fuzzy
 msgid "Enumerating cruft objects"
-msgstr "Enumerando objetos"
+msgstr "Enumerando objetos inalcanzables"
 
-#, fuzzy
 msgid "unable to add cruft objects"
-msgstr "incapaz de añadir objetos recientes"
+msgstr "incapaz de añadir objetos inalcanzables"
 
-#, fuzzy
 msgid "Traversing cruft objects"
-msgstr "Comprimiendo objetos"
+msgstr "Atravesando objetos inalcanzables"
 
 #, c-format
 msgid ""
@@ -8928,9 +9041,8 @@ msgstr ""
 "se esperaba ID de objeto, se obtuvo basura:\n"
 "%s"
 
-#, fuzzy
 msgid "could not load cruft pack .mtimes"
-msgstr "no se pudo cargar pack"
+msgstr "no se pudo cargar el .mtimes del pack de inalcanzables"
 
 msgid "cannot open pack index"
 msgstr "no se puede abrir índice de paquetes"
@@ -8940,7 +9052,7 @@ msgid "loose object at %s could not be examined"
 msgstr "objeto suelto en %s no pudo ser examinado"
 
 msgid "unable to force loose object"
-msgstr "incapaz de forzar que el objecto se suelte"
+msgstr "incapaz de forzar que el objeto se suelte"
 
 #, c-format
 msgid "not a rev '%s'"
@@ -9034,13 +9146,11 @@ msgstr "empaquetar objetos sueltos inalcanzables"
 msgid "unpack unreachable objects newer than <time>"
 msgstr "desempaquetar objetos inalcanzables más nuevos que <tiempo>"
 
-#, fuzzy
 msgid "create a cruft pack"
-msgstr "crear paquetes delgados"
+msgstr "crear un pack de inalcanzables"
 
-#, fuzzy
 msgid "expire cruft objects older than <time>"
-msgstr "caducar objetos más viejos a <tiempo>"
+msgstr "caducar objetos inalcanzables más viejos a <tiempo>"
 
 msgid "use the sparse reachability algorithm"
 msgstr "usar el algoritmo sparse reachability"
@@ -9119,19 +9229,16 @@ msgid "cannot use --filter with --stdin-packs"
 msgstr "no se puede usar --filter con --stdin-packs"
 
 msgid "cannot use internal rev list with --stdin-packs"
-msgstr "no se puede usar un lista interna de rev con --stdin-packs"
+msgstr "no se puede usar un lista interna de revisiones con --stdin-packs"
 
-#, fuzzy
 msgid "cannot use internal rev list with --cruft"
-msgstr "no se puede usar un lista interna de rev con --stdin-packs"
+msgstr "no se puede usar un lista interna de revisiones con --cruft"
 
-#, fuzzy
 msgid "cannot use --stdin-packs with --cruft"
-msgstr "no se puede usar -a con -d"
+msgstr "no se puede usar --stdin-packs con --cruft"
 
-#, fuzzy
 msgid "cannot use --max-pack-size with --cruft"
-msgstr "no se puede usar -a con -d"
+msgstr "no se puede usar --max-pack-size con --cruft"
 
 msgid "Enumerating objects"
 msgstr "Enumerando objetos"
@@ -9197,9 +9304,8 @@ msgstr "incorporar cambios por rebase en lugar de fusión"
 msgid "allow fast-forward"
 msgstr "permitir fast-forward"
 
-#, fuzzy
 msgid "control use of pre-merge-commit and commit-msg hooks"
-msgstr "hacer un bypass a hooks pre-merge-commit y commit-msg"
+msgstr "controlar el uso de los hooks pre-merge-commit y commit-msg"
 
 msgid "automatically stash/stash pop before and after"
 msgstr "ejecutar automáticamente stash/stash pop antes y después"
@@ -9283,7 +9389,6 @@ msgstr "no es posible acceder al commit %s"
 msgid "ignoring --verify-signatures for rebase"
 msgstr "ignorando --verify-signatures para rebase"
 
-#, fuzzy
 msgid ""
 "You have divergent branches and need to specify how to reconcile them.\n"
 "You can do so by running one of the following commands sometime before\n"
@@ -9299,18 +9404,18 @@ msgid ""
 "or --ff-only on the command line to override the configured default per\n"
 "invocation.\n"
 msgstr ""
-"Hacer un pull sin especificar cómo reconciliar las ramas es poco\n"
-"recomendable. Puedes eliminar este mensaje usando uno de los\n"
-"siguientes comandos antes de tu siguiente pull:\n"
+"Las ramas se han divergido y hay que especificar cómo reconciliarlas.\n"
+"Se puede hacerlo ejecutando uno de los comandos siguiente antes del\n"
+"próximo pull:\n"
 "\n"
-"  git config pull.rebase false  # hacer merge (estrategia por defecto)\n"
-"  git config pull.rebase true   # aplicar rebase\n"
-"  git config pull.ff only       # aplicar solo fast-forward\n"
+"  git config pull.rebase false  # fusionar\n"
+"  git config pull.rebase true   # rebasar\n"
+"  git config pull.ff only       # solo avance rápido\n"
 "\n"
-"Puedes reemplazar \"git config\" con \"git config --global\" para aplicar\n"
-"la preferencia en todos los repositorios. Puedes también pasar --rebase,\n"
-"--no-rebase, o --ff-only en el comando para sobrescribir la configuración\n"
-"por defecto en cada invocación.\n"
+"Se puede reemplazar \"git config\" con \"git config --global\" para aplicar\n"
+"la preferencia en todos los repositorios. También se puede pasar\n"
+"--rebase, --no-rebase o --ff-only en el comando para sobrescribir la\n"
+"configuración por defecto en cada invocación.\n"
 
 msgid "Updating an unborn branch with changes added to the index."
 msgstr "Actualizando una rama no nacida con cambios agregados al índice."
@@ -9373,14 +9478,13 @@ msgstr "taquigrafía de tag sin <tag>"
 msgid "--delete only accepts plain target ref names"
 msgstr "--delete solo acepta como objetivos nombres de ref planos"
 
-#, fuzzy
 msgid ""
 "\n"
 "To choose either option permanently, see push.default in 'git help config'.\n"
 msgstr ""
 "\n"
-"Para elegir si la opción es permanente, mira push.default en 'git help "
-"config'."
+"Para elegir una de las opciones permanentemente, mira push.default en 'git "
+"help config'.\n"
 
 msgid ""
 "\n"
@@ -9389,8 +9493,12 @@ msgid ""
 "autoSetupMerge\n"
 "in 'git help config'.\n"
 msgstr ""
+"\n"
+"Para evitar configurar una rama upstream automáticamente cuando su nombre\n"
+"no coincida con el de la rama local, mira la opción 'simple' de\n"
+"branch.autoSetupMerge en 'git help config'.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The upstream branch of your current branch does not match\n"
 "the name of your current branch.  To push to the upstream branch\n"
@@ -9412,7 +9520,7 @@ msgstr ""
 "Para empujar a la rama del mismo nombre en el remoto, ejecuta\n"
 "\n"
 "    git push %s HEAD\n"
-"%s"
+"%s%s"
 
 #, c-format
 msgid ""
@@ -9433,8 +9541,11 @@ msgid ""
 "To have this happen automatically for branches without a tracking\n"
 "upstream, see 'push.autoSetupRemote' in 'git help config'.\n"
 msgstr ""
+"\n"
+"Para hacer que esto pase automáticamente para las ramas que no rastrean\n"
+"un upstream, mira 'push.autoSetupRemote' en 'git help config'.\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The current branch %s has no upstream branch.\n"
 "To push the current branch and set the remote as upstream, use\n"
@@ -9445,7 +9556,8 @@ msgstr ""
 "La rama actual %s no tiene una rama upstream.\n"
 "Para empujar la rama actual y configurar el remoto como upstream, usa\n"
 "\n"
-"\tgit push --set-upstream %s %s\n"
+"    git push --set-upstream %s %s\n"
+"%s"
 
 #, c-format
 msgid "The current branch %s has multiple upstream branches, refusing to push."
@@ -9536,9 +9648,9 @@ msgstr "Empujando a %s\n"
 msgid "failed to push some refs to '%s'"
 msgstr "falló el empuje de algunas referencias a '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid value for '%s'"
-msgstr "valor inválido para %s"
+msgstr "valor inválido para '%s'"
 
 msgid "repository"
 msgstr "repositorio"
@@ -9657,12 +9769,17 @@ msgstr "solo emite salida relacionada con el primer rango"
 msgid "only emit output related to the second range"
 msgstr "solo emite salida relacionada con el segundo rango"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "no es una revisión: '%s'"
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "no es un rango de commit: '%s'"
 
-msgid "single arg format must be symmetric range"
-msgstr "argumento único de formato debe ser un rango simétrico"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "no es un rango simétrico: '%s'"
 
 msgid "need two commit ranges"
 msgstr "se necesitan dos rangos de commits"
@@ -9923,9 +10040,8 @@ msgstr "usar estrategias de fusión para el rebase"
 msgid "let the user edit the list of commits to rebase"
 msgstr "permitir al usuario editar la lista de commits para rebasar"
 
-#, fuzzy
 msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
-msgstr "(DEPRECADO) intentar recrear merges en lugar de ignorarlos"
+msgstr "(DEPRECADO) era: intentar recrear fusiones en lugar de ignorarlas"
 
 msgid "how to handle commits that become empty"
 msgstr "como manejar commits que se vuelven vacíos"
@@ -9936,6 +10052,9 @@ msgstr "mantener commits que comiencen con vacío"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "mover commits que comiencen con squash!/fixup! bajo -i"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr "actualizar ramas que apuntan a commits que se rebasan"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr "agregar líneas exec tras cada commit de la lista editable"
 
@@ -9976,12 +10095,19 @@ msgid ""
 "Use `git rebase --abort` to terminate current rebase.\n"
 "Or downgrade to v2.33, or earlier, to complete the rebase."
 msgstr ""
+"`rebase --preserve-merges` (-p) ya no es soportado.\n"
+"Usa `git rebase --abort` para terminar la rebase actual.\n"
+"O regresa a v2.33, o más antes, para completar la rebase."
 
 msgid ""
 "--preserve-merges was replaced by --rebase-merges\n"
-"Note: Your `pull.rebase` configuration may also be  set to 'preserve',\n"
+"Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
 "which is no longer supported; use 'merges' instead"
 msgstr ""
+"--rebase-merges ha reemplazado --preserve-merges\n"
+"Nota: Tu configuración de `pull.rebase` también podría estar\n"
+"configurada a 'preserve', el cual ya no es soportado; usa 'merges' en\n"
+"su lugar"
 
 msgid "No rebase in progress?"
 msgstr "¿No hay rebase en progreso?"
@@ -10037,9 +10163,10 @@ msgstr "Modo desconocido: %s"
 msgid "--strategy requires --merge or --interactive"
 msgstr "--strategy requiere --merge o --interactive"
 
-#, fuzzy
 msgid "apply options and merge options cannot be used together"
-msgstr "Opciones --add-file y --remote no pueden ser usadas juntas"
+msgstr ""
+"las opciones de aplicación y las opciones de fusión no pueden ser usadas "
+"juntas"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
@@ -10176,82 +10303,80 @@ msgstr ""
 msgid "quiet"
 msgstr "silencioso"
 
-#, fuzzy
 msgid "you must specify a directory"
-msgstr "Se tiene que especificar un directorio."
+msgstr "hay que especificar un directorio"
 
-#, fuzzy
 msgid "git reflog [show] [<log-options>] [<ref>]"
-msgstr "git remote show [<opciones>] <nombre>"
+msgstr "git reflog [show] [<opciones-de-log>] [<referencia>]"
 
-#, fuzzy
 msgid ""
 "git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n"
 "                  [--rewrite] [--updateref] [--stale-fix]\n"
 "                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
 "<refs>...]"
 msgstr ""
-"git reflog expire [--expire=<tiempo>] [--expire-unreachable=<tiempo>] [--"
-"rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] "
-"<refs>..."
+"git reflog expire [--expire=<tiempo>] [--expire-unreachable=<tiempo>]\n"
+"                  [--rewrite] [--updateref] [--stale-fix]\n"
+"                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
+"<referencias>...]"
 
-#, fuzzy
 msgid ""
 "git reflog delete [--rewrite] [--updateref]\n"
 "                  [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
 msgstr ""
-"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] "
-"<refs>..."
+"git reflog delete [--rewrite] [--updateref]\n"
+"                  [--dry-run | -n] [--verbose] "
+"<referencia>@{<especificador>}..."
 
 msgid "git reflog exists <ref>"
-msgstr "git reflog existe <ref>"
+msgstr "git reflog exists <referencia>"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid timestamp '%s' given to '--%s'"
-msgstr "regex inválido para -I: '%s'"
+msgstr "marca de tiempo inválida '%s' pasada a '--%s'"
 
-#, fuzzy
 msgid "do not actually prune any entries"
-msgstr "no tocar entradas index-only"
+msgstr "no recortar de verdad ninguna entrada"
 
 msgid ""
 "rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"
 msgstr ""
+"reescribir el SHA1 antiguo con el SHA1 nuevo de la entrada que ya lo precede"
 
 msgid "update the reference to the value of the top reflog entry"
-msgstr ""
+msgstr "actualizar la referencia al valor de la entrada superior del reflog"
 
-#, fuzzy
 msgid "print extra information on screen"
-msgstr "Información de output en cada ref"
+msgstr "imprimir información extra a la pantalla"
 
-#, fuzzy
 msgid "timestamp"
-msgstr "timestamp inválido"
+msgstr "marca de tiempo"
 
-#, fuzzy
 msgid "prune entries older than the specified time"
-msgstr "caducar árboles de trabajo más viejos a <tiempo>"
+msgstr "recortar entradas más viejas al tiempo especificado"
 
 msgid ""
 "prune entries older than <time> that are not reachable from the current tip "
 "of the branch"
 msgstr ""
+"recortar entradas más viejas de <tiempo> que están inalcanzables de la punta "
+"actual de la rama"
 
-#, fuzzy
 msgid "prune any reflog entries that point to broken commits"
-msgstr "mostrar solo ramas que contengan el commit"
+msgstr ""
+"recortar cualquier entrada del log de referencias que apunte a un commit roto"
 
-#, fuzzy
 msgid "process the reflogs of all references"
-msgstr "forzar sobrescritura de referencia local"
+msgstr "procesar los logs de referencias de todas las referencias"
 
 msgid "limits processing to reflogs from the current worktree only"
 msgstr ""
+"limita procesamiento a solo los logs de referencias del árbol de trabajo "
+"actual"
 
 #, c-format
 msgid "Marking reachable objects..."
-msgstr "Marcando objectos alcanzables..."
+msgstr "Marcando objetos alcanzables..."
 
 #, c-format
 msgid "%s points nowhere!"
@@ -10271,9 +10396,8 @@ msgstr ""
 "git remote add [-t <rama>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <nombre> <url>"
 
-#, fuzzy
 msgid "git remote rename [--[no-]progress] <old> <new>"
-msgstr "git remote rename <viejo> <nuevo>"
+msgstr "git remote rename [--[no-]progress] <viejo> <nuevo>"
 
 msgid "git remote remove <name>"
 msgstr "git remote remove <nombre>"
@@ -10431,9 +10555,8 @@ msgstr ""
 "\t%s\n"
 "\tPor favor actualiza la configuración manualmente si es necesario."
 
-#, fuzzy
 msgid "Renaming remote references"
-msgstr "no se pudo eliminar la referencia %s"
+msgstr "Renombrando referencias remotas"
 
 #, c-format
 msgid "deleting '%s' failed"
@@ -10468,6 +10591,9 @@ msgstr " nuevo (siguiente fetch se guardará en remotes/%s)"
 msgid " tracked"
 msgstr " rastreada"
 
+msgid " skipped"
+msgstr "saltado"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " viejo (usa 'git remote prune' para eliminar)"
 
@@ -10696,10 +10822,11 @@ msgstr "git repack [<opciones>]"
 
 msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
-"--no-write-bitmap-index or disable the pack.writebitmaps configuration."
+"--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
 msgstr ""
-"Reempaquetados incrementales son incompatibles con índices bitmap. Usa\n"
-"--no-write-bitmap-index o deshabilita la configuración pack.writebitmaps."
+"Los reempaquetados incrementales son incompatibles con las índices de "
+"bitmap.\n"
+"Usa --no-write-bitmap-index o deshabilita la configuración pack.writeBitmaps."
 
 msgid "could not start pack-objects to repack promisor objects"
 msgstr "no se puede iniciar pack-objects para reempaquetar objetos promisores"
@@ -10739,16 +10866,14 @@ msgstr "empaquetar todo en un único paquete"
 msgid "same as -a, and turn unreachable objects loose"
 msgstr "lo mismo que -a, y soltar objetos inalcanzables"
 
-#, fuzzy
 msgid "same as -a, pack unreachable cruft objects separately"
-msgstr "lo mismo que -a, y soltar objetos inalcanzables"
+msgstr "lo mismo que -a, empacar objetos inalcanzables separadamente"
 
 msgid "approxidate"
 msgstr "approxidate"
 
-#, fuzzy
 msgid "with -C, expire objects older than this"
-msgstr "caducar objetos más viejos a <tiempo>"
+msgstr "con -C, caducar objetos más viejos a esto"
 
 msgid "remove redundant packs, and run git-prune-packed"
 msgstr "eliminar paquetes redundantes, y ejecutar git-prune-packed"
@@ -10815,9 +10940,9 @@ msgstr "no se pueden borrar paquetes en un repositorio de objetos preciosos"
 msgid "Nothing new to pack."
 msgstr "Nada nuevo para empaquetar."
 
-#, fuzzy, c-format
+#, c-format
 msgid "pack prefix %s does not begin with objdir %s"
-msgstr "el nombre del archivo de paquete '%s' no termina con '.%s'"
+msgstr "el prefijo %s de pack no comienza con el objdir %s"
 
 #, c-format
 msgid "missing required file: %s"
@@ -11081,7 +11206,7 @@ msgid "be quiet, only report errors"
 msgstr "ser silencioso, solo reportar errores"
 
 msgid "skip refreshing the index after reset"
-msgstr ""
+msgstr "saltar refrescar el índice después de hacer reset"
 
 msgid "reset HEAD and index"
 msgstr "reiniciar HEAD e índice"
@@ -11121,14 +11246,13 @@ msgstr "%s reset no está permitido en un repositorio vacío"
 msgid "Unstaged changes after reset:"
 msgstr "Cambios fuera del área de stage tras el reset:"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "It took %.2f seconds to refresh the index after reset.  You can use\n"
 "'--no-refresh' to avoid this."
 msgstr ""
-"\n"
-"Tomó %.2f segundos para calcular los valores anterior/posterior del branch.\n"
-"Puedes usar '--no-ahead-behind' para evitar esto.\n"
+"Tomó %.2f segundos para refrescar el índice después de reiniciar.\n"
+"Se puede usar '--no-refresh' para evitar esto."
 
 #, c-format
 msgid "Could not reset index file to revision '%s'."
@@ -11141,12 +11265,16 @@ msgstr "No se puede escribir un nuevo archivo índice."
 msgid "unable to get disk usage of %s"
 msgstr "no se puede obtener el uso de disco de %s"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "valor inválido para '%s': '%s', el único formato permitido es '%s'"
+
 msgid "rev-list does not support display of notes"
 msgstr "rev-list no soporta mostrar notas"
 
-#, fuzzy, c-format
+#, c-format
 msgid "marked counting and '%s' cannot be used together"
-msgstr "--reject y --3way no se pueden utilizar juntas."
+msgstr "el conteo marcado y '%s' no pueden ser usados juntos"
 
 msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
 msgstr "git rev-parse --parseopt [<opciones>] -- [<args>...]"
@@ -11166,6 +11294,9 @@ msgstr "fin de input prematuro"
 msgid "no usage string given before the `--' separator"
 msgstr "no se ha entregado cadena antes del separador`--'"
 
+msgid "missing opt-spec before option flags"
+msgstr "falta opt-spec antes de los flags de opción"
+
 msgid "Needed a single revision"
 msgstr "Se necesitó una revisión singular"
 
@@ -11283,7 +11414,7 @@ msgid "keep redundant, empty commits"
 msgstr "mantener commits redundantes, vacíos"
 
 msgid "use the 'reference' format to refer to commits"
-msgstr ""
+msgstr "usar el formato 'de referencia' para referir a los commits"
 
 msgid "revert failed"
 msgstr "falló al revertir"
@@ -11573,9 +11704,8 @@ msgstr "mostrar refs de stdin que no estén en el repositorio local"
 msgid "git sparse-checkout (init|list|set|add|reapply|disable) <options>"
 msgstr "git sparse-checkout (init|list|set|add|reapply|disable) <opciones>"
 
-#, fuzzy
 msgid "this worktree is not sparse"
-msgstr "HEAD del árbol de trabajo %s no está actualizada"
+msgstr "este árbol de trabajo no es escaso"
 
 msgid "this worktree is not sparse (sparse-checkout file may not exist)"
 msgstr ""
@@ -11597,9 +11727,8 @@ msgstr "falló al borrar directorio '%s'"
 msgid "failed to create directory for sparse-checkout file"
 msgstr "falló al crear directorio para el archivo sparse-checkout"
 
-#, fuzzy
 msgid "failed to initialize worktree config"
-msgstr "falló al inicializar sparse-checkout"
+msgstr "falló al inicializar la configuración del árbol de trabajo"
 
 msgid "failed to modify sparse-index config"
 msgstr "falló al modificar la configuración del índice sparse"
@@ -11629,61 +11758,70 @@ msgstr "no es posible dequote la cadena de estilo C '%s'"
 msgid "unable to load existing sparse-checkout patterns"
 msgstr "no se pudo cargar patrones de sparse-checkout existentes"
 
-#, fuzzy
 msgid "existing sparse-checkout patterns do not use cone mode"
-msgstr "no se pudo cargar patrones de sparse-checkout existentes"
+msgstr "los patrones de checkout escaso existentes no usan el modo de cono"
 
 msgid "please run from the toplevel directory in non-cone mode"
-msgstr ""
+msgstr "por favor ejecuta desde el directorio superior en el modo no de cono"
 
 msgid "specify directories rather than patterns (no leading slash)"
-msgstr ""
+msgstr "especificar directorios en vez de patrones (sin slash inicial)"
 
 msgid ""
 "specify directories rather than patterns.  If your directory starts with a "
 "'!', pass --skip-checks"
 msgstr ""
+"especificar directorios en vez de patrones.  Si el directorio comienza con "
+"un '!', se necesita --skip-checks también"
 
 msgid ""
 "specify directories rather than patterns.  If your directory really has any "
 "of '*?[]\\' in it, pass --skip-checks"
 msgstr ""
+"especificar directorios en vez de patrones.  Si el directorio realmente "
+"lleva cualquier de '*?[]\\', se necesita --skip-checks también"
 
 #, c-format
 msgid ""
 "'%s' is not a directory; to treat it as a directory anyway, rerun with --"
 "skip-checks"
 msgstr ""
+"'%s' no es un directorio; para tratarlo como directorio de todas maneras, "
+"ejecuta otra vez con --skip-checks"
 
 #, c-format
 msgid ""
 "pass a leading slash before paths such as '%s' if you want a single file "
 "(see NON-CONE PROBLEMS in the git-sparse-checkout manual)."
 msgstr ""
+"pasa un slash inicial antes de rutas como '%s' si quieres un archivo soltero "
+"(mira NON-CONE PROBLEMS en el manual de git-sparse-checkout)."
 
-#, fuzzy
 msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
-msgstr "git sparse-checkout (set|add) (--stdin | <patrones>)"
+msgstr "git sparse-checkout add [--skip-checks] (--stdin | <patrones>)"
 
 msgid ""
 "skip some sanity checks on the given paths that might give false positives"
 msgstr ""
+"saltar algunas pruebas de sensatez en las rutas proporcionadas que podrían "
+"resultar en positivos falsos"
 
 msgid "read patterns from standard in"
 msgstr "leer patrones de standard in"
 
-#, fuzzy
 msgid "no sparse-checkout to add to"
-msgstr "git sparse-checkout list"
+msgstr "no hay checkout escaso a que añadir"
 
-#, fuzzy
 msgid ""
 "git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
 "(--stdin | <patterns>)"
-msgstr "git sparse-checkout init [--cone] [--[no-]sparse-index]"
+msgstr ""
+"git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
+"(--stdin | <patrones>)"
 
 msgid "must be in a sparse-checkout to reapply sparsity patterns"
 msgstr ""
+"hay que estar en un checkout escaso para volver a aplicar patrones de escasez"
 
 msgid "error while refreshing working directory"
 msgstr "error al refrescar directorio de trabajo"
@@ -11703,7 +11841,6 @@ msgstr "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
 msgid "git stash branch <branchname> [<stash>]"
 msgstr "git stash branch <nombre-de-rama> [<stash>]"
 
-#, fuzzy
 msgid ""
 "git stash [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
 "quiet]\n"
@@ -11711,18 +11848,19 @@ msgid ""
 "          [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
 "          [--] [<pathspec>...]]"
 msgstr ""
-"git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
+"git stash [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
+"quiet]\n"
 "          [-u|--include-untracked] [-a|--all] [-m|--message <mensaje>]\n"
 "          [--pathspec-from-file=<archivo> [--pathspec-file-nul]]\n"
 "          [--] [<pathspec>...]]"
 
-#, fuzzy
 msgid ""
 "git stash save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
 "quiet]\n"
 "          [-u|--include-untracked] [-a|--all] [<message>]"
 msgstr ""
-"git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
+"git stash save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
+"quiet]\n"
 "          [-u|--include-untracked] [-a|--all] [<mensaje>]"
 
 msgid "git stash pop [--index] [-q|--quiet] [<stash>]"
@@ -11845,9 +11983,8 @@ msgstr "mensaje de stash"
 msgid "\"git stash store\" requires one <commit> argument"
 msgstr "\"git stash store\" requiere un argumento <commit>"
 
-#, fuzzy
 msgid "No staged changes"
-msgstr "Sin cambios"
+msgstr "No hay cambios en stage"
 
 msgid "No changes selected"
 msgstr "Sin cambios seleccionados"
@@ -11864,9 +12001,8 @@ msgstr "No se pueden guardar los archivos no rastreados"
 msgid "Cannot save the current worktree state"
 msgstr "No se puede guardar el estado actual del árbol de trabajo"
 
-#, fuzzy
 msgid "Cannot save the current staged state"
-msgstr "No se puede guardar el estado actual del índice"
+msgstr "No se puede guardar el estado actualmente en stage"
 
 msgid "Cannot record working tree state"
 msgstr "No se puede grabar el estado del árbol de trabajo"
@@ -11874,9 +12010,9 @@ msgstr "No se puede grabar el estado del árbol de trabajo"
 msgid "Can't use --patch and --include-untracked or --all at the same time"
 msgstr "No se puede usar --patch y --include-untracked o --all al mismo tiempo"
 
-#, fuzzy
 msgid "Can't use --staged and --include-untracked or --all at the same time"
-msgstr "No se puede usar --patch y --include-untracked o --all al mismo tiempo"
+msgstr ""
+"No se puede usar --staged y --include-untracked o --all al mismo tiempo"
 
 msgid "Did you forget to 'git add'?"
 msgstr "¿Olvidaste 'git add'?"
@@ -11901,7 +12037,7 @@ msgid "keep index"
 msgstr "mantener index"
 
 msgid "stash staged changes only"
-msgstr ""
+msgstr "hacer stash a solo los cambios en stage"
 
 msgid "stash in patch mode"
 msgstr "stash en modo patch"
@@ -11926,6 +12062,10 @@ msgstr "anteponer carácter de comentario y espacio a cada línea"
 msgid "Expecting a full ref name, got %s"
 msgstr "Se esperaba un nombre de ref completo, se obtuvo %s"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "no se pudo conseguir un handle de repositorio para el submódulo '%s'"
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -11934,12 +12074,6 @@ msgstr ""
 "no se pudo encontrar configuración '%s'. Asumiendo que este repositorio es "
 "su propio upstream autoritario."
 
-msgid "alternative anchor for relative paths"
-msgstr "ancho alternativo para rutas relativas"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<ruta>] [<ruta>...]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "No se encontró url para la ruta del submódulo '%s' en .gitmodules"
@@ -11972,12 +12106,12 @@ msgstr "suprime la salida de inicializar cada comando de submódulo"
 msgid "recurse into nested submodules"
 msgstr "recursar en submódulos anidados"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <comando>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <comando>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
-msgstr "Falló al registrar el url para la ruta del submódulo '%s'"
+msgstr "Falló al registrar el url para la ruta de submódulo '%s'"
 
 #, c-format
 msgid "Submodule '%s' (%s) registered for path '%s'\n"
@@ -11986,7 +12120,8 @@ msgstr "Submódulo '%s' (%s) registrado para ruta '%s'\n"
 #, c-format
 msgid "warning: command update mode suggested for submodule '%s'\n"
 msgstr ""
-"peligro: modo de actualización de comandos sugerido para el submódulo '%s'\n"
+"advertencia: modo de actualización de comandos sugerido para el submódulo "
+"'%s'\n"
 
 #, c-format
 msgid "Failed to register update mode for submodule path '%s'"
@@ -11996,8 +12131,8 @@ msgstr ""
 msgid "suppress output for initializing a submodule"
 msgstr "suprime la salida de inicializar un submódulo"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<opciones>] [<path>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<opciones>] [<ruta>]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -12025,9 +12160,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<ruta>...]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <ruta>"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(blob)->%s(submodule)"
@@ -12064,8 +12196,8 @@ msgstr "omitir submódulos con el valor 'ignore_config' establecido en 'all'"
 msgid "limit the summary size"
 msgstr "limitar el tamaño de resumen"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<opciones>] [<commit>] [--] [<ruta>]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "no se puede obtener la revisión para HEAD"
@@ -12076,29 +12208,25 @@ msgstr "Sincronizando url del submódulo para '%s'\n"
 
 #, c-format
 msgid "failed to register url for submodule path '%s'"
-msgstr "falló al registrar el url para la ruta del submódulo '%s'"
-
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "error al conseguir el remoto por defecto para el submódulo '%s'"
+msgstr "falló al registrar el url para la ruta de submódulo '%s'"
 
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "error al actualizar el remoto para el submódulo '%s'"
 
 msgid "suppress output of synchronizing submodule url"
-msgstr "suprime la salida de sincronizar el url del submódulo"
+msgstr "suprimir la salida de sincronizar el url del submódulo"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<ruta>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<ruta>]"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Submodule work tree '%s' contains a .git directory. This will be replaced "
 "with a .git file by using absorbgitdirs."
 msgstr ""
-"El árbol de trabajo de submódulo '%s' contiene un directorio .git (usa 'rm -"
-"rf' si realmente quieres eliminarlo incluyendo todo en su historia)"
+"El árbol de trabajo de submódulo '%s' contiene un directorio .git. Este será "
+"reemplazado con un archivo .git usando absorbgitdirs."
 
 #, c-format
 msgid ""
@@ -12152,6 +12280,11 @@ msgstr ""
 "con\n"
 "'--reference-if-able' en lugar de '--reference'."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr ""
+"no se pudo conseguir un handle de repositorio para el directorio de git '%s'"
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "submódulo '%s' no puede agregar alterno: %s"
@@ -12180,6 +12313,9 @@ msgstr "directorio no está vacío: '%s'"
 msgid "could not get submodule directory for '%s'"
 msgstr "no se pudo obtener el directorio de submódulo para '%s'"
 
+msgid "alternative anchor for relative paths"
+msgstr "ancla alternativa para rutas relativas"
+
 msgid "where the new submodule will be cloned to"
 msgstr "a donde el nuevo submódulo será clonado"
 
@@ -12198,19 +12334,14 @@ msgstr "forzar el proceso de clonación"
 msgid "disallow cloning into non-empty directory"
 msgstr "no permitir clonar en directorios no vacíos"
 
-#, fuzzy
 msgid ""
 "git submodule--helper clone [--prefix=<path>] [--quiet] [--reference "
 "<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
 "<filter-spec>] --url <url> --path <path>"
 msgstr ""
 "git submodule--helper clone [--prefix=<ruta>] [--quiet] [--reference "
-"<repositorio>] [--name <nombre>] [--depth <profundidad>] [--single-branch] --"
-"url <url> --path <ruta>"
-
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Modo de actualización inválido '%s' para ruta de submódulo '%s'"
+"<repositorio>] [--name <nombre>] [--depth <profundidad>] [--single-branch] "
+"[--filter <especificación-de-filtro>] --url <url> --path <ruta>"
 
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
@@ -12286,6 +12417,10 @@ msgstr ""
 "Fetch realizado en la ruta de submódulo '%s', pero no contenía %s. Fetch "
 "directo del commit falló."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "no se pudo inicializar el submódulo a la ruta '%s'"
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12295,42 +12430,32 @@ msgstr ""
 "el superproyecto no está en ninguna rama"
 
 #, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "no se pudo conseguir un handle de repositorio para el submódulo '%s'"
-
-#, fuzzy, c-format
 msgid "Unable to find current revision in submodule path '%s'"
-msgstr ""
-"No se pudo encontrar la revisión actual en la ruta de submódulo "
-"'$displaypath'"
+msgstr "Incapaz de encontrar la revisión actual en la ruta de submódulo '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Unable to fetch in submodule path '%s'"
-msgstr "No es posible realizar fetch en la ruta de submódulo '$sm_path'"
+msgstr "Incapaz de realizar fetch en la ruta de submódulo '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Unable to find %s revision in submodule path '%s'"
-msgstr ""
-"No se pudo encontrar la revisión actual en la ruta de submódulo "
-"'$displaypath'"
+msgstr "Incapaz de encontrar la revisión %s en la ruta de submódulo '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to recurse into submodule path '%s'"
-msgstr "falló al recursar en el submódulo '%s'"
+msgstr "Falló al recursar en la ruta de submódulo '%s'"
 
 msgid "force checkout updates"
 msgstr "forzar actualizaciones de checkout"
 
-#, fuzzy
 msgid "initialize uninitialized submodules before update"
-msgstr "inicializar submódulos en el clon"
+msgstr "inicializar submódulos no inicializados antes de actualizar"
 
-#, fuzzy
 msgid "use SHA-1 of submodule's remote tracking branch"
-msgstr "cualquier submódulo clonado usará su branch de rastreo remoto"
+msgstr "usar el SHA-1 de la rama remota que el submódulo rastrea"
 
 msgid "traverse submodules recursively"
-msgstr ""
+msgstr "atravesar los submódulos recursivamente"
 
 msgid "don't fetch new objects from the remote site"
 msgstr "no recuperar objetos nuevos del sitio remoto"
@@ -12338,11 +12463,14 @@ msgstr "no recuperar objetos nuevos del sitio remoto"
 msgid "path into the working tree"
 msgstr "ruta al árbol de trabajo"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "ruta al árbol de trabajo, a través de fronteras de submódulos anidados"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "usar la estrategia de actualización 'checkout' (por defecto)"
+
+msgid "use the 'merge' update strategy"
+msgstr "usar la estrategia de actualización 'merge'"
 
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout o none"
+msgid "use the 'rebase' update strategy"
+msgstr "usar la estrategia de actualización 'rebase'"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "crea un clon superficial truncado al número especificado de revisiones"
@@ -12356,21 +12484,25 @@ msgstr "si el clon inicial debe seguir la recomendación de superficialidad"
 msgid "don't print cloning progress"
 msgstr "no mostrar el progreso de clonación"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "no permitir clonar en directorios no vacíos, implica --init"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
 "shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
 "[--] [<path>...]"
 msgstr ""
-
-msgid "bad value for update parameter"
-msgstr "mal valor para parámetro update"
+"git submodule [--quiet] update [--init [--filter=<especificación-de-"
+"filtro>]] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--"
+"rebase] [--[no-]recommend-shallow] [--reference <repositorio>] [--recursive] "
+"[--[no-]single-branch] [--] [<ruta>...]"
 
 msgid "recurse into submodules"
 msgstr "recurrir a submódulos"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<opciones>] [<path>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<opciones>] [<ruta>...]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr "revisar si es seguro escribir al archivo .gitmodules"
@@ -12391,8 +12523,8 @@ msgstr ""
 msgid "suppress output for setting url of a submodule"
 msgstr "suprime la salida de inicializar la url de un submódulo"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <ruta> <nueva url>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <ruta> <url-nuevo>"
 
 msgid "set the default tracking branch to master"
 msgstr "configurar la rama de rastreo por defecto a master"
@@ -12400,13 +12532,11 @@ msgstr "configurar la rama de rastreo por defecto a master"
 msgid "set the default tracking branch"
 msgstr "configurar la rama de rastreo por defecto"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <ruta>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <ruta>"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <rama> <ruta>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <rama> <ruta>"
 
 msgid "--branch or --default required"
 msgstr "--branch o --default requerido"
@@ -12415,20 +12545,21 @@ msgid "print only error messages"
 msgstr "mostrar solo mensajes de error"
 
 msgid "force creation"
-msgstr ""
+msgstr "forzar creación"
 
-#, fuzzy
 msgid "show whether the branch would be created"
-msgstr "mostrar lo que sería incluido en el commit"
+msgstr "mostrar si la rama sería creada"
 
 msgid ""
 "git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
 "quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"
 msgstr ""
+"git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--"
+"quiet] [-t|--track] [-n|--dry-run] <nombre> <oid-inicial> <nombre-inicial>"
 
-#, fuzzy, c-format
+#, c-format
 msgid "creating branch '%s'"
-msgstr "Reiniciar rama '%s'\n"
+msgstr "creando la rama '%s'"
 
 #, c-format
 msgid "Adding existing repo at '%s' to the index\n"
@@ -12497,16 +12628,15 @@ msgstr "permitir agregar una ruta de submódulo que de otro modo se ignora"
 msgid "borrow the objects from reference repositories"
 msgstr "prestar los objetos de los repositorios de referencia"
 
-#, fuzzy
 msgid ""
 "sets the submodule's name to the given string instead of defaulting to its "
 "path"
 msgstr ""
-"configura el nombre del submódulo para el string dado en lugar de ir a la "
-"ruta por defecto"
+"configura el nombre del submódulo a la cadena proporcionada en lugar de usar "
+"por defecto la ruta suya"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<options>] [--] <repository> [<path>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<opciones>] [--] <repositorio> [<ruta>]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
@@ -12690,9 +12820,9 @@ msgstr "solo imprimir las tags que no estén fusionadas"
 msgid "print only tags of the object"
 msgstr "solo imprimir tags del objeto"
 
-#, fuzzy, c-format
+#, c-format
 msgid "the '%s' option is only allowed in list mode"
-msgstr "opción -n solo es permitida en modo lista"
+msgstr "la opción '%s' solo es permitida en el modo de lista"
 
 #, c-format
 msgid "'%s' is not a valid tag name."
@@ -12713,6 +12843,16 @@ msgstr "Etiqueta '%s' actualizada (era %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "paquete excede el máximo tamaño permitido"
 
+msgid "failed to write object in stream"
+msgstr "falló al escribir objeto al stream"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "inflate devolvió (%d)"
+
+msgid "invalid blob object from stream"
+msgstr "objeto blob inválido del stream"
+
 msgid "Unpacking objects"
 msgstr "Desempaquetando objetos"
 
@@ -13000,9 +13140,8 @@ msgstr "git worktree prune [<opciones>]"
 msgid "git worktree remove [<options>] <worktree>"
 msgstr "git worktree remove [<opciones>] <worktree>"
 
-#, fuzzy
 msgid "git worktree repair [<path>...]"
-msgstr "git worktree prune [<opciones>]"
+msgstr "git worktree repair [<ruta>...]"
 
 msgid "git worktree unlock <path>"
 msgstr "git worktree unlock <ruta>"
@@ -13045,14 +13184,16 @@ msgstr ""
 #, c-format
 msgid "failed to copy '%s' to '%s'; sparse-checkout may not work correctly"
 msgstr ""
+"falló al copiar '%s' a '%s'; puede que el checkout escaso no funcione "
+"correctamente"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to copy worktree config from '%s' to '%s'"
-msgstr "falló al copiar notas de '%s' a '%s'"
+msgstr "falló al copiar la configuración del árbol de trabajo de '%s' a '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "failed to unset '%s' in '%s'"
-msgstr "falló al mover '%s' a '%s'"
+msgstr "falló al desconfigurar '%s' en '%s'"
 
 #, c-format
 msgid "could not create directory of '%s'"
@@ -13104,9 +13245,9 @@ msgid "try to match the new branch name with a remote-tracking branch"
 msgstr ""
 "intentar emparejar el nuevo nombre de rama con una rama de rastreo remoto"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s', '%s', and '%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '%s', '%s' y '%s' no pueden ser usadas juntas"
 
 msgid "added with --lock"
 msgstr "agregado con --lock"
@@ -13121,9 +13262,8 @@ msgid "add 'prunable' annotation to worktrees older than <time>"
 msgstr ""
 "agregar la anotación 'podable' a los árboles de trabajo anteriores a <tiempo>"
 
-#, fuzzy
 msgid "terminate records with a NUL character"
-msgstr "terminar registros de entrada y salida con un carácter NUL"
+msgstr "terminar registros con un carácter NUL"
 
 #, c-format
 msgid "'%s' is not a working tree"
@@ -13238,6 +13378,27 @@ msgstr "escribir objeto de árbol para un subdirectorio <prefijo>"
 msgid "only useful for debugging"
 msgstr "solo útil para depurar"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch no es soportado en este plataforma"
+
+msgid "failed to create temporary file"
+msgstr "falló al crear archivo temporal"
+
+msgid "insufficient capabilities"
+msgstr "capacidades insuficientes"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "falló al descargar bundle del URI '%s'"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "el archivo al URI '%s' no es un bundle"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "falló al extraer bundle del URI '%s'"
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "algoritmo bundle hash desconocido %s"
@@ -13260,20 +13421,20 @@ msgstr "Al repositorio le faltan estos commits prerrequisitos:"
 msgid "need a repository to verify a bundle"
 msgstr "se necesita un repositorio para verificar un bundle"
 
-#, fuzzy, c-format
+#, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
 msgstr[0] "El bundle contiene esta referencia:"
-msgstr[1] "El bundle contiene estas %d referencias:"
+msgstr[1] "El bundle contiene estas %<PRIuMAX> referencias:"
 
 msgid "The bundle records a complete history."
 msgstr "El bundle registra una historia completa."
 
-#, fuzzy, c-format
+#, c-format
 msgid "The bundle requires this ref:"
 msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "El bundle requiere esta referencia:"
-msgstr[1] "El bundle requiere estas %d referencias:"
+msgstr[1] "El bundle requiere estas %<PRIuMAX> referencias:"
 
 msgid "unable to dup bundle descriptor"
 msgstr "incapaz de duplicar bundle descriptor"
@@ -13445,6 +13606,9 @@ msgstr ""
 "Dar a un objeto un nombre legible por humanos basado en una referencia "
 "disponible"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Generar una crónica zip de información diagnóstica"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "Mostrar los cambios entre commits, commit y árbol de trabajo, etc"
 
@@ -13512,7 +13676,7 @@ msgid "Display help information about Git"
 msgstr "Mostrar información de ayuda sobre Git"
 
 msgid "Run git hooks"
-msgstr ""
+msgstr "Ejecutar hooks de git"
 
 msgid "Server side implementation of Git over HTTP"
 msgstr "Implementación de lado de servidor de Git por HTTP"
@@ -13574,8 +13738,8 @@ msgstr "Ejecutar una fusión para archivos que la necesiten"
 msgid "The standard helper program to use with git-merge-index"
 msgstr "El programa de ayuda estándar para usar con git-merge-index"
 
-msgid "Show three-way merge without touching index"
-msgstr "Mostrar fusión de tres vías sin tocar el índice"
+msgid "Perform merge without touching index or working tree"
+msgstr "Realizar fusión sin tocar el índice o el árbol de trabajo"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
@@ -13709,9 +13873,8 @@ msgstr "Mostrar el índice de crónica empaquetado"
 msgid "List references in a local repository"
 msgstr "Listar referencias en el repositorio local"
 
-#, fuzzy
 msgid "Reduce your working tree to a subset of tracked files"
-msgstr " (usa la opción -u para mostrar los archivos sin seguimiento)"
+msgstr "Reducir el árbol de trabajo a un subconjunto de archivos rastreados"
 
 msgid "Add file contents to the staging area"
 msgstr "Agregar contenidos de un archivo al área de staging"
@@ -13776,6 +13939,9 @@ msgstr "Validar crónicas Git empaquetadas"
 msgid "Check the GPG signature of tags"
 msgstr "Verificar la firma GPG de etiquetas"
 
+msgid "Display version information about Git"
+msgstr "Mostrar información de versión sobre Git"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Mostrar logs con las diferencias que cada commit introduce"
 
@@ -13809,6 +13975,24 @@ msgstr "Un conjunto mínimo útil de comandos cotidianos de Git"
 msgid "Frequently asked questions about using Git"
 msgstr "Preguntas frecuentes sobre el uso de Git"
 
+msgid "The bundle file format"
+msgstr "Formato de archivo de bundle"
+
+msgid "Chunk-based file formats"
+msgstr "Formatos de archivo basados en fragmentos"
+
+msgid "Git commit graph format"
+msgstr "Formato de grafo de commits de Git"
+
+msgid "Git index format"
+msgstr "Formato de índice de Git"
+
+msgid "Git pack format"
+msgstr "Formato de pack de Git"
+
+msgid "Git cryptographic signature formats"
+msgstr "Formatos de firma criptográfica de Git"
+
 msgid "A Git Glossary"
 msgstr "Un Glosario de Git"
 
@@ -13832,6 +14016,21 @@ msgstr "Definir las propiedades de submódulo"
 msgid "Git namespaces"
 msgstr "Namespaces de Git"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Capacidades de los protocolos v0 y v1"
+
+msgid "Things common to various protocols"
+msgstr "Cosas en común entre varios protocolos"
+
+msgid "Git HTTP-based protocols"
+msgstr "Protocolos de Git basados en HTTP"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Cómo los packs se transfieren en el alambre"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Protocolo de alambre de Git, versión 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Programas de ayuda para interactuar con repositorios remotos"
 
@@ -13856,6 +14055,9 @@ msgstr "Interfaz web Git (interfaz web para repositorios Git)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Una visión general de flujos de trabajo recomendados con Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Una herramienta para gestionar repositorios de Git grandes"
+
 msgid "commit-graph file is too small"
 msgstr "archivo commit-graph es demasiado pequeño"
 
@@ -13921,11 +14123,11 @@ msgstr "Calculando números de generación de commit graph"
 msgid "Collecting referenced commits"
 msgstr "Recolectando commits referenciados"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Finding commits for commit graph in %<PRIuMAX> pack"
 msgid_plural "Finding commits for commit graph in %<PRIuMAX> packs"
-msgstr[0] "Encontrando commits para commit graph en %d pack"
-msgstr[1] "Encontrando commits para commit graph en %d packs"
+msgstr[0] "Encontrando commits para el grafo de commits en %<PRIuMAX> pack"
+msgstr[1] "Encontrando commits para el grafo de commits en %<PRIuMAX> packs"
 
 #, c-format
 msgid "error adding pack %s"
@@ -14087,12 +14289,12 @@ msgstr "El commit %s tiene una buena firma GPG por %s\n"
 msgid ""
 "Warning: commit message did not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
-"variable i18n.commitencoding to the encoding your project uses.\n"
+"variable i18n.commitEncoding to the encoding your project uses.\n"
 msgstr ""
-"Peligro: el mensaje del commit no se ajusta a UTF-8.\n"
+"Advertencia: el mensaje del commit no se ajusta a UTF-8.\n"
 "Tal vez quieras enmendarlo después de arreglar el mensaje, o arreglar la\n"
-"variable de configuración i18n.commitencoding para la codificación que use "
-"tu proyecto.\n"
+"variable de configuración i18n.commitEncoding para la codificación que el "
+"proyecto use.\n"
 
 msgid "no compiler information available\n"
 msgstr "no hay información disponible del compilador\n"
@@ -14100,138 +14302,140 @@ msgstr "no hay información disponible del compilador\n"
 msgid "no libc information available\n"
 msgstr "no hay información disponible de libc\n"
 
-#, fuzzy, c-format
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "no se pudo determinar el espacio de disco libre de '%s'"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "no se pudo averiguar la información de '%s'"
+
+#, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
-msgstr "no se pudo abrir '%s'"
+msgstr "[GLE %ld] el hilo de salud no pudo abrir '%ls'"
 
 #, c-format
 msgid "[GLE %ld] health thread getting BHFI for '%ls'"
-msgstr ""
+msgstr "[GLE %ld] hilo de salud averiguando BHFI de '%ls'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not convert to wide characters: '%s'"
-msgstr ""
-"no se pudo convertir el siguiente graft(s):\n"
-"%s"
+msgstr "no se pudo convertir a caracteres anchos: '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "BHFI changed '%ls'"
-msgstr "no se puede cambiar a '%s'"
+msgstr "BHFI cambió '%ls'"
 
 #, c-format
 msgid "unhandled case in 'has_worktree_moved': %d"
-msgstr ""
+msgstr "caso no manejado en 'has_worktree_moved': %d"
 
 #, c-format
 msgid "health thread wait failed [GLE %ld]"
-msgstr ""
+msgstr "falló la espera del hilo de salud [GLE %ld]"
 
-#, fuzzy
 msgid "Unable to create FSEventStream."
-msgstr "no es posible crear hilo: %s"
+msgstr "Incapaz de crear FSEventStream."
 
-#, fuzzy
 msgid "Failed to start the FSEventStream"
-msgstr "Falló al iniciar emacsclient."
+msgstr "Falló al iniciar el FSEventStream"
 
 #, c-format
 msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
-msgstr ""
+msgstr "[GLE %ld] no se pudo convertir la ruta a UTF-8: '%.*ls'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "[GLE %ld] could not watch '%s'"
-msgstr "no se pudo hacer stat en '%s'"
+msgstr "[GLE %ld] no se pudo vigilar '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "[GLE %ld] could not get longname of '%s'"
-msgstr "no se pudo conseguir 'onto': '%s'"
+msgstr "[GLE %ld] no se pudo averiguar el nombre largo de '%s'"
 
 #, c-format
 msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "Falló ReadDirectoryChangedW en '%s' [GLE %ld]"
 
 #, c-format
 msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "Falló GetOverlappedResult en '%s' [GLE %ld]"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not read directory changes [GLE %ld]"
-msgstr "no se pudo crear directorios para %s"
+msgstr "no se pudo leer los cambios de directorio [GLE %ld]"
 
-#, fuzzy, c-format
-msgid "failed to copy SID (%ld)"
-msgstr "falló al copiar archivo a '%s'"
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] incapaz de abrir para leer '%ls'"
 
-#, fuzzy, c-format
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] incapaz de averiguar la información de protocolo de '%ls'"
+
+#, c-format
+msgid "failed to copy SID (%ld)"
+msgstr "falló al copiar SID (%ld)"
+
+#, c-format
 msgid "failed to get owner for '%s' (%ld)"
-msgstr "falló al iterar sobre '%s'"
+msgstr "falló al averiguar el propietario de '%s' (%ld)"
 
 msgid "memory exhausted"
 msgstr "memoria agotada"
 
 msgid "Success"
-msgstr ""
+msgstr "Éxito"
 
 msgid "No match"
-msgstr ""
+msgstr "Ninguna coincidencia"
 
-#, fuzzy
 msgid "Invalid regular expression"
-msgstr "usar expresiones regulares POSIX extendidas"
+msgstr "Expresión regular inválida"
 
-#, fuzzy
 msgid "Invalid collation character"
-msgstr "carácter lastre"
+msgstr "Carácter de colación inválido"
 
-#, fuzzy
 msgid "Invalid character class name"
-msgstr "carácter inválido en el nombre del host"
+msgstr "Nombre de clase de carácter inválido"
 
 msgid "Trailing backslash"
-msgstr ""
+msgstr "Backslash al final"
 
-#, fuzzy
 msgid "Invalid back reference"
-msgstr "referencia inválida: %s"
+msgstr "Referencia atrás inválida"
 
 msgid "Unmatched [ or [^"
-msgstr ""
+msgstr "[ o [^ sin pareja"
 
 msgid "Unmatched ( or \\("
-msgstr ""
+msgstr "( o \\( sin pareja"
 
 msgid "Unmatched \\{"
-msgstr ""
+msgstr "\\{ sin pareja"
 
-#, fuzzy
 msgid "Invalid content of \\{\\}"
-msgstr "contenido inválido: '%s'"
+msgstr "Contenido inválido de \\{\\}"
 
-#, fuzzy
 msgid "Invalid range end"
-msgstr "codificación de transferencia inválida"
+msgstr "Fin inválido de rango"
 
-#, fuzzy
 msgid "Memory exhausted"
-msgstr "memoria agotada"
+msgstr "Memoria agotada"
 
-#, fuzzy
 msgid "Invalid preceding regular expression"
-msgstr "usar expresiones regulares POSIX extendidas"
+msgstr "Expresión regular precedente inválida"
 
-#, fuzzy
 msgid "Premature end of regular expression"
-msgstr "usar expresiones regulares POSIX extendidas"
+msgstr "Fin prematuro de expresión regular"
 
 msgid "Regular expression too big"
-msgstr ""
+msgstr "Expresión regular demasiada larga"
 
 msgid "Unmatched ) or \\)"
-msgstr ""
+msgstr ") o \\) sin pareja"
 
-#, fuzzy
 msgid "No previous regular expression"
-msgstr "usar expresiones regulares compatibles con Perl"
+msgstr "No hay expresión regular previa"
 
 msgid "could not send IPC command"
 msgstr "no se pudo enviar el comando IPC"
@@ -14247,28 +14451,27 @@ msgstr "no se pudo iniciar el accept_thread '%s'"
 msgid "could not start worker[0] for '%s'"
 msgstr "no se pudo iniciar el worker[0] para '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "ConnectNamedPipe failed for '%s' (%lu)"
-msgstr "uname() falló con error '%s' (%d)\n"
+msgstr "ConnectNamedPipe falló en '%s' (%lu)"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not create fd from pipe for '%s'"
-msgstr "no se pudo crear directorios para %s"
+msgstr "no se pudo crear descriptor de archivo del pipe para '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not start thread[0] for '%s'"
-msgstr "no se pudo iniciar el worker[0] para '%s'"
+msgstr "no se pudo iniciar thread[0] para '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "wait for hEvent failed for '%s'"
-msgstr "Autenticación falló para '%s'"
+msgstr "espera de hEvent falló en '%s'"
 
 msgid "cannot resume in the background, please use 'fg' to resume"
-msgstr ""
+msgstr "no se puede resumir en el fondo, por favor usa 'fg' para resumir"
 
-#, fuzzy
 msgid "cannot restore terminal settings"
-msgstr "no se puede guardar el archivo índice"
+msgstr "no se puede restaurar la configuración de terminal"
 
 #, c-format
 msgid ""
@@ -14299,6 +14502,8 @@ msgid ""
 "remote URLs cannot be configured in file directly or indirectly included by "
 "includeIf.hasconfig:remote.*.url"
 msgstr ""
+"no se pueden configurar URLs remotos en archivo incluido directa o "
+"indirectamente por includeIf.hasconfig:remote.*.url"
 
 #, c-format
 msgid "invalid config format: %s"
@@ -14415,13 +14620,13 @@ msgstr ""
 msgid "bad numeric config value '%s' for '%s' in %s: %s"
 msgstr "mal valor de config numérico '%s' para '%s' en %s: %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "invalid value for variable %s"
-msgstr "valor inválido para %s"
+msgstr "valor inválido para la variable %s"
 
 #, c-format
 msgid "ignoring unknown core.fsync component '%s'"
-msgstr ""
+msgstr "ignorando componente desconocido de core.fsync '%s'"
 
 #, c-format
 msgid "bad boolean config value '%s' for '%s'"
@@ -14448,10 +14653,10 @@ msgstr "core.commentChar debería tener solo un carácter"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
-msgstr ""
+msgstr "ignorando valor desconocido de core.fsyncMethod '%s'"
 
 msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
-msgstr ""
+msgstr "core.fsyncObjectFiles es deprecado; usa core.fsync en su lugar"
 
 #, c-format
 msgid "invalid mode for object creation: %s"
@@ -14707,190 +14912,6 @@ msgstr "falló escribir a rev-list"
 msgid "failed to close rev-list's stdin"
 msgstr "falló al cerrar la entrada standard de rev-list"
 
-#, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' no existe"
-
-#, fuzzy
-msgid "need a working directory"
-msgstr "Incapaz de leer el directorio de trabajo actual"
-
-#, fuzzy
-msgid "could not find enlistment root"
-msgstr "no se pudo encontrar commit %s"
-
-#, fuzzy, c-format
-msgid "could not switch to '%s'"
-msgstr "no se pudo cambiar a %s"
-
-#, fuzzy, c-format
-msgid "could not configure %s=%s"
-msgstr "no se pudo bloquear archivo de configuración %s"
-
-msgid "could not configure log.excludeDecoration"
-msgstr ""
-
-msgid "Scalar enlistments require a worktree"
-msgstr ""
-
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "no se pudo abrir el directorio '%s'"
-
-#, fuzzy, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "destino '%s' no es un directorio"
-
-#, fuzzy, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "no se pudo crear un árbol de trabajo '%s'"
-
-#, fuzzy, c-format
-msgid "could not get info for '%s'"
-msgstr "no se pudo leer el log para '%s'"
-
-#, fuzzy, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "  Rama HEAD: %s"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-
-#, fuzzy
-msgid "failed to get default branch name"
-msgstr "falló al formatear el valor por defecto de configuración: %s"
-
-#, fuzzy
-msgid "failed to unregister repository"
-msgstr "falló al crear directorio %s"
-
-#, fuzzy
-msgid "failed to delete enlistment directory"
-msgstr "falló al eliminar directorio %s"
-
-msgid "branch to checkout after clone"
-msgstr ""
-
-#, fuzzy
-msgid "when cloning, create full working directory"
-msgstr "no es posible obtener el directorio de trabajo actual"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr ""
-
-#, fuzzy
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "git clone [<opciones>] [--] <repo> [<directorio>]"
-
-#, fuzzy, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "No se puede acceder al árbol de trabajo '%s'"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "error al conseguir el remoto por defecto para el submódulo '%s'"
-
-#, fuzzy, c-format
-msgid "could not configure remote in '%s'"
-msgstr "no se pudo crear el archivo '%s'"
-
-#, fuzzy, c-format
-msgid "could not configure '%s'"
-msgstr "no se pudo cerrar '%s'"
-
-msgid "partial clone failed; attempting full clone"
-msgstr ""
-
-#, fuzzy
-msgid "could not configure for full clone"
-msgstr "no se pudo bloquear archivo de configuración %s"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "could not create directory for '%s'"
-msgstr "No se pudo crear el directorio para '%s'"
-
-#, fuzzy
-msgid "could not duplicate stdout"
-msgstr "no se puede actualizar %s"
-
-#, fuzzy
-msgid "failed to write archive"
-msgstr "falló al leer la cache"
-
-#, fuzzy
-msgid "`scalar list` does not take arguments"
-msgstr "%%(rest) no toma ningún argumento"
-
-msgid "scalar register [<enlistment>]"
-msgstr ""
-
-msgid "reconfigure all registered enlistments"
-msgstr ""
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr ""
-
-msgid "--all or <enlistment>, but not both"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "git repository gone in '%s'"
-msgstr "no es un repositorio git: '%s'"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "no such task: '%s'"
-msgstr "no existe tal rama: '%s'"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr ""
-
-msgid "scalar delete <enlistment>"
-msgstr ""
-
-#, fuzzy
-msgid "refusing to delete current working directory"
-msgstr "no es posible obtener el directorio de trabajo actual"
-
-#, fuzzy
-msgid "include Git version"
-msgstr "versión de hash inválida"
-
-msgid "include Git's build options"
-msgstr ""
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr ""
-
-#, fuzzy
-msgid "-C requires a <directory>"
-msgstr "--stdin requiere un repositorio git"
-
-#, fuzzy, c-format
-msgid "could not change to '%s'"
-msgstr "no se puede cambiar a '%s'"
-
-#, fuzzy
-msgid "-c requires a <key>=<value> argument"
-msgstr "-n requiere un argumento"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-
 #, c-format
 msgid "illegal crlf_action %d"
 msgstr "crlf_action %d ilegal"
@@ -14904,6 +14925,8 @@ msgid ""
 "in the working copy of '%s', CRLF will be replaced by LF the next time Git "
 "touches it"
 msgstr ""
+"en la copia de trabajo de '%s', CRLF será reemplazado con LF la próxima vez "
+"que Git la toque"
 
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
@@ -14914,6 +14937,8 @@ msgid ""
 "in the working copy of '%s', LF will be replaced by CRLF the next time Git "
 "touches it"
 msgstr ""
+"en la copia de trabajo de '%s', LF será reemplazado con CRLF la próxima vez "
+"que Git la toque"
 
 #, c-format
 msgid "BOM is prohibited in '%s' if encoded as %s"
@@ -15092,6 +15117,32 @@ msgstr "regex isla de config tiene demasiados grupos de captura (max=%d)"
 msgid "Marked %d islands, done.\n"
 msgstr "%d islas marcadas, listo.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "valor de --%s inválido '%s'"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "no se pudo archivar el directorio faltante '%s'"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "no se pudo abrir el directorio '%s'"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "saltando '%s', el cual no es ni archivo ni directorio"
+
+msgid "could not duplicate stdout"
+msgstr "no se pudo duplicar stdout"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "no se pudo añadir el directorio '%s' al cronista"
+
+msgid "failed to write archive"
+msgstr "falló al escribir crónica"
+
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base no funciona con rangos"
 
@@ -15165,18 +15216,21 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "diff externo murió, deteniendo en %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
-msgstr "Opciones --squash y --fixup no pueden ser usadas juntas"
+msgstr "las opciones '%s', '%s', '%s' y '%s' no pueden ser usadas juntas"
 
-#, fuzzy, c-format
+#, c-format
 msgid "options '%s' and '%s' cannot be used together, use '%s' with '%s'"
-msgstr "'%s' o '%s' no puede ser usado con %s"
+msgstr ""
+"las opciones '%s' y '%s' no pueden ser usadas juntas, usa '%s' con '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
-msgstr "'%s' o '%s' no puede ser usado con %s"
+msgstr ""
+"las opciones '%s' y '%s' no pueden ser usadas juntas, usa '%s' con '%s' y "
+"'%s'"
 
 msgid "--follow requires exactly one pathspec"
 msgstr "--follow requiere exactamente un pathspec"
@@ -15596,9 +15650,8 @@ msgstr "seleccionar archivos por tipo de diff"
 msgid "<file>"
 msgstr "<archivo>"
 
-#, fuzzy
 msgid "output to a specific file"
-msgstr "Output a un archivo específico"
+msgstr "emitir a un archivo específico"
 
 msgid "exhaustive rename detection was skipped due to too many files."
 msgstr ""
@@ -15714,6 +15767,9 @@ msgstr "git fetch-pack: se esperaba ACK/NAK, se obtuvo '%s'"
 msgid "unable to write to remote"
 msgstr "no se puede escribir al remoto"
 
+msgid "Server supports filter"
+msgstr "El servidor soporta filtración"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "línea shallow inválida: %s"
@@ -15824,9 +15880,6 @@ msgstr "el servidor no soporta el algoritmo '%s'"
 msgid "Server does not support shallow requests"
 msgstr "El servidor no soporta peticiones superficiales"
 
-msgid "Server supports filter"
-msgstr "El servidor soporta filtración"
-
 msgid "unable to write request to remote"
 msgstr "no se puede escribir request al remoto"
 
@@ -15834,9 +15887,9 @@ msgstr "no se puede escribir request al remoto"
 msgid "expected '%s', received '%s'"
 msgstr "se esperaba '%s', se recibió '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "expected '%s'"
-msgstr "línea inesperada: '%s'"
+msgstr "se esperó '%s'"
 
 #, c-format
 msgid "unexpected acknowledgment line: '%s'"
@@ -15849,16 +15902,17 @@ msgstr "error al procesar acks: %d"
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "expected packfile to be sent after '%s'"
-msgstr "se esperaba que el packfile fuera enviado luego del 'listo'"
+msgstr "se esperaba que el archivo de pack fuera enviado luego del '%s'"
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "expected no other sections to be sent after no '%s'"
-msgstr "se esperaba que ninguna otra sección fuera enviada luego del 'listo'"
+msgstr ""
+"se esperaba que ninguna otra sección fuera enviada luego de la falta de '%s'"
 
 #, c-format
 msgid "error processing shallow info: %d"
@@ -15895,41 +15949,42 @@ msgstr "El servidor no permite solicitudes de objetos inadvertidos %s"
 
 #, c-format
 msgid "fsmonitor_ipc__send_query: invalid path '%s'"
-msgstr ""
+msgstr "fsmonitor_ipc__send_query: ruta inválida '%s'"
 
 #, c-format
 msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
-msgstr ""
+msgstr "fsmonitor_ipc__send_query: error no especificado en '%s'"
 
 msgid "fsmonitor--daemon is not running"
-msgstr ""
+msgstr "fsmonitor--daemon no está ejecutándose"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not send '%s' command to fsmonitor--daemon"
-msgstr "no se pudo enviar el comando IPC"
+msgstr "no se pudo enviar el comando '%s' a fsmonitor--daemon"
 
-#, fuzzy, c-format
+#, c-format
 msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr "%s es incompatible con %s"
+msgstr "el repositorio desnudo '%s es incompatible con fsmonitor"
 
 #, c-format
 msgid "repository '%s' is incompatible with fsmonitor due to errors"
-msgstr ""
+msgstr "el repositorio '%s' es incompatible con fsmonitor a causa de errores"
 
-#, fuzzy, c-format
+#, c-format
 msgid "remote repository '%s' is incompatible with fsmonitor"
-msgstr "%s es incompatible con %s"
+msgstr "el repositorio remoto '%s' es incompatible con fsmonitor"
 
-#, fuzzy, c-format
+#, c-format
 msgid "virtual repository '%s' is incompatible with fsmonitor"
-msgstr "%s es incompatible con %s"
+msgstr "el repositorio virtual '%s' es incompatible con fsmonitor"
 
 #, c-format
 msgid ""
 "repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"
 msgstr ""
+"el repositorio '%s' es incompatible con fsmonitor a causa de falta de "
+"sockets de Unix"
 
-#, fuzzy
 msgid ""
 "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
@@ -15939,14 +15994,14 @@ msgid ""
 "           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
 "           <command> [<args>]"
 msgstr ""
-"git [--version] [--help] [-C <ruta>] [-c <nombre>=<valor>]\n"
-"            [--exec-path [= <path>]] [--html-path] [--man-path] [--info-"
-"path]\n"
-"            [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
+"git [-v | --version] [-h | --help] [-C <ruta>] [-c <nombre>=<valor>]\n"
+"           [--exec-path[=<ruta>]] [--html-path] [--man-path] [--info-path]\n"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
-"            [--git-dir=<ruta>] [--work-tree=<ruta>] [--namespace=<nombre>]\n"
-"            [--super-prefix=<ruta>] [--config-env=<nombre>=<envvar>]\n"
-"            <comando> [<args>]"
+"           [--git-dir=<ruta>] [--work-tree=<ruta>] [--namespace=<nombre>]\n"
+"           [--super-prefix=<ruta>] [--config-env=<nombre>=<variable-de-"
+"entorno>]\n"
+"           <comando> [<argumentos>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -15963,9 +16018,9 @@ msgstr ""
 msgid "unsupported command listing type '%s'"
 msgstr "tipo de listado de comandos no soportado '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no directory given for '%s' option\n"
-msgstr "no se entregó directorio para -C\n"
+msgstr "no se entregó un directorio para la opción '%s'\n"
 
 #, c-format
 msgid "no namespace given for --namespace\n"
@@ -16090,8 +16145,8 @@ msgstr "gpg.ssh.defaultKeyCommand falló: %s %s"
 msgid "gpg failed to sign the data"
 msgstr "gpg falló al firmar los datos"
 
-msgid "user.signingkey needs to be set for ssh signing"
-msgstr "user.signingkey necesita ser configurado para firmar con ssh"
+msgid "user.signingKey needs to be set for ssh signing"
+msgstr "user.signingKey necesita ser configurado para firmar con ssh"
 
 #, c-format
 msgid "failed writing ssh signing key to '%s'"
@@ -16170,6 +16225,14 @@ msgstr "Comandos de bajo nivel / Sincronización de repositorios"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Comandos de bajo nivel / Auxiliares internos"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "Interfaces de repositorio, comando y archivo orientadas al usuario"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr ""
+"Formatos de archivo, protocolos e otras interfaces orientados al "
+"desarrollador"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "comandos disponibles de git en '%s'"
@@ -16183,6 +16246,13 @@ msgstr "Estos son comandos comunes de Git usados en varias situaciones:"
 msgid "The Git concept guides are:"
 msgstr "Las guías de conceptos de Git son:"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Interfaces de repositorio, comando y archivo orientadas al usuario:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr ""
+"Formatos de archivo, protocolos y otras interfaces para el desarrollador:"
+
 msgid "External commands"
 msgstr "Comandos externos"
 
@@ -16209,15 +16279,15 @@ msgstr "Oh oh. Tu sistema no reporta ningún comando de Git."
 
 #, c-format
 msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr "PELIGRO: Has llamado a un comando de Git '%s', el cual no existe."
+msgstr "ADVERTENCIA: Has llamado a un comando de Git '%s', el cual no existe."
 
 #, c-format
 msgid "Continuing under the assumption that you meant '%s'."
 msgstr "Continuando asumiendo que quisiste decir '%s'."
 
-#, fuzzy, c-format
+#, c-format
 msgid "Run '%s' instead [y/N]? "
-msgstr "Ejecutar '%s' en su lugar? (y/N)"
+msgstr "¿Ejecutar '%s' en su lugar [y/N]? "
 
 #, c-format
 msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
@@ -16264,10 +16334,6 @@ msgstr ""
 "El hook '%s' fue ignorado porque no ha sido configurado como ejecutable.\n"
 "Puedes desactivar esta advertencia con `git config advice.ignoredHook false`."
 
-#, fuzzy, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "No se pudo hacer stat en '%s'"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "argumento para --packfile tiene que se un hash válido (se obtuvo '%s')"
@@ -16276,8 +16342,8 @@ msgid "not a git repository"
 msgstr "no es un repositorio git"
 
 #, c-format
-msgid "negative value for http.postbuffer; defaulting to %d"
-msgstr "valor negativo para http.postbuffer; poniendo el default %d"
+msgid "negative value for http.postBuffer; defaulting to %d"
+msgstr "valor negativo de http.postBuffer; usando el valor por defecto %d"
 
 msgid "Delegation control is not supported with cURL < 7.22.0"
 msgstr "Delegación de control no es soportada con cURL < 7.22.0"
@@ -16453,19 +16519,14 @@ msgstr "se esperaba un flush luego de argumentos ls-refs"
 msgid "quoted CRLF detected"
 msgstr "CRLF con comillas detectado"
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Los cambios locales de los siguientes archivos serán sobreescritos por "
-"merge:\n"
-"  %s"
-
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "Falló al fusionar el submódulo %s (no revisado)"
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Falló al fusionar el submódulo %s (no hay base de fusión)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "Falló al fusionar el submódulo %s (commits no presentes)"
@@ -16484,28 +16545,10 @@ msgstr "Falló al fusionar el submódulo %s"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"Falló al fusionar el submódulo %s, pero existen posibles soluciones de "
-"fusión:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
 msgstr ""
-"Si esto es correcto simplemente agrégalo al índice por ejemplo\n"
-"usando:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"el cual aceptará esta sugerencia.\n"
+"Falló al fusionar el submódulo %s, pero existe una solución de fusión "
+"posible: %s"
 
 #, c-format
 msgid ""
@@ -16559,7 +16602,7 @@ msgid ""
 "WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
 "renamed."
 msgstr ""
-"PELIGRO: Evitando aplicar %s -> %s renombrado a %s, porque %s mismo fue "
+"ADVERTENCIA: Evitando aplicar %s -> %s renombrado a %s, porque %s mismo fue "
 "renombrado."
 
 #, c-format
@@ -16671,13 +16714,45 @@ msgstr ""
 "CONFLICTO (modificar / eliminar): %s eliminado en %s y modificado en %s. "
 "Versión %s de %s restante en el árbol."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#. - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - ve al submódulo (%s), y después o fusiona el commit %s\n"
+"   o actualiza a un commit existente en que ya se han fusionado esos "
+"cambios\n"
+
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
 msgstr ""
-"Nota: %s no está actualizado y en conflicto con la versión; la copia antigua "
-"fue renombrada a %s"
+"La fusión recursiva con submódulos actualmente solo soporta casos "
+"triviales.\n"
+"Por favor, maneja manualmente la fusión de cada submódulo en conflicto.\n"
+"Esto se puede lograr con los pasos siguientes:\n"
+"%s - volver al superproyecto y ejecutar:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   para registrar la fusión de arriba o actualizar\n"
+" - resolver cualquier otro conflicto en el superproyecto\n"
+" - hace commit al índice resultante en el superproyecto\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -16749,6 +16824,22 @@ msgstr "Falló al fusionar el submódulo %s (avance rápido no es posible)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "Se encontró una posible solución de fusión para el submódulo:\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Si esto es correcto simplemente agrégalo al índice por ejemplo\n"
+"usando:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"el cual aceptará esta sugerencia.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr "Falló al fusionar el submódulo %s (múltiples fusiones encontradas)"
@@ -17020,9 +17111,8 @@ msgstr "pack de referencia '% s' ha expirado"
 msgid "no pack files to index."
 msgstr "no hay archivos pack para indexar."
 
-#, fuzzy
 msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr "no se pudo escribir bitmap multi-paquete"
+msgstr "rehusando escribir .bitmap de multi-pack sin ningún objeto"
 
 msgid "could not write multi-pack bitmap"
 msgstr "no se pudo escribir bitmap multi-paquete"
@@ -17282,6 +17372,22 @@ msgstr "deflateEnd en objeto %s falló (%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "confundido por fuente de data de objetos inestable para %s"
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "objeto de stream de escritura %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "incapaz de desinflar dinamicamente el objeto nuevo (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "deflateEnd en el objeto de stream falló (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "incapaz de crear directorio %s"
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr "no se pudo leer el objeto para %s"
@@ -17340,23 +17446,23 @@ msgstr "no es posible desempaquetar contenidos de %s"
 #. output shown when we cannot look up or parse the
 #. object in question. E.g. "deadbeef [bad object]".
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "%s [bad object]"
-msgstr "tipo de objeto erróneo."
+msgstr "%s [mal objeto]"
 
 #. TRANSLATORS: This is a line of ambiguous commit
 #. object output. E.g.:
 #. *
-#.    "deadbeef commit 2021-01-01 - Some Commit Message"
+#. "deadbeef commit 2021-01-01 - Some Commit Message"
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "%s commit %s - %s"
-msgstr "%s: %s - %s"
+msgstr "%s commit %s - %s"
 
 #. TRANSLATORS: This is a line of ambiguous
 #. tag object output. E.g.:
 #. *
-#.    "deadbeef tag 2022-01-01 - Some Tag Message"
+#. "deadbeef tag 2022-01-01 - Some Tag Message"
 #. *
 #. The second argument is the YYYY-MM-DD found
 #. in the tag.
@@ -17364,33 +17470,33 @@ msgstr "%s: %s - %s"
 #. The third argument is the "tag" string
 #. from object.c.
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "%s tag %s - %s"
-msgstr "%s: %s - %s"
+msgstr "%s etiqueta %s - %s"
 
 #. TRANSLATORS: This is a line of ambiguous
 #. tag object output where we couldn't parse
 #. the tag itself. E.g.:
 #. *
-#.    "deadbeef [bad tag, could not parse it]"
+#. "deadbeef [bad tag, could not parse it]"
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "%s [bad tag, could not parse it]"
-msgstr "%s: no se pudo analizar objeto: %s"
+msgstr "%s [mala etiqueta, no se pudo analizar]"
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef tree".
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "%s tree"
-msgstr "hilo %s falló"
+msgstr "árbol %s"
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef blob".
 #.
-#, fuzzy, c-format
+#, c-format
 msgid "%s blob"
-msgstr "blob"
+msgstr "blob %s"
 
 #, c-format
 msgid "short object ID %s is ambiguous"
@@ -17400,11 +17506,13 @@ msgstr "el ID de objeto corto %s es ambiguo"
 #. objects composed in show_ambiguous_object(). See
 #. its "TRANSLATORS" comments for details.
 #.
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The candidates are:\n"
 "%s"
-msgstr "Los candidatos son:"
+msgstr ""
+"Los candidatos son:\n"
+"%s"
 
 msgid ""
 "Git normally never creates a ref that ends with 40 hex characters\n"
@@ -17482,7 +17590,7 @@ msgstr ""
 
 #, c-format
 msgid "<object>:<path> required, only <object> '%s' given"
-msgstr ""
+msgstr "<objeto>:<ruta> requerido, solo <objeto> '%s' proporcionado"
 
 #, c-format
 msgid "invalid object name '%.*s'."
@@ -17508,40 +17616,144 @@ msgstr "incapaz de analizar objeto: %s"
 msgid "hash mismatch %s"
 msgstr "hash no concuerda %s"
 
+msgid "trying to write commit not in index"
+msgstr "intentando escribir un commit que no está en el índice"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "falló al cargar el índice de bitmap (¿corrupto?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "índice de bitmap corrupto (demasiado pequeño)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "archivo de índice de bitmap corrupto (cabecera errónea)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "versión no soportada '%d' de archivo de índice de bitmap"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"archivo de índice de bitmap corrupto (demasiado corto para el cache de hash)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"archivo de índice de bitmap corrupto (demasiado corto para la tabla de "
+"consultación)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "entrada duplicada en el índice de bitmap: '%s'"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "bitmap ewah corrupto: cabecera truncada en la entrada %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "bitmap ewah corrupto: índice de commit %u fuera de rango"
+
+msgid "corrupted bitmap pack index"
+msgstr "índice de pack de bitmap corrupto"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "offset XOR inválido en el índice de pack de bitmap"
+
+msgid "cannot fstat bitmap file"
+msgstr "no se puede hacer fstat en el archivo de bitmap"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "ignorando el archivo extra de bitmap: '%s'"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "no se concuerden los checksums del MIDX y del bitmap"
+
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "a multi-pack-index le falta un índice reveretido"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not open pack %s"
-msgstr "no se pudo abrir '%s'"
+msgstr "no se pudo abrir el pack %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "preferred pack (%s) is invalid"
-msgstr "pack de referencia '% s' ha expirado"
+msgstr "el pack preferido (%s) es inválido"
+
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "tabla de consultación corrupta: posición de trillizo fuera del índice"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr ""
+"tabla de consultación de bitmap corrupta: la cadena xor excede el número de "
+"entradas"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr ""
+"tabla de consultación de bitmap corrupta: índice de commit %u fuera de rango"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr "bitmap ewah corrupto: cabecera truncada del bitmap del commit \"%s\""
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "objeto '%s' no encontrado en bitmaps de tipo"
+
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "el objeto '%s' no tiene un tipo único"
+
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "objeto '%s': tipo real '%s', esperado: '%s'"
+
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "objeto no en bitmap: '%s'"
+
+msgid "failed to load bitmap indexes"
+msgstr "falló en cargar índices de bitmap"
+
+msgid "you must specify exactly one commit to test"
+msgstr "hay que especificar exactamente un commit para probar"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "el commit '%s' no tiene un bitmap indexado"
+
+msgid "mismatch in bitmap results"
+msgstr "discordancia en los resultados de bitmap"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "no se pudo encontrar '%s' en el pack '%s' al offset %<PRIuMAX>"
 
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "no se pudo encontrar %s en paquete %s en el offset %<PRIuMAX>"
+msgid "unable to get disk usage of '%s'"
+msgstr "incapaz de obtener el uso de disco de '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s is too small"
-msgstr "el archivo multi-pack-index %s es demasiado pequeño"
+msgstr "el archivo de mtimes %s es demasiado pequeño"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s has unknown signature"
-msgstr "el archivo de índice inverso %s tiene una firma desconocida"
+msgstr "el archivo de mtimes %s tiene una firma desconocida"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s has unsupported version %<PRIu32>"
-msgstr "archivo reverse-index %s tiene una versión no soportada %<PRIu32>"
+msgstr "el archivo de mtimes %s tiene una versión no soportada %<PRIu32>"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s has unsupported hash id %<PRIu32>"
-msgstr "archivo reverse-index %s tiene un id de hash no soportado %<PRIu32>"
+msgstr ""
+"el archivo de mtimes %s tiene un identificador de hash no soportado %<PRIu32>"
 
-#, fuzzy, c-format
+#, c-format
 msgid "mtimes file %s is corrupt"
-msgstr "el archivo de índice inverso %s está dañado"
+msgstr "el archivo de mtimes %s es corrupto"
 
 #, c-format
 msgid "reverse-index file %s is too small"
@@ -17557,11 +17769,13 @@ msgstr "el archivo de índice inverso %s tiene una firma desconocida"
 
 #, c-format
 msgid "reverse-index file %s has unsupported version %<PRIu32>"
-msgstr "archivo reverse-index %s tiene una versión no soportada %<PRIu32>"
+msgstr "el archivo reverse-index %s tiene la versión no soportada %<PRIu32>"
 
 #, c-format
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
-msgstr "archivo reverse-index %s tiene un id de hash no soportado %<PRIu32>"
+msgstr ""
+"el archivo reverse-index %s tiene el identificador de hash no soportado "
+"%<PRIu32>"
 
 msgid "cannot both write and verify reverse index"
 msgstr "no puede escribir y verificar el índice inverso"
@@ -17607,9 +17821,9 @@ msgstr "opción `%s' puede usar \"always\", \"auto\", o \"never\""
 msgid "malformed object name '%s'"
 msgstr "nombre de objeto mal formado '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "option `%s' expects \"%s\" or \"%s\""
-msgstr "opción `%s' puede usar \"always\", \"auto\", o \"never\""
+msgstr "la opción `%s' espera \"%s\" o \"%s\""
 
 #, c-format
 msgid "%s requires a value"
@@ -17647,6 +17861,9 @@ msgstr "¿quisiste decir `--%s` (con dos guiones)?"
 msgid "alias of --%s"
 msgstr "alias de --%s"
 
+msgid "need a subcommand"
+msgstr "se necesita un subcomando"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "opción `%s' desconocida"
@@ -18025,9 +18242,8 @@ msgstr "no se pudo refrescar el índice compartido '%s'"
 msgid "broken index, expect %s in %s, got %s"
 msgstr "index roto, se esperaba %s en %s, se obtuvo %s"
 
-#, fuzzy
 msgid "cannot write split index for a sparse index"
-msgstr "activar el uso de un índice sparse"
+msgstr "no se puede escribir un índice dividido para un índice escaso"
 
 msgid "failed to convert to a sparse-index"
 msgstr "falló al convertir a un índice sparse"
@@ -18084,9 +18300,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -18096,20 +18315,23 @@ msgstr ""
 "r, reword <commit> = usar commit, pero refrasear el mensaje de commit\n"
 "e, edit <commit> = usar commit, pero parar para enmendar\n"
 "s, squash <commit> = usar commit, pero aplastarlo en el commit previo\n"
-"f, fixup <commit> = como \"squash\", pero descarta el mensaje del log de "
-"este commit\n"
-"\t, a menos que se use -C, en cuyo caso\n"
-"\tmantiene solo el mensaje del commit; -c es lo mismo que -C\n"
-"\tpero abre el editor\n"
+"f, fixup [-C | -c] <commit> = como \"squash\", pero descarta el mensaje del\n"
+"                   log de este commit, a menos que se use -C, en cuyo caso\n"
+"                   mantiene solo el mensaje del commit; -c es lo mismo que\n"
+"                   -C pero abre el editor\n"
 "x, exec <commit> = ejecutar comando (el resto de la línea) usando un shell\n"
 "b, break = parar aquí (continuar rebase luego con 'git rebase --continue')\n"
 "d, drop <commit> = eliminar commit\n"
 "l, label <label> = poner label al HEAD actual con un nombre\n"
 "t, reset <label> = reiniciar HEAD al label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       crear un commit de fusión usando el mensaje original de\n"
-".       fusión (o la línea de oneline, si no se especifica un mensaje\n"
-".       de commit). Use -c <commit> para reescribir el mensaje del commit.\n"
+"        crear un commit de fusión usando el mensaje original de\n"
+"        fusión (o la línea de oneline, si no se especifica un mensaje\n"
+"        de commit). Use -c <commit> para reescribir el mensaje del commit.\n"
+"u, update-ref <referencia> = rasrear un marcador de posición para que la\n"
+"                             <referencia> sea actualizada a esta posición\n"
+"                             en los commits nuevos. Se actualiza la\n"
+"                             <referencia> al fin de la rebase\n"
 "\n"
 "Estas líneas pueden ser reordenadas; son ejecutadas desde arriba hacia "
 "abajo.\n"
@@ -18165,7 +18387,8 @@ msgid ""
 "Warning: some commits may have been dropped accidentally.\n"
 "Dropped commits (newer to older):\n"
 msgstr ""
-"Peligro: algunos commits pueden haber sido descartados de forma accidental.\n"
+"Advertencia: algunos commits pueden haber sido descartados de forma "
+"accidental.\n"
 "Commits descartados (empezando con el más nuevo):\n"
 
 #, c-format
@@ -18291,9 +18514,9 @@ msgstr ""
 "no es un repositorio git, pero el campo '%.*s' requiere acceso a los datos "
 "de objeto"
 
-#, fuzzy, c-format
+#, c-format
 msgid "format: %%(%s) atom used without a %%(%s) atom"
-msgstr "formato: átomo %%(else) usado sin un átomo %%(if)"
+msgstr "formato: átomo %%(%s) usado sin un átomo %%(%s)"
 
 #, c-format
 msgid "format: %%(then) atom used more than once"
@@ -18584,6 +18807,13 @@ msgstr "error de protocolo: se esperaba sha/ref, se obtuvo '%s'"
 msgid "http transport does not support %s"
 msgstr "http transport no soporta %s"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "error de protocolo: se esperaba '<url> <ruta>', falta el espacio"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "falló al descargar el archivo al URL '%s'"
+
 msgid "git-http-push failed"
 msgstr "git-http-push falló"
 
@@ -18610,13 +18840,13 @@ msgstr "más de un receivepack dado, usando el primero"
 msgid "more than one uploadpack given, using the first"
 msgstr "más de un uploadpack dado, usando el primero"
 
-#, fuzzy, c-format
-msgid "unrecognized value fetch.credentialsInURL: '%s'"
-msgstr "patrón desconocido: '%s'"
+#, c-format
+msgid "unrecognized value transfer.credentialsInUrl: '%s'"
+msgstr "valor desconocido de transfer.credentialsInUrl: '%s'"
 
 #, c-format
 msgid "URL '%s' uses plaintext credentials"
-msgstr ""
+msgstr "El URL '%s' usa credenciales de texto claro"
 
 #, c-format
 msgid "Cannot fetch both %s and %s to %s"
@@ -18925,6 +19155,14 @@ msgstr "no se pudo determinar revisión HEAD"
 msgid "failed to find tree of %s"
 msgstr "falló al encontrar árbol de %s"
 
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo registra '%s' el cual falta"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "no se pudo determinar el commit del argumento de ancestry-path %s"
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<packfile> ya no es soportado"
 
@@ -18945,6 +19183,174 @@ msgstr "-L no soporta todavía formatos de diff fuera de -p y -s"
 msgid "cannot create async thread: %s"
 msgstr "no es posible crear hilo async: %s"
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' no existe"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "no se pudo cambiar a '%s'"
+
+msgid "need a working directory"
+msgstr "se necesita un directorio de trabajo"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "alistamientos de Scalar requieren un árbol de trabajo"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "no se pudo configurar %s=%s"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "no se pudo configurar log.excludeDecoration"
+
+msgid "could not add enlistment"
+msgstr "no se pudo añadir alistamiento"
+
+msgid "could not set recommended config"
+msgstr "no se pudo establecer la configuración recomendada"
+
+msgid "could not turn on maintenance"
+msgstr "no se pudo activar mantenimiento"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "no se pudo iniciar el demonio de FSMonitor"
+
+msgid "could not turn off maintenance"
+msgstr "no se pudo desactivar mantenimiento"
+
+msgid "could not remove enlistment"
+msgstr "no se pudo eliminar alistamiento"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "la HEAD remota no es una rama: '%.*s'"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"falló al obtener el nombre de rama por defecto del remoto; usando el valor "
+"local por defecto"
+
+msgid "failed to get default branch name"
+msgstr "falló al determinar el nombre de rama por defecto"
+
+msgid "failed to unregister repository"
+msgstr "falló al desregistrar repositorio"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "falló al parar el demonio de FSMonitor"
+
+msgid "failed to delete enlistment directory"
+msgstr "falló al eliminar el directorio de alistamiento"
+
+msgid "branch to checkout after clone"
+msgstr "rama a que cambiar después de clonar"
+
+msgid "when cloning, create full working directory"
+msgstr "cuando se clona, crear un directorio pleno de trabajo"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "solo descargar metadatos de la rama a que cambiar"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<opciones>] [--] <repositorio> [<directorio>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "no se puede deducir de '%s' el nombre del árbol de trabajo"
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "el directorio '%s' ya existe"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "falló al determinar la rama por defecto para '%s'"
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "no se pudo configurar el remoto en '%s'"
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "no se pudo configurar '%s'"
+
+msgid "partial clone failed; attempting full clone"
+msgstr "falló la clonación parcial; intentando clonación plena"
+
+msgid "could not configure for full clone"
+msgstr "no se pudo configurar para una clonación plena"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<alistamiento>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` no toma ningún argumento"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<alistamiento>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "reconfigurar todos los alistamientos registrados"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <alistamiento>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all o <alistamiento>, pero no los dos"
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "el repositorio de git en '%s' ya no está"
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <tarea> [<alistamiento>]\n"
+"Tareas:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "no existe tal tarea: '%s'"
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<alistamiento>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <alistamiento>"
+
+msgid "refusing to delete current working directory"
+msgstr "rehusando eliminar el directorio de trabajo actual"
+
+msgid "include Git version"
+msgstr "incluir la versión de Git"
+
+msgid "include Git's build options"
+msgstr "incluir las opciones de compilación de Git"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C requiere un <directorio>"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "no se pudo cambiar a '%s'"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c requiere un argumento <clave>=<valor>"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <directorio>] [-c <clave>=<valor>] <comando> [<opciones>]\n"
+"\n"
+"Comandos:\n"
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr ""
 "flush packet inesperado mientras se leía estatus de desempaquetado remoto"
@@ -19067,10 +19473,6 @@ msgstr "tus cambios locales serán sobreescritos por %s."
 msgid "commit your changes or stash them to proceed."
 msgstr "realiza un commit con tus cambios o haz un stash para proceder."
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: avance rápido"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -19421,7 +19823,7 @@ msgstr "final de archivo inesperado"
 
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
-msgstr "archivo HEAD '%s' guardado antes de cherry-pick está corrupto"
+msgstr "archivo HEAD '%s' guardado antes de cherry-pick está corrupto"
 
 msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
 msgstr "Parece que se ha movido HEAD. No se hace rebobinado, ¡revisa tu HEAD!"
@@ -19555,6 +19957,28 @@ msgstr "ni se pudo intentar fusionar '%.*s'"
 msgid "merge: Unable to write new index file"
 msgstr "fusión: No se puede escribir el nuevo archivo índice"
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr ""
+"parece que otro proceso 'rebase' ya se está ejecutando; '%s.lock' ya existe"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Se han actualizado las referencias siguientes con %s:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Falló al abrir las referencias siguientes con %s:\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "No se puede ejecutar autostash"
 
@@ -19722,6 +20146,10 @@ msgstr "no se pudo saltar los comandos pick innecesarios"
 msgid "the script was already rearranged."
 msgstr "este script ya fue reorganizado."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "el archivo de update-refs a '%s' es inválido"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "'%s' está fuera del repositorio en '%s'"
@@ -19845,11 +20273,20 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
+"\n"
+"\tgit config --global --add safe.directory %s"
+msgstr ""
+"posesión dudosa detectada en el repositorio a '%s'\n"
+"%sPara añadir una excepción para este directorio, ejecuta:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
+
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
 msgstr ""
+"no se puede usar el repositorio desnudo '%s' (safe.bareRepository es '%s')"
 
 #, c-format
 msgid ""
@@ -19869,9 +20306,8 @@ msgstr "falló setsid"
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "la entrada de índice es un directorio, pero no escaso (%08x)"
 
-#, fuzzy
 msgid "cannot use split index with a sparse index"
-msgstr "no se puede leer el índice"
+msgstr "no se puede usar un índice dividido con un índice escaso"
 
 #. TRANSLATORS: IEC 80000-13:2008 gibibyte
 #, c-format
@@ -19925,8 +20361,8 @@ msgstr "no se pudo editar '%s'"
 msgid "ignoring suspicious submodule name: %s"
 msgstr "ignorando nombre de submódulo sospechoso: %s"
 
-msgid "negative values not allowed for submodule.fetchjobs"
-msgstr "no se permiten valores negativos para submodule.fetchjobs"
+msgid "negative values not allowed for submodule.fetchJobs"
+msgstr "no se permiten valores negativos para submodule.fetchJobs"
 
 #, c-format
 msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
@@ -20006,13 +20442,13 @@ msgstr "Haciendo fetch al submódulo %s%s\n"
 msgid "Could not access submodule '%s'\n"
 msgstr "No se pudo acceder al submódulo '%s'\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Could not access submodule '%s' at commit %s\n"
-msgstr "No se pudo acceder al submódulo '%s'\n"
+msgstr "No se pudo acceder al submódulo '%s' al commit %s\n"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Fetching submodule %s%s at commit %s\n"
-msgstr "Haciendo fetch al submódulo %s%s\n"
+msgstr "Haciendo fetch al submódulo %s%s al commit %s\n"
 
 #, c-format
 msgid ""
@@ -20158,7 +20594,7 @@ msgid "number of threads in server thread pool"
 msgstr "número de hilos en el pool de hilos del servidor"
 
 msgid "seconds to wait for daemon to start or stop"
-msgstr "segundos a esperar para que el dominio empiece o se detenga"
+msgstr "segundos a esperar que el demonio se inicie o se detenga"
 
 msgid "number of bytes"
 msgstr "número de bytes"
@@ -20519,11 +20955,13 @@ msgstr ""
 "seguimiento en ellos:\n"
 "%s"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Refusing to remove the current working directory:\n"
 "%s"
-msgstr "no es posible obtener el directorio de trabajo actual"
+msgstr ""
+"Rehusando eliminar el directorio de trabajo actual:\n"
+"%s"
 
 #, c-format
 msgid ""
@@ -20712,7 +21150,7 @@ msgid "expected flush after fetch arguments"
 msgstr "se espera flush tras argumentos fetch"
 
 msgid "invalid URL scheme name or missing '://' suffix"
-msgstr "nombre de URL inválido o sufijo '://' faltante"
+msgstr "nombre de URL inválido o sufijo '://' faltante"
 
 #, c-format
 msgid "invalid %XX escape sequence"
@@ -20728,11 +21166,23 @@ msgid "invalid characters in host name"
 msgstr "carácter inválido en el nombre del host"
 
 msgid "invalid port number"
-msgstr "número de puerto inválido"
+msgstr "número de puerto inválido"
 
 msgid "invalid '..' path segment"
 msgstr "segmento de ruta '..' inválido"
 
+msgid "usage: "
+msgstr "uso: "
+
+msgid "fatal: "
+msgstr "fatal: "
+
+msgid "error: "
+msgstr "error: "
+
+msgid "warning: "
+msgstr "advertencia: "
+
 msgid "Fetching objects"
 msgstr "Haciendo fetch a objetos"
 
@@ -20807,13 +21257,13 @@ msgstr "archivo gitdir inválido"
 msgid "gitdir file points to non-existent location"
 msgstr "archivo gitdir apunta a una ubicación inexistente"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unable to set %s in '%s'"
-msgstr "incapaz de hacer stat en '%s'"
+msgstr "incapaz de configurar %s en '%s'"
 
-#, fuzzy, c-format
+#, c-format
 msgid "unable to unset %s in '%s'"
-msgstr "no se pudo poner permisos a '%s'"
+msgstr "incapaz de desconfigurar %s en '%s'"
 
 msgid "failed to set extensions.worktreeConfig setting"
 msgstr "falló al configurar opción extensions.worktreeConfig"
@@ -20893,7 +21343,7 @@ msgstr ""
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr ""
-"  (usa \"git %s <archivo>...\" para incluirlo a lo que se será confirmado)"
+"  (usa \"git %s <archivo>...\" para incluirlo a lo que será confirmado)"
 
 msgid "both deleted:"
 msgstr "borrados por ambos:"
@@ -21005,10 +21455,11 @@ msgstr "  (arregla los conflictos y luego ejecuta \"git am --continue\""
 msgid "  (use \"git am --skip\" to skip this patch)"
 msgstr "  (usa \"git am --skip\" para saltar este parche)"
 
-#, fuzzy
 msgid ""
 "  (use \"git am --allow-empty\" to record this patch as an empty commit)"
-msgstr "  (usa \"git commit --amend\" para enmendar el commit actual)"
+msgstr ""
+"  (usa \"git am --allow-empty\" para registrar este parche como un commit "
+"vacío)"
 
 msgid "  (use \"git am --abort\" to restore the original branch)"
 msgstr "  (usa \"git am --abort\" para restaurar la rama original)"
@@ -21019,11 +21470,11 @@ msgstr "git-rebase-todo no está presente."
 msgid "No commands done."
 msgstr "No se realizaron los comandos."
 
-#, fuzzy, c-format
+#, c-format
 msgid "Last command done (%<PRIuMAX> command done):"
 msgid_plural "Last commands done (%<PRIuMAX> commands done):"
-msgstr[0] "El último comando realizado (%d comando realizado):"
-msgstr[1] "Los últimos comandos realizados (%d comandos realizados):"
+msgstr[0] "El último comando realizado (%<PRIuMAX> comando realizado):"
+msgstr[1] "Los últimos comandos realizados (%<PRIuMAX> comandos realizados):"
 
 #, c-format
 msgid "  (see more in file %s)"
@@ -21032,11 +21483,11 @@ msgstr "  (ver más en el archivo %s)"
 msgid "No commands remaining."
 msgstr "No quedan más comandos."
 
-#, fuzzy, c-format
+#, c-format
 msgid "Next command to do (%<PRIuMAX> remaining command):"
 msgid_plural "Next commands to do (%<PRIuMAX> remaining commands):"
-msgstr[0] "Siguiente comando a realizar (%d comando restante):"
-msgstr[1] "Siguientes comandos a realizar (%d comandos faltantes):"
+msgstr[0] "Siguiente comando a realizar (%<PRIuMAX> comando restante):"
+msgstr[1] "Siguientes comandos a realizar (%<PRIuMAX> comandos faltantes):"
 
 msgid "  (use \"git rebase --edit-todo\" to view and edit)"
 msgstr "  (usa \"git rebase --edit-todo\" para ver y editar)"
@@ -21547,22 +21998,6 @@ msgstr "¡Los hunks seleccionados no aplican al índice!\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "ignorando lo no fusionado: %s\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "¿Aplicar cambio de modo al árbol de trabajo [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "¿Aplicar eliminación al árbol de trabajo [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "¿Aplicar adición al árbol de trabajo [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "¿Aplicar este fragmento al árbol de trabajo [y,n,q,a,d,/%s,?]? "
-
 msgid "No other hunks to goto\n"
 msgstr "No hay más fragmentos a que ir\n"
 
@@ -21693,11 +22128,11 @@ msgstr "Configuración --confirm desconocida: '%s'\n"
 
 #, perl-format
 msgid "warning: sendmail alias with quotes is not supported: %s\n"
-msgstr "peligro: alias de sendmail con comillas no es soportado: %s\n"
+msgstr "advertencia: alias de sendmail con comillas no es soportado: %s\n"
 
 #, perl-format
 msgid "warning: `:include:` not supported: %s\n"
-msgstr "peligro: `:include:` no soportado: %s\n"
+msgstr "advertencia: `:include:` no soportado: %s\n"
 
 #, perl-format
 msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
@@ -21929,15 +22364,15 @@ msgstr "no se puede mandar mensaje como 7bit"
 msgid "invalid transfer encoding"
 msgstr "codificación de transferencia inválida"
 
-#, fuzzy, perl-format
+#, perl-format
 msgid ""
 "fatal: %s: rejected by %s hook\n"
 "%s\n"
 "warning: no patches were sent\n"
 msgstr ""
-"fatal: %s: rechazado por hook sendmail-validate\n"
+"fatal: %s: rechazado por el hook %s\n"
 "%s\n"
-"peligro: no se mandaron parches\n"
+"advertencia: no se mandó ningún parche\n"
 
 #, perl-format
 msgid "unable to open %s: %s\n"
@@ -21949,7 +22384,7 @@ msgid ""
 "warning: no patches were sent\n"
 msgstr ""
 "fatal: %s: %d es más grande que 998 caracteres\n"
-"peligro: no se mandaron parches\n"
+"advertencia: no se mandó ningún parche\n"
 
 #, perl-format
 msgid "Skipping %s with backup suffix '%s'.\n"
index f601f4063639337f1a6ccb992ae33ec11d7125c4..b29d34100204664e4716badf519f9ac320f831dd 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -78,8 +78,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-24 21:43+0200\n"
-"PO-Revision-Date: 2022-06-24 21:58+0200\n"
+"POT-Creation-Date: 2022-09-28 21:43+0200\n"
+"PO-Revision-Date: 2022-09-28 21:45+0200\n"
 "Last-Translator: Cédric Malard <c.malard-git@valdun.net>\n"
 "Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n"
 "Language: fr\n"
@@ -491,6 +491,23 @@ msgstr ""
 "a - appliquer cette section et toutes les suivantes de ce fichier\n"
 "d - ne pas appliquer cette section ni les suivantes de ce fichier\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+"Appliquer le changement de mode dans l'arbre de travail [y,n,q,a,d%s,?] ? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Appliquer la suppression dans l'arbre de travail [y,n,q,a,d%s,?] ? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Appliquer l'ajout dans l'arbre de travail [y,n,q,a,d%s,?] ? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Appliquer la section à l'arbre de travail [y,n,q,a,d%s,?] ? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -508,10 +525,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "impossible d'analyser l'entête de section '%.*s'"
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "impossible d'analyser l'entête coloré de section '%.*s'"
-
 msgid "could not parse diff"
 msgstr "impossible d'analyser la diff"
 
@@ -803,6 +816,25 @@ msgstr ""
 "detachedHead à false\n"
 "\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Les chemins suivants ont été déplacés hors de\n"
+"la définition d'extraction clairsemée mai ne sont pas\n"
+"clairsemés à cause de modifications locales\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Pour corriger l'état clairsemé de ces chemins, faites ceci :\n"
+"* Lancez \"git add --sparse <chemins>\" pour mettre l'index à jour\n"
+"* Lancez \"git sparse-checkout reapply\" pour réappliquer les règles"
+
 msgid "cmdline ends with \\"
 msgstr "cmdline se termine par \\"
 
@@ -1322,6 +1354,10 @@ msgstr "impossible de transmettre le blob %s en flux"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "mode de fichier non supporté :0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "erreur de compression (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "impossible de démarrer le filtre '%s'"
@@ -1341,10 +1377,6 @@ msgstr "le chemin n'est pas codé en UTF-8 valide : %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "le chemin est trop long (%d caractères, SHA1 : %s) : %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "erreur de compression (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "l'horodatage est trop grand pour ce système : %<PRIuMAX>"
@@ -3143,8 +3175,12 @@ msgstr "info libc : "
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "lancé hors d'un dépôt git - aucun crochet à montrer\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <fichier>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <fichier>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3182,16 +3218,29 @@ msgstr ""
 "Veuillez relire le rapport de bogue ci-dessous.\n"
 "Vous pouvez supprimer toute ligne que vous ne souhaitez pas envoyer.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "spécifier la destination du fichier de rapport de bogue"
+msgid "mode"
+msgstr "mode"
 
-msgid "specify a strftime format suffix for the filename"
-msgstr "spécifier une suffixe au format strftime pour le nom de fichier"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"créer une archive zip supplémentaire de diagnostique détaillé (par défaut "
+"'stats')"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "spécifier la destination du/des fichier(s) de rapport de bogue"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "spécifier une suffixe au format strftime pour le(s) nom(s) de fichier"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "impossible de créer les répertoires de premier niveau pour '%s'"
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "impossible de créer l'archive de diagnostique %s"
+
 msgid "System Info"
 msgstr "Info système"
 
@@ -3249,10 +3298,6 @@ msgstr "Le dépaquetage d'un colis requiert un dépôt."
 msgid "Unbundling objects"
 msgstr "Dépaquetage d'objets"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Sous-commande inconnue : %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "impossible de lire l'objet %s '%s'"
@@ -3330,6 +3375,9 @@ msgstr "afficher la taille de l'objet"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "autoriser -s et -t à travailler sur des objets cassés/corrompus"
 
+msgid "use mail map file"
+msgstr "utiliser le fichier de correspondance de mail"
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "Traiter par lot les objets demandés sur stdin (ou --batch-all-objects)"
 
@@ -3339,6 +3387,9 @@ msgstr "afficher tout le contenu de <objet> ou <rev>"
 msgid "like --batch, but don't emit <contents>"
 msgstr "comme --batch, mais ne pas émettre <contenu>"
 
+msgid "stdin is NUL-terminated"
+msgstr "l'entrée se termine par NUL"
+
 msgid "read commands from stdin"
 msgstr "lire les commandes depuis l'entrée standard"
 
@@ -4225,6 +4276,14 @@ msgstr ""
 "initialiser le fichier d'extraction clairsemée pour n'inclure que les "
 "fichiers à la racine"
 
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+"un URI pour télécharger des paquets avant de récupérer depuis le distant "
+"d'origine"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info : impossible d'ajouter une alternative pour '%s' : %s\n"
@@ -4284,10 +4343,10 @@ msgstr "impossible de mettre à jour %s"
 msgid "failed to initialize sparse-checkout"
 msgstr "échec lors de l'initialisation l'extraction clairsemée"
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr ""
 "la HEAD distante réfère à une référence non existante, impossible de "
-"l'extraire.\n"
+"l'extraire"
 
 msgid "unable to checkout working tree"
 msgstr "impossible d'extraire la copie de travail"
@@ -4311,6 +4370,13 @@ msgstr "Vous devez spécifier un dépôt à cloner."
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "les options '%s' et '%s %s' ne peuvent pas être utilisées ensemble"
 
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri est incompatible avec --depth, --shallow-since, et --shallow-"
+"exclude"
+
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "le dépôt '%s' n'existe pas"
@@ -4388,6 +4454,13 @@ msgstr "--local est ignoré"
 msgid "cannot clone from filtered bundle"
 msgstr "impossible de cloner depuis un colis filtré"
 
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "échec lors de l'initialisation du dépôt, URI du paquet ignoré"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "impossible de récupérer les objets depuis l'URI de paquet '%s'"
+
 msgid "remote transport reported error"
 msgstr "le transport distant a retourné une erreur"
 
@@ -4504,10 +4577,6 @@ msgstr "utilisez un seul parmi --reachable, --stdin-commits ou --stdin-packs"
 msgid "Collecting commits from input"
 msgstr "Collecte des commits depuis l'entrée"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "sous-commande non reconnue : %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -4869,9 +4938,6 @@ msgstr "afficher l'état en format long (par défaut)"
 msgid "terminate entries with NUL"
 msgstr "terminer les éléments par NUL"
 
-msgid "mode"
-msgstr "mode"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "afficher les fichiers non suivis, \"mode\" facultatif : all (tous), normal, "
@@ -5476,6 +5542,22 @@ msgid "option '%s' and commit-ishes cannot be used together"
 msgstr ""
 "l'option '%s' et des commit-esques ne peuvent pas être utilisées ensemble"
 
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <fichier>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "spécifier la destination de l'archive de diagnostique"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "spécifier une suffixe au format strftime pour le nom de fichier"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "spécifier le contenu de l'archive de diagnostique"
+
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base ne fonctionne qu'avec deux commits"
 
@@ -5865,11 +5947,8 @@ msgstr "[à jour]"
 msgid "[rejected]"
 msgstr "[rejeté]"
 
-msgid "can't fetch in current branch"
-msgstr "impossible de récupérer dans la branche actuelle"
-
-msgid "checked out in another worktree"
-msgstr "extrait dans un autre arbre de travail"
+msgid "can't fetch into checked-out branch"
+msgstr "impossible de récupérer dans la branche extraite"
 
 msgid "[tag update]"
 msgstr "[mise à jour de l'étiquette]"
@@ -6303,6 +6382,10 @@ msgstr "%s : pointer sha1 invalide dans l'arbre de cache"
 msgid "non-tree in cache-tree"
 msgstr "non-arbre dans l'arbre de cache"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s : pointeur sha1 invalide dans resolve-undo"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<options>] [<objet>...]"
 
@@ -6640,14 +6723,17 @@ msgstr ""
 "echec du lancement de 'crontab -l' ; votre système n'a pas l'air de fournir "
 "'cron'"
 
+msgid "failed to create crontab temporary file"
+msgstr "impossible de créer un fichier crontab temporaire"
+
+msgid "failed to open temporary file"
+msgstr "impossible d'ouvrir un fichier temporaire"
+
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "echec du lancement de 'crontab' ; votre système n'a pas l'air de fournir "
 "'cron'"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "échec à l'ouverture de stdin de 'crontab'"
-
 msgid "'crontab' died"
 msgstr "'crontab' est mort"
 
@@ -6696,10 +6782,6 @@ msgstr "échec de l'ajout du dépôt à la config globale"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <subcommand> [<options>]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "sous-commande invalide : %s"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<options>] [-e] <motif> [<révision>...] [[--] <chemin>...]"
 
@@ -6877,6 +6959,9 @@ msgstr "afficher les fichiers correspondant dans le pagineur"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "permettre l'appel de grep(1) (ignoré par ce build)"
 
+msgid "maximum number of results per file"
+msgstr "nombre maximum de résultats par fichier"
+
 msgid "no pattern given"
 msgstr "aucun motif fourni"
 
@@ -6965,11 +7050,19 @@ msgstr "afficher la description de la commande"
 msgid "print list of useful guides"
 msgstr "afficher une liste de guides utiles"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr "afficher les liste des dépôts publics, des commandes et des interfaces"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr ""
+"afficher la liste des formats de fichier, des protocoles et des autres "
+"interfaces pour développeur"
+
 msgid "print all configuration variable names"
 msgstr "afficher tous les noms de variables de configuration"
 
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<commande>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<commande>|<doc>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -7442,8 +7535,8 @@ msgstr "supprimer la sortie des différences"
 msgid "show source"
 msgstr "afficher la source"
 
-msgid "use mail map file"
-msgstr "utiliser le fichier de correspondance de mail"
+msgid "clear all previously-defined decoration filters"
+msgstr "effacer tous les filtres de décoration précédemment définis"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "décorer seulement les références correspondant à <motif>"
@@ -7711,6 +7804,11 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr "pourcentage par lequel la création est pondérée"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr ""
+"montrer les From: inclus même s'ils sont identiques à celui de l'entête du "
+"courriel"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "ligne d'identification invalide : %s"
@@ -7771,6 +7869,18 @@ msgstr ""
 "Impossible de trouver une branche distante suivie, merci de spécifier "
 "<branche_amont> manuellement.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "mauvais format ls-files : l'élément '%s' ne commence pas par '('"
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "mauvais format ls-files : l'élément '%s' ne se termine pas par ')'"
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "mauvais format ls-files : %%%.*s"
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<options>] [<fichier>...]"
 
@@ -7858,6 +7968,13 @@ msgstr "supprimer les entrées dupliquées"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "afficher les répertoires clairsemés en présence d'un index clairsemé"
 
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format ne peut pas être utilisé avec -s, -o, -k, -t, --resolve-undo, --"
+"deduplicate, --eol"
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url]\n"
@@ -8082,6 +8199,39 @@ msgstr "impossible de résoudre la référence '%s'"
 msgid "Merging %s with %s\n"
 msgstr "Fusion de %s avec %s\n"
 
+msgid "not something we can merge"
+msgstr "pas possible de fusionner ceci"
+
+msgid "refusing to merge unrelated histories"
+msgstr "refus de fusionner des historiques sans relation"
+
+msgid "failure to merge"
+msgstr "échec de la fusion"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<options>] <branche1> <branche2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <arbre-de-base> <branche1> <branche2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "faire une fusion réelle au lieu d'une fusion triviale"
+
+msgid "do a trivial merge only"
+msgstr "faire seulement une fusion triviale"
+
+msgid "also show informational/conflict messages"
+msgstr "afficher aussi les messages d'information/de conflit"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "lister les noms de fichier sans modes/oids/indexation"
+
+msgid "allow merging unrelated histories"
+msgstr "permettre la fusion d'historiques sans rapport"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge est incompatible avec d'autres options"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<options>] [<commit>...]"
 
@@ -8164,9 +8314,6 @@ msgstr "--abort mais laisser l'index et l'arbre de travail inchangés"
 msgid "continue the current in-progress merge"
 msgstr "continuer la fusion en cours"
 
-msgid "allow merging unrelated histories"
-msgstr "permettre la fusion d'historiques sans rapport"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "ne pas utiliser les crochets pre-merge-commit et commit-msg"
 
@@ -8289,9 +8436,6 @@ msgstr "impossible de fermer '%s'"
 msgid "not something we can merge in %s: %s"
 msgstr "pas possible de fusionner ceci dans %s : %s"
 
-msgid "not something we can merge"
-msgstr "pas possible de fusionner ceci"
-
 msgid "--abort expects no arguments"
 msgstr "--abort n'accepte pas d'argument"
 
@@ -8342,13 +8486,19 @@ msgid "Can merge only exactly one commit into empty head"
 msgstr ""
 "Possible de fusionner exactement une seule validation dans une tête vide"
 
-msgid "refusing to merge unrelated histories"
-msgstr "refus de fusionner des historiques sans relation"
-
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Mise à jour %s..%s\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Vos modifications locales aux fichiers suivants seraient écrasées par la "
+"fusion :\n"
+"  %s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Essai de fusion vraiment triviale dans l'index...\n"
@@ -8382,6 +8532,11 @@ msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "La fusion automatique a réussi ; stoppée avant la validation comme demandé\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr ""
+"Une fois terminé, appliquer les modifications remisées avec `git stash pop`\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "attention : l'entrée d'étiquette ne passe pas fsck : %s"
@@ -8502,6 +8657,9 @@ msgstr "Vérification du renommage de '%s' en '%s'\n"
 msgid "bad source"
 msgstr "mauvaise source"
 
+msgid "destination exists"
+msgstr "la destination existe"
+
 msgid "can not move directory into itself"
 msgstr "impossible de déplacer un répertoire dans lui-même"
 
@@ -8517,9 +8675,6 @@ msgstr "pas sous le contrôle de version"
 msgid "conflicted"
 msgstr "en conflit"
 
-msgid "destination exists"
-msgstr "la destination existe"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "écrasement de '%s'"
@@ -8533,6 +8688,9 @@ msgstr "multiples sources pour la même destination"
 msgid "destination directory does not exist"
 msgstr "le répertoire de destination n'existe pas"
 
+msgid "destination exists in the index"
+msgstr "la destination existe dans l'index"
+
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, source=%s, destination=%s"
@@ -8894,8 +9052,8 @@ msgid "use notes from <notes-ref>"
 msgstr "utiliser les notes depuis <références-notes>"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "sous-commande inconnue : %s"
+msgid "unknown subcommand: `%s'"
+msgstr "sous-commande inconnue : `%s'"
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -9442,7 +9600,7 @@ msgstr ""
 "les réconcilier. Vous pouvez le faire en lançant une des\n"
 "commandes suivantes avant votre prochain tirage :\n"
 "\n"
-"  git config pull.rebase false  # fusion (stratégie par défaut)\n"
+"  git config pull.rebase false  # fusion\n"
 "  git config pull.rebase true   # rebasage\n"
 "  git config pull.ff only       # avance rapide seulement\n"
 "\n"
@@ -9822,12 +9980,17 @@ msgstr "afficher seulement les sorties liées à la première plage"
 msgid "only emit output related to the second range"
 msgstr "afficher seulement les sorties liées à la deuxième plage"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "'%s' n'est pas une révision"
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "pas une plage de commit : '%s'"
 
-msgid "single arg format must be symmetric range"
-msgstr "un format d'argument unique doit être une plage symétrique"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "pas une plage symétrique : '%s'"
 
 msgid "need two commit ranges"
 msgstr "plage entre deux commits requise"
@@ -10103,6 +10266,11 @@ msgstr "conserver les commits qui commencent vides"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "déplace les commits qui commencent par squash!/fixup! sous -i"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr ""
+"mettre à jour les branches qui pointent sur les commits qui sont en cours de "
+"rebasage"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr "ajouter les lignes exec après chaque commit de la liste éditable"
 
@@ -10639,6 +10807,9 @@ msgstr " nouveau (le prochain rapatriement (fetch) stockera dans remotes/%s)"
 msgid " tracked"
 msgstr " suivi"
 
+msgid " skipped"
+msgstr " sauté"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " dépassé (utilisez 'git remote prune' pour supprimer)"
 
@@ -11322,6 +11493,10 @@ msgstr "Impossible d'écrire le nouveau fichier d'index."
 msgid "unable to get disk usage of %s"
 msgstr "impossible de récupérer l'utilisation du disque de %s"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "valeur invalide pour '%s' : '%s', le seul format permis est '%s'"
+
 msgid "rev-list does not support display of notes"
 msgstr "rev-list ne supporte l'affichage des notes"
 
@@ -11347,6 +11522,9 @@ msgstr "fin prématurée de l'entrée"
 msgid "no usage string given before the `--' separator"
 msgstr "pas de chaîne d'usage fournie avant le séparateur `--'"
 
+msgid "missing opt-spec before option flags"
+msgstr "opt-spec manquant avant les drapeaux d'option"
+
 msgid "Needed a single revision"
 msgstr "Une seule révision attendue"
 
@@ -12132,6 +12310,10 @@ msgstr "ajouter devant chaque ligne le caractère de commentaire et un espace"
 msgid "Expecting a full ref name, got %s"
 msgstr "Nom de référence complet attendu, %s obtenu"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "impossible de trouver une poignée de dépôt pour le sous-module '%s'"
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -12140,12 +12322,6 @@ msgstr ""
 "impossible de trouver la configuration '%s'. Ce dépôt est considéré comme "
 "son propre amont d'autorité."
 
-msgid "alternative anchor for relative paths"
-msgstr "ancre alternative pour les chemins relatifs"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<chemin>] [<chemin>...]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "URL non trouvée pour le chemin de sous-module '%s' dans .gitmodules"
@@ -12179,8 +12355,8 @@ msgstr ""
 msgid "recurse into nested submodules"
 msgstr "parcourir récursivement les sous-modules"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <commande>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <commande>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -12205,8 +12381,8 @@ msgstr ""
 msgid "suppress output for initializing a submodule"
 msgstr "supprimer la sortie lors de l'initialisation d'un sous-module"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<options>] [<chemin>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<options>] [<chemin>]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -12235,9 +12411,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<chemin>...]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper <nom> <chemin>"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(blob)->%s(submodule)"
@@ -12271,8 +12444,8 @@ msgstr "sauter les sous-modules avec la valeur 'ignore_config' à 'all'"
 msgid "limit the summary size"
 msgstr "limiter la taille du résumé"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<options>] [<commit>] [--] [<chemin>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<options>] [<commit>] [--] [<chemin>]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "impossible de récupérer une révision pour HEAD"
@@ -12285,10 +12458,6 @@ msgstr "Synchronisation de l'URL sous-module pour '%s'\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "échec d'enregistrement de l'URL pour le chemin de sous-module '%s'"
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "échec d'obtention du dépôt distant par défaut pour le sous-module '%s'"
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "échec de mise à jour du dépôt distant pour le sous-module '%s'"
@@ -12297,8 +12466,8 @@ msgid "suppress output of synchronizing submodule url"
 msgstr ""
 "supprimer la sortie lors de la synchronisation de l'URL d'un sous-module"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<chemin>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<chemin>]"
 
 #, c-format
 msgid ""
@@ -12360,6 +12529,10 @@ msgstr ""
 "submodule.alternateErrorStrategy à 'info', ou de manière équivalente,\n"
 "clonez avec '--reference-if-able' au lieu de '--reference'."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "impossible de trouver une poignée de dépôt pour le répertoire git '%s'"
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "le sous-module '%s' ne peut pas ajouter d'alternative : %s"
@@ -12390,6 +12563,9 @@ msgstr "le répertoire n'est pas vide : '%s'"
 msgid "could not get submodule directory for '%s'"
 msgstr "impossible de créer le répertoire de sous-module pour '%s'"
 
+msgid "alternative anchor for relative paths"
+msgstr "ancre alternative pour les chemins relatifs"
+
 msgid "where the new submodule will be cloned to"
 msgstr "emplacement où le sous-module sera cloné"
 
@@ -12417,10 +12593,6 @@ msgstr ""
 "<dépôt>] [--name <nom>] [--depth <profondeur>] [--single-branch] [--filter "
 "<spécificateur-de-filtre>]--url <url> --path <chemin>"
 
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Mode de mise à jour '%s' invalide pour le chemin de sous-module '%s'"
-
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr ""
@@ -12495,6 +12667,10 @@ msgstr ""
 "Chemin de sous-module '%s' récupéré, mais il ne contenait pas %s. La "
 "récupération directe de ce commit a échoué."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "impossible d'initialiser le sous-module dans le chemin '%s'"
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12503,10 +12679,6 @@ msgstr ""
 "La branche du sous-module %s est configurée pour hériter de la branche du "
 "superprojet, mais le superprojet n'est sur aucune branche"
 
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "impossible de trouver une poignée de dépôt pour le sous-module '%s'"
-
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr ""
@@ -12543,12 +12715,14 @@ msgstr "ne pas récupérer les nouveaux objets depuis le site distant"
 msgid "path into the working tree"
 msgstr "chemin dans la copie de travail"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr ""
-"chemin dans la copie de travail, traversant les frontières de sous-modules"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "utiliser la stratégie de mise à jour 'checkout' (valeur par défaut)"
+
+msgid "use the 'merge' update strategy"
+msgstr "utiliser la stratégie de mise à jour par fusion"
 
-msgid "rebase, merge, checkout or none"
-msgstr "valeurs possibles : rebase, merge, checkout ou none"
+msgid "use the 'rebase' update strategy"
+msgstr "utiliser la stratégie de mise à jour par rebasage"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "créer un clone superficiel tronqué au nombre de révisions spécifié"
@@ -12562,6 +12736,9 @@ msgstr "spécifie si le clonage initial doit être aussi superficiel"
 msgid "don't print cloning progress"
 msgstr "ne pas afficher la progression du clonage"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "interdire de cloner dans un répertoire non-vide, implique --init"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12573,14 +12750,11 @@ msgstr ""
 "[no-]recommend-shallow] [--reference <dépôt>] [--recursive] [--[no-]single-"
 "branch] [--] [<chemin>...]"
 
-msgid "bad value for update parameter"
-msgstr "valeur invalide pour la mise à jour du paramètre"
-
 msgid "recurse into submodules"
 msgstr "parcourir récursivement les sous-modules"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<options>] [<chemin>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<options>] [<chemin>...]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr "vérifier si écrire dans le fichier .gitmodules est sur"
@@ -12601,8 +12775,8 @@ msgstr ""
 msgid "suppress output for setting url of a submodule"
 msgstr "supprimer la sortie lors du paramétrage de l'url d'un sous-module"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper sync [--quiet] <chemin> <nouvelle-url>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <chemin> <nouvelle-url>"
 
 msgid "set the default tracking branch to master"
 msgstr "régler la branche de suivi par défaut à master"
@@ -12610,14 +12784,11 @@ msgstr "régler la branche de suivi par défaut à master"
 msgid "set the default tracking branch"
 msgstr "régler la branche de suivi par défaut"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <chemin>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <chemin>"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branche> "
-"<chemin>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <branche> <chemin>"
 
 msgid "--branch or --default required"
 msgstr "--branch ou --default requis"
@@ -12716,8 +12887,8 @@ msgstr ""
 "configurer le nom du sous-module avec la chaîne passée au lieu d'utiliser "
 "par défaut son chemin"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<options>] [--] <dépôt> [<chemin>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<options>] [--] <dépôt> [<chemin>]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
@@ -12927,6 +13098,16 @@ msgstr "Étiquette '%s' mise à jour (elle était sur %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "le paquet dépasse la taille maximale permise"
 
+msgid "failed to write object in stream"
+msgstr "impossible d'écrire l'objet dans le flux"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "la décompression (inflate) a retourné (%d)"
+
+msgid "invalid blob object from stream"
+msgstr "objet blob invalide depuis le flux"
+
 msgid "Unpacking objects"
 msgstr "Dépaquetage des objets"
 
@@ -13470,6 +13651,27 @@ msgstr "écrire l'objet arbre pour un sous-répertoire <préfixe>"
 msgid "only useful for debugging"
 msgstr "seulement utile pour le débogage"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch non géré sur cette plateforme"
+
+msgid "failed to create temporary file"
+msgstr "impossible de créer un fichier temporaire"
+
+msgid "insufficient capabilities"
+msgstr "capacités insuffisantes"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "impossible de télécharger le colis depuis l'URI '%s'"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "le fichier à l'URI '%s' n'est pas un colis"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "échec pour ouvrir le colis de l'URI '%s'"
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "algorithme d'empreinte du colis inconnu : %s"
@@ -13679,6 +13881,9 @@ msgid "Give an object a human readable name based on an available ref"
 msgstr ""
 "Baptiser un objet avec un nom lisible à partir d'une référence disponible"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Générer une archive zip d'information de diagnostic"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr ""
 "Afficher les changements entre les validations, entre validation et copie de "
@@ -13815,8 +14020,8 @@ msgstr "Lancer une fusion à 3 points pour les fichiers à fusionner"
 msgid "The standard helper program to use with git-merge-index"
 msgstr "Le programme assistant standard à utiliser avec git-merge-index"
 
-msgid "Show three-way merge without touching index"
-msgstr "Afficher la fusion à trois points sans modifier l'index"
+msgid "Perform merge without touching index or working tree"
+msgstr "effectuer la fusion sans toucher à l'index ni à l'arbre de travail"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
@@ -14018,6 +14223,9 @@ msgstr "Valider des fichiers d'archive Git empaquetés"
 msgid "Check the GPG signature of tags"
 msgstr "Vérifier la signature GPG d'étiquettes"
 
+msgid "Display version information about Git"
+msgstr "Afficher l'information de version à propos de Git"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Afficher les journaux avec la différence que chaque commit introduit"
 
@@ -14051,6 +14259,24 @@ msgstr "Un ensemble minimal utile des commandes de Git pour tous les jours"
 msgid "Frequently asked questions about using Git"
 msgstr "Foire aux questions sur l'utilisation de Git"
 
+msgid "The bundle file format"
+msgstr "le format du fichier de colis"
+
+msgid "Chunk-based file formats"
+msgstr "format de fichier avec des sections"
+
+msgid "Git commit graph format"
+msgstr "format de graphe de commit de Gti"
+
+msgid "Git index format"
+msgstr "format d'index Git"
+
+msgid "Git pack format"
+msgstr "format de paquet Git"
+
+msgid "Git cryptographic signature formats"
+msgstr "formats de signature cryptographique Git"
+
 msgid "A Git Glossary"
 msgstr "Un glossaire Git"
 
@@ -14073,6 +14299,21 @@ msgstr "Définition des propriétés de sous-module"
 msgid "Git namespaces"
 msgstr "Espaces de nom de Git"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Capacités des protocoles v0 et v1"
+
+msgid "Things common to various protocols"
+msgstr "Choses communes aux différents protocoles"
+
+msgid "Git HTTP-based protocols"
+msgstr "protocoles Git basés sur HTTP"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Comment les paquets sont transférés sur le réseau"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Protocole réseau Git, version 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Programmes assistants pour interagir avec des dépôts distants"
 
@@ -14097,6 +14338,9 @@ msgstr "Interface web de Git"
 msgid "An overview of recommended workflows with Git"
 msgstr "Un aperçu des flux de travail recommandés avec Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Un outil pour gérer les grands dépôts Git"
+
 msgid "commit-graph file is too small"
 msgstr "le graphe de commit est trop petit"
 
@@ -14358,6 +14602,14 @@ msgstr "aucune information de compilateur disponible\n"
 msgid "no libc information available\n"
 msgstr "aucune information de libc disponible\n"
 
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "impossible de déterminer l'espace libre du disque pour '%s'"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "impossible d'avoir des informations pour '%s'"
+
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
 msgstr "[GLE %ld] le fil de santé n'a pas pu ouvrir '%ls'"
@@ -14412,6 +14664,14 @@ msgstr "GetOverlappedResult a échoué sur '%s' [GLE %ld]"
 msgid "could not read directory changes [GLE %ld]"
 msgstr "impossible de lire les modifications du répertoire [GLE %ld]"
 
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] impossible d'ouvrir pour lire '%ls'"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] impossible d'obtenir l'information de protocole pour '%ls'"
+
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr "échec de la copie du SID (%ld)"
@@ -14970,200 +15230,24 @@ msgid "failed to close rev-list's stdin"
 msgstr "impossible de fermer l'entrée standard du rev-list"
 
 #, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' n'existe pas"
-
-msgid "need a working directory"
-msgstr "répertoire de travail nécessaire"
-
-msgid "could not find enlistment root"
-msgstr "impossible de trouver la racine d'enrôlement"
+msgid "illegal crlf_action %d"
+msgstr "crlf_action illégal %d"
 
 #, c-format
-msgid "could not switch to '%s'"
-msgstr "impossible de basculer vers '%s'"
+msgid "CRLF would be replaced by LF in %s"
+msgstr "Les CRLF seraient remplacés par des LF dans %s"
 
 #, c-format
-msgid "could not configure %s=%s"
-msgstr "impossible de configurer %s=%s"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "impossible de configurer log.excludeDecoration"
-
-msgid "Scalar enlistments require a worktree"
-msgstr "Les enrôlements scalaires requièrent un arbre de travail"
+msgid ""
+"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
+"touches it"
+msgstr ""
+"dans la copie de travail pour '%s', CRLF sera remplacé par LF la prochaine "
+"fois que Git le touche"
 
 #, c-format
-msgid "could not open directory '%s'"
-msgstr "impossible d'ouvrir le répertoire '%s'"
-
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "'%s' sauté, qui n'est ni un fichier ni un répertoire"
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "impossible de déterminer l'espace libre du disque pour '%s'"
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "impossible d'avoir des informations pour '%s'"
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "la HEAD distante n'est pas une branche : '%.*s'"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-"échec de récupération de la branche par défaut depuis le distant ; "
-"utilisation de la valeur par défaut locale"
-
-msgid "failed to get default branch name"
-msgstr "échec de l'obtention du nom de branche par défaut"
-
-msgid "failed to unregister repository"
-msgstr "échec du désenregistrement du dépôt"
-
-msgid "failed to delete enlistment directory"
-msgstr "échec de la suppression du répertoire d'enrôlement"
-
-msgid "branch to checkout after clone"
-msgstr "branche à extraire après le clonage"
-
-msgid "when cloning, create full working directory"
-msgstr "lors d'un clonage, créer un répertoire de travail complet"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "ne télécharger les méta-données que pour la branche qui sera extraite"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<options>] [--] <dépôt> [<répertoire>]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "impossible de déduire le nom de l'arbre de travail depuis '%s'"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "le répertoire '%s' existe déjà"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "échec d'obtention de la branche par défaut pour '%s'"
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "impossible de paramétrer le distant dans '%s'"
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "impossible de configurer '%s'"
-
-msgid "partial clone failed; attempting full clone"
-msgstr "échec du clonage partiel ; tentative de clonage complet"
-
-msgid "could not configure for full clone"
-msgstr "impossible de configurer pour le clonage complet"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<enrôlement>]"
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "impossible de créer le répertoire pour '%s'"
-
-msgid "could not duplicate stdout"
-msgstr "impossible de dupliquer stdout"
-
-msgid "failed to write archive"
-msgstr "impossible d'écrire l'archive"
-
-msgid "`scalar list` does not take arguments"
-msgstr "`scalar list` n'accepte pas d'argument"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<enrôlement>]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "reconfigurer tous les enrôlements enregistrés"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scala reconfigure [--all|<enrôlement>]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "--all ou <enrôlement>, mais pas les deux"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "dépôt git parti dans '%s'"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <tâche> [<enrôlement>]\n"
-"Tâches :\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "pas de tâche : '%s'"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<enrôlement>]"
-
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <enrôlement>"
-
-msgid "refusing to delete current working directory"
-msgstr "refus de la suppression du répertoire de travail actuel"
-
-msgid "include Git version"
-msgstr "inclure la version Git"
-
-msgid "include Git's build options"
-msgstr "inclure les options de construction de Git"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "-C requiert un <répertoire>"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "échec de modification en '%s'"
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c exige un argument <clé>=<valeur>"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <répertoire>] [-c <clé>=<valeur>] <commande> [<options>]\n"
-"\n"
-"Commandes :\n"
-
-#, c-format
-msgid "illegal crlf_action %d"
-msgstr "crlf_action illégal %d"
-
-#, c-format
-msgid "CRLF would be replaced by LF in %s"
-msgstr "Les CRLF seraient remplacés par des LF dans %s"
-
-#, c-format
-msgid ""
-"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
-"touches it"
-msgstr ""
-"dans la copie de travail pour '%s', CRLF sera remplacé par LF la prochaine "
-"fois que Git le touche"
-
-#, c-format
-msgid "LF would be replaced by CRLF in %s"
-msgstr "Les LF seraient remplacés par des CRLF dans %s"
+msgid "LF would be replaced by CRLF in %s"
+msgstr "Les LF seraient remplacés par des CRLF dans %s"
 
 #, c-format
 msgid ""
@@ -15357,6 +15441,32 @@ msgstr ""
 msgid "Marked %d islands, done.\n"
 msgstr "Marquage de %d îlots, fait.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "valeur invalide de --%s : %s"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "impossible d'archiver le répertoire manquant '%s'"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "impossible d'ouvrir le répertoire '%s'"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "'%s' sauté, qui n'est ni un fichier ni un répertoire"
+
+msgid "could not duplicate stdout"
+msgstr "impossible de dupliquer stdout"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "impossible d'ajouter le répertoire '%s' à l'archiveur"
+
+msgid "failed to write archive"
+msgstr "impossible d'écrire l'archive"
+
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base ne fonctionne pas avec des plages"
 
@@ -16000,6 +16110,9 @@ msgstr "git fetch-pack : ACK/NACK attendu, '%s' reçu"
 msgid "unable to write to remote"
 msgstr "impossible d'écrire sur un distant"
 
+msgid "Server supports filter"
+msgstr "Le serveur supporte filter"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "ligne de superficiel invalide : %s"
@@ -16110,9 +16223,6 @@ msgstr "le serveur ne supporte pas l'algorithme '%s'"
 msgid "Server does not support shallow requests"
 msgstr "Le serveur ne supporte pas les requêtes superficielles"
 
-msgid "Server supports filter"
-msgstr "Le serveur supporte filter"
-
 msgid "unable to write request to remote"
 msgstr "impossible d'écrire la requête sur le distant"
 
@@ -16458,6 +16568,12 @@ msgstr "Commandes bas niveau / Synchronisation de dépôts"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Commandes bas niveau / Assistants internes"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "dépôts publics, commandes et interfaces de fichier"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Formats de fichier, protocoles et interfaces de niveau développeur"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "commandes git disponibles dans '%s'"
@@ -16471,6 +16587,12 @@ msgstr "Ci-dessous les commandes Git habituelles dans diverses situations :"
 msgid "The Git concept guides are:"
 msgstr "Les guides des concepts de Git sont :"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Dépôts publics, commandes et interfaces de fichier :"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "formats de fichiers, protocoles et interfaces de niveau développeur :"
+
 msgid "External commands"
 msgstr "Commandes externes"
 
@@ -16557,10 +16679,6 @@ msgstr ""
 "Vous pouvez désactiver cet avertissement avec `git config advice.ignoredHook "
 "false`."
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "impossible de démarrer le crochet '%s'\n"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "l'argument de --packfile doit être une empreinte valide ('%s' reçu)"
@@ -16749,19 +16867,14 @@ msgstr "vidage attendu après les arguments ls-refs"
 msgid "quoted CRLF detected"
 msgstr "CRLF citées détectées"
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Vos modifications locales aux fichiers suivants seraient écrasées par la "
-"fusion :\n"
-"  %s"
-
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "Échec de la fusion du sous-module %s (non extrait)"
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Échec de la fusion du sous-module %s (pas de base de fusion)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "Échec de fusion du sous-module %s (commits non présents)"
@@ -16782,28 +16895,10 @@ msgstr "Échec de la fusion du sous-module %s"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
 msgstr ""
 "Échec de fusion du sous-module %s mais une résolution possible de fusion "
-"existe :\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"Si c'est correct, ajoutez le simplement à l'index\n"
-"en utilisant par exemple :\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"qui acceptera cette suggestion.\n"
+"existe : %s"
 
 #, c-format
 msgid ""
@@ -16968,13 +17063,46 @@ msgstr ""
 "CONFLIT (modification/suppression) : %s supprimé dans %s et modifié dans %s. "
 "Version %s de %s laissée dans l'arbre."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - aller au sous-module (%s), et soit fusionner le commit %s,\n"
+"   soit mettre à jour vers un commit exstant qui intègre déjà ces "
+"modifications\n"
+
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
 msgstr ""
-"Note :%s pas à jour et au milieu de l'extraction d'une version "
-"conflictuelle ; la vielle copie a été renommée en %s"
+"La fusion récursive des sous-modules ne gère actuellement que les cas "
+"triviaux.\n"
+"Veuillez procéder à la fusion manuellement pour chaque sous-module en "
+"conflit.\n"
+"Ceci peut être réalisé par les étapes suivantes :\n"
+"%s - revenir au super-projet et lancer :\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   pour enregistrer la fusion ci-dessus et mettre à jour\n"
+" - résoudre tous les autres conflits dans le super-projet\n"
+" - valider l'index résultant dans le super-projet\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -17045,6 +17173,22 @@ msgstr "Échec de fusion du sous-module %s (pas en avance rapide)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "Résolution possible de fusion trouvée pour le sous-module :\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Si c'est correct, ajoutez le simplement à l'index\n"
+"en utilisant par exemple :\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"qui acceptera cette suggestion.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr "Échec de fusion du sous-module %s (plusieurs fusions trouvées)"
@@ -17571,6 +17715,22 @@ msgstr "échec de deflateEnd sur l'objet %s (%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "données de source d'objet instable pour %s"
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "écrire l'objet de flux %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "impossible de compresser le nouvel objet dans le flux (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "échec de deflateEnd sur l'objet (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "échec de la création du répertoire %s"
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr "impossible de lire l'objet pour %s"
@@ -17782,39 +17942,143 @@ msgid "invalid object name '%.*s'."
 msgstr "nom d'objet invalide : '%.*s'."
 
 #, c-format
-msgid "invalid object type \"%s\""
-msgstr "type d'objet invalide \"%s\""
+msgid "invalid object type \"%s\""
+msgstr "type d'objet invalide \"%s\""
+
+#, c-format
+msgid "object %s is a %s, not a %s"
+msgstr "l'objet %s est de type %s, pas de type %s"
+
+#, c-format
+msgid "object %s has unknown type id %d"
+msgstr "l'objet %s a un id de type inconnu %d"
+
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "impossible d'analyser l'objet : %s"
+
+#, c-format
+msgid "hash mismatch %s"
+msgstr "incohérence de hachage %s"
+
+msgid "trying to write commit not in index"
+msgstr "échec de l'écriture de l'objet commit absent de l'index"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "échec du chargement de l'index en bitmap (corruption ?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "index en bitmap corrompu (trop court)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "fichier d'index en bitmap corrompu (mauvais entête)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "version non gérée '%d' pour le fichier d'index en bitmap"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"fichier d'index en bitmap corrompu (trop court pour correspondre à un cache "
+"d'empreinte)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"fichier d'index en bitmap corrompu (trop court pour correspondre à une table "
+"de recherche)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "entrée dupliquée dans l'index en bitmap : '%s'"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "bitmap ewah corrompu : entête tronqué pour l'entrée %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "bitmap ewah corrompu : index de commit %u hors plage"
+
+msgid "corrupted bitmap pack index"
+msgstr "index de paquet en bitmap corrompu"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "décalage XOR invalide dans l'index de paquet en bitmap"
+
+msgid "cannot fstat bitmap file"
+msgstr "impossible d'obtenir le statut (fstat) du fichier de bitmap"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "fichier bitmap extra ignoré : '%s'"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "la somme de contrôle ne correspond pas entre MIDX et bitmap"
+
+msgid "multi-pack bitmap is missing required reverse index"
+msgstr "l'index inverse requis manque dans l'index multi-paquet"
+
+#, c-format
+msgid "could not open pack %s"
+msgstr "impossible d'ouvrir le paquet '%s'"
+
+#, c-format
+msgid "preferred pack (%s) is invalid"
+msgstr "le paquet préféré (%s) est invalide"
+
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr ""
+"table de recherche en bitmap corrompue : position de triplet hors d'index"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr ""
+"table de recherche en bitmap corrompue : la chaîne de xor dépasse le nombre "
+"d'entrées"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr "table de recherche en bitmap corrompue : index de commit %u hors plage"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr "bitmap ewah corrompue : entête tronqué pour la bitmap du commit '%s'"
 
 #, c-format
-msgid "object %s is a %s, not a %s"
-msgstr "l'objet %s est de type %s, pas de type %s"
+msgid "object '%s' not found in type bitmaps"
+msgstr "objet '%s' non trouvé dans les bitmaps de type"
 
 #, c-format
-msgid "object %s has unknown type id %d"
-msgstr "l'objet %s a un id de type inconnu %d"
+msgid "object '%s' does not have a unique type"
+msgstr "l'objet '%s' n'a pas un type unique"
 
 #, c-format
-msgid "unable to parse object: %s"
-msgstr "impossible d'analyser l'objet : %s"
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "objet '%s' : type réel '%s', attendu : '%s'"
 
 #, c-format
-msgid "hash mismatch %s"
-msgstr "incohérence de hachage %s"
+msgid "object not in bitmap: '%s'"
+msgstr "objet non trouvé dans la bitmap : '%s'"
 
-msgid "multi-pack bitmap is missing required reverse index"
-msgstr "l'index inverse requis manque dans l'index multi-paquet"
+msgid "failed to load bitmap indexes"
+msgstr "échec de chargement des index de bitmap"
+
+msgid "you must specify exactly one commit to test"
+msgstr "vous devez spécifier un seul commit à tester"
 
 #, c-format
-msgid "could not open pack %s"
-msgstr "impossible d'ouvrir le paquet '%s'"
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "le commit '%s' n'a pas de bitmap indexée"
+
+msgid "mismatch in bitmap results"
+msgstr "décalage dans le résultats de bitmap"
 
 #, c-format
-msgid "preferred pack (%s) is invalid"
-msgstr "le paquet préféré (%s) est invalide"
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "impossible de trouver '%s' dans le paquet '%s' à l'offset %<PRIuMAX>"
 
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "impossible de trouver %s dans le paquet %s à l'offset %<PRIuMAX>"
+msgid "unable to get disk usage of '%s'"
+msgstr "impossible de récupérer l'utilisation du disque de '%s'"
 
 #, c-format
 msgid "mtimes file %s is too small"
@@ -17939,6 +18203,9 @@ msgstr "vouliez-vous dire `--%s` (avec deux signes moins)?"
 msgid "alias of --%s"
 msgstr "alias pour --%s"
 
+msgid "need a subcommand"
+msgstr "sous-commande requise"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "option inconnue « %s »"
@@ -18385,9 +18652,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -18415,6 +18685,11 @@ msgstr ""
 "         créer un commit de fusion utilisant le message de fusion original\n"
 "         (ou l'uniligne, si aucun commit de fusion n'a été spécifié).\n"
 "         Utilisez -c <commit> pour reformuler le message de validation.\n"
+" u, update-ref <réf> = suivre un espace réservé pour la <réf> à mettre à "
+"jour\n"
+"                       à cette position dans les nouveaux commits. La <réf> "
+"est\n"
+"                       mise à jour à la fin du rebasage\n"
 "\n"
 "Vous pouvez réordonner ces lignes ; elles sont exécutées de haut en bas.\n"
 
@@ -18886,6 +19161,13 @@ msgstr "erreur de protocole : sha/ref attendu, '%s' trouvé"
 msgid "http transport does not support %s"
 msgstr "le transport http ne supporte pas %s"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "erreur de protocole : '<url> <chemin>' attendu, espace manquant"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "échec du téléchargement du fichier à l'URL '%s'"
+
 msgid "git-http-push failed"
 msgstr "échec de git-http-push"
 
@@ -19236,6 +19518,15 @@ msgstr "impossible de déterminer la révision HEAD"
 msgid "failed to find tree of %s"
 msgstr "impossible de trouver l'arbre de %s"
 
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo enregistre `%s` qui manque"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr ""
+"impossible de récupérer le commit pour l'argument de chemin d'ascendance %s"
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<fichier-paquet> n'est plus géré"
 
@@ -19256,6 +19547,174 @@ msgstr "-L ne supporte pas encore les formats de diff autres que -p et -s"
 msgid "cannot create async thread: %s"
 msgstr "impossible de créer un fil asynchrone : %s"
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' n'existe pas"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "impossible de basculer vers '%s'"
+
+msgid "need a working directory"
+msgstr "répertoire de travail nécessaire"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Les enrôlements scalaires requièrent un arbre de travail"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "impossible de configurer %s=%s"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "impossible de configurer log.excludeDecoration"
+
+msgid "could not add enlistment"
+msgstr "impossible d'ajouter l'enrôlement"
+
+msgid "could not set recommended config"
+msgstr "impossible de réglér la configuration recommandée"
+
+msgid "could not turn on maintenance"
+msgstr "impossible d'activer la maintenance"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "impossible de démarrer le daemon FSMonitor"
+
+msgid "could not turn off maintenance"
+msgstr "impossible de désactiver la maintenance"
+
+msgid "could not remove enlistment"
+msgstr "impossible de supprimer l'enrôlement"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "la HEAD distante n'est pas une branche : '%.*s'"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"échec de récupération de la branche par défaut depuis le distant ; "
+"utilisation de la valeur par défaut locale"
+
+msgid "failed to get default branch name"
+msgstr "échec de l'obtention du nom de branche par défaut"
+
+msgid "failed to unregister repository"
+msgstr "échec du désenregistrement du dépôt"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "Échec de l'arrêt de FSEVEntStream"
+
+msgid "failed to delete enlistment directory"
+msgstr "échec de la suppression du répertoire d'enrôlement"
+
+msgid "branch to checkout after clone"
+msgstr "branche à extraire après le clonage"
+
+msgid "when cloning, create full working directory"
+msgstr "lors d'un clonage, créer un répertoire de travail complet"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "ne télécharger les méta-données que pour la branche qui sera extraite"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<options>] [--] <dépôt> [<répertoire>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "impossible de déduire le nom de l'arbre de travail depuis '%s'"
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "le répertoire '%s' existe déjà"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "échec d'obtention de la branche par défaut pour '%s'"
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "impossible de paramétrer le distant dans '%s'"
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "impossible de configurer '%s'"
+
+msgid "partial clone failed; attempting full clone"
+msgstr "échec du clonage partiel ; tentative de clonage complet"
+
+msgid "could not configure for full clone"
+msgstr "impossible de configurer pour le clonage complet"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<enrôlement>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` n'accepte pas d'argument"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<enrôlement>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "reconfigurer tous les enrôlements enregistrés"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scala reconfigure [--all|<enrôlement>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all ou <enrôlement>, mais pas les deux"
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "dépôt git parti dans '%s'"
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <tâche> [<enrôlement>]\n"
+"Tâches :\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "pas de tâche : '%s'"
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<enrôlement>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <enrôlement>"
+
+msgid "refusing to delete current working directory"
+msgstr "refus de la suppression du répertoire de travail actuel"
+
+msgid "include Git version"
+msgstr "inclure la version Git"
+
+msgid "include Git's build options"
+msgstr "inclure les options de construction de Git"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C requiert un <répertoire>"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "échec de modification en '%s'"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c exige un argument <clé>=<valeur>"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <répertoire>] [-c <clé>=<valeur>] <commande> [<options>]\n"
+"\n"
+"Commandes :\n"
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr ""
 "paquet de nettoyage inattendu pendant la lecture de l'état de dépaquetage "
@@ -19379,10 +19838,6 @@ msgstr "vos modifications locales seraient écrasées par %s."
 msgid "commit your changes or stash them to proceed."
 msgstr "validez vos modifications ou les remiser pour continuer."
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s : avance rapide"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -19872,6 +20327,27 @@ msgstr "impossible de seulement essayer de fusionner '%.*s'"
 msgid "merge: Unable to write new index file"
 msgstr "fusion : Impossible d'écrire le nouveau fichier index"
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "un processu 'rebase' semble déjà lancé; '%s.lock' existe déjà"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Les références suivantes ont été mises à jour avec %s :\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Échec des mises à jour des références suivantes avec %s :\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "Autoremisage impossible"
 
@@ -20038,6 +20514,10 @@ msgstr "impossible d'éviter les commandes de picorage non nécessaires"
 msgid "the script was already rearranged."
 msgstr "le script a déjà été réarrangé."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "le fichier update-refs %s est invalide"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "'%s' est hors du dépôt à '%s'"
@@ -20164,16 +20644,20 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"dépôt non sécurisé ('%s' appartient à quelqu'un d'autre)\n"
-"Pour ajouter une exception pour ce dépôt, lancez :\n"
+"propriétaire douteux détecté dans le dépôt à '%s'\n"
+"%sPour ajouter une exception pour ce dépôt, lancez :\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "impossible d'utiliser le dépôt nu '%s' (safe.bareRepository vaut '%s')"
+
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -21061,6 +21545,18 @@ msgstr "numéro de port invalide"
 msgid "invalid '..' path segment"
 msgstr "segment de chemin '..' invalide"
 
+msgid "usage: "
+msgstr "usage : "
+
+msgid "fatal: "
+msgstr "fatal : "
+
+msgid "error: "
+msgstr "erreur : "
+
+msgid "warning: "
+msgstr "avertissement : "
+
 msgid "Fetching objects"
 msgstr "Récupération des objets"
 
@@ -21502,7 +21998,7 @@ msgid "HEAD detached from "
 msgstr "HEAD détachée depuis "
 
 msgid "Not currently on any branch."
-msgstr "Actuellement sur aucun branche."
+msgstr "Actuellement sur aucune branche."
 
 msgid "Initial commit"
 msgstr "Validation initiale"
@@ -21874,23 +22370,6 @@ msgstr "Les sections sélectionnées ne s'applique pas à l'index !\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "fichier non-fusionné ignoré : %s\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Appliquer le changement de mode dans l'arbre de travail [y,n,q,a,d%s,?] ? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Appliquer la suppression dans l'arbre de travail [y,n,q,a,d%s,?] ? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Appliquer l'ajout dans l'arbre de travail [y,n,q,a,d%s,?] ? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "Appliquer la section à l'arbre de travail [y,n,q,a,d%s,?] ? "
-
 msgid "No other hunks to goto\n"
 msgstr "Aucune autre section à atteindre\n"
 
@@ -22289,5 +22768,87 @@ msgstr "%s sauté avec un suffix de sauvegarde '%s'.\n"
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : "
 
+#~ msgid "(stats|all)"
+#~ msgstr "(stats|all)"
+
+#~ msgid "git maintenance register"
+#~ msgstr "git maintenance register"
+
+#~ msgid "git maintenance unregister"
+#~ msgstr "git maintenance unregister"
+
+#~ msgid "git maintenance stop"
+#~ msgstr "git maintenance stop"
+
+#, c-format
+#~ msgid "could not parse colored hunk header '%.*s'"
+#~ msgstr "impossible d'analyser l'entête coloré de section '%.*s'"
+
+#, c-format
+#~ msgid "Unknown subcommand: %s"
+#~ msgstr "Sous-commande inconnue : %s"
+
+#~ msgid "checked out in another worktree"
+#~ msgstr "extrait dans un autre arbre de travail"
+
+#~ msgid "failed to open stdin of 'crontab'"
+#~ msgstr "échec à l'ouverture de stdin de 'crontab'"
+
+#, c-format
+#~ msgid "invalid subcommand: %s"
+#~ msgstr "sous-commande invalide : %s"
+
+#~ msgid "single arg format must be symmetric range"
+#~ msgstr "un format d'argument unique doit être une plage symétrique"
+
+#~ msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
+#~ msgstr "git submodule--helper list [--prefix=<chemin>] [<chemin>...]"
+
+#~ msgid "git submodule--helper name <path>"
+#~ msgstr "git submodule--helper <nom> <chemin>"
+
+#, c-format
+#~ msgid "failed to get the default remote for submodule '%s'"
+#~ msgstr ""
+#~ "échec d'obtention du dépôt distant par défaut pour le sous-module '%s'"
+
+#, c-format
+#~ msgid "Invalid update mode '%s' for submodule path '%s'"
+#~ msgstr ""
+#~ "Mode de mise à jour '%s' invalide pour le chemin de sous-module '%s'"
+
+#~ msgid "path into the working tree, across nested submodule boundaries"
+#~ msgstr ""
+#~ "chemin dans la copie de travail, traversant les frontières de sous-modules"
+
+#~ msgid "rebase, merge, checkout or none"
+#~ msgstr "valeurs possibles : rebase, merge, checkout ou none"
+
+#~ msgid "bad value for update parameter"
+#~ msgstr "valeur invalide pour la mise à jour du paramètre"
+
+#~ msgid "Show three-way merge without touching index"
+#~ msgstr "Afficher la fusion à trois points sans modifier l'index"
+
+#, c-format
+#~ msgid "could not create directory for '%s'"
+#~ msgstr "impossible de créer le répertoire pour '%s'"
+
+#, c-format
+#~ msgid "Couldn't start hook '%s'\n"
+#~ msgstr "impossible de démarrer le crochet '%s'\n"
+
+#, c-format
+#~ msgid ""
+#~ "Note: %s not up to date and in way of checking out conflicted version; "
+#~ "old copy renamed to %s"
+#~ msgstr ""
+#~ "Note :%s pas à jour et au milieu de l'extraction d'une version "
+#~ "conflictuelle ; la vielle copie a été renommée en %s"
+
+#, c-format
+#~ msgid "%s: fast-forward"
+#~ msgstr "%s : avance rapide"
+
 #~ msgid "--preserve-merges was replaced by --rebase-merges"
 #~ msgstr "--preserve-merges a été remplacé par --rebase-merges"
index 794bf8f1c560eac43e538a98e3a7e2c375b56111..7ce5acb674ced672d168b21029d0cadf29000924 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-21 20:20+0000\n"
-"PO-Revision-Date: 2022-06-18 16:30+0700\n"
+"POT-Creation-Date: 2022-09-28 14:31+0700\n"
+"PO-Revision-Date: 2022-09-28 14:50+0700\n"
 "Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n"
 "Language-Team: Indonesian\n"
 "Language: id\n"
@@ -22,7 +22,7 @@ msgstr ""
 msgid "Huh (%s)?"
 msgstr "Huh (%s)?"
 
-#: add-interactive.c builtin/rebase.c reset.c sequencer.c
+#: add-interactive.c builtin/merge.c builtin/rebase.c reset.c sequencer.c
 msgid "could not read index"
 msgstr "tidak dapat membaca indeks"
 
@@ -203,8 +203,8 @@ msgid "unstaged"
 msgstr "tak tergelar"
 
 #: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
-#: builtin/fetch.c builtin/merge.c builtin/pull.c builtin/submodule--helper.c
-#: git-add--interactive.perl
+#: builtin/diagnose.c builtin/fetch.c builtin/merge.c builtin/pull.c
+#: builtin/submodule--helper.c git-add--interactive.perl
 msgid "path"
 msgstr "jalur"
 
@@ -464,22 +464,22 @@ msgstr ""
 #: add-patch.c git-add--interactive.perl
 #, c-format, perl-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Terapkan perubahan mode ke indeks dan pohon kerja [y,n,q,a,d%s,?]? "
+msgstr "Terapkan perubahan mode pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
 #: add-patch.c git-add--interactive.perl
 #, c-format, perl-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Terapkan penghapusan ke indeks dan pohon kerja [y,n,q,a,d%s,?]? "
+msgstr "Terapkan penghapusan pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
 #: add-patch.c git-add--interactive.perl
 #, c-format, perl-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Terapkan penambahan ke indeks dan pohon kerja [y,n,q,a,d%s,?]? "
+msgstr "Terapkan penambahan pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
 #: add-patch.c git-add--interactive.perl
 #, c-format, perl-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Terapkan bingkah ini ke indeks dan pohon kerja [y,n,q,a,d%s,?]? "
+msgstr "Terapkan bingkah ini pada indeks dan pohon kerja [y,n,q,a,d%s,?]? "
 
 #: add-patch.c
 msgid ""
@@ -495,6 +495,26 @@ msgstr ""
 "a - terapkan bingkah ini dan semua bingkah selanjutnya dalam berkas\n"
 "d - jangan terapkan bingkah ini atau bingkah selanjutnya dalam berkas\n"
 
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Terapkan perubahan mode pada pohon kerja [y,n,q,a,d%s,?]?"
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Terapkan penghapusan pada pohon kerja [y,n,q,a,d%s,?]?"
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Terapkan penambahan pada pohon kerja [y,n,q,a,d%s,?]?"
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Terapkan bingkah ini pada pohon kerja [y,n,q,a,d%s,?]?"
+
 #: add-patch.c
 msgid ""
 "y - apply this hunk to worktree\n"
@@ -514,11 +534,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "tidak dapat menguraikan kepala bingkah '%.*s'"
 
-#: add-patch.c
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "tidak dapat menguraikan kepala bingkah berwarna '%.*s'"
-
 #: add-patch.c
 msgid "could not parse diff"
 msgstr "tidak dapat menguraikan diff"
@@ -626,11 +641,11 @@ msgstr ""
 
 #: add-patch.c
 msgid "The selected hunks do not apply to the index!"
-msgstr "Bingkah yang dipilih tidak diterapkan ke indeks!"
+msgstr "Bingkah yang dipilih tidak diterapkan pada indeks!"
 
 #: add-patch.c git-add--interactive.perl
 msgid "Apply them to the worktree anyway? "
-msgstr "Tetap terapkan itu ke pohon kerja? "
+msgstr "Tetap terapkan pada pohon kerja? "
 
 #: add-patch.c git-add--interactive.perl
 msgid "Nothing was applied.\n"
@@ -857,6 +872,26 @@ msgstr ""
 "ke false\n"
 "\n"
 
+#: advice.c
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Jalur berikut sudah dipindahkan di luar definisi sparse-checkout\n"
+"tetapi bukan jarang karena perubahan lokal.\n"
+
+#: advice.c
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Untuk memperbaiki kejarangan jalur tersebut, lakukan hal-hal berikut:\n"
+"* Gunakan \"git add --sparse <jalur>\" untuk memperbarui indeks\n"
+"* Gunakan \"git sparse-checkout reapply\" untuk menerapkan aturan kejarangan"
+
 #: alias.c
 msgid "cmdline ends with \\"
 msgstr "baris perintah diakhiri dengan \\"
@@ -1097,7 +1132,7 @@ msgstr ""
 msgid "patch failed: %s:%ld"
 msgstr "tambalan gagal: %s:%ld"
 
-#: apply.c
+#: apply.c builtin/mv.c
 #, c-format
 msgid "cannot checkout %s"
 msgstr "tidak dapat men-checkout %s"
@@ -1495,6 +1530,11 @@ msgstr "tidak dapat mengaruskan blob %s"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "mode berkas tidak didukung: 0%o (SHA1: %s)"
 
+#: archive-tar.c archive-zip.c builtin/pack-objects.c
+#, c-format
+msgid "deflate error (%d)"
+msgstr "kesalahan deflasi (%d)"
+
 #: archive-tar.c
 #, c-format
 msgid "unable to start '%s' filter"
@@ -1519,11 +1559,6 @@ msgstr "jalur bukan UTF-8 valid: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "jalur terlalu panjang (%d karakter, SHA1: %s): %s"
 
-#: archive-zip.c builtin/pack-objects.c
-#, c-format
-msgid "deflate error (%d)"
-msgstr "kesalahan deflasi (%d)"
-
 #: archive-zip.c
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
@@ -1841,8 +1876,8 @@ msgstr ""
 "--reverse dan --first-parent bersama-sama butuh komit terbaru yang disebutkan"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c ref-filter.c
-#: remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c pack-bitmap.c
+#: ref-filter.c remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "persiapan jalan revisi gagal"
 
@@ -1937,7 +1972,7 @@ msgstr "tak melacak: informasi ambigu untuk referensi '%s'"
 #: branch.c object-name.c
 #, c-format
 msgid "  %s\n"
-msgstr ""
+msgstr "  %s\n"
 
 #. TRANSLATORS: The second argument is a \n-delimited list of
 #. duplicate refspecs, composed above.
@@ -1954,6 +1989,13 @@ msgid ""
 "different remotes' fetch refspecs map into different\n"
 "tracking namespaces."
 msgstr ""
+"Ada banyak remote yang spek referensi pengambilan terpetakan ke referensi\n"
+"pelacak remote '%s'\n"
+"%s\n"
+"Hal ini biasanya merupakan kesalahan konfigurasi.\n"
+"\n"
+"Untuk mendukung menyetel cabang pelacakan, pastikan bahwa spek referensi\n"
+"remote yang berbeda terpetakan ke ruang nama pelacakan yang berbeda."
 
 #: branch.c
 #, c-format
@@ -1993,6 +2035,14 @@ msgid ""
 "will track its remote counterpart, you may want to use\n"
 "\"git push -u\" to set the upstream config as you push."
 msgstr ""
+"\n"
+"Jika Anda berencana mendasarkan karya Anda pada sebuah cabang hulu\n"
+"yang sudah ada pada remote, Anda mungkin perlu menjalankan\n"
+"\"git fetch\" untuk mendapatkannya.\n"
+"\n"
+"Jika Anda berencana mendorong sebuah cabang lokal baru yang akan melacak\n"
+"pasangan remotenya, Anda dapat menggunakan \"git push -u\" untuk menyetel\n"
+"konfigurasi hulu saat Anda dorong."
 
 #: branch.c builtin/replace.c
 #, c-format
@@ -2248,19 +2298,19 @@ msgstr ""
 #: builtin/reset.c builtin/rm.c builtin/submodule--helper.c read-cache.c
 #: rerere.c submodule.c
 msgid "index file corrupt"
-msgstr ""
+msgstr "berkas indeks rusak"
 
 #: builtin/am.c builtin/mailinfo.c mailinfo.c
 #, c-format
 msgid "bad action '%s' for '%s'"
-msgstr ""
+msgstr "tindakan jelek '%s' untuk '%s'"
 
 #: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c
 #: builtin/pull.c diff-merges.c gpg-interface.c ls-refs.c parallel-checkout.c
 #: sequencer.c setup.c
 #, c-format
 msgid "invalid value for '%s': '%s'"
-msgstr ""
+msgstr "nilai tidak valid untuk '%s': '%s'"
 
 #: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c
 #, c-format
@@ -2274,7 +2324,7 @@ msgstr "tidak dapat mengurai skrip pengarang"
 #: builtin/am.c builtin/replace.c commit.c sequencer.c
 #, c-format
 msgid "could not parse %s"
-msgstr ""
+msgstr "tidak dapat menguraikan %s"
 
 #: builtin/am.c
 #, c-format
@@ -2300,7 +2350,7 @@ msgstr "fseek gagal"
 msgid "could not open '%s' for reading"
 msgstr "tidak dapat membuka '%s' untuk dibaca"
 
-#: builtin/am.c builtin/rebase.c strbuf.c wrapper.c
+#: builtin/am.c builtin/rebase.c sequencer.c strbuf.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "tidak dapat membuka '%s' untuk ditulis"
@@ -2384,7 +2434,7 @@ msgstr "baris identitas tidak valid: %.*s"
 #: builtin/am.c builtin/checkout.c builtin/clone.c commit-graph.c
 #, c-format
 msgid "unable to parse commit %s"
-msgstr ""
+msgstr "tidak dapat menguraikan komit %s"
 
 #: builtin/am.c
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
@@ -2618,8 +2668,8 @@ msgid "n"
 msgstr "n"
 
 #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
-#: builtin/for-each-ref.c builtin/ls-tree.c builtin/replace.c builtin/tag.c
-#: builtin/verify-tag.c
+#: builtin/diagnose.c builtin/for-each-ref.c builtin/ls-files.c
+#: builtin/ls-tree.c builtin/replace.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "format"
 
@@ -2723,7 +2773,7 @@ msgstr "mode interaktif butuh tambalan pada baris perintah"
 msgid "git apply [<options>] [<patch>...]"
 msgstr "git apply [<opsi>] [<tambalan>...]"
 
-#: builtin/archive.c contrib/scalar/scalar.c
+#: builtin/archive.c diagnose.c
 msgid "could not redirect output"
 msgstr "tidak dapat mengalihkan keluaran"
 
@@ -3611,8 +3661,8 @@ msgstr "pengurutan dan penyaringan tak peka kapital"
 msgid "recurse through submodules"
 msgstr "rekursi melalui submodul"
 
-#: builtin/branch.c builtin/for-each-ref.c builtin/ls-tree.c builtin/tag.c
-#: builtin/verify-tag.c
+#: builtin/branch.c builtin/for-each-ref.c builtin/ls-files.c builtin/ls-tree.c
+#: builtin/tag.c builtin/verify-tag.c
 msgid "format to use for the output"
 msgstr "format yang digunakan untuk keluaran"
 
@@ -3721,28 +3771,34 @@ msgstr ""
 
 #: builtin/bugreport.c
 msgid "git version:\n"
-msgstr ""
+msgstr "versi git:\n"
 
 #: builtin/bugreport.c
 #, c-format
 msgid "uname() failed with error '%s' (%d)\n"
-msgstr ""
+msgstr "uname() gagal dengan kesalahan '%s' (%d)\n"
 
 #: builtin/bugreport.c
 msgid "compiler info: "
-msgstr ""
+msgstr "info pengompilasi: "
 
 #: builtin/bugreport.c
 msgid "libc info: "
-msgstr ""
+msgstr "info pustaka c: "
 
 #: builtin/bugreport.c
 msgid "not run from a git repository - no hooks to show\n"
 msgstr ""
+"tidak dijalankan dari sebuah repositori git - tidak ada kait yang "
+"diperlihatkan\n"
 
 #: builtin/bugreport.c
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
 msgstr ""
+"git bugreport [-o|--output-directory <berkas>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]]"
 
 #: builtin/bugreport.c
 msgid ""
@@ -3762,37 +3818,67 @@ msgid ""
 "Please review the rest of the bug report below.\n"
 "You can delete any lines you don't wish to share.\n"
 msgstr ""
+"Terima kasih telah mengisi laporan bug Git!\n"
+"Mohon jawab pertanyaan berikut untuk membantu memahami masalah Anda.\n"
+"\n"
+"Apa yang Anda lakukan sebelum bug terjadi? (Tahap-tahap untuk mereproduksi "
+"masalah Anda)\n"
+"Apa yang Anda harapkan? (Perilaku yang diharapkan)\n"
+"\n"
+"Apa yang terjadi? (Perilaku sebenarnya)\n"
+"\n"
+"Apa yang berbeda antara apa yang Anda harapkan dan yang sebenarnya terjadi?\n"
+"\n"
+"Apalagi yang Anda ingin tambahkan?\n"
+"\n"
+"Mohon tinjau sisa laporan bug di bawah ini.\n"
+"Anda dapat menghapus baris-baris yang Anda tidak ingin dibagi.\n"
+
+#: builtin/bugreport.c builtin/commit.c builtin/fast-export.c builtin/rebase.c
+#: parse-options.h
+msgid "mode"
+msgstr "mode"
 
 #: builtin/bugreport.c
-msgid "specify a destination for the bugreport file"
-msgstr ""
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr "buat arsip zip tambahan dari diagnostik terperinci (asali 'stats')"
 
 #: builtin/bugreport.c
-msgid "specify a strftime format suffix for the filename"
-msgstr ""
+msgid "specify a destination for the bugreport file(s)"
+msgstr "sebutkan tujuan untuk berkas(-berkas) laporan bug"
 
 #: builtin/bugreport.c
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "sebutkan akhiran format strftime untuk nama(-nama) berkas"
+
+#: builtin/bugreport.c builtin/diagnose.c
 #, c-format
 msgid "could not create leading directories for '%s'"
-msgstr ""
+msgstr "tidak dapat membuat direktori utama untuk '%s'"
+
+#: builtin/bugreport.c builtin/diagnose.c
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "tidak dapat membuat arsip diagnostik %s"
 
 #: builtin/bugreport.c
 msgid "System Info"
-msgstr ""
+msgstr "Informasi Sistem"
 
 #: builtin/bugreport.c
 msgid "Enabled Hooks"
-msgstr ""
+msgstr "Kait Aktif"
 
 #: builtin/bugreport.c
 #, c-format
 msgid "unable to write to %s"
-msgstr ""
+msgstr "tidak dapat menulis ke %s"
 
 #: builtin/bugreport.c
 #, c-format
 msgid "Created new report at '%s'.\n"
-msgstr ""
+msgstr "Laporan baru dibuat pada '%s'.\n"
 
 #: builtin/bundle.c
 msgid "git bundle create [<options>] <file> <git-rev-list args>"
@@ -3851,11 +3937,6 @@ msgstr "Perlu sebuah repositori untuk membongkar bundel."
 msgid "Unbundling objects"
 msgstr "Membongkar bundel objek"
 
-#: builtin/bundle.c builtin/remote.c
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Subperintah tidak dikenal: %s"
-
 #: builtin/cat-file.c merge-recursive.c
 #, c-format
 msgid "cannot read object %s '%s'"
@@ -3954,6 +4035,10 @@ msgstr "perlihatkan ukuran objek"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "perbolehkan -s dan -t bekerja dengan objek rusak"
 
+#: builtin/cat-file.c builtin/log.c
+msgid "use mail map file"
+msgstr "gunakan berkas peta surat"
+
 #: builtin/cat-file.c
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "Objek batch diminta pada masukan standar (atau --batch-all-objects)"
@@ -3966,6 +4051,10 @@ msgstr "perlihatkan isi <objek> atau <revisi> penuh"
 msgid "like --batch, but don't emit <contents>"
 msgstr "seperti --batch, tapi jangan keluarkan <isi>"
 
+#: builtin/cat-file.c
+msgid "stdin is NUL-terminated"
+msgstr "stdin diakhiri dengan NUL"
+
 #: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "baca perintah dari masukan standar"
@@ -4062,137 +4151,139 @@ msgstr ""
 
 #: builtin/check-attr.c
 msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr ""
+msgstr "git check-attr [-a | --all | <atribut>...] [--] <nama jalur>..."
 
 #: builtin/check-attr.c
 msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr ""
+msgstr "git check-attr --stdin [-z] [-a | --all | <attribut>...]"
 
 #: builtin/check-attr.c
 msgid "report all attributes set on file"
-msgstr ""
+msgstr "laporkan semua atribut yang disetel pada berkas"
 
 #: builtin/check-attr.c
 msgid "use .gitattributes only from the index"
-msgstr ""
+msgstr "hanya gunakan .gitattributes dari indeks"
 
 #: builtin/check-attr.c builtin/check-ignore.c builtin/hash-object.c
 msgid "read file names from stdin"
-msgstr ""
+msgstr "baca nama berkas dari masukan standar"
 
 #: builtin/check-attr.c builtin/check-ignore.c
 msgid "terminate input and output records by a NUL character"
-msgstr ""
+msgstr "akhiri masukan dan keluarkan rekaman oleh sebuah karakter NUL"
 
 #: builtin/check-ignore.c builtin/checkout.c builtin/gc.c builtin/worktree.c
 msgid "suppress progress reporting"
-msgstr ""
+msgstr "padamkan pelaporan kemajuan"
 
 #: builtin/check-ignore.c
 msgid "show non-matching input paths"
-msgstr ""
+msgstr "perlihatkan jalur input yang tak cocok"
 
 #: builtin/check-ignore.c
 msgid "ignore index when checking"
-msgstr ""
+msgstr "abaikan indeks ketika memeriksa"
 
 #: builtin/check-ignore.c
 msgid "cannot specify pathnames with --stdin"
-msgstr ""
+msgstr "tidak dapat menyebutkan nama jalur dengan --stdin"
 
 #: builtin/check-ignore.c
 msgid "-z only makes sense with --stdin"
-msgstr ""
+msgstr "-z hanya masuk akal dengan --stdin"
 
 #: builtin/check-ignore.c
 msgid "no path specified"
-msgstr ""
+msgstr "tidak ada jalur yang disebutkan"
 
 #: builtin/check-ignore.c
 msgid "--quiet is only valid with a single pathname"
-msgstr ""
+msgstr "--quiet hanya valid dengan satu nama jalur"
 
 #: builtin/check-ignore.c
 msgid "cannot have both --quiet and --verbose"
-msgstr ""
+msgstr "tidak dapat punya baik --quiet dan --verbose"
 
 #: builtin/check-ignore.c
 msgid "--non-matching is only valid with --verbose"
-msgstr ""
+msgstr "--non-matching hanya valid dengan --verbose"
 
 #: builtin/check-mailmap.c
 msgid "git check-mailmap [<options>] <contact>..."
-msgstr ""
+msgstr "git check-mailmap [<opsi>] <kontak>..."
 
 #: builtin/check-mailmap.c
 msgid "also read contacts from stdin"
-msgstr ""
+msgstr "juga baca kontak dari masukan standar"
 
 #: builtin/check-mailmap.c
 #, c-format
 msgid "unable to parse contact: %s"
-msgstr ""
+msgstr "tidak dapat menguraikan kontak: %s"
 
 #: builtin/check-mailmap.c
 msgid "no contacts specified"
-msgstr ""
+msgstr "tidak ada kontak yang disebutkan"
 
 #: builtin/checkout--worker.c
 msgid "git checkout--worker [<options>]"
-msgstr ""
+msgstr "git checkout--worker [<opsi>]"
 
 #: builtin/checkout--worker.c builtin/checkout-index.c builtin/column.c
 #: builtin/submodule--helper.c builtin/worktree.c
 msgid "string"
-msgstr ""
+msgstr "untai"
 
 #: builtin/checkout--worker.c builtin/checkout-index.c
 msgid "when creating files, prepend <string>"
-msgstr ""
+msgstr "saat membuat berkas, awali dengan <string>"
 
 #: builtin/checkout-index.c
 msgid "git checkout-index [<options>] [--] [<file>...]"
-msgstr ""
+msgstr "git checkout-index [<opsi>] [--] [<berkas>...]"
 
 #: builtin/checkout-index.c
 msgid "stage should be between 1 and 3 or all"
-msgstr ""
+msgstr "tahap seharusnya antara 1 dan 3 atau semua"
 
 #: builtin/checkout-index.c
 msgid "check out all files in the index"
-msgstr ""
+msgstr "check out semua berkas di dalam indeks"
 
 #: builtin/checkout-index.c
 msgid "do not skip files with skip-worktree set"
-msgstr ""
+msgstr "jangan lewatkan berkas dengan skip-worktree tersetel"
 
 #: builtin/checkout-index.c
 msgid "force overwrite of existing files"
-msgstr ""
+msgstr "paksa timpa berkas yang ada"
 
 #: builtin/checkout-index.c
 msgid "no warning for existing files and files not in index"
 msgstr ""
+"tanpa peringatan untuk berkas yang ada dan berkas yang tidak ada di dalam "
+"indeks"
 
 #: builtin/checkout-index.c
 msgid "don't checkout new files"
-msgstr ""
+msgstr "jangan checkout berkas baru"
 
 #: builtin/checkout-index.c
 msgid "update stat information in the index file"
-msgstr ""
+msgstr "perbarui informasi stat di dalam berkas indeks"
 
 #: builtin/checkout-index.c
 msgid "read list of paths from the standard input"
-msgstr ""
+msgstr "baca daftar jalur dari masukan standar"
 
 #: builtin/checkout-index.c
 msgid "write the content to temporary files"
-msgstr ""
+msgstr "tulis isi ke berkas sementara"
 
 #: builtin/checkout-index.c
 msgid "copy out the files from named stage"
-msgstr ""
+msgstr "salin berkas dari tahap bernama"
 
 #: builtin/checkout.c
 msgid "git checkout [<options>] <branch>"
@@ -5062,6 +5153,14 @@ msgid "initialize sparse-checkout file to include only files at root"
 msgstr ""
 "inisialisasi berkas checkout tipis agar memasukkan hanya berkas pada akar"
 
+#: builtin/clone.c
+msgid "uri"
+msgstr "URI"
+
+#: builtin/clone.c
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "sebuah URI untuk mengunduh bundel sebelum mengambil dari remote asal"
+
 #: builtin/clone.c
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
@@ -5136,9 +5235,8 @@ msgid "failed to initialize sparse-checkout"
 msgstr "gagal menginisalisasi checkout tipis"
 
 #: builtin/clone.c
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr ""
-"HEAD remote merujuk pada ref yang tidak ada, tidak dapat men-checkout.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "HEAD remote merujuk pada ref yang tidak ada, tidak dapat men-checkout"
 
 #: builtin/clone.c
 msgid "unable to checkout working tree"
@@ -5160,7 +5258,7 @@ msgstr "tidak dapat batal-taut berkas alternatif sementara"
 msgid "Too many arguments."
 msgstr "Terlalu banyak argumen."
 
-#: builtin/clone.c contrib/scalar/scalar.c
+#: builtin/clone.c scalar.c
 msgid "You must specify a repository to clone."
 msgstr "Anda harus sebutkan repositori untuk diklon."
 
@@ -5169,6 +5267,14 @@ msgstr "Anda harus sebutkan repositori untuk diklon."
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "opsi '%s' dan '%s %s' tidak dapat digunakan bersamaan"
 
+#: builtin/clone.c
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri tidak kompatibel dengan --depth, --shallow-since, dan --shallow-"
+"exclude"
+
 #: builtin/clone.c
 #, c-format
 msgid "repository '%s' does not exist"
@@ -5261,6 +5367,15 @@ msgstr "--local diabaikan"
 msgid "cannot clone from filtered bundle"
 msgstr "tidak dapat mengkloning dari bundel tersaring"
 
+#: builtin/clone.c
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "gagal menginisialisasi repo, melewatkan URI bundel"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "gagal mengambil objek dari URI bundel '%s'"
+
 #: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "transportasi remote melaporkan kesalahan"
@@ -5276,40 +5391,42 @@ msgstr "Anda tampaknya mengklon repositori kosong."
 
 #: builtin/column.c
 msgid "git column [<options>]"
-msgstr ""
+msgstr "git column [<opsi>]"
 
 #: builtin/column.c
 msgid "lookup config vars"
-msgstr ""
+msgstr "cari variabel konfigurasi"
 
 #: builtin/column.c
 msgid "layout to use"
-msgstr ""
+msgstr "layout yang digunakan"
 
 #: builtin/column.c
 msgid "maximum width"
-msgstr ""
+msgstr "lebar maksimum"
 
 #: builtin/column.c
 msgid "padding space on left border"
-msgstr ""
+msgstr "bantalan spasi pada perbatasan kiri"
 
 #: builtin/column.c
 msgid "padding space on right border"
-msgstr ""
+msgstr "bantalan spasi pada perbatasan kanan"
 
 #: builtin/column.c
 msgid "padding space between columns"
-msgstr ""
+msgstr "bantalan spasi di antara kolom"
 
 #: builtin/column.c
 msgid "--command must be the first argument"
-msgstr ""
+msgstr "--command harus menjadi argumen pertama"
 
 #: builtin/commit-graph.c
 msgid ""
 "git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"
 msgstr ""
+"git commit-graph verify [--object-dir <direktori objek>] [--shallow] [--"
+"[no-]progress]"
 
 #: builtin/commit-graph.c
 msgid ""
@@ -5317,96 +5434,96 @@ msgid ""
 "split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] [--changed-"
 "paths] [--[no-]max-new-filters <n>] [--[no-]progress] <split options>"
 msgstr ""
+"git commit-graph write [--object-dir <direktori objek>] [--append] [--"
+"split[=<strategi>]] [--reachable|--stdin-packs|--stdin-commits] [--changed-"
+"paths] [--[no-]max-new-filters <n>] [--[-no-]progrss] <opsi pemisah>"
 
 #: builtin/commit-graph.c builtin/fetch.c builtin/log.c
 msgid "dir"
-msgstr ""
+msgstr "direktori"
 
 #: builtin/commit-graph.c
 msgid "the object directory to store the graph"
-msgstr ""
+msgstr "direktori objek untuk menyimpan grafik"
 
 #: builtin/commit-graph.c
 msgid "if the commit-graph is split, only verify the tip file"
-msgstr ""
+msgstr "jika grafik komit terpisah, hanya verifikasi berkas ujung"
 
 #: builtin/commit-graph.c
 #, c-format
 msgid "Could not open commit-graph '%s'"
-msgstr ""
+msgstr "Tidak dapat membuka grafik komit '%s'"
 
 #: builtin/commit-graph.c
 #, c-format
 msgid "unrecognized --split argument, %s"
-msgstr ""
+msgstr "argumen --split tidak dikenal, %s"
 
 #: builtin/commit-graph.c
 #, c-format
 msgid "unexpected non-hex object ID: %s"
-msgstr ""
+msgstr "ID objek non-heks tidak diharapkan: %s"
 
 #: builtin/commit-graph.c
 #, c-format
 msgid "invalid object: %s"
-msgstr ""
+msgstr "objek tidak valid: %s"
 
 #: builtin/commit-graph.c parse-options-cb.c
 #, c-format
 msgid "option `%s' expects a numerical value"
-msgstr ""
+msgstr "opsi `%s' mengharapkan nilai numerik"
 
 #: builtin/commit-graph.c
 msgid "start walk at all refs"
-msgstr ""
+msgstr "mulai berjalan pada semua referensi"
 
 #: builtin/commit-graph.c
 msgid "scan pack-indexes listed by stdin for commits"
-msgstr ""
+msgstr "pindai indeks pak yang disebutkan oleh masukan standar untuk komit"
 
 #: builtin/commit-graph.c
 msgid "start walk at commits listed by stdin"
-msgstr ""
+msgstr "mulai berjalan pada komit yang disebutkan oleh masukan standar"
 
 #: builtin/commit-graph.c
 msgid "include all commits already in the commit-graph file"
-msgstr ""
+msgstr "masukkan semua komit yang sudah ada di dalam berkas grafik komit"
 
 #: builtin/commit-graph.c
 msgid "enable computation for changed paths"
-msgstr ""
+msgstr "aktifkan perhitungan perubahan jalur"
 
 #: builtin/commit-graph.c
 msgid "allow writing an incremental commit-graph file"
-msgstr ""
+msgstr "perbolehkan menulis berkas grafik komit bertambah"
 
 #: builtin/commit-graph.c
 msgid "maximum number of commits in a non-base split commit-graph"
-msgstr ""
+msgstr "jumlah komit maksimal di dalam grafik komit terpisah non-dasar"
 
 #: builtin/commit-graph.c
 msgid "maximum ratio between two levels of a split commit-graph"
-msgstr ""
+msgstr "rasio maksimum di antara dua tingkat grafik komit terpisah"
 
 #: builtin/commit-graph.c
 msgid "only expire files older than a given date-time"
 msgstr ""
+"hanya kadaluarsakan berkas yang lebih tua dari tanggal-waktu yang diberikan"
 
 #: builtin/commit-graph.c
 msgid "maximum number of changed-path Bloom filters to compute"
-msgstr ""
+msgstr "jumlah penyaring Bloom berubah jalur maksimum yang dihitung"
 
 #: builtin/commit-graph.c
 msgid "use at most one of --reachable, --stdin-commits, or --stdin-packs"
 msgstr ""
+"gunakan hanya satu dari --reachable, --stdin-commits, atau --stdin-packs"
 
 #: builtin/commit-graph.c
 msgid "Collecting commits from input"
-msgstr ""
-
-#: builtin/commit-graph.c builtin/multi-pack-index.c
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr ""
+msgstr "Mengumpulkan komit dari masukan"
 
 #: builtin/commit-tree.c
 msgid ""
@@ -5842,10 +5959,6 @@ msgstr "perlihatkan status dalam format panjang (asali)"
 msgid "terminate entries with NUL"
 msgstr "akhiri entri dengan NUL"
 
-#: builtin/commit.c builtin/fast-export.c builtin/rebase.c parse-options.h
-msgid "mode"
-msgstr "mode"
-
 #: builtin/commit.c
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
@@ -6416,23 +6529,28 @@ msgid ""
 "\n"
 "\tchmod 0700 %s"
 msgstr ""
+"Perizinan pada direktori soket Anda terlalu longgar; pengguna lainnya\n"
+"dapat membaca kredensial tertembolok Anda. Pertimbangkan menjalankan:\n"
+"\n"
+"\tchmod 0700 %s"
 
 #: builtin/credential-cache--daemon.c
 msgid "print debugging messages to stderr"
-msgstr ""
+msgstr "cetak pesan penirkutuan ke kesalahan standar"
 
 #: builtin/credential-cache--daemon.c
 msgid "credential-cache--daemon unavailable; no unix socket support"
-msgstr ""
+msgstr "credential-cache--daemon tidak tersedia; tidak ada dukungan soket unix"
 
 #: builtin/credential-cache.c
 msgid "credential-cache unavailable; no unix socket support"
-msgstr ""
+msgstr "credential-cache tidak tersedia; tidak ada dukungan soket unix"
 
 #: builtin/credential-store.c
 #, c-format
 msgid "unable to get credential storage lock in %d ms"
 msgstr ""
+"tidak dapat mendapatkan kunci penyimpanan kredensial dalam %d milidetik"
 
 #: builtin/describe.c
 msgid "git describe [<options>] [<commit-ish>...]"
@@ -6593,6 +6711,26 @@ msgstr "Tidak ada nama yang ditemukan, tidak dapat menjelaskan apapun."
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "opsi '%s' dan mirip-komit tidak dapat digunakan bersamaan"
 
+#: builtin/diagnose.c
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <jalur>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+
+#: builtin/diagnose.c
+msgid "specify a destination for the diagnostics archive"
+msgstr "sebutkan tujuan untuk arsip diagnostik"
+
+#: builtin/diagnose.c
+msgid "specify a strftime format suffix for the filename"
+msgstr "sebutkan akhiran format strftime untuk nama berkas"
+
+#: builtin/diagnose.c
+msgid "specify the content of the diagnostic archive"
+msgstr "sebutkan isi arsip diagnostik"
+
 #: builtin/diff-tree.c
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base hanya bekerja dengan dua komit"
@@ -6749,20 +6887,22 @@ msgstr "tidak ada <perintah> yang diberikan untuk --extcmd=<perintah>"
 
 #: builtin/env--helper.c
 msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr ""
+msgstr "git env--helper --type=[bool|ulong] <opsi> <variabel lingkungan>"
 
 #: builtin/env--helper.c
 msgid "default for git_env_*(...) to fall back on"
-msgstr ""
+msgstr "asali untuk git_env_*(...) agar kembali"
 
 #: builtin/env--helper.c
 msgid "be quiet only use git_env_*() value as exit code"
-msgstr ""
+msgstr "jadi diam; hanya gunakan nilai git_env_*() sebagai kode keluar"
 
 #: builtin/env--helper.c
 #, c-format
 msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
 msgstr ""
+"opsi `--default' mengharapkan sebuah nilai boolean dengan `--type=bool`, "
+"bukan `%s`"
 
 #: builtin/env--helper.c
 #, c-format
@@ -6770,6 +6910,8 @@ msgid ""
 "option `--default' expects an unsigned long value with `--type=ulong`, not `"
 "%s`"
 msgstr ""
+"opsi `--default' mengharapkan sebuah nilai unsigned long dengan `--"
+"type=ulong`, bukan `%s`"
 
 #: builtin/fast-export.c
 msgid "git fast-export [<rev-list-opts>]"
@@ -7074,12 +7216,8 @@ msgid "[rejected]"
 msgstr "[tertolak]"
 
 #: builtin/fetch.c
-msgid "can't fetch in current branch"
-msgstr "tidak dapat mengambil di cabang saat ini"
-
-#: builtin/fetch.c
-msgid "checked out in another worktree"
-msgstr "ter-check out di dalam pohon kerja lainnya"
+msgid "can't fetch into checked-out branch"
+msgstr "tidak dapat mengambil ke dalam cabang ter-checkout"
 
 #: builtin/fetch.c
 msgid "[tag update]"
@@ -7327,106 +7465,107 @@ msgstr "--stdin hanya dapat digunakan saat mengambil dari satu remote"
 msgid ""
 "git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"
 msgstr ""
+"git fmt-merge-msg [-m <pesan>] [--log[=<n>] | --no-log] [--file <berkas>]"
 
 #: builtin/fmt-merge-msg.c
 msgid "populate log with at most <n> entries from shortlog"
-msgstr ""
+msgstr "isi log dengan paling banyak <n> entri dari shortlog"
 
 #: builtin/fmt-merge-msg.c
 msgid "alias for --log (deprecated)"
-msgstr ""
+msgstr "alias untuk --log (usang)"
 
 #: builtin/fmt-merge-msg.c
 msgid "text"
-msgstr ""
+msgstr "teks"
 
 #: builtin/fmt-merge-msg.c
 msgid "use <text> as start of message"
-msgstr ""
+msgstr "gunakan <teks> sebagai awal pesan"
 
 #: builtin/fmt-merge-msg.c
 msgid "use <name> instead of the real target branch"
-msgstr ""
+msgstr "gunakan <nama> daripada cabang target sebenarnya"
 
 #: builtin/fmt-merge-msg.c
 msgid "file to read from"
-msgstr ""
+msgstr "berkas untuk dibaca"
 
 #: builtin/for-each-ref.c
 msgid "git for-each-ref [<options>] [<pattern>]"
-msgstr ""
+msgstr "git for-each-ref [<opsi>] [<pola>]"
 
 #: builtin/for-each-ref.c
 msgid "git for-each-ref [--points-at <object>]"
-msgstr ""
+msgstr "git for-each-ref [--points-at <objek>]"
 
 #: builtin/for-each-ref.c
 msgid "git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"
-msgstr ""
+msgstr "git for-each-ref [--merged [<komit>]] [--no-merged [<komit>]]"
 
 #: builtin/for-each-ref.c
 msgid "git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"
-msgstr ""
+msgstr "git for-each-ref [--contains [<komit>]] [--no-contains [<komit>]]"
 
 #: builtin/for-each-ref.c
 msgid "quote placeholders suitably for shells"
-msgstr ""
+msgstr "kutip tempat penampung yang sesuai untuk cangkang"
 
 #: builtin/for-each-ref.c
 msgid "quote placeholders suitably for perl"
-msgstr ""
+msgstr "kutip tempat penampung yang sesuai untuk perl"
 
 #: builtin/for-each-ref.c
 msgid "quote placeholders suitably for python"
-msgstr ""
+msgstr "kutip tempat penampung yang sesuai untuk python"
 
 #: builtin/for-each-ref.c
 msgid "quote placeholders suitably for Tcl"
-msgstr ""
+msgstr "kutip tempat penampung yang sesuai untuk Tcl"
 
 #: builtin/for-each-ref.c
 msgid "show only <n> matched refs"
-msgstr ""
+msgstr "hanya perlihatkan <n> referensi yang cocok"
 
 #: builtin/for-each-ref.c builtin/tag.c
 msgid "respect format colors"
-msgstr ""
+msgstr "hargai warna format"
 
 #: builtin/for-each-ref.c
 msgid "print only refs which points at the given object"
-msgstr ""
+msgstr "hanya cetak referensi yang menunjuk pada objek yang diberikan"
 
 #: builtin/for-each-ref.c
 msgid "print only refs that are merged"
-msgstr ""
+msgstr "hanya cetak referensi yang tergabung"
 
 #: builtin/for-each-ref.c
 msgid "print only refs that are not merged"
-msgstr ""
+msgstr "hanya cetak referensi yang tidak tergabung"
 
 #: builtin/for-each-ref.c
 msgid "print only refs which contain the commit"
-msgstr ""
+msgstr "hanya cetak referensi yang berisi komit"
 
 #: builtin/for-each-ref.c
 msgid "print only refs which don't contain the commit"
-msgstr ""
+msgstr "hanya cetak referensi yang tidak berisi komit"
 
 #: builtin/for-each-repo.c
 msgid "git for-each-repo --config=<config> <command-args>"
-msgstr ""
+msgstr "git for-each-repo --config=<konfigurasi> <argumen perintah>"
 
 #: builtin/for-each-repo.c
 msgid "config"
-msgstr ""
+msgstr "konfigurasi"
 
 #: builtin/for-each-repo.c
 msgid "config key storing a list of repository paths"
-msgstr ""
+msgstr "kunci konfigurasi yang menampung daftar jalur repositori"
 
 #: builtin/for-each-repo.c
 msgid "missing --config=<config>"
-msgstr ""
+msgstr "kehilangan --config=<config>"
 
 #: builtin/fsck.c
 msgid "unknown"
@@ -7625,6 +7764,11 @@ msgstr "%s: penunjuk sha1 tidak valid pada pohon tembolok"
 msgid "non-tree in cache-tree"
 msgstr "bukan pohon pada pohon tembolok"
 
+#: builtin/fsck.c
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s: penunjuk sha1 tidak valid di resolve-undo"
+
 #: builtin/fsck.c
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<opsi>] [<objek>...]"
@@ -7693,128 +7837,129 @@ msgstr "parameter tidak valid: sha1 diharapkan, dapat '%s'"
 
 #: builtin/fsmonitor--daemon.c
 msgid "git fsmonitor--daemon start [<options>]"
-msgstr ""
+msgstr "git fsmonitor--daemon start [<opsi>]"
 
 #: builtin/fsmonitor--daemon.c
 msgid "git fsmonitor--daemon run [<options>]"
-msgstr ""
+msgstr "git fsmonitor--daemon run [<opsi>]"
 
 #: builtin/fsmonitor--daemon.c
 msgid "git fsmonitor--daemon stop"
-msgstr ""
+msgstr "git fsmonitor--daemon stop"
 
 #: builtin/fsmonitor--daemon.c
 msgid "git fsmonitor--daemon status"
-msgstr ""
+msgstr "git fsmonitor--daemon status"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "value of '%s' out of range: %d"
-msgstr ""
+msgstr "nilai '%s' di luar jangkauan: %d"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "value of '%s' not bool or int: %d"
-msgstr ""
+msgstr "nilai '%s' bukan bool atau int: %d"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor-daemon is watching '%s'\n"
-msgstr ""
+msgstr "fsmonitor-daemon mengawasi '%s'\n"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor-daemon is not watching '%s'\n"
-msgstr ""
+msgstr "fsmonitor-daemon tidak mengawasi '%s'\n"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "could not create fsmonitor cookie '%s'"
-msgstr ""
+msgstr "tidak dapat membuat kuki fsmonitor '%s'"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor: cookie_result '%d' != SEEN"
-msgstr ""
+msgstr "fsmonitor: cookie_result '%d' != SEEN"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "could not start IPC thread pool on '%s'"
-msgstr ""
+msgstr "tidak dapat memulai lubuk utas IPC pada '%s'"
 
 #: builtin/fsmonitor--daemon.c
 msgid "could not start fsmonitor listener thread"
-msgstr ""
+msgstr "tidak dapat memulai utas pendengar fsmonitor"
 
 #: builtin/fsmonitor--daemon.c
 msgid "could not start fsmonitor health thread"
-msgstr ""
+msgstr "tidak dapat memulai utas kesehatan fsmonitor"
 
 #: builtin/fsmonitor--daemon.c
 msgid "could not initialize listener thread"
-msgstr ""
+msgstr "tidak dapat menginisialisasi utas pendengar"
 
 #: builtin/fsmonitor--daemon.c
 msgid "could not initialize health thread"
-msgstr ""
+msgstr "tidak dapat menginisialisasi utas kesehatan"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "could not cd home '%s'"
-msgstr ""
+msgstr "tidak dapat berganti direktori ke rumah '%s'"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "fsmonitor--daemon is already running '%s'"
-msgstr ""
+msgstr "fsmonitor--daemon sudah berjalan '%s'"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "running fsmonitor-daemon in '%s'\n"
-msgstr ""
+msgstr "menjalankan fsmonitor-daemon di '%s'\n"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "starting fsmonitor-daemon in '%s'\n"
-msgstr ""
+msgstr "menjalankan fsmonitor-daemon di '%s'\n"
 
 #: builtin/fsmonitor--daemon.c
 msgid "daemon failed to start"
-msgstr ""
+msgstr "daemon gagal dijalankan"
 
 #: builtin/fsmonitor--daemon.c
 msgid "daemon not online yet"
-msgstr ""
+msgstr "daemon belum daring"
 
 #: builtin/fsmonitor--daemon.c
 msgid "daemon terminated"
-msgstr ""
+msgstr "daemon berhenti"
 
 #: builtin/fsmonitor--daemon.c
 msgid "detach from console"
-msgstr ""
+msgstr "lepas dari konsol"
 
 #: builtin/fsmonitor--daemon.c
 msgid "use <n> ipc worker threads"
-msgstr ""
+msgstr "gunakan <n> utas pekerja ipc"
 
 #: builtin/fsmonitor--daemon.c
 msgid "max seconds to wait for background daemon startup"
 msgstr ""
+"maksimal waktu (detik) untuk menunggu dimulainya daemon dari balik layar"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "invalid 'ipc-threads' value (%d)"
-msgstr ""
+msgstr "nilai 'ipc-threads' tidak valid (%d)"
 
 #: builtin/fsmonitor--daemon.c
 #, c-format
 msgid "Unhandled subcommand '%s'"
-msgstr ""
+msgstr "Subperintah tidak tertangani '%s'"
 
 #: builtin/fsmonitor--daemon.c
 msgid "fsmonitor--daemon not supported on this platform"
-msgstr ""
+msgstr "fsmonitor--daemon tidak didukung pada platform ini"
 
 #: builtin/gc.c
 msgid "git gc [<options>]"
@@ -8047,15 +8192,19 @@ msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr ""
 "gagal menjalankan 'crontab -l'; sistem Anda mungkin tidak mendukung 'cron'"
 
+#: builtin/gc.c
+msgid "failed to create crontab temporary file"
+msgstr "tidak dapat membuat berkas crontab sementara"
+
+#: builtin/gc.c
+msgid "failed to open temporary file"
+msgstr "tidak dapat membuka berkas sementara"
+
 #: builtin/gc.c
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 "gagal menjalankan 'crontab'; sistem Anda mungkin tidak mendukung 'cron'"
 
-#: builtin/gc.c
-msgid "failed to open stdin of 'crontab'"
-msgstr "gagal membuka masukan standar dari 'crontab'"
-
 #: builtin/gc.c
 msgid "'crontab' died"
 msgstr "'crontab' mati"
@@ -8116,11 +8265,6 @@ msgstr "gagal menambahkan repositori ke konfigurasi global"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <subperintah> [<opsi>]"
 
-#: builtin/gc.c
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "subperintah tidak valid: %s"
-
 #: builtin/grep.c
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<opsi>] [-e] <pola> [<revisi>...] [[--] <pola>...]"
@@ -8345,6 +8489,10 @@ msgstr "perlihatkan berkas yang cocok dalam penghalaman"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "perbolehkan pemanggilan grep(1) (diabaikan oleh bangunan ini)"
 
+#: builtin/grep.c
+msgid "maximum number of results per file"
+msgstr "jumlah hasil maksimum tiap berkas"
+
 #: builtin/grep.c
 msgid "no pattern given"
 msgstr "tidak ada pola yang diberikan"
@@ -8457,13 +8605,24 @@ msgstr "perlihatkan deskripsi perintah"
 msgid "print list of useful guides"
 msgstr "cetak daftar panduan berguna"
 
+#: builtin/help.c
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr ""
+"cetak daftar repositori, perintah, dan antarmuka berkas yang menghadap "
+"pengguna"
+
+#: builtin/help.c
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr "cetak daftar format berkas, protokol, dan antarmuka pengembang lainnya"
+
 #: builtin/help.c
 msgid "print all configuration variable names"
 msgstr "cetak semua nama variabel konfigurasi"
 
 #: builtin/help.c
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<perintah>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr ""
+"git help [[-i|--info] [-m|--man] [-w|--web]] [<perintah>|<dokumentasi>]"
 
 #: builtin/help.c
 #, c-format
@@ -8538,6 +8697,7 @@ msgstr "opsi '%s' tidak mengambil argumen bukan opsi"
 msgid ""
 "the '--no-[external-commands|aliases]' options can only be used with '--all'"
 msgstr ""
+"opsi '--no-[external-commands|aliases]' hanya dapat digunakan dengan '--all'"
 
 #: builtin/help.c
 #, c-format
@@ -8550,11 +8710,11 @@ msgstr "'git help config' untuk informasi lebih lanjut"
 
 #: builtin/hook.c
 msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr ""
+msgstr "git hook run [--ignore-missing] <nama kait> [-- <argumen kait>]"
 
 #: builtin/hook.c
 msgid "silently ignore missing requested <hook-name>"
-msgstr ""
+msgstr "diam-diam abaikan <nama kait> yang diminta yang hilang"
 
 #: builtin/index-pack.c
 #, c-format
@@ -8980,58 +9140,60 @@ msgid ""
 "git interpret-trailers [--in-place] [--trim-empty] [(--trailer "
 "<token>[(=|:)<value>])...] [<file>...]"
 msgstr ""
+"git interpret-trailers [--in-place] [--trim-empty] [(--trailer "
+"<token>[(=|:)<nilai>])...] [<berkas>...]"
 
 #: builtin/interpret-trailers.c
 msgid "edit files in place"
-msgstr ""
+msgstr "sunting berkas di tempat"
 
 #: builtin/interpret-trailers.c
 msgid "trim empty trailers"
-msgstr ""
+msgstr "pangkas trailer kosong"
 
 #: builtin/interpret-trailers.c
 msgid "where to place the new trailer"
-msgstr ""
+msgstr "dimana trailer baru ditempatkan"
 
 #: builtin/interpret-trailers.c
 msgid "action if trailer already exists"
-msgstr ""
+msgstr "tindakan jika trailer sudah ada"
 
 #: builtin/interpret-trailers.c
 msgid "action if trailer is missing"
-msgstr ""
+msgstr "tindakan jika trailer hilang"
 
 #: builtin/interpret-trailers.c
 msgid "output only the trailers"
-msgstr ""
+msgstr "keluarkan hanya trailer"
 
 #: builtin/interpret-trailers.c
 msgid "do not apply config rules"
-msgstr ""
+msgstr "jangan terapkan aturan konfigurasi"
 
 #: builtin/interpret-trailers.c
 msgid "join whitespace-continued values"
-msgstr ""
+msgstr "gabungkan nilai yang dilanjutkan oleh spasi"
 
 #: builtin/interpret-trailers.c
 msgid "set parsing options"
-msgstr ""
+msgstr "setel opsi penguraian"
 
 #: builtin/interpret-trailers.c
 msgid "do not treat --- specially"
-msgstr ""
+msgstr "jangan memperlakukan khusus ---"
 
 #: builtin/interpret-trailers.c
 msgid "trailer(s) to add"
-msgstr ""
+msgstr "trailer untuk ditambah"
 
 #: builtin/interpret-trailers.c
 msgid "--trailer with --only-input does not make sense"
-msgstr ""
+msgstr "--trailer dengan --only-input tidak masuk akal"
 
 #: builtin/interpret-trailers.c
 msgid "no input file given for in-place editing"
-msgstr ""
+msgstr "tidak ada berkas masukan yang diberikan untuk penyuntingan di tempat"
 
 #: builtin/log.c
 msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
@@ -9055,8 +9217,8 @@ msgid "show source"
 msgstr "perlihatkan sumber"
 
 #: builtin/log.c
-msgid "use mail map file"
-msgstr "gunakan berkas peta surat"
+msgid "clear all previously-defined decoration filters"
+msgstr "bersihkan semua penyaring dekorasi yang sebelumnya didefinisikan"
 
 #: builtin/log.c
 msgid "only decorate refs that match <pattern>"
@@ -9389,6 +9551,10 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr "persentase dimana pembuatan tertimbang"
 
+#: builtin/log.c
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "perlihatkan From: dalam tubuh bahkan jika sama dengan kepala surel"
+
 #: builtin/log.c
 #, c-format
 msgid "invalid ident line: %s"
@@ -9466,11 +9632,26 @@ msgstr ""
 "Tidak dapat menemukan cabang remote terlacak, mohon sebutkan <hulu>\n"
 "secara manual.\n"
 
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "format ls-files jelek: elemen '%s' tidak dimulai dengan '('"
+
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "format ls-files jelek: elemen '%s' tidak diakhiri dengan ')'"
+
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "format ls-files jelek: %%%.*s"
+
 #: builtin/ls-files.c
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<opsi>] [<berkas>...]"
 
-#: builtin/ls-files.c
+#: builtin/ls-files.c builtin/merge-tree.c
 msgid "separate paths with the NUL character"
 msgstr "pisahkan jalur dengan karakter NUL"
 
@@ -9579,6 +9760,14 @@ msgstr "hapus entri duplikat"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "perlihatkan direktori tipis di hadapan indeks tipis"
 
+#: builtin/ls-files.c
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format tidak dapat digunakan dengan -s, -o, -k, -t, --resolve-undo, --"
+"deduplicate, --eol"
+
 #: builtin/ls-remote.c
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
@@ -9695,60 +9884,60 @@ msgstr "--format tidak dapat digabungkan opsi pengubah format lainnya"
 #. TRANSLATORS: keep <> in "<" mail ">" info.
 #: builtin/mailinfo.c
 msgid "git mailinfo [<options>] <msg> <patch> < mail >info"
-msgstr ""
+msgstr "git mailinfo [<opsi>] <pesan> <tambalan> < surat >info"
 
 #: builtin/mailinfo.c
 msgid "keep subject"
-msgstr ""
+msgstr "pertahankan subjek"
 
 #: builtin/mailinfo.c
 msgid "keep non patch brackets in subject"
-msgstr ""
+msgstr "pertahankan tanda kurung non tambalan dalam subjek"
 
 #: builtin/mailinfo.c
 msgid "copy Message-ID to the end of commit message"
-msgstr ""
+msgstr "salin Message-ID pada akhir pesan komit"
 
 #: builtin/mailinfo.c
 msgid "re-code metadata to i18n.commitEncoding"
-msgstr ""
+msgstr "kodekan ulang metadata ke i18n.commitEncoding"
 
 #: builtin/mailinfo.c
 msgid "disable charset re-coding of metadata"
-msgstr ""
+msgstr "nonaktifkan pengkodean ulang set karakter metadata"
 
 #: builtin/mailinfo.c
 msgid "encoding"
-msgstr ""
+msgstr "pengkodean"
 
 #: builtin/mailinfo.c
 msgid "re-code metadata to this encoding"
-msgstr ""
+msgstr "kodekan ulang metadata ke pengkodean ini"
 
 #: builtin/mailinfo.c
 msgid "use scissors"
-msgstr ""
+msgstr "gunakan gunting"
 
 #: builtin/mailinfo.c
 msgid "<action>"
-msgstr ""
+msgstr "<tindakan>"
 
 #: builtin/mailinfo.c
 msgid "action when quoted CR is found"
-msgstr ""
+msgstr "bertindak ketika CR terkutip ditemukan"
 
 #: builtin/mailinfo.c
 msgid "use headers in message's body"
-msgstr ""
+msgstr "gunakan kepala di dalam badan pesan"
 
 #: builtin/mailsplit.c
 msgid "reading patches from stdin/tty..."
-msgstr ""
+msgstr "membaca tambalan dari masukan standar/tty..."
 
 #: builtin/mailsplit.c
 #, c-format
 msgid "empty mbox: '%s'"
-msgstr ""
+msgstr "mbox kosong: '%s'"
 
 #: builtin/merge-base.c
 msgid "git merge-base [-a | --all] <commit> <commit>..."
@@ -9795,73 +9984,119 @@ msgid ""
 "git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> "
 "<orig-file> <file2>"
 msgstr ""
+"git merge-file [<opsi>] [-L <nama 1> [-L <asli> [-L <nama 2>]]] <berkas 1> "
+"<berkas asli> <berkas 2>"
 
 #: builtin/merge-file.c
 msgid "send results to standard output"
-msgstr ""
+msgstr "kirim hasil ke keluaran standar"
 
 #: builtin/merge-file.c
 msgid "use a diff3 based merge"
-msgstr ""
+msgstr "gunakan penggabungan berdasarkan diff3"
 
 #: builtin/merge-file.c
 msgid "use a zealous diff3 based merge"
-msgstr ""
+msgstr "gunakan penggabungan berdasarkan diff3 yang bersemangat"
 
 #: builtin/merge-file.c
 msgid "for conflicts, use our version"
-msgstr ""
+msgstr "untuk konflik, gunakan versi kami"
 
 #: builtin/merge-file.c
 msgid "for conflicts, use their version"
-msgstr ""
+msgstr "untuk konflik, gunakan versi mereka"
 
 #: builtin/merge-file.c
 msgid "for conflicts, use a union version"
-msgstr ""
+msgstr "untuk konflik, gunakan versi bersatu"
 
 #: builtin/merge-file.c
 msgid "for conflicts, use this marker size"
-msgstr ""
+msgstr "untuk konflik, gunakan ukuran penanda ini"
 
 #: builtin/merge-file.c
 msgid "do not warn about conflicts"
-msgstr ""
+msgstr "jangan peringatkan tentang konflik"
 
 #: builtin/merge-file.c
 msgid "set labels for file1/orig-file/file2"
-msgstr ""
+msgstr "setel label untuk file1/orig-file/file2"
 
 #: builtin/merge-recursive.c
 #, c-format
 msgid "unknown option %s"
-msgstr ""
+msgstr "opsi tidak dikenal %s"
 
 #: builtin/merge-recursive.c
 #, c-format
 msgid "could not parse object '%s'"
-msgstr ""
+msgstr "tidak dapat menguraikan objek '%s'"
 
 #: builtin/merge-recursive.c
 #, c-format
 msgid "cannot handle more than %d base. Ignoring %s."
 msgid_plural "cannot handle more than %d bases. Ignoring %s."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "tidak dapat menangani lebih dari %d dasar. Mengabaikan %s."
+msgstr[1] "tidak dapat menangani lebih dari %d dasar. Mengabaikan %s."
 
 #: builtin/merge-recursive.c
 msgid "not handling anything other than two heads merge."
-msgstr ""
+msgstr "tidak menangani apapun selain penggabungan dua kepala"
 
 #: builtin/merge-recursive.c
 #, c-format
 msgid "could not resolve ref '%s'"
-msgstr ""
+msgstr "tidak dapat menguraikan referensi '%s'"
 
 #: builtin/merge-recursive.c
 #, c-format
 msgid "Merging %s with %s\n"
-msgstr ""
+msgstr "Menggabungkan %s dengan %s\n"
+
+#: builtin/merge-tree.c builtin/merge.c
+msgid "not something we can merge"
+msgstr "bukan sesuatu yang kami bisa gabungkan"
+
+#: builtin/merge-tree.c builtin/merge.c
+msgid "refusing to merge unrelated histories"
+msgstr "menolak menggabungkan riwayat tak terkait"
+
+#: builtin/merge-tree.c
+msgid "failure to merge"
+msgstr "kegagalan penggabungan"
+
+#: builtin/merge-tree.c
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<opsi>] <cabang 1> <cabang 2>"
+
+#: builtin/merge-tree.c
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <pohon dasar> <cabang 1> <cabang 2>"
+
+#: builtin/merge-tree.c
+msgid "do a real merge instead of a trivial merge"
+msgstr "lakukan penggabungan sebenarnya daripada penggabungan sepele"
+
+#: builtin/merge-tree.c
+msgid "do a trivial merge only"
+msgstr "hanya lakukan penggabungan sepele"
+
+#: builtin/merge-tree.c
+msgid "also show informational/conflict messages"
+msgstr "perlihatkan juga pesan informasi/konflik"
+
+#: builtin/merge-tree.c
+msgid "list filenames without modes/oids/stages"
+msgstr "daftar nama berkas tanpa mode/oid/tahap"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "allow merging unrelated histories"
+msgstr "perbolehkan penggabungan riwayat yang tak terkait"
+
+#: builtin/merge-tree.c
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge tidak kompatibel dengan semua opsi lainnya"
 
 #: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
@@ -9969,10 +10204,6 @@ msgstr "--abort tapi biarkan indeks dan pohon kerja"
 msgid "continue the current in-progress merge"
 msgstr "lanjutkan penggabungan yang sedang berlangsung saat ini"
 
-#: builtin/merge.c builtin/pull.c
-msgid "allow merging unrelated histories"
-msgstr "perbolehkan penggabungan riwayat yang tak terkait"
-
 #: builtin/merge.c
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "lewati kail pre-merge-commit dan commit-msg"
@@ -10114,17 +10345,13 @@ msgstr "Nilai jelek '%s' dalam lingkungan '%s'"
 #: builtin/merge.c read-cache.c strbuf.c wrapper.c
 #, c-format
 msgid "could not close '%s'"
-msgstr ""
+msgstr "tidak dapat menutup '%s'"
 
 #: builtin/merge.c
 #, c-format
 msgid "not something we can merge in %s: %s"
 msgstr "bukan sesuatu yang kami bisa gabungkan di %s: %s"
 
-#: builtin/merge.c
-msgid "not something we can merge"
-msgstr "bukan sesuatu yang kami bisa gabungkan"
-
 #: builtin/merge.c
 msgid "--abort expects no arguments"
 msgstr "--abort harap tanpa argumen"
@@ -10187,15 +10414,21 @@ msgstr "%s - bukan sesuatu yang kami bisa gabungkan"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Hanya bisa menggabungkan tepantnya satu komit ke kepala kosong"
 
-#: builtin/merge.c
-msgid "refusing to merge unrelated histories"
-msgstr "menolak menggabungkan riwayat tak terkait"
-
 #: builtin/merge.c
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Memperbarui %s..%s\n"
 
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh "
+"penggabungan:\n"
+"  %s"
+
 #: builtin/merge.c
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
@@ -10238,30 +10471,35 @@ msgstr ""
 "Penggabungan otomatis berjalan baik; berhenti sebelum mengkomit seperti yang "
 "diminta\n"
 
+#: builtin/merge.c
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "Ketika selesai, terapkan perubahan terstase dengan `git stash pop`\n"
+
 #: builtin/mktag.c
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
-msgstr ""
+msgstr "peringatan: masukan tag tidak lolos fsck: %s"
 
 #: builtin/mktag.c
 #, c-format
 msgid "error: tag input does not pass fsck: %s"
-msgstr ""
+msgstr "kesalahan: masukan tag tidak lolos fsck: %s"
 
 #: builtin/mktag.c
 #, c-format
 msgid "%d (FSCK_IGNORE?) should never trigger this callback"
-msgstr ""
+msgstr "%d (FSCK_IGNORE?) seharusnya tidak pernah memicu pemanggilan balik ini"
 
 #: builtin/mktag.c
 #, c-format
 msgid "could not read tagged object '%s'"
-msgstr ""
+msgstr "tidak dapat membaca objek tertag '%s'"
 
 #: builtin/mktag.c
 #, c-format
 msgid "object '%s' tagged as '%s', but is a '%s' type"
-msgstr ""
+msgstr "objek '%s' ditag sebagai '%s', tetapi bertipe '%s'"
 
 #: builtin/mktag.c imap-send.c trailer.c
 msgid "could not read from stdin"
@@ -10269,27 +10507,27 @@ msgstr "tidak dapat membaca dari masukan standar"
 
 #: builtin/mktag.c
 msgid "tag on stdin did not pass our strict fsck check"
-msgstr ""
+msgstr "tag pada masukan standar tidak lolos pemeriksaan fsck ketat kami"
 
 #: builtin/mktag.c
 msgid "tag on stdin did not refer to a valid object"
-msgstr ""
+msgstr "tag pada masukan standar tidak merujuk pada objek valid"
 
 #: builtin/mktag.c builtin/tag.c
 msgid "unable to write tag file"
-msgstr ""
+msgstr "tidak dapat menulis berkas tag"
 
 #: builtin/mktree.c
 msgid "input is NUL terminated"
-msgstr ""
+msgstr "masukan diakhiri dengan NUL"
 
 #: builtin/mktree.c builtin/write-tree.c
 msgid "allow missing objects"
-msgstr ""
+msgstr "perbolehkan objek hilang"
 
 #: builtin/mktree.c
 msgid "allow creation of more than one tree"
-msgstr ""
+msgstr "perbolehkan pembuatan lebih dari satu pohon"
 
 #: builtin/multi-pack-index.c
 msgid ""
@@ -10387,6 +10625,10 @@ msgstr "Memeriksa penamaan ulang '%s' ke '%s'\n"
 msgid "bad source"
 msgstr "sumber jelek"
 
+#: builtin/mv.c
+msgid "destination exists"
+msgstr "tujuan ada"
+
 #: builtin/mv.c
 msgid "can not move directory into itself"
 msgstr "tidak dapat memindahkan direktori ke dirinya sendiri"
@@ -10407,10 +10649,6 @@ msgstr "bukan dalam kontrol versi"
 msgid "conflicted"
 msgstr "terkonflik"
 
-#: builtin/mv.c
-msgid "destination exists"
-msgstr "tujuan ada"
-
 #: builtin/mv.c
 #, c-format
 msgid "overwriting '%s'"
@@ -10428,6 +10666,10 @@ msgstr "banyak asal untuk target yang sama"
 msgid "destination directory does not exist"
 msgstr "direktori tujuan tidak ada"
 
+#: builtin/mv.c
+msgid "destination exists in the index"
+msgstr "tujuan ada dalam indeks"
+
 #: builtin/mv.c
 #, c-format
 msgid "%s, source=%s, destination=%s"
@@ -10882,10 +11124,10 @@ msgstr "referensi catatan"
 msgid "use notes from <notes-ref>"
 msgstr "gunakan catatan dari <referensi catatan>"
 
-#: builtin/notes.c builtin/stash.c
+#: builtin/notes.c builtin/remote.c parse-options.c
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "subperintah tidak dikenal: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "subperintah tidak dikenal: `%s'"
 
 #: builtin/pack-objects.c
 msgid ""
@@ -11371,6 +11613,11 @@ msgid ""
 "and let us know you still use it by sending an e-mail\n"
 "to <git@vger.kernel.org>.  Thanks.\n"
 msgstr ""
+"'git pack-redundant' dinominasikan untuk dihapus.\n"
+"Jika Anda masih menggunakan perintah ini, mohon tambahkan sebuah opsi\n"
+"ekstra, '--i-still-use-this', pada baris perintah dan beri tahu kami jika\n"
+"Anda masih menggunakannya dengan mengirimkan surel ke\n"
+"<git@vger.kernel.org>. Terima kasih.\n"
 
 #: builtin/pack-refs.c
 msgid "git pack-refs [<options>]"
@@ -11498,7 +11745,7 @@ msgstr "Lihat git-pull(1) untuk selengkapnya."
 msgid "<remote>"
 msgstr "<remote>"
 
-#: builtin/pull.c contrib/scalar/scalar.c
+#: builtin/pull.c scalar.c
 msgid "<branch>"
 msgstr "<cabang>"
 
@@ -11944,47 +12191,54 @@ msgstr "opsi dorong harus tidak ada karakter baris baru"
 #: builtin/range-diff.c
 msgid "git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"
 msgstr ""
+"git range-diff [<opsi>] <dasar lama>..<ujung lama> <dasar-baru>..<ujung baru>"
 
 #: builtin/range-diff.c
 msgid "git range-diff [<options>] <old-tip>...<new-tip>"
-msgstr ""
+msgstr "git range-diff [<opsi>] <ujung lama>...<ujung baru>"
 
 #: builtin/range-diff.c
 msgid "git range-diff [<options>] <base> <old-tip> <new-tip>"
-msgstr ""
+msgstr "git range-diff [<opsi>] <dasar> <ujung lama> <ujung baru>"
 
 #: builtin/range-diff.c
 msgid "use simple diff colors"
-msgstr ""
+msgstr "gunakan warna diff sederhana"
 
 #: builtin/range-diff.c
 msgid "notes"
-msgstr ""
+msgstr "catatan"
 
 #: builtin/range-diff.c
 msgid "passed to 'git log'"
-msgstr ""
+msgstr "lewatkan ke 'git log'"
 
 #: builtin/range-diff.c
 msgid "only emit output related to the first range"
-msgstr ""
+msgstr "hanya keluarkan keluaran relatif terhadap rentang pertama"
 
 #: builtin/range-diff.c
 msgid "only emit output related to the second range"
-msgstr ""
+msgstr "hanya keluarkan keluaran relatif terhadap rentang kedua"
+
+#: builtin/range-diff.c
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "bukan sebuah revisi: '%s'"
 
 #: builtin/range-diff.c
 #, c-format
 msgid "not a commit range: '%s'"
-msgstr ""
+msgstr "bukan sebuah rentang komit '%s'"
 
 #: builtin/range-diff.c
-msgid "single arg format must be symmetric range"
-msgstr ""
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "bukan sebuah rentang simetris: '%s'"
 
 #: builtin/range-diff.c
 msgid "need two commit ranges"
-msgstr ""
+msgstr "butuh dua rentang komit"
 
 #: builtin/read-tree.c
 msgid ""
@@ -12322,6 +12576,10 @@ msgstr "simpan komit yang dimulai kosong"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "pindahakan komit yang diawali dengan squash!/fixup! di bawah -i"
 
+#: builtin/rebase.c
+msgid "update branches that point to commits that are being rebased"
+msgstr "perbarui cabang yang menunjuk pada komit yang akan didasarkan ulang"
+
 #: builtin/rebase.c
 msgid "add exec lines after each commit of the editable list"
 msgstr ""
@@ -12373,6 +12631,9 @@ msgid ""
 "Use `git rebase --abort` to terminate current rebase.\n"
 "Or downgrade to v2.33, or earlier, to complete the rebase."
 msgstr ""
+"`rebase --preserve-merges` (-p) tidak lagi didukung.\n"
+"Gunakan `git rebase --abort` untuk menghentikan pendasaran ulang saat ini.\n"
+"Atau turun ke v2.33 atau lebih awal untuk menyelesaikan pendasaran ulang."
 
 #: builtin/rebase.c
 msgid ""
@@ -12380,6 +12641,9 @@ msgid ""
 "Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
 "which is no longer supported; use 'merges' instead"
 msgstr ""
+"--preserve-merges diganti oleh --rebase-merges\n"
+"Catatan: Konfigurasi `pull.rebase` Anda mungkin juga disetel ke 'preserve',\n"
+"yang tidak lagi didukung; gunakan 'merges' sebagai gantinya"
 
 #: builtin/rebase.c
 msgid "No rebase in progress?"
@@ -12955,6 +13219,10 @@ msgstr " baru (pengambilan berikutnya akan simpan di remotes/%s)"
 msgid " tracked"
 msgstr " dilacak"
 
+#: builtin/remote.c
+msgid " skipped"
+msgstr " dilewati"
+
 #: builtin/remote.c
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " basi (gunakan 'git remote prune' untuk hapus)"
@@ -13412,23 +13680,23 @@ msgstr "tidak dapat membatal taut: %s"
 
 #: builtin/replace.c
 msgid "git replace [-f] <object> <replacement>"
-msgstr ""
+msgstr "git replace [-f] <objek> <pengganti>"
 
 #: builtin/replace.c
 msgid "git replace [-f] --edit <object>"
-msgstr ""
+msgstr "git replace [-f] --edit <objek>"
 
 #: builtin/replace.c
 msgid "git replace [-f] --graft <commit> [<parent>...]"
-msgstr ""
+msgstr "git replace [-f] --graft <komit> [<induk>...]"
 
 #: builtin/replace.c
 msgid "git replace -d <object>..."
-msgstr ""
+msgstr "git replace -d <objek>..."
 
 #: builtin/replace.c
 msgid "git replace [--format=<format>] [-l [<pattern>]]"
-msgstr ""
+msgstr "git replace [--format=<format>] [-l [<pola>]]"
 
 #: builtin/replace.c
 #, c-format
@@ -13436,26 +13704,28 @@ msgid ""
 "invalid replace format '%s'\n"
 "valid formats are 'short', 'medium' and 'long'"
 msgstr ""
+"format penggantian '%s' tidak valid\n"
+"yang valid adalah 'short', 'medium' dan 'long'"
 
 #: builtin/replace.c
 #, c-format
 msgid "replace ref '%s' not found"
-msgstr ""
+msgstr "referensi penggantian '%s' tidak ditemukan"
 
 #: builtin/replace.c
 #, c-format
 msgid "Deleted replace ref '%s'"
-msgstr ""
+msgstr "Referensi penggantian '%s' dihapus"
 
 #: builtin/replace.c
 #, c-format
 msgid "'%s' is not a valid ref name"
-msgstr ""
+msgstr "'%s' bukan nama referensi valid"
 
 #: builtin/replace.c
 #, c-format
 msgid "replace ref '%s' already exists"
-msgstr ""
+msgstr "referensi penggantian '%s' sudah ada"
 
 #: builtin/replace.c
 #, c-format
@@ -13464,74 +13734,77 @@ msgid ""
 "'%s' points to a replaced object of type '%s'\n"
 "while '%s' points to a replacement object of type '%s'."
 msgstr ""
+"Objek harus bertipe sama.\n"
+"'%s' menunjuk pada objek yang diganti bertipe '%s'\n"
+"sedangkan '%s' menunjuk pada objek pengganti bertipe '%s'."
 
 #: builtin/replace.c
 #, c-format
 msgid "unable to open %s for writing"
-msgstr ""
+msgstr "tidak dapat membuka %s untuk ditulis"
 
 #: builtin/replace.c
 msgid "cat-file reported failure"
-msgstr ""
+msgstr "cat-file melaporkan kegagalan"
 
 #: builtin/replace.c
 #, c-format
 msgid "unable to open %s for reading"
-msgstr ""
+msgstr "tidak dapat membuka %s untuk dibaca"
 
 #: builtin/replace.c
 msgid "unable to spawn mktree"
-msgstr ""
+msgstr "tidak dapat memunculkan mktree"
 
 #: builtin/replace.c
 msgid "unable to read from mktree"
-msgstr ""
+msgstr "tidak dapat membaca dari mktree"
 
 #: builtin/replace.c
 msgid "mktree reported failure"
-msgstr ""
+msgstr "mktree melaporkan kegagalan"
 
 #: builtin/replace.c
 msgid "mktree did not return an object name"
-msgstr ""
+msgstr "mktree tidak mengembalikan sebuah nama objek"
 
 #: builtin/replace.c
 #, c-format
 msgid "unable to fstat %s"
-msgstr ""
+msgstr "tidak dapat men-fstat %s"
 
 #: builtin/replace.c
 msgid "unable to write object to database"
-msgstr ""
+msgstr "tidak dapat menulis objek ke basis data"
 
 #: builtin/replace.c
 #, c-format
 msgid "unable to get object type for %s"
-msgstr ""
+msgstr "tidak dapat mendapatkan tipe objek untuk %s"
 
 #: builtin/replace.c
 msgid "editing object file failed"
-msgstr ""
+msgstr "gagal menyunting berkas objek"
 
 #: builtin/replace.c
 #, c-format
 msgid "new object is the same as the old one: '%s'"
-msgstr ""
+msgstr "objek baru sama dengan objek lama: '%s'"
 
 #: builtin/replace.c
 #, c-format
 msgid "could not parse %s as a commit"
-msgstr ""
+msgstr "tidak dapat menguraikan %s sebagai sebuah komit"
 
 #: builtin/replace.c
 #, c-format
 msgid "bad mergetag in commit '%s'"
-msgstr ""
+msgstr "tag penggabungan jelek pada komit '%s'"
 
 #: builtin/replace.c
 #, c-format
 msgid "malformed mergetag in commit '%s'"
-msgstr ""
+msgstr "tag penggabungan rusak pada komit '%s'"
 
 #: builtin/replace.c
 #, c-format
@@ -13539,30 +13812,32 @@ msgid ""
 "original commit '%s' contains mergetag '%s' that is discarded; use --edit "
 "instead of --graft"
 msgstr ""
+"komit asal '%s' berisi tag penggabungan '%s' yang dibuang; gunakan --edit "
+"daripada --graft"
 
 #: builtin/replace.c
 #, c-format
 msgid "the original commit '%s' has a gpg signature"
-msgstr ""
+msgstr "komit asal '%s' punya tandatangan gpg"
 
 #: builtin/replace.c
 msgid "the signature will be removed in the replacement commit!"
-msgstr ""
+msgstr "tandatangan akan dihapus di dalam komit pengganti!"
 
 #: builtin/replace.c
 #, c-format
 msgid "could not write replacement commit for: '%s'"
-msgstr ""
+msgstr "tidak dapat menulis komit pengganti untuk: '%s'"
 
 #: builtin/replace.c
 #, c-format
 msgid "graft for '%s' unnecessary"
-msgstr ""
+msgstr "cangkuk untuk '%s' tidak diperlukan"
 
 #: builtin/replace.c
 #, c-format
 msgid "new commit is the same as the old one: '%s'"
-msgstr ""
+msgstr "komit baru sama dengan komit lama: '%s'"
 
 #: builtin/replace.c
 #, c-format
@@ -13570,91 +13845,93 @@ msgid ""
 "could not convert the following graft(s):\n"
 "%s"
 msgstr ""
+"tidak dapat mengkonversi cangkuk berikut:\n"
+"%s"
 
 #: builtin/replace.c
 msgid "list replace refs"
-msgstr ""
+msgstr "daftar referensi penggantian"
 
 #: builtin/replace.c
 msgid "delete replace refs"
-msgstr ""
+msgstr "hapus referensi penggantian"
 
 #: builtin/replace.c
 msgid "edit existing object"
-msgstr ""
+msgstr "sunting objek yang ada"
 
 #: builtin/replace.c
 msgid "change a commit's parents"
-msgstr ""
+msgstr "ubah induk sebuah komit"
 
 #: builtin/replace.c
 msgid "convert existing graft file"
-msgstr ""
+msgstr "konversi berkas cangkuk yang anda"
 
 #: builtin/replace.c
 msgid "replace the ref if it exists"
-msgstr ""
+msgstr "ganti referensi jika ada"
 
 #: builtin/replace.c
 msgid "do not pretty-print contents for --edit"
-msgstr ""
+msgstr "jangan cetak cantik isi untuk --edit"
 
 #: builtin/replace.c
 msgid "use this format"
-msgstr ""
+msgstr "gunakan format ini"
 
 #: builtin/replace.c
 msgid "--format cannot be used when not listing"
-msgstr ""
+msgstr "--format tidak dapat digunakan ketika mendaftar"
 
 #: builtin/replace.c
 msgid "-f only makes sense when writing a replacement"
-msgstr ""
+msgstr "-f hanya masuk akal ketika menulis pengganti"
 
 #: builtin/replace.c
 msgid "--raw only makes sense with --edit"
-msgstr ""
+msgstr "--raw hanya masuk akal dengan --edit"
 
 #: builtin/replace.c
 msgid "-d needs at least one argument"
-msgstr ""
+msgstr "-d butuh setidaknya satu argumen"
 
 #: builtin/replace.c
 msgid "bad number of arguments"
-msgstr ""
+msgstr "jumlah argumen jelek"
 
 #: builtin/replace.c
 msgid "-e needs exactly one argument"
-msgstr ""
+msgstr "-e butuh tepat satu argumen"
 
 #: builtin/replace.c
 msgid "-g needs at least one argument"
-msgstr ""
+msgstr "-g butuh setidaknya satu argumen"
 
 #: builtin/replace.c
 msgid "--convert-graft-file takes no argument"
-msgstr ""
+msgstr "--convert-graft-file tidak mengambil argumen"
 
 #: builtin/replace.c
 msgid "only one pattern can be given with -l"
-msgstr ""
+msgstr "hanya satu pola yang dapat diberikan dengan -l"
 
 #: builtin/rerere.c
 msgid "git rerere [clear | forget <path>... | status | remaining | diff | gc]"
-msgstr ""
+msgstr "git rerere [clear | forge <jalur>... | status | remaining | diff | gc]"
 
 #: builtin/rerere.c
 msgid "register clean resolutions in index"
-msgstr ""
+msgstr "daftar resolusi bersih di dalam indeks"
 
 #: builtin/rerere.c
 msgid "'git rerere forget' without paths is deprecated"
-msgstr ""
+msgstr "'git rerere forget' tanpa jalur usang"
 
 #: builtin/rerere.c
 #, c-format
 msgid "unable to generate diff for '%s'"
-msgstr ""
+msgstr "tidak dapat membuat diff untuk '%s'"
 
 #: builtin/reset.c
 msgid ""
@@ -13725,7 +14002,7 @@ msgstr "diam, hanya laporkan kesalahan"
 
 #: builtin/reset.c
 msgid "skip refreshing the index after reset"
-msgstr ""
+msgstr "lewati penyegaran indeks setelah reset"
 
 #: builtin/reset.c
 msgid "reset HEAD and index"
@@ -13794,10 +14071,16 @@ msgstr "Tidak dapat menyetel ulang berkas indeks ke revisi '%s'."
 msgid "Could not write new index file."
 msgstr "Tidak dapat menulis berkas indeks baru."
 
-#: builtin/rev-list.c pack-bitmap.c
+#: builtin/rev-list.c
 #, c-format
 msgid "unable to get disk usage of %s"
+msgstr "tidak dapat mendapatkan penggunaan disk %s"
+
+#: builtin/rev-list.c
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
 msgstr ""
+"nilai tidak valid untuk '%s': '%s', format yang diperbolehkan hanyalah '%s'"
 
 #: builtin/rev-list.c
 msgid "rev-list does not support display of notes"
@@ -13832,6 +14115,10 @@ msgstr "akhir masukan prematur"
 msgid "no usage string given before the `--' separator"
 msgstr "tidak ada untai penggunaan yang diberikan sebelum pemisah `--'"
 
+#: builtin/rev-parse.c
+msgid "missing opt-spec before option flags"
+msgstr "kehilangan spek opsi sebelum bendera opsi"
+
 #: builtin/rev-parse.c
 msgid "Needed a single revision"
 msgstr "Butuh satu revisi"
@@ -13982,7 +14269,7 @@ msgstr "simpan komit kosong mubazir"
 
 #: builtin/revert.c
 msgid "use the 'reference' format to refer to commits"
-msgstr ""
+msgstr "gunakan format 'reference' untuk merujuk pada komit"
 
 #: builtin/revert.c
 msgid "revert failed"
@@ -14392,10 +14679,10 @@ msgstr "inisialisasi checkout tipis dalam mode kerucut"
 msgid "toggle the use of a sparse index"
 msgstr "gunakan indeks tipis"
 
-#: builtin/sparse-checkout.c commit-graph.c midx.c
+#: builtin/sparse-checkout.c commit-graph.c midx.c sequencer.c
 #, c-format
 msgid "unable to create leading directories of %s"
-msgstr ""
+msgstr "tidak dapat membuat direktori utama dari %s"
 
 #: builtin/sparse-checkout.c
 #, c-format
@@ -14787,17 +15074,22 @@ msgstr "masukkan berkas ignore"
 
 #: builtin/stripspace.c
 msgid "skip and remove all lines starting with comment character"
-msgstr ""
+msgstr "lewati dan hapus semua baris yang diawali dengan karakter komentar"
 
 #: builtin/stripspace.c
 msgid "prepend comment character and space to each line"
-msgstr ""
+msgstr "tambahkan karakter komentar dan spasi di awal setiap baris"
 
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Expecting a full ref name, got %s"
 msgstr "Mengharapkan nama referensi penuh, dapat %s"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "tidak dapat mendapat pegangan repositori untuk submodul '%s'"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid ""
@@ -14807,14 +15099,6 @@ msgstr ""
 "tidak dapat mencari konfigurasi '%s'. Asumsi bahwa repositori ini adalah "
 "hulu otoritatif tersendiri."
 
-#: builtin/submodule--helper.c
-msgid "alternative anchor for relative paths"
-msgstr "jangkar alternatif untuk jalur relatif"
-
-#: builtin/submodule--helper.c
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<jalur>] [<jalur>...]"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
@@ -14854,9 +15138,8 @@ msgid "recurse into nested submodules"
 msgstr "rekursi ke dalam submodul bersarang"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr ""
-"git submodule--helper foreach [--quiet] [--recursive] [--] [<perintah>]"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] [<perintah>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14883,8 +15166,8 @@ msgid "suppress output for initializing a submodule"
 msgstr "sembunyikan keluaran menginisialisasi submodul"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<opsi>] [<jalur>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<opsi>] [<jalur>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14917,10 +15200,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<jalur>...]"
 
-#: builtin/submodule--helper.c
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <jalur>"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
@@ -14963,8 +15242,8 @@ msgid "limit the summary size"
 msgstr "batasi ukuran ringkasan"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<opsi>] [<commit>] -- [<jalur>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<opsi>] [<commit>] -- [<jalur>]"
 
 #: builtin/submodule--helper.c
 msgid "could not fetch a revision for HEAD"
@@ -14980,11 +15259,6 @@ msgstr "Mensinkronisasi url submodul untuk '%s'\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "gagal mendaftarkan url untuk jalur submodul '%s'"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "gagal mendapatkan remote asali untuk submodul '%s'"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "failed to update remote for submodule '%s'"
@@ -14995,8 +15269,8 @@ msgid "suppress output of synchronizing submodule url"
 msgstr "sembunyikan keluaran mensinkronisasi url submodul"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<jalur>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<jalur>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -15067,6 +15341,11 @@ msgstr ""
 " itu, setel submodule.alternateErrorStrategy ke 'info' atau yang sama,\n"
 "kloning degan '--reference-if-able' daripada '--reference'."
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "tidak dapat mendapat pegangan repositori untuk direktori git '%s'"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
@@ -15103,6 +15382,10 @@ msgstr "direktori tidak kosong: '%s'"
 msgid "could not get submodule directory for '%s'"
 msgstr "tidak dapat mendapatkan direktori submodul untuk '%s'"
 
+#: builtin/submodule--helper.c
+msgid "alternative anchor for relative paths"
+msgstr "jangkar alternatif untuk jalur relatif"
+
 #: builtin/submodule--helper.c
 msgid "where the new submodule will be cloned to"
 msgstr "di mana submodul baru akan dikloning"
@@ -15137,11 +15420,6 @@ msgstr ""
 "<repositori>] [--name <nama>] [--depth <kedalaman>] [--single-branch] [--"
 "filter <spek filter>] --url <url> --path <jalur>"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Mode pembaruan '%s' tidak valid untuk jalur submodul '%s'"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
@@ -15232,6 +15510,11 @@ msgstr ""
 "Terambil di dalam jalur submodul '%s', tetapi itu tidak berisi %s. "
 "Pengambilan langsung komit tersebut gagal."
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "tidak dapat menginisialisasi submodul pada jalur '%s'"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid ""
@@ -15241,11 +15524,6 @@ msgstr ""
 "Cabang submodul (%s) dikonfigurasikan untuk mewarisi cabang dari proyek "
 "super, tapi proyek super tidak pada cabang apapun"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "tidak dapat mendapat pegangan repositori untuk submodul '%s'"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
@@ -15291,12 +15569,16 @@ msgid "path into the working tree"
 msgstr "jalur ke dalam pohon kerja"
 
 #: builtin/submodule--helper.c
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "jalur ke dalam pohon kerja, melintasi perbatasan submodul bersarang"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "gunakan strategi pembaruan 'checkout' (asali)"
+
+#: builtin/submodule--helper.c
+msgid "use the 'merge' update strategy"
+msgstr "gunakan strategi penmbaruan 'merge'"
 
 #: builtin/submodule--helper.c
-msgid "rebase, merge, checkout or none"
-msgstr "dasarkan ulang, gabungkan, checkout atau tidak sama sekali"
+msgid "use the 'rebase' update strategy"
+msgstr "gunakan strategi pembaruan 'rebase'"
 
 #: builtin/submodule--helper.c
 msgid "create a shallow clone truncated to the specified number of revisions"
@@ -15314,6 +15596,11 @@ msgstr "apakah klon awal seharusnya mengikuti rekomendasi dangkal"
 msgid "don't print cloning progress"
 msgstr "jangan cetak perkembangan pengkloningan"
 
+#: builtin/submodule--helper.c
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr ""
+"tak perbolehkan kloning ke dalam direktori berisi, mengimplikasikan --init"
+
 #: builtin/submodule--helper.c
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
@@ -15326,17 +15613,13 @@ msgstr ""
 "shallow] [--reference <repositori>] [--recursive] [--[no-]single-branch] "
 "[--] [<jalur>...]"
 
-#: builtin/submodule--helper.c
-msgid "bad value for update parameter"
-msgstr "nilai jelek untuk parameter pembaruan"
-
 #: builtin/submodule--helper.c
 msgid "recurse into submodules"
 msgstr "rekursi ke dalam submodul"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<opsi>] [<jalur>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<opsi>] [<jalur>...]"
 
 #: builtin/submodule--helper.c
 msgid "check if it is safe to write to the .gitmodules file"
@@ -15363,8 +15646,8 @@ msgid "suppress output for setting url of a submodule"
 msgstr "sembunyikan keluaran penyetelan url submodule"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <jalur> <url baru>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <jalur> <url baru>"
 
 #: builtin/submodule--helper.c
 msgid "set the default tracking branch to master"
@@ -15375,14 +15658,12 @@ msgid "set the default tracking branch"
 msgstr "setel cabang pelacak asali"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <jalur>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <jalur>"
 
 #: builtin/submodule--helper.c
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <cabang> <jalur>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <cabang> <jalur>"
 
 #: builtin/submodule--helper.c
 msgid "--branch or --default required"
@@ -15478,7 +15759,7 @@ msgstr "'%s' sudah ada di dalam indeks dan bukan submodul"
 #: builtin/submodule--helper.c read-cache.c
 #, c-format
 msgid "'%s' does not have a commit checked out"
-msgstr ""
+msgstr "'%s' tidak punya sebuah komit tercheckout"
 
 #: builtin/submodule--helper.c
 msgid "branch of repository to add as submodule"
@@ -15500,8 +15781,8 @@ msgstr ""
 "setel nama submodul ke untai yang diberikan daripada diasalkan ke jalurnya"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<opsi>] [--] <repositori> [<jalur>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<opsi>] [--] <repositori> [<jalur>]"
 
 #: builtin/submodule--helper.c
 msgid "Relative path can only be used from the toplevel of the working tree"
@@ -15758,12 +16039,25 @@ msgid "pack exceeds maximum allowed size"
 msgstr "paket melebihi ukuran maksimum yang diperbolehkan"
 
 #: builtin/unpack-objects.c
-msgid "Unpacking objects"
-msgstr "Membongkar objek"
+msgid "failed to write object in stream"
+msgstr "gagal menulis objek di dalam arus"
 
-#: builtin/update-index.c
+#: builtin/unpack-objects.c
 #, c-format
-msgid "failed to create directory %s"
+msgid "inflate returned (%d)"
+msgstr "inflate mengembalikan (%d)"
+
+#: builtin/unpack-objects.c
+msgid "invalid blob object from stream"
+msgstr "objek blob tidak valid dari arus"
+
+#: builtin/unpack-objects.c
+msgid "Unpacking objects"
+msgstr "Membongkar objek"
+
+#: builtin/update-index.c
+#, c-format
+msgid "failed to create directory %s"
 msgstr "gagal membuat direktori %s"
 
 #: builtin/update-index.c
@@ -16414,6 +16708,33 @@ msgstr "tulis objek pohon untuk subdirektori <prefiks>"
 msgid "only useful for debugging"
 msgstr "hanya berguna untuk penirkutuan"
 
+#: bulk-checkin.c
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch tidak didukung pada platform ini"
+
+#: bundle-uri.c
+msgid "failed to create temporary file"
+msgstr "tidak dapat membuat berkas sementara"
+
+#: bundle-uri.c
+msgid "insufficient capabilities"
+msgstr "tidak cukup kemampuan"
+
+#: bundle-uri.c
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "gagal mengunduh bundel dari URI '%s'"
+
+#: bundle-uri.c
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "berkas pada URI '%s' bukan sebuah bundle"
+
+#: bundle-uri.c
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "gagal membongkar bundel dari URI '%s'"
+
 #: bundle.c
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
@@ -16502,941 +16823,1013 @@ msgstr "index-pack mati"
 
 #: chunk-format.c
 msgid "terminating chunk id appears earlier than expected"
-msgstr ""
+msgstr "id bingkah pengakhiran muncul lebih awal dari yang diharapkan"
 
 #: chunk-format.c
 #, c-format
 msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
-msgstr ""
+msgstr "offset bingkah %<PRIx64> dan %<PRIx64> tidak tepat"
 
 #: chunk-format.c
 #, c-format
 msgid "duplicate chunk ID %<PRIx32> found"
-msgstr ""
+msgstr "ID bingkah duplikat %<PRIx32> ditemukan"
 
 #: chunk-format.c
 #, c-format
 msgid "final chunk has non-zero id %<PRIx32>"
-msgstr ""
+msgstr "bingkah terakhir punya id bukan nol %<PRIx32>"
 
 #: chunk-format.c
 msgid "invalid hash version"
-msgstr ""
+msgstr "versi hash tidak valid"
 
 #: color.c
 #, c-format
 msgid "invalid color value: %.*s"
-msgstr ""
+msgstr "nilai warna tidak valid: %.*s"
 
 #: command-list.h
 msgid "Add file contents to the index"
-msgstr ""
+msgstr "Tambahkan isi berkas ke indeks"
 
 #: command-list.h
 msgid "Apply a series of patches from a mailbox"
-msgstr ""
+msgstr "Terapkan rangkaian tambalan dari kotak surat"
 
 #: command-list.h
 msgid "Annotate file lines with commit information"
-msgstr ""
+msgstr "Anotasi baris berkas dengan informasi komit"
 
 #: command-list.h
 msgid "Apply a patch to files and/or to the index"
-msgstr ""
+msgstr "Terapkan tambalan pada berkas dan/atau pada indeks"
 
 #: command-list.h
 msgid "Import a GNU Arch repository into Git"
-msgstr ""
+msgstr "Impor repositori GNU Arch ke dalam Git"
 
 #: command-list.h
 msgid "Create an archive of files from a named tree"
-msgstr ""
+msgstr "Buat arsip berkas dari pohon bernama"
 
 #: command-list.h
 msgid "Use binary search to find the commit that introduced a bug"
-msgstr ""
+msgstr "Gunakan pencarian biner untuk mencari komit yang memasukkan bug"
 
 #: command-list.h
 msgid "Show what revision and author last modified each line of a file"
 msgstr ""
+"Perlihatkan revisi dan pengarang apa yang terakhir kali mengubah setiap "
+"baris berkas"
 
 #: command-list.h
 msgid "List, create, or delete branches"
-msgstr ""
+msgstr "Daftar, buat, atau hapus cabang"
 
 #: command-list.h
 msgid "Collect information for user to file a bug report"
-msgstr ""
+msgstr "Kumpulkan informasi agar pengguna melaporkan laporan bug"
 
 #: command-list.h
 msgid "Move objects and refs by archive"
-msgstr ""
+msgstr "Pindahkan objek dan referensi oleh arsip"
 
 #: command-list.h
 msgid "Provide content or type and size information for repository objects"
 msgstr ""
+"Sediakan isi atau informasi tipe dan ukuran berkas untuk objek repositori"
 
 #: command-list.h
 msgid "Display gitattributes information"
-msgstr ""
+msgstr "Perlihatkan informasi gitattributes"
 
 #: command-list.h
 msgid "Debug gitignore / exclude files"
-msgstr ""
+msgstr "Nirkutukan berkas gitignore / exclude"
 
 #: command-list.h
 msgid "Show canonical names and email addresses of contacts"
-msgstr ""
+msgstr "Perlihatkan nama dan alamat email kanonikal"
 
 #: command-list.h
 msgid "Ensures that a reference name is well formed"
-msgstr ""
+msgstr "Pastikan bahwa nama referensi baik dan benar"
 
 #: command-list.h
 msgid "Switch branches or restore working tree files"
-msgstr ""
+msgstr "Ganti cabang atau kembalikan berkas pohon kerja"
 
 #: command-list.h
 msgid "Copy files from the index to the working tree"
-msgstr ""
+msgstr "Salin berkas dari indeks ke pohon kerja"
 
 #: command-list.h
 msgid "Find commits yet to be applied to upstream"
-msgstr ""
+msgstr "Cari komit yang belum diterapkan pada hulu"
 
 #: command-list.h
 msgid "Apply the changes introduced by some existing commits"
-msgstr ""
+msgstr "Terapkan perubahan yang dimasukkan oleh beberapa komit yang ada"
 
 #: command-list.h
 msgid "Graphical alternative to git-commit"
-msgstr ""
+msgstr "Alternatif grafik untuk git-commit"
 
 #: command-list.h
 msgid "Remove untracked files from the working tree"
-msgstr ""
+msgstr "Hapus berkas tak terlacak dari pohon kerja"
 
 #: command-list.h
 msgid "Clone a repository into a new directory"
-msgstr ""
+msgstr "Salin repositori ke dalam direktori baru"
 
 #: command-list.h
 msgid "Display data in columns"
-msgstr ""
+msgstr "Tampilkan data dalam kolom"
 
 #: command-list.h
 msgid "Record changes to the repository"
-msgstr ""
+msgstr "Rekam perubahan ke dalam repositori"
 
 #: command-list.h
 msgid "Write and verify Git commit-graph files"
-msgstr ""
+msgstr "Tulis dan verifikasi berkas Git commit-graph"
 
 #: command-list.h
 msgid "Create a new commit object"
-msgstr ""
+msgstr "Buat objek komit baru"
 
 #: command-list.h
 msgid "Get and set repository or global options"
-msgstr ""
+msgstr "Dapatkan dan setel opsi repositori atau global"
 
 #: command-list.h
 msgid "Count unpacked number of objects and their disk consumption"
-msgstr ""
+msgstr "Hitung jumlah berkas tak terlacak dan penggunaan disknya"
 
 #: command-list.h
 msgid "Retrieve and store user credentials"
-msgstr ""
+msgstr "Dapatkan dan simpan kredensial pengguna"
 
 #: command-list.h
 msgid "Helper to temporarily store passwords in memory"
-msgstr ""
+msgstr "Pembantu untuk sementara simpan kata sandi di memori"
 
 #: command-list.h
 msgid "Helper to store credentials on disk"
-msgstr ""
+msgstr "Pembantu untuk menyimpan kredensial pada disk"
 
 #: command-list.h
 msgid "Export a single commit to a CVS checkout"
-msgstr ""
+msgstr "Ekspor satu komit tunggal ke checkout CVS"
 
 #: command-list.h
 msgid "Salvage your data out of another SCM people love to hate"
-msgstr ""
+msgstr "Selamatkan data karena pengguna SCM lainnya yang suka membenci"
 
 #: command-list.h
 msgid "A CVS server emulator for Git"
-msgstr ""
+msgstr "Emulator peladen CVS untuk Git"
 
 #: command-list.h
 msgid "A really simple server for Git repositories"
-msgstr ""
+msgstr "Peladen sederhana beneran untuk repositori Git"
 
 #: command-list.h
 msgid "Give an object a human readable name based on an available ref"
 msgstr ""
+"Berikan nama yang dapat dibaca manusia pada objek berdasarkan referensi yang "
+"ada"
+
+#: command-list.h
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Buat arsip zip informasi diagnostik"
 
 #: command-list.h
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr ""
+"Perlihatkan perubahan di antara komit-komit, komit dan pohon kerja, dll"
 
 #: command-list.h
 msgid "Compares files in the working tree and the index"
-msgstr ""
+msgstr "Bandingkan berkas di dalam pohon kerja dan indeks"
 
 #: command-list.h
 msgid "Compare a tree to the working tree or index"
-msgstr ""
+msgstr "Bandingkan pohon kepada pohon kerja atau indeks"
 
 #: command-list.h
 msgid "Compares the content and mode of blobs found via two tree objects"
-msgstr ""
+msgstr "Bandingkan isi dan mode blob yang ditemukan lewat dua objek pohon"
 
 #: command-list.h
 msgid "Show changes using common diff tools"
-msgstr ""
+msgstr "Perlihatkan perubahan menggunakan alat diff umum"
 
 #: command-list.h
 msgid "Git data exporter"
-msgstr ""
+msgstr "Eksportir data Git"
 
 #: command-list.h
 msgid "Backend for fast Git data importers"
-msgstr ""
+msgstr "Tulang punggung untuk importir data Git"
 
 #: command-list.h
 msgid "Download objects and refs from another repository"
-msgstr ""
+msgstr "Unduh objek dan referensi dari repositori yang lain"
 
 #: command-list.h
 msgid "Receive missing objects from another repository"
-msgstr ""
+msgstr "Terima objek yang hilang dari repositori yang lain"
 
 #: command-list.h
 msgid "Rewrite branches"
-msgstr ""
+msgstr "Tulis ulang cabang"
 
 #: command-list.h
 msgid "Produce a merge commit message"
-msgstr ""
+msgstr "Buat pesan komit penggabungan"
 
 #: command-list.h
 msgid "Output information on each ref"
-msgstr ""
+msgstr "Keluarkan informasi pada setiap referensi"
 
 #: command-list.h
 msgid "Run a Git command on a list of repositories"
-msgstr ""
+msgstr "Jalankan perintah Git pada daftar repositori"
 
 #: command-list.h
 msgid "Prepare patches for e-mail submission"
-msgstr ""
+msgstr "Siapkan tambalan untuk pengiriman surel"
 
 #: command-list.h
 msgid "Verifies the connectivity and validity of the objects in the database"
-msgstr ""
+msgstr "Verifikasi hubungan dan validitas objek di dalam basis data"
 
 #: command-list.h
 msgid "Cleanup unnecessary files and optimize the local repository"
-msgstr ""
+msgstr "Bersihkan berkas yang tak perlu dan optimalkan repositori lokal"
 
 #: command-list.h
 msgid "Extract commit ID from an archive created using git-archive"
-msgstr ""
+msgstr "Ekstrak ID komit dari arsip yang dibuat dengan git-archive"
 
 #: command-list.h
 msgid "Print lines matching a pattern"
-msgstr ""
+msgstr "Cetak baris yang cocok dengan sebuah pola"
 
 #: command-list.h
 msgid "A portable graphical interface to Git"
-msgstr ""
+msgstr "Sebuah antarmuka grafis Git portabel"
 
 #: command-list.h
 msgid "Compute object ID and optionally creates a blob from a file"
-msgstr ""
+msgstr "Hitung ID objek dan buat blob dari berkas (opsional)"
 
 #: command-list.h
 msgid "Display help information about Git"
-msgstr ""
+msgstr "Perlihatkan bantuan mengenai Git"
 
 #: command-list.h
 msgid "Run git hooks"
-msgstr ""
+msgstr "Jalankan kait git"
 
 #: command-list.h
 msgid "Server side implementation of Git over HTTP"
-msgstr ""
+msgstr "Impementasi sisi peladen dari Git lewat HTTP"
 
 #: command-list.h
 msgid "Download from a remote Git repository via HTTP"
-msgstr ""
+msgstr "Unduh dari repositori Git remote lewat HTTP"
 
 #: command-list.h
 msgid "Push objects over HTTP/DAV to another repository"
-msgstr ""
+msgstr "Dorong objek lewat HTTP/DAV ke repositori lainnya"
 
 #: command-list.h
 msgid "Send a collection of patches from stdin to an IMAP folder"
-msgstr ""
+msgstr "Kirim koleksi tambalan dari masukan standar ke sebuah direktori IMAP"
 
 #: command-list.h
 msgid "Build pack index file for an existing packed archive"
-msgstr ""
+msgstr "Bangun berkas indeks pak dari arsip terpak yang sudah ada"
 
 #: command-list.h
 msgid "Create an empty Git repository or reinitialize an existing one"
-msgstr ""
+msgstr "Buat repositori Git kosong atau inisialisasi ulang yang sudah ada"
 
 #: command-list.h
 msgid "Instantly browse your working repository in gitweb"
-msgstr ""
+msgstr "Jelajahi repositori kerja Anda secara instan di gitweb"
 
 #: command-list.h
 msgid "Add or parse structured information in commit messages"
-msgstr ""
+msgstr "Tambah atau urai informasi terstruktur di dalam pesan komit"
 
 #: command-list.h
 msgid "Show commit logs"
-msgstr ""
+msgstr "Perlihatkan log komit"
 
 #: command-list.h
 msgid "Show information about files in the index and the working tree"
 msgstr ""
+"Perlihatkan informasi mengenai berkas-berkas di dalam indeks dan pohon kerja"
 
 #: command-list.h
 msgid "List references in a remote repository"
-msgstr ""
+msgstr "Daftar referensi di repositori remote"
 
 #: command-list.h
 msgid "List the contents of a tree object"
-msgstr ""
+msgstr "Daftar isi objek pohon"
 
 #: command-list.h
 msgid "Extracts patch and authorship from a single e-mail message"
-msgstr ""
+msgstr "Ekstrak berkas dan kepengarangan dari pesan surel tunggal"
 
 #: command-list.h
 msgid "Simple UNIX mbox splitter program"
-msgstr ""
+msgstr "Program pemisah mbox UNIX sederhana"
 
 #: command-list.h
 msgid "Run tasks to optimize Git repository data"
-msgstr ""
+msgstr "Jalankan tugas untuk mengoptimalkan data repositori Git"
 
 #: command-list.h
 msgid "Join two or more development histories together"
-msgstr ""
+msgstr "Gabungkan dua riwayat pengembangan atau lebih bersama-sama"
 
 #: command-list.h
 msgid "Find as good common ancestors as possible for a merge"
-msgstr ""
+msgstr "Cari leluhur umum sebaik-baiknya untuk penggabungan"
 
 #: command-list.h
 msgid "Run a three-way file merge"
-msgstr ""
+msgstr "Lakukan penggabungan berkas tiga arah"
 
 #: command-list.h
 msgid "Run a merge for files needing merging"
-msgstr ""
+msgstr "Lakukan penggabungan untuk berkas yang perlu digabungkan"
 
 #: command-list.h
 msgid "The standard helper program to use with git-merge-index"
-msgstr ""
+msgstr "Program pembantu standar untuk digunakan dengan git-merge-index"
 
 #: command-list.h
-msgid "Show three-way merge without touching index"
-msgstr ""
+msgid "Perform merge without touching index or working tree"
+msgstr "Lakukan penggabungan tanpa menyentuh indeks atau pohon kerja"
 
 #: command-list.h
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
+"Jalankan alat penyelesaian konflik penggabungan untuk menyelesaikan konflik "
+"penggabungan"
 
 #: command-list.h
 msgid "Creates a tag object with extra validation"
-msgstr ""
+msgstr "Buat objek tag dengan validasi ekstra"
 
 #: command-list.h
 msgid "Build a tree-object from ls-tree formatted text"
-msgstr ""
+msgstr "Bangun objek pohon dari teks berformat ls-tree"
 
 #: command-list.h
 msgid "Write and verify multi-pack-indexes"
-msgstr ""
+msgstr "Tulis dan verifikasi indeks multipak"
 
 #: command-list.h
 msgid "Move or rename a file, a directory, or a symlink"
-msgstr ""
+msgstr "Pindahkan atau namai ulang berkas, direktori, atau tautan simbolik"
 
 #: command-list.h
 msgid "Find symbolic names for given revs"
-msgstr ""
+msgstr "Cari nama simbolik untuk revisi yang diberikan"
 
 #: command-list.h
 msgid "Add or inspect object notes"
-msgstr ""
+msgstr "Tambahkan atau inspeksi catatan objek"
 
 #: command-list.h
 msgid "Import from and submit to Perforce repositories"
-msgstr ""
+msgstr "Impor dari dan kirimkan ke repositori Perfore"
 
 #: command-list.h
 msgid "Create a packed archive of objects"
-msgstr ""
+msgstr "Buat arsip terpak dari objek"
 
 #: command-list.h
 msgid "Find redundant pack files"
-msgstr ""
+msgstr "Cari berkas pak berlebihan"
 
 #: command-list.h
 msgid "Pack heads and tags for efficient repository access"
-msgstr ""
+msgstr "Pak kepala dan tag untuk akses repositori yang efisien"
 
 #: command-list.h
 msgid "Compute unique ID for a patch"
-msgstr ""
+msgstr "Hitung ID unik untuk sebuah tambalan"
 
 #: command-list.h
 msgid "Prune all unreachable objects from the object database"
-msgstr ""
+msgstr "Pangkas semua objek tak tercapai dari basis data objek"
 
 #: command-list.h
 msgid "Remove extra objects that are already in pack files"
-msgstr ""
+msgstr "Hapus semua objek ekstra yang sudah ada di dalam berkas pak"
 
 #: command-list.h
 msgid "Fetch from and integrate with another repository or a local branch"
-msgstr ""
+msgstr "Ambil dan integrasikan dengan repositori lain atau sebuah cabang lokal"
 
 #: command-list.h
 msgid "Update remote refs along with associated objects"
-msgstr ""
+msgstr "Perbarui referensi remote bersama dengan objek yang terkait"
 
 #: command-list.h
 msgid "Applies a quilt patchset onto the current branch"
-msgstr ""
+msgstr "Terapkan set tambalan quilt pada cabang saat ini"
 
 #: command-list.h
 msgid "Compare two commit ranges (e.g. two versions of a branch)"
-msgstr ""
+msgstr "Bandingkan dua rentang komit (misalnya dua versi cabang)"
 
 #: command-list.h
 msgid "Reads tree information into the index"
-msgstr ""
+msgstr "Baca informasi pohon ke dalam indeks"
 
 #: command-list.h
 msgid "Reapply commits on top of another base tip"
-msgstr ""
+msgstr "Terapkan ulang komit-komit di atas dasar ujung yang lainnya"
 
 #: command-list.h
 msgid "Receive what is pushed into the repository"
-msgstr ""
+msgstr "Terima apa yang didorong pada repositori"
 
 #: command-list.h
 msgid "Manage reflog information"
-msgstr ""
+msgstr "Kelola informasi log referensi"
 
 #: command-list.h
 msgid "Manage set of tracked repositories"
-msgstr ""
+msgstr "Kelola set repositori terlacak"
 
 #: command-list.h
 msgid "Pack unpacked objects in a repository"
-msgstr ""
+msgstr "Pak objek tak terpak di dalam repositori"
 
 #: command-list.h
 msgid "Create, list, delete refs to replace objects"
-msgstr ""
+msgstr "Buat, daftar, hapus referensi untuk mengganti objek"
 
 #: command-list.h
 msgid "Generates a summary of pending changes"
-msgstr ""
+msgstr "Buat ringkasan perubahan tertunda"
 
 #: command-list.h
 msgid "Reuse recorded resolution of conflicted merges"
-msgstr ""
+msgstr "Gunakan ulang resolusi konflik penggabungan terekam"
 
 #: command-list.h
 msgid "Reset current HEAD to the specified state"
-msgstr ""
+msgstr "Setel ulang HEAD saat ini ke keadaan yang disebutkan"
 
 #: command-list.h
 msgid "Restore working tree files"
-msgstr ""
+msgstr "Pulihkan berkas pohon kerja"
 
 #: command-list.h
 msgid "Lists commit objects in reverse chronological order"
-msgstr ""
+msgstr "Daftar objek komit dalam urutan kronologis terbalik"
 
 #: command-list.h
 msgid "Pick out and massage parameters"
-msgstr ""
+msgstr "Ambil dan pijat parameter"
 
 #: command-list.h
 msgid "Revert some existing commits"
-msgstr ""
+msgstr "Balikkan beberapa komit yang sudah ada"
 
 #: command-list.h
 msgid "Remove files from the working tree and from the index"
-msgstr ""
+msgstr "Hapus berkas dari pohon kerja dan indeks"
 
 #: command-list.h
 msgid "Send a collection of patches as emails"
-msgstr ""
+msgstr "Kirim koleksi tambalan sebagai surel"
 
 #: command-list.h
 msgid "Push objects over Git protocol to another repository"
-msgstr ""
+msgstr "Dorong objek lewat protokol Git ke repositori lainnya"
 
 #: command-list.h
 msgid "Git's i18n setup code for shell scripts"
-msgstr ""
+msgstr "kode penyusunan i18n Git untuk skrip cangkang"
 
 #: command-list.h
 msgid "Common Git shell script setup code"
-msgstr ""
+msgstr "kode penyusunan skrip cangkang umum Git"
 
 #: command-list.h
 msgid "Restricted login shell for Git-only SSH access"
-msgstr ""
+msgstr "Cangkang masuk terbatas untuk akses SSH hanya Git"
 
 #: command-list.h
 msgid "Summarize 'git log' output"
-msgstr ""
+msgstr "Rangkum keluaran 'git log'"
 
 #: command-list.h
 msgid "Show various types of objects"
-msgstr ""
+msgstr "Perlihatkan berbagai tipe objek"
 
 #: command-list.h
 msgid "Show branches and their commits"
-msgstr ""
+msgstr "Perlihatkan cabang dan komitnya"
 
 #: command-list.h
 msgid "Show packed archive index"
-msgstr ""
+msgstr "Perlihatkan indeks arsip terpak"
 
 #: command-list.h
 msgid "List references in a local repository"
-msgstr ""
+msgstr "Daftar referensi di repositori lokal"
 
 #: command-list.h
 msgid "Reduce your working tree to a subset of tracked files"
-msgstr ""
+msgstr "Kurangi pohon kerja Anda sampai subset berkas terlacak"
 
 #: command-list.h
 msgid "Add file contents to the staging area"
-msgstr ""
+msgstr "Tambahkan isi berkas ke area penggelaran"
 
 #: command-list.h
 msgid "Stash the changes in a dirty working directory away"
-msgstr ""
+msgstr "Stase perubahan di dalam direktori kerja"
 
 #: command-list.h
 msgid "Show the working tree status"
-msgstr ""
+msgstr "Perlihatkan status pohon kerja"
 
 #: command-list.h
 msgid "Remove unnecessary whitespace"
-msgstr ""
+msgstr "Hapus spasi yang tidak diperlukan"
 
 #: command-list.h
 msgid "Initialize, update or inspect submodules"
-msgstr ""
+msgstr "Inisialisasi, perbarui atau inspeksi submodul"
 
 #: command-list.h
 msgid "Bidirectional operation between a Subversion repository and Git"
-msgstr ""
+msgstr "Operasi dua arah antara repositori Subversion dan Git"
 
 #: command-list.h
 msgid "Switch branches"
-msgstr ""
+msgstr "Ganti cabang"
 
 #: command-list.h
 msgid "Read, modify and delete symbolic refs"
-msgstr ""
+msgstr "Baca, ubah dan hapus referensi simbolik"
 
 #: command-list.h
 msgid "Create, list, delete or verify a tag object signed with GPG"
 msgstr ""
+"Buat, daftar, hapus atau verifikasi objek tag yang ditandatangani dengan GPG"
 
 #: command-list.h
 msgid "Creates a temporary file with a blob's contents"
-msgstr ""
+msgstr "Buat berkas sementara dengan isi blob"
 
 #: command-list.h
 msgid "Unpack objects from a packed archive"
-msgstr ""
+msgstr "Bongkar objek dari arsip terpak"
 
 #: command-list.h
 msgid "Register file contents in the working tree to the index"
-msgstr ""
+msgstr "Daftarkan isi berkas dalam pohon kerja ke indeks"
 
 #: command-list.h
 msgid "Update the object name stored in a ref safely"
-msgstr ""
+msgstr "Perbarui nama objek yang disimpan di dalam referensi secara aman"
 
 #: command-list.h
 msgid "Update auxiliary info file to help dumb servers"
-msgstr ""
+msgstr "Perbarui berkas info tambahan untuk membantu peladen bodoh"
 
 #: command-list.h
 msgid "Send archive back to git-archive"
-msgstr ""
+msgstr "Kirim arsip kembali ke git-archive"
 
 #: command-list.h
 msgid "Send objects packed back to git-fetch-pack"
-msgstr ""
+msgstr "Kirim objek terpak kembali ke git-fetch-pack"
 
 #: command-list.h
 msgid "Show a Git logical variable"
-msgstr ""
+msgstr "Perlihatkan variabel logikal Git"
 
 #: command-list.h
 msgid "Check the GPG signature of commits"
-msgstr ""
+msgstr "Periksa tandatangan GPG komit"
 
 #: command-list.h
 msgid "Validate packed Git archive files"
-msgstr ""
+msgstr "Validasi berkas arsip Git terpak"
 
 #: command-list.h
 msgid "Check the GPG signature of tags"
-msgstr ""
+msgstr "Periksa tandatangan GPG tag"
+
+#: command-list.h
+msgid "Display version information about Git"
+msgstr "Perlihatkan info versi Git"
 
 #: command-list.h
 msgid "Show logs with difference each commit introduces"
-msgstr ""
+msgstr "Perlihatkan log dengan perbedaan yang dimasukkan setiap komit"
 
 #: command-list.h
 msgid "Manage multiple working trees"
-msgstr ""
+msgstr "Kelola banyak pohon kerja"
 
 #: command-list.h
 msgid "Create a tree object from the current index"
-msgstr ""
+msgstr "Buat objek pohon dari indeks saat ini"
 
 #: command-list.h
 msgid "Defining attributes per path"
-msgstr ""
+msgstr "Tentukan atribut tiap jalur"
 
 #: command-list.h
 msgid "Git command-line interface and conventions"
-msgstr ""
+msgstr "Antarmuka baris perintah dan konvensi Git"
 
 #: command-list.h
 msgid "A Git core tutorial for developers"
-msgstr ""
+msgstr "Tutorial Git dasar untuk pengembang"
 
 #: command-list.h
 msgid "Providing usernames and passwords to Git"
-msgstr ""
+msgstr "Sediakan nama pengguna dan kata sandi ke Git"
 
 #: command-list.h
 msgid "Git for CVS users"
-msgstr ""
+msgstr "Git untuk pengguna CVS"
 
 #: command-list.h
 msgid "Tweaking diff output"
-msgstr ""
+msgstr "Ubah keluaran diff"
 
 #: command-list.h
 msgid "A useful minimum set of commands for Everyday Git"
-msgstr ""
+msgstr "Set perintah berguna minimal untuk Git setiap hari"
 
 #: command-list.h
 msgid "Frequently asked questions about using Git"
-msgstr ""
+msgstr "Pertanyaan yang sering diajukan tentang penggunaan Git"
+
+#: command-list.h
+msgid "The bundle file format"
+msgstr "Format berkas bundel"
+
+#: command-list.h
+msgid "Chunk-based file formats"
+msgstr "Berkas format berbasis bingkah"
+
+#: command-list.h
+msgid "Git commit graph format"
+msgstr "Format grafik komit Git"
+
+#: command-list.h
+msgid "Git index format"
+msgstr "Format indeks Git"
+
+#: command-list.h
+msgid "Git pack format"
+msgstr "Format pak Git"
+
+#: command-list.h
+msgid "Git cryptographic signature formats"
+msgstr "Format tandatangan kriptografik Git"
 
 #: command-list.h
 msgid "A Git Glossary"
-msgstr ""
+msgstr "Glosarium Git"
 
 #: command-list.h
 msgid "Hooks used by Git"
-msgstr ""
+msgstr "Kait yang digunakan oleh Git"
 
 #: command-list.h
 msgid "Specifies intentionally untracked files to ignore"
-msgstr ""
+msgstr "Sengaja menyebutkan berkas tak terlacak untuk diabaikan"
 
 #: command-list.h
 msgid "The Git repository browser"
-msgstr ""
+msgstr "Penjelajah repositori Git"
 
 #: command-list.h
 msgid "Map author/committer names and/or E-Mail addresses"
-msgstr ""
+msgstr "Petakan nama pengarang/pengkomit dan/atau alamat surel"
 
 #: command-list.h
 msgid "Defining submodule properties"
-msgstr ""
+msgstr "Menentukan properti submodul"
 
 #: command-list.h
 msgid "Git namespaces"
-msgstr ""
+msgstr "Nama lingkup Git"
+
+#: command-list.h
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Kemampuan protokol v0 dan v1"
+
+#: command-list.h
+msgid "Things common to various protocols"
+msgstr "Hal-hal yang umum pada berbagai protokol"
+
+#: command-list.h
+msgid "Git HTTP-based protocols"
+msgstr "Protokol Git berbasis HTTP"
+
+#: command-list.h
+msgid "How packs are transferred over-the-wire"
+msgstr "Bagaimana pak ditransfer lewat kabel"
+
+#: command-list.h
+msgid "Git Wire Protocol, Version 2"
+msgstr "Protokol kabel Git, versi 2"
 
 #: command-list.h
 msgid "Helper programs to interact with remote repositories"
-msgstr ""
+msgstr "Program pembantu untuk berinteraksi dengan repositori remote"
 
 #: command-list.h
 msgid "Git Repository Layout"
-msgstr ""
+msgstr "Tata letak repositori Git"
 
 #: command-list.h
 msgid "Specifying revisions and ranges for Git"
-msgstr ""
+msgstr "Menyebutkan revisi dan rentang untuk Git"
 
 #: command-list.h
 msgid "Mounting one repository inside another"
-msgstr ""
+msgstr "Menaiki satu repositori di dalam lainnya"
 
 #: command-list.h
 msgid "A tutorial introduction to Git"
-msgstr ""
+msgstr "Tutorial perkenalan Git"
 
 #: command-list.h
 msgid "A tutorial introduction to Git: part two"
-msgstr ""
+msgstr "Tutorial perkenalan Git: bagian dua"
 
 #: command-list.h
 msgid "Git web interface (web frontend to Git repositories)"
-msgstr ""
+msgstr "Antarmuka web Git (tampilan depan web untuk repositori Git)"
 
 #: command-list.h
 msgid "An overview of recommended workflows with Git"
-msgstr ""
+msgstr "Selayang pandang alur kerja yang direkomendasikan dengan Git"
+
+#: command-list.h
+msgid "A tool for managing large Git repositories"
+msgstr "Alat untuk mengelola repositori Git besar"
 
 #: commit-graph.c
 msgid "commit-graph file is too small"
-msgstr ""
+msgstr "berkas grafik komit terlalu kecil"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph signature %X does not match signature %X"
-msgstr ""
+msgstr "tanda tangan grafik komit %X tidak cocok dengan tanda tangan %X"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph version %X does not match version %X"
-msgstr ""
+msgstr "versi grafik komit %X tidak cocok dengan versi %X"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph hash version %X does not match version %X"
-msgstr ""
+msgstr "versi hash grafik komit %X tidak cocok dengan versi %X"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph file is too small to hold %u chunks"
-msgstr ""
+msgstr "berkas grafik komit terlalu kecil untuk menyimpan %u bingkah"
 
 #: commit-graph.c
 msgid "commit-graph has no base graphs chunk"
-msgstr ""
+msgstr "grafik komit tidak punya bingkah grafik dasar"
 
 #: commit-graph.c
 msgid "commit-graph chain does not match"
-msgstr ""
+msgstr "rantai grafik komit tidak cocok"
 
 #: commit-graph.c
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
-msgstr ""
+msgstr "rantai grafik komit tidak cocok: baris '%s' bukan sebuah hash"
 
 #: commit-graph.c
 msgid "unable to find all commit-graph files"
-msgstr ""
+msgstr "tidak dapat menemukan semua berkas grafik komit"
 
 #: commit-graph.c
 msgid "invalid commit position. commit-graph is likely corrupt"
-msgstr ""
+msgstr "posisi komit tidak valid. grafik komit mungkin rusak"
 
 #: commit-graph.c
 #, c-format
 msgid "could not find commit %s"
-msgstr ""
+msgstr "tidak dapat menemukan komit %s"
 
 #: commit-graph.c
 msgid "commit-graph requires overflow generation data but has none"
-msgstr ""
+msgstr "grafik komit memerlukan pembuatan data meluap tapi tidak punya"
 
 #: commit-graph.c
 msgid "Loading known commits in commit graph"
-msgstr ""
+msgstr "Memuat komit yang dikenal di grafik komit"
 
 #: commit-graph.c
 msgid "Expanding reachable commits in commit graph"
-msgstr ""
+msgstr "Memperluas komit yang dapat dijangkau di grafik komit"
 
 #: commit-graph.c
 msgid "Clearing commit marks in commit graph"
-msgstr ""
+msgstr "Membersihkan penanda komit di grafik komit"
 
 #: commit-graph.c
 msgid "Computing commit graph topological levels"
-msgstr ""
+msgstr "Menghitung tingat topologis grafik komit"
 
 #: commit-graph.c
 msgid "Computing commit graph generation numbers"
-msgstr ""
+msgstr "Menghitung jumlah pembuatan grafik komit"
 
 #: commit-graph.c
 msgid "Computing commit changed paths Bloom filters"
-msgstr ""
+msgstr "Menghitung komit yang berubah jalurnya oleh penyaring Bloom"
 
 #: commit-graph.c
 msgid "Collecting referenced commits"
-msgstr ""
+msgstr "Mengumpulkan komit tereferensi"
 
 #: commit-graph.c
 #, c-format
 msgid "Finding commits for commit graph in %<PRIuMAX> pack"
 msgid_plural "Finding commits for commit graph in %<PRIuMAX> packs"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Mencari komit untuk grafik komit di dalam pak %<PRIuMAX>"
+msgstr[1] "Mencari komit untuk grafik komit di dalam pak %<PRIuMAX>"
 
 #: commit-graph.c
 #, c-format
 msgid "error adding pack %s"
-msgstr ""
+msgstr "kesalahan menambahkan pak %s"
 
 #: commit-graph.c
 #, c-format
 msgid "error opening index for %s"
-msgstr ""
+msgstr "kesalahan membuka indeks untuk %s"
 
 #: commit-graph.c
 msgid "Finding commits for commit graph among packed objects"
-msgstr ""
+msgstr "Mencari komit untuk grafik komit di antara objek terpak"
 
 #: commit-graph.c
 msgid "Finding extra edges in commit graph"
-msgstr ""
+msgstr "Mencari tepi ekstra di dalam grafik komit"
 
 #: commit-graph.c
 msgid "failed to write correct number of base graph ids"
-msgstr ""
+msgstr "gagal menulis jumlah id grafik dasar yang benar"
 
 #: commit-graph.c
 msgid "unable to create temporary graph layer"
-msgstr ""
+msgstr "tidak dapat membuat lapisan grafik dasar"
 
 #: commit-graph.c
 #, c-format
 msgid "unable to adjust shared permissions for '%s'"
-msgstr ""
+msgstr "tidak dapat menyesuaikan perizinan berbagi untuk '%s'"
 
 #: commit-graph.c
 #, c-format
 msgid "Writing out commit graph in %d pass"
 msgid_plural "Writing out commit graph in %d passes"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Menulis grafik komit dalam %d fase"
+msgstr[1] "Menulis grafik komit dalam %d fase"
 
 #: commit-graph.c
 msgid "unable to open commit-graph chain file"
-msgstr ""
+msgstr "tidak dapat membuka berkas rantai grafik komit"
 
 #: commit-graph.c
 msgid "failed to rename base commit-graph file"
-msgstr ""
+msgstr "gagal menamai ulang berkas grafik komit dasar"
 
 #: commit-graph.c
 msgid "failed to rename temporary commit-graph file"
-msgstr ""
+msgstr "gagal menamai ulang berkas grafik komit sementara"
 
 #: commit-graph.c
 msgid "Scanning merged commits"
-msgstr ""
+msgstr "Memindai komit tergabung"
 
 #: commit-graph.c
 msgid "Merging commit-graph"
-msgstr ""
+msgstr "Menggabungkan grafik komit"
 
 #: commit-graph.c
 msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
-msgstr ""
+msgstr "mencoba menulis grafik komit, tapi 'core.commitGraph' dimatikan"
 
 #: commit-graph.c
 msgid "too many commits to write graph"
-msgstr ""
+msgstr "terlalu banyak komit untuk menulis grafik"
 
 #: commit-graph.c
 msgid "the commit-graph file has incorrect checksum and is likely corrupt"
-msgstr ""
+msgstr "berkas grafik komit punya checksum salah dan mungkin rusak"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph has incorrect OID order: %s then %s"
-msgstr ""
+msgstr "grafik komit punya urutan OID salah: %s lalu %s"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
-msgstr ""
+msgstr "grafik komit punya nilai kipas keluar salah: fanout[%d] = %u != %u"
 
 #: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from commit-graph"
-msgstr ""
+msgstr "gagal menguraikan komit %s dari grafik komit"
 
 #: commit-graph.c
 msgid "Verifying commits in commit graph"
-msgstr ""
+msgstr "Memverifikasi komit di dalam grafik komit"
 
 #: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
-msgstr ""
+msgstr "gagal menguraikan komit %s dari basis data objek untuk grafik komit"
 
 #: commit-graph.c
 #, c-format
 msgid "root tree OID for commit %s in commit-graph is %s != %s"
-msgstr ""
+msgstr "OID pohon akar untuk komit %s di dalam grafik komit yaitu %s != %s"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph parent list for commit %s is too long"
-msgstr ""
+msgstr "daftar induk grafik komit untuk %s terlalu panjang"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph parent for %s is %s != %s"
-msgstr ""
+msgstr "induk grafik komit untuk %s adalah %s != %s"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph parent list for commit %s terminates early"
-msgstr ""
+msgstr "daftar induk grafik komit untuk komit %s berakhir lebih awal"
 
 #: commit-graph.c
 #, c-format
 msgid ""
 "commit-graph has generation number zero for commit %s, but non-zero elsewhere"
 msgstr ""
+"grafik komit punya angka pembuatan nol untuk komit %s, tapi bukan nol di "
+"tempat lain"
 
 #: commit-graph.c
 #, c-format
 msgid ""
 "commit-graph has non-zero generation number for commit %s, but zero elsewhere"
 msgstr ""
+"grafik komit punya angka pembuatan bukan nol untuk komit %s, tapi nol di "
+"tempat lain"
 
 #: commit-graph.c
 #, c-format
 msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
-msgstr ""
+msgstr "pembuatan grafik komit untuk komit %s yaitu %<PRIuMAX> < %<PRIuMAX>"
 
 #: commit-graph.c
 #, c-format
 msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
 msgstr ""
+"tanggal komit untuk komit %s di dalam grafik komit yaitu %<PRIuMAX> != "
+"%<PRIuMAX>"
 
 #: commit.c
 #, c-format
 msgid "%s %s is not a commit!"
-msgstr ""
+msgstr "%s %s bukan sebuah komit!"
 
 #: commit.c
 msgid ""
@@ -17449,26 +17842,34 @@ msgid ""
 "Turn this message off by running\n"
 "\"git config advice.graftFileDeprecated false\""
 msgstr ""
+"Dukungan untuk <GIT_DIR>/info/grafts usang dan akan dihapus\n"
+"pada versi Git di masa yang akan datang.\n"
+"\n"
+"Mohon gunakan \"git replace --convert-graft-file\"\n"
+"untuk mengkonversi cangkuk ke referensi penggantian.\n"
+"\n"
+"Matikan pesan ini dengan menjalankan\n"
+"\"git config advice.graftFileDeprecated false\""
 
 #: commit.c
 #, c-format
 msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
-msgstr ""
+msgstr "Komit %s punya tandatangan GPG tak dipercaya, dituduh sebagai %s."
 
 #: commit.c
 #, c-format
 msgid "Commit %s has a bad GPG signature allegedly by %s."
-msgstr ""
+msgstr "Komit %s punya tandatangan GPG tak jelek, dituduh sebagai %s."
 
 #: commit.c
 #, c-format
 msgid "Commit %s does not have a GPG signature."
-msgstr ""
+msgstr "Komit %s tidak punya tandatangan GPG."
 
 #: commit.c
 #, c-format
 msgid "Commit %s has a good GPG signature by %s\n"
-msgstr ""
+msgstr "Komit %s punya tandatangan GPG bagus oleh %s\n"
 
 #: commit.c
 msgid ""
@@ -17476,214 +17877,239 @@ msgid ""
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitEncoding to the encoding your project uses.\n"
 msgstr ""
+"Peringatan: pesan komit tidak sesuai dengan UTF-8.\n"
+"Anda dapat mengubahnya setelah memperbaiki pesan, atau menyetel variabel\n"
+"konfigurasi i18n.commitEncoding ke pengkodean yang proyek Anda gunakan.\n"
 
 #: compat/compiler.h
 msgid "no compiler information available\n"
-msgstr ""
+msgstr "informasi pengompilasi tidak tersedia\n"
 
 #: compat/compiler.h
 msgid "no libc information available\n"
-msgstr ""
+msgstr "informasi libc tidak tersedia\n"
+
+#: compat/disk.h
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "tidak dapat menentukan ukuran disk kosong untuk '%s'"
+
+#: compat/disk.h
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "tidak dapat mendapatkan informasi untuk '%s'"
 
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
-msgstr ""
+msgstr "[GLE %ld] utas kesehatan tidak dapat membuka '%ls'"
 
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "[GLE %ld] health thread getting BHFI for '%ls'"
-msgstr ""
+msgstr "[GLE %ld] utas kesehatan mendapatkan BHFI untuk '%ls'"
 
 #: compat/fsmonitor/fsm-health-win32.c compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "could not convert to wide characters: '%s'"
-msgstr ""
+msgstr "tidak dapat mengkonversi ke karakter lebar: '%s'"
 
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "BHFI changed '%ls'"
-msgstr ""
+msgstr "BHFI mengubah '%ls'"
 
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "unhandled case in 'has_worktree_moved': %d"
-msgstr ""
+msgstr "kasus tak tertangani di 'has_worktree_moved': %d"
 
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "health thread wait failed [GLE %ld]"
-msgstr ""
+msgstr "antri utas kesehatan gagal [GLE %ld]"
 
 #: compat/fsmonitor/fsm-listen-darwin.c
 msgid "Unable to create FSEventStream."
-msgstr ""
+msgstr "tidak dapat membuat FSEventStream."
 
 #: compat/fsmonitor/fsm-listen-darwin.c
 msgid "Failed to start the FSEventStream"
-msgstr ""
+msgstr "Gagal memulai FSEventStream"
 
 #: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
-msgstr ""
+msgstr "[GLE %ld] tidak dapat mengkonversi jalur ke UTF-8: '%.*ls'"
 
 #: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "[GLE %ld] could not watch '%s'"
-msgstr ""
+msgstr "[GLE %ld] tidak dapat menonton '%s'"
 
 #: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "[GLE %ld] could not get longname of '%s'"
-msgstr ""
+msgstr "[GLE %ld] tidak dapat mendapatkan nama panjang dari '%s'"
 
 #: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "ReadDirectoryChangedW gagal pada '%s' [GLE %ld]"
 
 #: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "GetOverlappedResult gagal pada '%s' [GLE %ld]"
 
 #: compat/fsmonitor/fsm-listen-win32.c
 #, c-format
 msgid "could not read directory changes [GLE %ld]"
-msgstr ""
+msgstr "tidak dapat membaca perubahan direktori [GLE %ld]"
+
+#: compat/fsmonitor/fsm-settings-win32.c
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] tidak dapat membuka untuk dibaca '%ls'"
+
+#: compat/fsmonitor/fsm-settings-win32.c
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] tidak dapat mendapatkan informasi protokol untuk '%ls'"
 
 #: compat/mingw.c
 #, c-format
 msgid "failed to copy SID (%ld)"
-msgstr ""
+msgstr "gagal menyalin SID (%ld)"
 
 #: compat/mingw.c
 #, c-format
 msgid "failed to get owner for '%s' (%ld)"
-msgstr ""
+msgstr "gagal mendapatkan pemilik untuk '%s' (%ld)"
 
 #: compat/obstack.c
 msgid "memory exhausted"
-msgstr ""
+msgstr "memory habis"
 
 #: compat/regex/regcomp.c
 msgid "Success"
-msgstr ""
+msgstr "Success"
 
 #: compat/regex/regcomp.c
 msgid "No match"
-msgstr ""
+msgstr "Tidak ada yang cocok"
 
 #: compat/regex/regcomp.c
 msgid "Invalid regular expression"
-msgstr ""
+msgstr "Ekspresi reguler tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Invalid collation character"
-msgstr ""
+msgstr "Karakter kolase tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Invalid character class name"
-msgstr ""
+msgstr "Nama kelas karakter tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Trailing backslash"
-msgstr ""
+msgstr "Garis miring terbalik tertinggal"
 
 #: compat/regex/regcomp.c
 msgid "Invalid back reference"
-msgstr ""
+msgstr "Referensi balik tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Unmatched [ or [^"
-msgstr ""
+msgstr "[ atau [^ tak tercocok"
 
 #: compat/regex/regcomp.c
 msgid "Unmatched ( or \\("
-msgstr ""
+msgstr "( atau \\( tak tercocok"
 
 #: compat/regex/regcomp.c
 msgid "Unmatched \\{"
-msgstr ""
+msgstr "\\{ tak tercocok"
 
 #: compat/regex/regcomp.c
 msgid "Invalid content of \\{\\}"
-msgstr ""
+msgstr "Isi \\{\\} tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Invalid range end"
-msgstr ""
+msgstr "Ujung rentang tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Memory exhausted"
-msgstr ""
+msgstr "Memori habis"
 
 #: compat/regex/regcomp.c
 msgid "Invalid preceding regular expression"
-msgstr ""
+msgstr "Ekspresi reguler sebelumnya tidak valid"
 
 #: compat/regex/regcomp.c
 msgid "Premature end of regular expression"
-msgstr ""
+msgstr "Akhir ekspresi reguler prematur"
 
 #: compat/regex/regcomp.c
 msgid "Regular expression too big"
-msgstr ""
+msgstr "Ekspresi reguler terlalu besar"
 
 #: compat/regex/regcomp.c
 msgid "Unmatched ) or \\)"
-msgstr ""
+msgstr ") atau \\) tak tercocok"
 
 #: compat/regex/regcomp.c
 msgid "No previous regular expression"
-msgstr ""
+msgstr "Tidak ada ekspresi reguler sebelumnya"
 
 #: compat/simple-ipc/ipc-unix-socket.c compat/simple-ipc/ipc-win32.c
 msgid "could not send IPC command"
-msgstr ""
+msgstr "tidak dapat mengirimkan perintah IPC"
 
 #: compat/simple-ipc/ipc-unix-socket.c compat/simple-ipc/ipc-win32.c
 msgid "could not read IPC response"
-msgstr ""
+msgstr "tidak dapat membaca jawaban IPC"
 
 #: compat/simple-ipc/ipc-unix-socket.c
 #, c-format
 msgid "could not start accept_thread '%s'"
-msgstr ""
+msgstr "tidak dapat memulai accept_thread '%s'"
 
 #: compat/simple-ipc/ipc-unix-socket.c
 #, c-format
 msgid "could not start worker[0] for '%s'"
-msgstr ""
+msgstr "tidak dapat memulai worker[0] untuk '%s'"
 
 #: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "ConnectNamedPipe failed for '%s' (%lu)"
-msgstr ""
+msgstr "ConnectNamedPipe gagal untuk '%s' (%lu)"
 
 #: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "could not create fd from pipe for '%s'"
-msgstr ""
+msgstr "tidak dapat membuat penjelas berkas dari pipa untuk '%s'"
 
 #: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "could not start thread[0] for '%s'"
-msgstr ""
+msgstr "tidak dapat memulai thread[0] untuk '%s'"
 
 #: compat/simple-ipc/ipc-win32.c
 #, c-format
 msgid "wait for hEvent failed for '%s'"
-msgstr ""
+msgstr "antri untuk hEvent gagal untuk '%s'"
 
 #: compat/terminal.c
 msgid "cannot resume in the background, please use 'fg' to resume"
 msgstr ""
+"tidak dapat melanjutkan di belakang layar, mohon gunakan 'fg' untuk "
+"melanjutkan"
 
 #: compat/terminal.c
 msgid "cannot restore terminal settings"
-msgstr ""
+msgstr "tidak dapat mengembalikan setelan terminal"
 
 #: config.c
 #, c-format
@@ -18231,233 +18657,15 @@ msgstr "gagal menulis ke rev-list"
 msgid "failed to close rev-list's stdin"
 msgstr "gagal menutup masukan standar rev-list"
 
-#: contrib/scalar/scalar.c worktree.c
-#, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' tidak ada"
-
-#: contrib/scalar/scalar.c
-msgid "need a working directory"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "could not find enlistment root"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not switch to '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure %s=%s"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "could not configure log.excludeDecoration"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "Scalar enlistments require a worktree"
-msgstr ""
-
-#: contrib/scalar/scalar.c dir.c
-#, c-format
-msgid "could not open directory '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not get info for '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "failed to get default branch name"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "failed to unregister repository"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "failed to delete enlistment directory"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "branch to checkout after clone"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "when cloning, create full working directory"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "only download metadata for the branch that will be checked out"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "directory '%s' exists already"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "partial clone failed; attempting full clone"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "could not configure for full clone"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar diagnose [<enlistment>]"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "could not duplicate stdout"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "failed to write archive"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "`scalar list` does not take arguments"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar register [<enlistment>]"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "reconfigure all registered enlistments"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "--all or <enlistment>, but not both"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "no such task: '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar unregister [<enlistment>]"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar delete <enlistment>"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "refusing to delete current working directory"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "include Git version"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "include Git's build options"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "-C requires a <directory>"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not change to '%s'"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid "-c requires a <key>=<value> argument"
-msgstr ""
-
-#: contrib/scalar/scalar.c
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-
 #: convert.c
 #, c-format
 msgid "illegal crlf_action %d"
-msgstr ""
+msgstr "crlf_action %d ilegal"
 
 #: convert.c
 #, c-format
 msgid "CRLF would be replaced by LF in %s"
-msgstr ""
+msgstr "CRLF akan digantikan oleh LF di %s"
 
 #: convert.c
 #, c-format
@@ -18465,11 +18673,13 @@ msgid ""
 "in the working copy of '%s', CRLF will be replaced by LF the next time Git "
 "touches it"
 msgstr ""
+"di dalam salinan kerja '%s', CRLF akan digantikan oleh LF pada saat Git "
+"menyentuhnya lain kali"
 
 #: convert.c
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
-msgstr ""
+msgstr "LF akan digantikan oleh CRLF di %s"
 
 #: convert.c
 #, c-format
@@ -18477,11 +18687,13 @@ msgid ""
 "in the working copy of '%s', LF will be replaced by CRLF the next time Git "
 "touches it"
 msgstr ""
+"di dalam salinan kerja '%s', LF akan digantikan oleh LF pada saat Git "
+"menyentuhnya lain kali"
 
 #: convert.c
 #, c-format
 msgid "BOM is prohibited in '%s' if encoded as %s"
-msgstr ""
+msgstr "BOM tidak diperbolehkan di '%s' jika dikodekan sebagai %s"
 
 #: convert.c
 #, c-format
@@ -18489,11 +18701,13 @@ msgid ""
 "The file '%s' contains a byte order mark (BOM). Please use UTF-%.*s as "
 "working-tree-encoding."
 msgstr ""
+"Berkas '%s' berisi tanda urutan bita (BOM). Mohon gunakan UTF-%.*s sebagai "
+"pengkodean pohon kerja."
 
 #: convert.c
 #, c-format
 msgid "BOM is required in '%s' if encoded as %s"
-msgstr ""
+msgstr "BOM diperlukan di '%s' jika dikodekan sebagai %s"
 
 #: convert.c
 #, c-format
@@ -18501,49 +18715,51 @@ msgid ""
 "The file '%s' is missing a byte order mark (BOM). Please use UTF-%sBE or UTF-"
 "%sLE (depending on the byte order) as working-tree-encoding."
 msgstr ""
+"Berkas '%s' kehilangan tanda urutan bita (BOM). Mohon gunakan UTF-%sBE atau "
+"UTF-%sLE (tergantung pada urutan bita) sebagai pengkodean pohon kerja."
 
 #: convert.c
 #, c-format
 msgid "failed to encode '%s' from %s to %s"
-msgstr ""
+msgstr "gagal mengkodekan '%s' dari %s ke %s"
 
 #: convert.c
 #, c-format
 msgid "encoding '%s' from %s to %s and back is not the same"
-msgstr ""
+msgstr "pengkodean '%s' dari %s ke %s dan sebaliknya berbeda"
 
 #: convert.c
 #, c-format
 msgid "cannot fork to run external filter '%s'"
-msgstr ""
+msgstr "tidak dapat menggarpu untuk menjalankan penyaring eksternal '%s'"
 
 #: convert.c
 #, c-format
 msgid "cannot feed the input to external filter '%s'"
-msgstr ""
+msgstr "tidak dapat mengumpan masukan ke penyaring eksternal '%s'"
 
 #: convert.c
 #, c-format
 msgid "external filter '%s' failed %d"
-msgstr ""
+msgstr "penyaring eksternal '%s' gagal %d"
 
 #: convert.c
 #, c-format
 msgid "read from external filter '%s' failed"
-msgstr ""
+msgstr "gagal membaca dari penyaring eksternal '%s'"
 
 #: convert.c
 #, c-format
 msgid "external filter '%s' failed"
-msgstr ""
+msgstr "penyaring eksternal '%s' gagal"
 
 #: convert.c
 msgid "unexpected filter type"
-msgstr ""
+msgstr "tipe penyaring tidak diharapkan"
 
 #: convert.c
 msgid "path name too long for external filter"
-msgstr ""
+msgstr "nama jalur terlalu panjang untuk penyaring eksternal"
 
 #: convert.c
 #, c-format
@@ -18551,48 +18767,50 @@ msgid ""
 "external filter '%s' is not available anymore although not all paths have "
 "been filtered"
 msgstr ""
+"penyaring eksternal '%s' tidak tersedia lagi walaupun tidak semua jalur "
+"sudah disaring"
 
 #: convert.c
 msgid "true/false are no valid working-tree-encodings"
-msgstr ""
+msgstr "true/false bukanlah pengkodean pohon kerja valid"
 
 #: convert.c
 #, c-format
 msgid "%s: clean filter '%s' failed"
-msgstr ""
+msgstr "%s: penyaring bersih '%s' gagal"
 
 #: convert.c
 #, c-format
 msgid "%s: smudge filter %s failed"
-msgstr ""
+msgstr "%s: penyaring noda %s gagal"
 
 #: credential.c
 #, c-format
 msgid "skipping credential lookup for key: credential.%s"
-msgstr ""
+msgstr "melewati pencarian kredensial untuk kunci: credential.%s"
 
 #: credential.c
 msgid "refusing to work with credential missing host field"
-msgstr ""
+msgstr "menolak bekerja dengan kredensial yang kehilangan bidang host"
 
 #: credential.c
 msgid "refusing to work with credential missing protocol field"
-msgstr ""
+msgstr "menolak bekerja dengan kredensial yang kehilangan bidang protokol"
 
 #: credential.c
 #, c-format
 msgid "url contains a newline in its %s component: %s"
-msgstr ""
+msgstr "url berisi baris baru pada komponen %s: %s"
 
 #: credential.c
 #, c-format
 msgid "url has no scheme: %s"
-msgstr ""
+msgstr "url tidak punya skema: %s"
 
 #: credential.c
 #, c-format
 msgid "credential url cannot be parsed: %s"
-msgstr ""
+msgstr "url kredensial tidak dapat diuraikan: %s"
 
 #: date.c
 msgid "in the future"
@@ -18664,57 +18882,93 @@ msgstr[1] "%<PRIuMAX> tahun yang lalu"
 
 #: delta-islands.c
 msgid "Propagating island marks"
-msgstr ""
+msgstr "Menyebarkan penanda pulau"
 
 #: delta-islands.c
 #, c-format
 msgid "bad tree object %s"
-msgstr ""
+msgstr "objek pohon jelek %s"
 
 #: delta-islands.c
 #, c-format
 msgid "failed to load island regex for '%s': %s"
-msgstr ""
+msgstr "gagal memuat regex pulau untuk '%s': %s"
 
 #: delta-islands.c
 #, c-format
 msgid "island regex from config has too many capture groups (max=%d)"
 msgstr ""
+"regeks pulau dari konfigurasi punya terlalu banyak grup tangkap (max=%d)"
 
 #: delta-islands.c
 #, c-format
 msgid "Marked %d islands, done.\n"
-msgstr ""
+msgstr "%d pulau ditandai, selesai.\n"
+
+#: diagnose.c
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "nilai --%s tidak valid '%s'"
+
+#: diagnose.c
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "tidak dapat mengarsipkan direktori hilang '%s'"
+
+#: diagnose.c dir.c
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "tidak dapat membuka direktori '%s'"
+
+#: diagnose.c
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "melewatkan '%s', yang bukan berkas atau direktori"
+
+#: diagnose.c
+msgid "could not duplicate stdout"
+msgstr "tidak dapat menggandakan keluaran standar"
+
+#: diagnose.c
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "tidak dapat menambahkan direktori '%s' ke pengarsip"
+
+#: diagnose.c
+msgid "failed to write archive"
+msgstr "gagal menulis arsip"
 
 #: diff-lib.c
 msgid "--merge-base does not work with ranges"
-msgstr ""
+msgstr "--merge-base tidak bekerja dengan rentang"
 
 #: diff-lib.c
 msgid "--merge-base only works with commits"
-msgstr ""
+msgstr "--merge-base hanya bekerja dengan komit"
 
 #: diff-lib.c
 msgid "unable to get HEAD"
-msgstr ""
+msgstr "tidak dapat mendapatkan HEAD"
 
 #: diff-lib.c
 msgid "no merge base found"
-msgstr ""
+msgstr "dasar penggabungan tidak ditemukan"
 
 #: diff-lib.c
 msgid "multiple merge bases found"
-msgstr ""
+msgstr "banyak dasar penggabungan ditemukan"
 
 #: diff-no-index.c
 msgid "git diff --no-index [<options>] <path> <path>"
-msgstr ""
+msgstr "git diff --no-index [<opsi>] <jalur> <jalur>"
 
 #: diff-no-index.c
 msgid ""
 "Not a git repository. Use --no-index to compare two paths outside a working "
 "tree"
 msgstr ""
+"Bukan sebuah repositori git. Gunakan --no-index untuk membandingkan dua "
+"jalur di luar pohon kerja"
 
 #: diff.c
 #, c-format
@@ -18802,7 +19056,7 @@ msgstr "nilai --stat tidak valid: %s"
 #: diff.c parse-options.c
 #, c-format
 msgid "%s expects a numerical value"
-msgstr "%s harap nilai numerik"
+msgstr "%s berharap nilai numerik"
 
 #: diff.c
 #, c-format
@@ -19343,53 +19597,53 @@ msgstr ""
 #: diffcore-order.c
 #, c-format
 msgid "failed to read orderfile '%s'"
-msgstr ""
+msgstr "gagal membaca berkas urutan '%s'"
 
 #: diffcore-rename.c
 msgid "Performing inexact rename detection"
-msgstr ""
+msgstr "Melakukan deteksi penamaan ulang tidak eksak"
 
 #: diffcore-rotate.c
 #, c-format
 msgid "No such path '%s' in the diff"
-msgstr ""
+msgstr "Tidak ada jalur seperti '%s' di dalam diff"
 
 #: dir.c
 #, c-format
 msgid "pathspec '%s' did not match any file(s) known to git"
-msgstr ""
+msgstr "spek jalur '%s' tidak cocok dengan berkas apapun yang git kenal"
 
 #: dir.c
 #, c-format
 msgid "unrecognized pattern: '%s'"
-msgstr ""
+msgstr "pola tidak dikenal: '%s'"
 
 #: dir.c
 #, c-format
 msgid "unrecognized negative pattern: '%s'"
-msgstr ""
+msgstr "pola negatif tidak dikenal: '%s'"
 
 #: dir.c
 #, c-format
 msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
-msgstr ""
+msgstr "berkas sparse-checkout Anda mungkin ada masalah: pola '%s' diulangi"
 
 #: dir.c
 msgid "disabling cone pattern matching"
-msgstr ""
+msgstr "mematikan pencocokan pola kerucut"
 
 #: dir.c
 #, c-format
 msgid "cannot use %s as an exclude file"
-msgstr ""
+msgstr "tidak dapat menggunakan %s sebagai berkas pengecualian"
 
 #: dir.c
 msgid "failed to get kernel name and information"
-msgstr ""
+msgstr "gagal mendapatkan nama dan informasi kernel"
 
 #: dir.c
 msgid "untracked cache is disabled on this system or location"
-msgstr ""
+msgstr "tembolok tak terlacat dimatikan pada sistem atau lokasi ini"
 
 #: dir.c
 msgid ""
@@ -19402,41 +19656,41 @@ msgstr ""
 #: dir.c
 #, c-format
 msgid "index file corrupt in repo %s"
-msgstr ""
+msgstr "berkas indeks rusak pada repo %s"
 
 #: dir.c
 #, c-format
 msgid "could not create directories for %s"
-msgstr ""
+msgstr "tidak dapat membuat direktori untuk %s"
 
 #: dir.c
 #, c-format
 msgid "could not migrate git directory from '%s' to '%s'"
-msgstr ""
+msgstr "tidak dapat memigrasikan direktori git dari '%s' ke '%s'"
 
 #: editor.c
 #, c-format
 msgid "hint: Waiting for your editor to close the file...%c"
-msgstr ""
+msgstr "petunjuk: Menunggu penyunting Anda untuk menutup berkas...%c"
 
 #: entry.c
 msgid "Filtering content"
-msgstr ""
+msgstr "Menyaring isi"
 
 #: entry.c
 #, c-format
 msgid "could not stat file '%s'"
-msgstr ""
+msgstr "tidak dapat men-stat berkas '%s'"
 
 #: environment.c
 #, c-format
 msgid "bad git namespace path \"%s\""
-msgstr ""
+msgstr "jalur ruang nama git jelek \"%s\""
 
 #: exec-cmd.c
 #, c-format
 msgid "too many args to run %s"
-msgstr ""
+msgstr "terlalu banyak argumen untuk menjalankan %s"
 
 #: fetch-pack.c
 msgid "git fetch-pack: expected shallow list"
@@ -19459,6 +19713,10 @@ msgstr "git fetch-pack: ACK/NAK diharapkan, dapat '%s'"
 msgid "unable to write to remote"
 msgstr "tidak dapat menulis ke remote"
 
+#: fetch-pack.c
+msgid "Server supports filter"
+msgstr "Peladen mendukung saringan"
+
 #: fetch-pack.c
 #, c-format
 msgid "invalid shallow line: %s"
@@ -19600,10 +19858,6 @@ msgstr "peladen tidak mendukung algoritma '%s'"
 msgid "Server does not support shallow requests"
 msgstr "Peladen tidak mendukung permintaan dangkal"
 
-#: fetch-pack.c
-msgid "Server supports filter"
-msgstr "Peladen mendukung saringan"
-
 #: fetch-pack.c
 msgid "unable to write request to remote"
 msgstr "tidak dapat menulis permintaan kepada remote"
@@ -19690,47 +19944,49 @@ msgstr "Peladen tidak memperbolehkan permintaan untuk objek tak diiklankan %s"
 #: fsmonitor-ipc.c
 #, c-format
 msgid "fsmonitor_ipc__send_query: invalid path '%s'"
-msgstr ""
+msgstr "fsmonitor_ipc__send_query: jalur tidak valid '%s'"
 
 #: fsmonitor-ipc.c
 #, c-format
 msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
-msgstr ""
+msgstr "fsmonitor_ipc__send_query: kesalahan tidak dijelaskan pada '%s'"
 
 #: fsmonitor-ipc.c
 msgid "fsmonitor--daemon is not running"
-msgstr ""
+msgstr "fsmonitor--daemon tidak berjalan"
 
 #: fsmonitor-ipc.c
 #, c-format
 msgid "could not send '%s' command to fsmonitor--daemon"
-msgstr ""
+msgstr "tidak dapat mengirimkan perintah '%s' ke fsmonitor--daemon"
 
 #: fsmonitor-settings.c
 #, c-format
 msgid "bare repository '%s' is incompatible with fsmonitor"
-msgstr ""
+msgstr "repositori bare '%s' tidak kompatibel dengan fsmonitor"
 
 #: fsmonitor-settings.c
 #, c-format
 msgid "repository '%s' is incompatible with fsmonitor due to errors"
-msgstr ""
+msgstr "repositori '%s' tidak kompatibel dengan fsmonitor karena kesalahan"
 
 #: fsmonitor-settings.c
 #, c-format
 msgid "remote repository '%s' is incompatible with fsmonitor"
-msgstr ""
+msgstr "repositori remote '%s' tidak kompatibel dengan fsmonitor"
 
 #: fsmonitor-settings.c
 #, c-format
 msgid "virtual repository '%s' is incompatible with fsmonitor"
-msgstr ""
+msgstr "repositori virtual '%s' tidka kompatibel dengan fsmonitor"
 
 #: fsmonitor-settings.c
 #, c-format
 msgid ""
 "repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"
 msgstr ""
+"repositori '%s' tidak kompatibel dengan fsmonitor karena kekurangan soket "
+"Unix"
 
 #: git.c
 msgid ""
@@ -20026,6 +20282,14 @@ msgstr "Perintah Tingkat Rendah / Sinkronisasi Repositori"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Perintah Tingak Rendah / Pembantu Internal"
 
+#: help.c
+msgid "User-facing repository, command and file interfaces"
+msgstr "Antarmuka repositori, perintah, dan berkas menghadap-pengguna"
+
+#: help.c
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Antarmuka menghadap-pengembang format berkas, protokol, dan lainnya"
+
 #: help.c
 #, c-format
 msgid "available git commands in '%s'"
@@ -20043,6 +20307,14 @@ msgstr "Berikut ini perintah Git umum yang digunakan dalam beragam situasi:"
 msgid "The Git concept guides are:"
 msgstr "Panduan konsep Git adalah:"
 
+#: help.c
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Antarmuka repositori, perintah, dan berkas menghadap-pengguna:"
+
+#: help.c
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Antarmuka format berkas, protokol, dan antarmuka lainnya:"
+
 #: help.c
 msgid "External commands"
 msgstr "Perintah eksternal"
@@ -20140,51 +20412,48 @@ msgstr ""
 "Anda dapat menonaktifkan peringatan ini dengan `git config advice."
 "ignoredHook false`."
 
-#: hook.c
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "Tidak dapat memulai kait '%s'\n"
-
 #: http-fetch.c
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
-msgstr ""
+msgstr "argumen ke --packfile harus sebuah hash valid (dapat '%s')"
 
 #: http-fetch.c
 msgid "not a git repository"
-msgstr ""
+msgstr "bukan sebuah repositori git"
 
 #: http.c
 #, c-format
 msgid "negative value for http.postBuffer; defaulting to %d"
-msgstr ""
+msgstr "nilai negatif untuk http.postBuffer; asalkan ke %d"
 
 #: http.c
 msgid "Delegation control is not supported with cURL < 7.22.0"
-msgstr ""
+msgstr "Kontrol delegasi tidak didukung oleh cURL < 7.22.0"
 
 #: http.c
 msgid "Public key pinning not supported with cURL < 7.39.0"
-msgstr ""
+msgstr "Penyematan kunci publik tidak didukung oleh cURL < 7.39.0"
 
 #: http.c
 msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
-msgstr ""
+msgstr "CURLSSLOPT_NO_REVOKE tidak didukung dengan cURL < 7.44.0"
 
 #: http.c
 #, c-format
 msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
-msgstr ""
+msgstr "Tulang punggung SSL '%s' tidak didukung, yang didukung:"
 
 #: http.c
 #, c-format
 msgid "Could not set SSL backend to '%s': cURL was built without SSL backends"
 msgstr ""
+"Tidak dapat menyetel tulang punggung SSL ke '%s': cURL dibangun tanpa tulang "
+"punggung SSL"
 
 #: http.c
 #, c-format
 msgid "Could not set SSL backend to '%s': already set"
-msgstr ""
+msgstr "Tidak dapat menyetel tulang punggung SSL ke '%s': sudah disetel"
 
 #: http.c
 #, c-format
@@ -20193,6 +20462,9 @@ msgid ""
 "  asked for: %s\n"
 "   redirect: %s"
 msgstr ""
+"tidak dapat memperbarui dasar url dari pengalihan:\n"
+"     diminta: %s\n"
+"  pengalihan: %s"
 
 #: ident.c
 msgid "Author identity unknown\n"
@@ -20258,71 +20530,72 @@ msgstr "nama hanya terdiri dari karakter yang tidak diperbolehkan: %s"
 
 #: list-objects-filter-options.c
 msgid "expected 'tree:<depth>'"
-msgstr ""
+msgstr "'tree:<kedalaman> diharapkan'"
 
 #: list-objects-filter-options.c
 msgid "sparse:path filters support has been dropped"
-msgstr ""
+msgstr "dukungan penyaring sparse:path sudah ditiadakan"
 
 #: list-objects-filter-options.c
 #, c-format
 msgid "'%s' for 'object:type=<type>' is not a valid object type"
-msgstr ""
+msgstr "'%s' untuk 'object:type=<tipe>' bukan tipe objek valid"
 
 #: list-objects-filter-options.c
 #, c-format
 msgid "invalid filter-spec '%s'"
-msgstr ""
+msgstr "spek penyaring tidak valid '%s'"
 
 #: list-objects-filter-options.c
 #, c-format
 msgid "must escape char in sub-filter-spec: '%c'"
-msgstr ""
+msgstr "harus melarikan karakter pada spek subpenyaring: '%c'"
 
 #: list-objects-filter-options.c
 msgid "expected something after combine:"
-msgstr ""
+msgstr "sesuatu setelah pencampuran diharapkan:"
 
 #: list-objects-filter-options.c
 msgid "multiple filter-specs cannot be combined"
-msgstr ""
+msgstr "spek penyaring lebih dari satu tidak dapat dicampurkan"
 
 #: list-objects-filter-options.c
 msgid "unable to upgrade repository format to support partial clone"
 msgstr ""
+"tidak dapat meningkatkan format repositori untuk mendukung klon parsial"
 
 #: list-objects-filter-options.h
 msgid "args"
-msgstr ""
+msgstr "argumen"
 
 #: list-objects-filter-options.h
 msgid "object filtering"
-msgstr ""
+msgstr "penyaringan objek"
 
 #: list-objects-filter.c
 #, c-format
 msgid "unable to access sparse blob in '%s'"
-msgstr ""
+msgstr "tidak dapat mengakses blob tipis di '%s'"
 
 #: list-objects-filter.c
 #, c-format
 msgid "unable to parse sparse filter data in %s"
-msgstr ""
+msgstr "tidak dapat menyaring data penyaring tipis di %s"
 
 #: list-objects.c
 #, c-format
 msgid "entry '%s' in tree %s has tree mode, but is not a tree"
-msgstr ""
+msgstr "entri '%s' di dalam pohon %s punya mode pohon, tetapi bukan pohon"
 
 #: list-objects.c
 #, c-format
 msgid "entry '%s' in tree %s has blob mode, but is not a blob"
-msgstr ""
+msgstr "entri '%s' di dalam pohon %s punya mode blob, tetapi bukan blob"
 
 #: list-objects.c
 #, c-format
 msgid "unable to load root tree for commit %s"
-msgstr ""
+msgstr "tidak dapat memuat pohon akar untuk komit %s"
 
 #: lockfile.c
 #, c-format
@@ -20335,40 +20608,41 @@ msgid ""
 "may have crashed in this repository earlier:\n"
 "remove the file manually to continue."
 msgstr ""
+"Tidak dapat membuat '%s.lock': %s.\n"
+"\n"
+"Sepertinya proses git lainnya berjalan pada repositori ini, seperti\n"
+"penyunting yang dibuka oleh 'git commit'. Mohon pastikan semua proses\n"
+"berhenti dan coba lagi. Jika masih gagal, mungkin sebuah proses git hancur\n"
+"pada repositori ini sebelumnya: hapus berkas secara manual untuk melanjutkan."
 
 #: lockfile.c
 #, c-format
 msgid "Unable to create '%s.lock': %s"
-msgstr ""
+msgstr "Tidak dapat membuat '%s.lock': %s"
 
 #: ls-refs.c
 #, c-format
 msgid "unexpected line: '%s'"
-msgstr ""
+msgstr "baris tak diharapkan: '%s'"
 
 #: ls-refs.c
 msgid "expected flush after ls-refs arguments"
-msgstr ""
+msgstr "bilasan diharapkan setelah argumen ls-refs"
 
 #: mailinfo.c
 msgid "quoted CRLF detected"
-msgstr ""
-
-#: merge-ort-wrappers.c merge-recursive.c
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh "
-"penggabungan:\n"
-"  %s"
+msgstr "CRLF terkutip terdeteksi"
 
 #: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "Gagal menggabungkan submodul %s (tidak di-checkout)"
 
+#: merge-ort.c
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Gagal menggabungkan submodul %s (tidak ada dasar penggabungan)"
+
 #: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
@@ -20393,28 +20667,10 @@ msgstr "Gagal menggabungkan submodul %s"
 #: merge-ort.c
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"Gagal menggabungkan submodul %s, tetapi sebuah penyelesaian penggabungan "
-"yang mungkin ada:\n"
-"%s\n"
-
-#: merge-ort.c merge-recursive.c
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
 msgstr ""
-"Jika benar, cukup misalkan tambahkan ke indeks dengan menggunakan:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"yang akan menerima saran ini.\n"
+"Gagal menggabungkan submodul %s, tetapi ada kemungkinan penyelesaian "
+"penggabungan: %s"
 
 #: merge-ort.c
 #, c-format
@@ -20603,14 +20859,47 @@ msgstr ""
 "KONFLIK (pengubahan/penghapusan): %s dihapus di %s dan diubah di %s. Versi "
 "%s dari %s ditinggalkan di dalam pohon."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
 #: merge-ort.c
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
 msgstr ""
-"Catatan: %s tidak terbaru dan dalam men-checkout versi berkonflik; salinan "
-"lama dinamai ulang ke %s"
+" - pergi ke submodul (%s), dan baik gabungkan komit %s\n"
+"   atau perbarui ke komit yang sudah ada yang sudah menggabungkan "
+"perubahan    tersebut\n"
+
+#: merge-ort.c
+#, c-format
+msgid ""
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
+msgstr ""
+"Saat ini penggabungan rekursif dengan submodul hanya mendukung kasus-kasus "
+"sepele.\n"
+"Mohon tangani penggabungan setiap submodul berkonflik secara manual.\n"
+"Hal ini dapat dicapai dengan langkah berikut:\n"
+"%s - kembali ke proyek induk dan jalankan:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   untuk merekam penggabungan di atas atau perbarui\n"
+" - selesaikan semua konflik lainnya di dalam proyek induk\n"
+" - komit hasil indeks di dalam proyek induk\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -20700,6 +20989,22 @@ msgstr "Gagal menggabungkan submodul %s (bukan maju-cepat)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "Sebuah resolusi penggabungan yang mungkin ditemukan untuk submodul:\n"
 
+#: merge-recursive.c
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Jika benar, cukup misalkan tambahkan ke indeks dengan menggunakan:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"yang akan menerima saran ini.\n"
+
 #: merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
@@ -21120,17 +21425,17 @@ msgstr "tidak dapat menyelesaikan pack-objects"
 #: name-hash.c
 #, c-format
 msgid "unable to create lazy_dir thread: %s"
-msgstr ""
+msgstr "tidak dapat membuat utas lazy_dir: %s"
 
 #: name-hash.c
 #, c-format
 msgid "unable to create lazy_name thread: %s"
-msgstr ""
+msgstr "tidak dapat membuat utas lazy_name: %s"
 
 #: name-hash.c
 #, c-format
 msgid "unable to join lazy_name thread: %s"
-msgstr ""
+msgstr "tidak dapat menggabungkan utas lazy_name: %s"
 
 #: notes-merge.c
 #, c-format
@@ -21139,25 +21444,29 @@ msgid ""
 "Please, use 'git notes merge --commit' or 'git notes merge --abort' to "
 "commit/abort the previous merge before you start a new notes merge."
 msgstr ""
+"Anda belum menyelesaikan penggabungan catatan Anda sebelumnya (%s ada).\n"
+"Mohon gunakan 'git notes merge --commit' atau 'git notes merge --abort' "
+"untuk mengkomit/membatalkan penggabungan sebelumnya sebelum Anda memulai "
+"penggabungan catatan baru."
 
 #: notes-merge.c
 #, c-format
 msgid "You have not concluded your notes merge (%s exists)."
-msgstr ""
+msgstr "Anda belum menyelesaikan penggabungan catatan Anda (%s ada)."
 
 #: notes-utils.c
 msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr ""
+msgstr "Tidak dapat mengkomit pohon catatan tak dinisialisasi/tak dirujuk"
 
 #: notes-utils.c
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
-msgstr ""
+msgstr "Nilai notes.rewriteMode jelek: '%s'"
 
 #: notes-utils.c
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr ""
+msgstr "Menolak menulis ulang catatan di %s (di luar refs/notes/)"
 
 #. TRANSLATORS: The first %s is the name of
 #. the environment variable, the second %s is
@@ -21166,7 +21475,7 @@ msgstr ""
 #: notes-utils.c
 #, c-format
 msgid "Bad %s value: '%s'"
-msgstr ""
+msgstr "Nilai %s jelek: '%s'"
 
 #: object-file.c
 #, c-format
@@ -21348,6 +21657,26 @@ msgstr "deflateEnd pada objek %s gagal (%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "kebingungan oleh data sumber objek tidak stabil untuk %s"
 
+#: object-file.c
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "tulis objek arus %ld != %<PRIuMAX>"
+
+#: object-file.c
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "tidak dapat mengempis arus objek baru (%d)"
+
+#: object-file.c
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "deflateEnd pada objek arus gagal (%d)"
+
+#: object-file.c
+#, c-format
+msgid "unable to create directory %s"
+msgstr "gagal membuat direktori %s"
+
 #: object-file.c
 #, c-format
 msgid "cannot read object for %s"
@@ -21616,6 +21945,72 @@ msgstr "tidak dapat menguraikan objek: %s"
 msgid "hash mismatch %s"
 msgstr "hash tidak cocok %s"
 
+#: pack-bitmap-write.c
+msgid "trying to write commit not in index"
+msgstr "mencoba menulis komit yang bukan di indeks"
+
+#: pack-bitmap.c
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "gagal menulis indeks bitmap (rusak?)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index (too small)"
+msgstr "indeks bitmap rusak (terlalu kecil)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "berkas indeks bitmap rusak (kepala salah)"
+
+#: pack-bitmap.c
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "versi '%d' tidak didukung untuk berkas indeks bitmap"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr "berkas indeks bitmap rusak (terlalu pendek untuk masuk tembolok hash)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"berkas indeks bitmap rusak (terlalu pendek untuk masuk tabel pencarian)"
+
+#: pack-bitmap.c
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "entri duplikat di indeks bitmap: '%s'"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "bitmap ewah rusak: kepala terpotong untuk entri %d"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "bitmap ewah rusak: indeks komit %u di luar jangkauan"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap pack index"
+msgstr "indeks pak bitmap rusak"
+
+#: pack-bitmap.c
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "offset XOR tidak valid di indeks pak bitmap"
+
+#: pack-bitmap.c
+msgid "cannot fstat bitmap file"
+msgstr "tidak dapat fstat berkas bitmap"
+
+#: pack-bitmap.c
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "mengabaikan berkas bitmap tambahan: '%s'"
+
+#: pack-bitmap.c
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "checksum tidak cocok di MIDX dan bitmap"
+
 #: pack-bitmap.c
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "bitmap multipak kehilangan indeks balik yang diperlukan"
@@ -21630,10 +22025,70 @@ msgstr "tidak dapat membuka '%s'"
 msgid "preferred pack (%s) is invalid"
 msgstr "pak yang disukai '%s' kadaluarsa"
 
+#: pack-bitmap.c
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "tabel pencarian bitmap rusak: posisi kembar tiga di luar indeks"
+
+#: pack-bitmap.c
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr "tabel pencarian bitmap rusak: rantai xor melebihi hitungan entri"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr "tabel pencarian bitmap rusak: indeks komit %u di luar jangkauan"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr "bitmap ewah rusak: kepala terpotong untuk bitmap komit \"%s\""
+
+#: pack-bitmap.c
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "objek '%s' tidak ditemukan di bitmap tipe"
+
+#: pack-bitmap.c
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "objek '%s' tidak punya tipe unik"
+
+#: pack-bitmap.c
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "objek '%s': bertipe sebenarnya '%s', diharapkan '%s'"
+
+#: pack-bitmap.c
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "object bukan di bitmap: '%s'"
+
+#: pack-bitmap.c
+msgid "failed to load bitmap indexes"
+msgstr "gagal memuat indeks bitmap"
+
+#: pack-bitmap.c
+msgid "you must specify exactly one commit to test"
+msgstr "Anda harus sebutkan tepat satu komit untuk diuji"
+
+#: pack-bitmap.c
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "komit '%s' tidak punya bitmap terindeks"
+
+#: pack-bitmap.c
+msgid "mismatch in bitmap results"
+msgstr "ketidaksesuaian di dalam hasil bitmap"
+
+#: pack-bitmap.c
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "tidak dapat menemukan %s di dalam pak '%s' pada offset %<PRIuMAX>"
+
 #: pack-bitmap.c
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "tidak dapat menemukan %s di dalam pak %s pada offset %<PRIuMAX>"
+msgid "unable to get disk usage of '%s'"
+msgstr "tidak dapat mendapatkan penggunaan disk dari '%s'"
 
 #: pack-mtimes.c
 #, c-format
@@ -21726,91 +22181,97 @@ msgstr "offset di luar ujung indeks pak untuk %s (indeks terpotong?)"
 #: parse-options-cb.c
 #, c-format
 msgid "malformed expiration date '%s'"
-msgstr ""
+msgstr "tanggal kadaluarsa rusak '%s'"
 
 #: parse-options-cb.c
 #, c-format
 msgid "option `%s' expects \"always\", \"auto\", or \"never\""
-msgstr ""
+msgstr "opsi `%s' mengharapkan \"always\", \"auto\", atau \"never\""
 
 #: parse-options-cb.c
 #, c-format
 msgid "malformed object name '%s'"
-msgstr ""
+msgstr "nama objek rusak '%s'"
 
 #: parse-options-cb.c
 #, c-format
 msgid "option `%s' expects \"%s\" or \"%s\""
-msgstr ""
+msgstr "opsi `%s' mengharapkan \"%s\" atau \"%s\""
 
 #: parse-options.c
 #, c-format
 msgid "%s requires a value"
-msgstr ""
+msgstr "%s butuh sebuah nilai"
 
 #: parse-options.c
 #, c-format
 msgid "%s is incompatible with %s"
-msgstr ""
+msgstr "%s tidak kompatibel dengan %s"
 
 #: parse-options.c
 #, c-format
 msgid "%s : incompatible with something else"
-msgstr ""
+msgstr "%s : tidak kompatibel dengan sesuatu yang lain"
 
 #: parse-options.c
 #, c-format
 msgid "%s takes no value"
-msgstr ""
+msgstr "%s tidak mengambil nilai apapun"
 
 #: parse-options.c
 #, c-format
 msgid "%s isn't available"
-msgstr ""
+msgstr "%s tidak ada"
 
 #: parse-options.c
 #, c-format
 msgid "%s expects a non-negative integer value with an optional k/m/g suffix"
 msgstr ""
+"%s mengharapkan nilai bilangan bulat non negatif dengan akhiran opsional k/m/"
+"g"
 
 #: parse-options.c
 #, c-format
 msgid "ambiguous option: %s (could be --%s%s or --%s%s)"
-msgstr ""
+msgstr "opsi ambigu: %s (bisa jadi --%s%s atau --%s%s)"
 
 #: parse-options.c
 #, c-format
 msgid "did you mean `--%s` (with two dashes)?"
-msgstr ""
+msgstr "mungkin maksud Anda `--%s` (dengan dua tanda strip)?"
 
 #: parse-options.c
 #, c-format
 msgid "alias of --%s"
-msgstr ""
+msgstr "alias untuk --%s"
+
+#: parse-options.c
+msgid "need a subcommand"
+msgstr "butuh sebuah subperintah"
 
 #: parse-options.c
 #, c-format
 msgid "unknown option `%s'"
-msgstr ""
+msgstr "opsi tidak dikenal `%s'"
 
 #: parse-options.c
 #, c-format
 msgid "unknown switch `%c'"
-msgstr ""
+msgstr "sakelar tidak dikenal `%c'"
 
 #: parse-options.c
 #, c-format
 msgid "unknown non-ascii option in string: `%s'"
-msgstr ""
+msgstr "opsi non-ascii di dalam untai tidak dikenal: `%s'"
 
 #: parse-options.c
 msgid "..."
-msgstr ""
+msgstr "..."
 
 #: parse-options.c
 #, c-format
 msgid "usage: %s"
-msgstr ""
+msgstr "penggunaan: %s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation.
@@ -21818,7 +22279,7 @@ msgstr ""
 #: parse-options.c
 #, c-format
 msgid "   or: %s"
-msgstr ""
+msgstr "      atau: %s"
 
 #. TRANSLATORS: You should only need to translate this format
 #. string if your language is a RTL language (e.g. Arabic,
@@ -21842,237 +22303,243 @@ msgstr ""
 #: parse-options.c
 #, c-format
 msgid "%*s%s"
-msgstr ""
+msgstr "%*s%s"
 
 #: parse-options.c
 #, c-format
 msgid "    %s"
-msgstr ""
+msgstr "    %s"
 
 #: parse-options.c
 msgid "-NUM"
-msgstr ""
+msgstr "-NUM"
 
 #: parse-options.h
 msgid "expiry-date"
-msgstr ""
+msgstr "tanggal kadaluarsa"
 
 #: parse-options.h
 msgid "no-op (backward compatibility)"
-msgstr ""
+msgstr "tanpa operasi (kompatibilitas ke belakang)"
 
 #: parse-options.h
 msgid "be more verbose"
-msgstr ""
+msgstr "jadi lebih berkata-kata"
 
 #: parse-options.h
 msgid "be more quiet"
-msgstr ""
+msgstr "jadi lebih dian"
 
 #: parse-options.h
 msgid "use <n> digits to display object names"
-msgstr ""
+msgstr "gunakan <n> digit untuk menampilkan nama objek"
 
 #: parse-options.h
 msgid "how to strip spaces and #comments from message"
-msgstr ""
+msgstr "bagaimana cara mengupas spasi dan #komentar dari pesan"
 
 #: parse-options.h
 msgid "read pathspec from file"
-msgstr ""
+msgstr "baca spek jalur dari berkas"
 
 #: parse-options.h
 msgid ""
 "with --pathspec-from-file, pathspec elements are separated with NUL character"
 msgstr ""
+"dengan --pathspec-from-file, elemen spek jalur dipisahkan dengan karakter NUL"
 
 #: path.c
 #, c-format
 msgid "Could not make %s writable by group"
-msgstr ""
+msgstr "Tidak dapat membuat %s bisa ditulis oleh grup"
 
 #: pathspec.c
 msgid "Escape character '\\' not allowed as last character in attr value"
 msgstr ""
+"Karakter pelarian '\\' tidak diperbolehkan sebagai karakter terakhir dalam "
+"nilai atribut"
 
 #: pathspec.c
 msgid "Only one 'attr:' specification is allowed."
-msgstr ""
+msgstr "Hanya satu spesifikasi 'attr:' yang diperbolehkan."
 
 #: pathspec.c
 msgid "attr spec must not be empty"
-msgstr ""
+msgstr "spek atribut tidak boleh kosong"
 
 #: pathspec.c
 #, c-format
 msgid "invalid attribute name %s"
-msgstr ""
+msgstr "nama atribut tidak valid %s"
 
 #: pathspec.c
 msgid "global 'glob' and 'noglob' pathspec settings are incompatible"
-msgstr ""
+msgstr "setelan spek jalur global 'glob' dan 'noglob' tidak kompatibel"
 
 #: pathspec.c
 msgid ""
 "global 'literal' pathspec setting is incompatible with all other global "
 "pathspec settings"
 msgstr ""
+"setelan spek jalur global 'literal' tidak kompatibel dengan semua setelan "
+"spek jalur lainnya"
 
 #: pathspec.c
 msgid "invalid parameter for pathspec magic 'prefix'"
-msgstr ""
+msgstr "parameter tidak valid untuk spek jalur ajaib 'prefix'"
 
 #: pathspec.c
 #, c-format
 msgid "Invalid pathspec magic '%.*s' in '%s'"
-msgstr ""
+msgstr "Spek jalur ajaib '%.*s' tidak valid di '%s'"
 
 #: pathspec.c
 #, c-format
 msgid "Missing ')' at the end of pathspec magic in '%s'"
-msgstr ""
+msgstr "Kehilangan ')' pada akhir spek jalur ajaib di '%s'"
 
 #: pathspec.c
 #, c-format
 msgid "Unimplemented pathspec magic '%c' in '%s'"
-msgstr ""
+msgstr "Spek jalur ajaib '%c' tidak diterapkan di '%s'"
 
 #: pathspec.c
 #, c-format
 msgid "%s: 'literal' and 'glob' are incompatible"
-msgstr ""
+msgstr "%s: 'literal' dan 'glob' tidak kompatibel"
 
 #: pathspec.c
 #, c-format
 msgid "%s: '%s' is outside repository at '%s'"
-msgstr ""
+msgstr "%s: '%s' di luar repositori pada '%s'"
 
 #: pathspec.c
 #, c-format
 msgid "'%s' (mnemonic: '%c')"
-msgstr ""
+msgstr "'%s' (mnemonik: '%c')"
 
 #: pathspec.c
 #, c-format
 msgid "%s: pathspec magic not supported by this command: %s"
-msgstr ""
+msgstr "%s: spek jalur ajaib tidak didukung oleh perintah ini: %s"
 
 #: pathspec.c
 #, c-format
 msgid "pathspec '%s' is beyond a symbolic link"
-msgstr ""
+msgstr "spek jalur '%s' di luar tautan simbolik"
 
 #: pathspec.c
 #, c-format
 msgid "line is badly quoted: %s"
-msgstr ""
+msgstr "baris dikutip jelek: %s"
 
 #: pkt-line.c
 msgid "unable to write flush packet"
-msgstr ""
+msgstr "tidak dapat menulis paket bilas"
 
 #: pkt-line.c
 msgid "unable to write delim packet"
-msgstr ""
+msgstr "tidak dapat menulis paket pembatas"
 
 #: pkt-line.c
 msgid "unable to write response end packet"
-msgstr ""
+msgstr "tidak dapat menulis paket ujung jawaban"
 
 #: pkt-line.c
 msgid "flush packet write failed"
-msgstr ""
+msgstr "gagal membilas penulisan paket"
 
 #: pkt-line.c
 msgid "protocol error: impossibly long line"
-msgstr ""
+msgstr "kesalahan protokol: baris panjang tidak mungkin"
 
 #: pkt-line.c
 msgid "packet write with format failed"
-msgstr ""
+msgstr "gagal menulis paket dengan format"
 
 #: pkt-line.c
 msgid "packet write failed - data exceeds max packet size"
-msgstr ""
+msgstr "gagal menulis paket - data melebihi ukuran paket maksimum"
 
 #: pkt-line.c
 #, c-format
 msgid "packet write failed: %s"
-msgstr ""
+msgstr "gagal menulis paket: %s"
 
 #: pkt-line.c
 msgid "read error"
-msgstr ""
+msgstr "kesalahan membaca"
 
 #: pkt-line.c
 msgid "the remote end hung up unexpectedly"
-msgstr ""
+msgstr "ujung remote menggantung secara tidak terduga"
 
 #: pkt-line.c
 #, c-format
 msgid "protocol error: bad line length character: %.4s"
-msgstr ""
+msgstr "kesalahan protokol: karakter panjang baris jelek: %.4s"
 
 #: pkt-line.c
 #, c-format
 msgid "protocol error: bad line length %d"
-msgstr ""
+msgstr "kesalahan protokol: panjang baris %d jelek"
 
 #: pkt-line.c sideband.c
 #, c-format
 msgid "remote error: %s"
-msgstr ""
+msgstr "kesalahan remote: %s"
 
 #: preload-index.c
 msgid "Refreshing index"
-msgstr ""
+msgstr "Menyegarkan indeks"
 
 #: preload-index.c
 #, c-format
 msgid "unable to create threaded lstat: %s"
-msgstr ""
+msgstr "tidak dapat membuat lstat terutas: %s"
 
 #: pretty.c
 msgid "unable to parse --pretty format"
-msgstr ""
+msgstr "tidak dapat menguraikan format --pretty"
 
 #: promisor-remote.c
 msgid "promisor-remote: unable to fork off fetch subprocess"
-msgstr ""
+msgstr "promisor-remote: tidak dapat menggarpu subproses pengambilan"
 
 #: promisor-remote.c
 msgid "promisor-remote: could not write to fetch subprocess"
-msgstr ""
+msgstr "promisor-remote: tidak dapat menulis ke subproses pengambilan"
 
 #: promisor-remote.c
 msgid "promisor-remote: could not close stdin to fetch subprocess"
 msgstr ""
+"promisor-remote: tidak dapat menutup masukan standar ke subproses pengambilan"
 
 #: promisor-remote.c
 #, c-format
 msgid "promisor remote name cannot begin with '/': %s"
-msgstr ""
+msgstr "nama remote penjanji tidak dapat diawali dengan '/': %s"
 
 #: protocol-caps.c
 msgid "object-info: expected flush after arguments"
-msgstr ""
+msgstr "object-info: bilasan diharapkan setelah argumen"
 
 #: prune-packed.c
 msgid "Removing duplicate objects"
-msgstr ""
+msgstr "Menghapus objek duplikat"
 
 #: range-diff.c
 msgid "could not start `log`"
-msgstr ""
+msgstr "tidak dapat memulai `log`"
 
 #: range-diff.c
 msgid "could not read `log` output"
-msgstr ""
+msgstr "tidak dapat membaca keluaran `log`"
 
 #: range-diff.c sequencer.c
 #, c-format
 msgid "could not parse commit '%s'"
-msgstr ""
+msgstr "tidak dapat menguraikan komit '%s'"
 
 #: range-diff.c
 #, c-format
@@ -22080,58 +22547,63 @@ msgid ""
 "could not parse first line of `log` output: did not start with 'commit ': "
 "'%s'"
 msgstr ""
+"tidak dapat menguraikan baris pertama dari keluaran `log`: tidak dimulai "
+"dengan 'commit ': '%s'"
 
 #: range-diff.c
 #, c-format
 msgid "could not parse git header '%.*s'"
-msgstr ""
+msgstr "tidak dapat menguraikan kepala git '%.*s'"
 
 #: range-diff.c
 msgid "failed to generate diff"
-msgstr ""
+msgstr "gagal membuat diff"
 
 #: range-diff.c
 #, c-format
 msgid "could not parse log for '%s'"
-msgstr ""
+msgstr "tidak dapat menguraikan log untuk '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr ""
+"tidak akan menambahkan alias berkas '%s' ('%s' sudah ada di dalam indeks)"
 
 #: read-cache.c
 msgid "cannot create an empty blob in the object database"
-msgstr ""
+msgstr "tidak dapat membuat sebuah blob kosong di dalam basis data objek"
 
 #: read-cache.c
 #, c-format
 msgid "%s: can only add regular files, symbolic links or git-directories"
 msgstr ""
+"%s: hanya dapat menambahkan berkas reguler, tautan simbolik, atau direktori "
+"git"
 
 #: read-cache.c
 #, c-format
 msgid "unable to index file '%s'"
-msgstr ""
+msgstr "tidak dapat menulis berkas indeks '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "unable to add '%s' to index"
-msgstr ""
+msgstr "tidak dapat menambahkan '%s' ke indeks"
 
 #: read-cache.c
 #, c-format
 msgid "unable to stat '%s'"
-msgstr ""
+msgstr "tidak dapat men-stat '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "'%s' appears as both a file and as a directory"
-msgstr ""
+msgstr "'%s' muncul baik sebagai sebuah berkas dan sebagai sebuah direktori"
 
 #: read-cache.c
 msgid "Refresh index"
-msgstr ""
+msgstr "Segarkan indeks indeks"
 
 #: read-cache.c
 #, c-format
@@ -22139,6 +22611,8 @@ msgid ""
 "index.version set, but the value is invalid.\n"
 "Using version %i"
 msgstr ""
+"index.version disetel, tetapi nilainya tidak valid.\n"
+"Menggunakan versi %i"
 
 #: read-cache.c
 #, c-format
@@ -22146,137 +22620,139 @@ msgid ""
 "GIT_INDEX_VERSION set, but the value is invalid.\n"
 "Using version %i"
 msgstr ""
+"GIT_INDEX_VERSION disetel, tetapi nilainya tidak valid.\n"
+"Menggunakan versi %i"
 
 #: read-cache.c
 #, c-format
 msgid "bad signature 0x%08x"
-msgstr ""
+msgstr "tandatangan 0x%08x jelek"
 
 #: read-cache.c
 #, c-format
 msgid "bad index version %d"
-msgstr ""
+msgstr "versi indeks %d jelek"
 
 #: read-cache.c
 msgid "bad index file sha1 signature"
-msgstr ""
+msgstr "tandatangan sha1 berkas indeks jelek"
 
 #: read-cache.c
 #, c-format
 msgid "index uses %.4s extension, which we do not understand"
-msgstr ""
+msgstr "indeks menggunakan ekstensi %s, yang kami tidak mengerti"
 
 #: read-cache.c
 #, c-format
 msgid "ignoring %.4s extension"
-msgstr ""
+msgstr "mengabaikan ekstensi %.4s"
 
 #: read-cache.c
 #, c-format
 msgid "unknown index entry format 0x%08x"
-msgstr ""
+msgstr "format entri indeks 0x%08x tidak dikenal"
 
 #: read-cache.c
 #, c-format
 msgid "malformed name field in the index, near path '%s'"
-msgstr ""
+msgstr "bidang nama di dalam indeks rusak, di dekat jalur '%s'"
 
 #: read-cache.c
 msgid "unordered stage entries in index"
-msgstr ""
+msgstr "entri gelaran tidak terurut di dalam indeks"
 
 #: read-cache.c
 #, c-format
 msgid "multiple stage entries for merged file '%s'"
-msgstr ""
+msgstr "banyak entri gelaran untuk berkas tergabung '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "unordered stage entries for '%s'"
-msgstr ""
+msgstr "entri gelaran tidak terurut untuk '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "unable to create load_cache_entries thread: %s"
-msgstr ""
+msgstr "tidak dapat membuat utas load_cache_entries: %s"
 
 #: read-cache.c
 #, c-format
 msgid "unable to join load_cache_entries thread: %s"
-msgstr ""
+msgstr "tidak dapat menggabungkan utas load_cache_entries: %s"
 
 #: read-cache.c
 #, c-format
 msgid "%s: index file open failed"
-msgstr ""
+msgstr "%s: gagal membuka berkas indeks"
 
 #: read-cache.c
 #, c-format
 msgid "%s: cannot stat the open index"
-msgstr ""
+msgstr "%s: tidak dapat men-stat indeks terbuka"
 
 #: read-cache.c
 #, c-format
 msgid "%s: index file smaller than expected"
-msgstr ""
+msgstr "%s: berkas indeks lebih kecil dari yang diharapkan"
 
 #: read-cache.c
 #, c-format
 msgid "%s: unable to map index file%s"
-msgstr ""
+msgstr "%s: tidak dapat memetakan berkas indeks%s"
 
 #: read-cache.c
 #, c-format
 msgid "unable to create load_index_extensions thread: %s"
-msgstr ""
+msgstr "tidak dapat membuat utas load_index_extensions: %s"
 
 #: read-cache.c
 #, c-format
 msgid "unable to join load_index_extensions thread: %s"
-msgstr ""
+msgstr "tidak dapat menggabungkan utas load_index_extensions: %s"
 
 #: read-cache.c
 #, c-format
 msgid "could not freshen shared index '%s'"
-msgstr ""
+msgstr "tidak dapat menyegarkan indeks berbagi '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "broken index, expect %s in %s, got %s"
-msgstr ""
+msgstr "indeks rusak, mengharapkan %s di %s, dapat %s"
 
 #: read-cache.c
 msgid "cannot write split index for a sparse index"
-msgstr ""
+msgstr "tidak dapat membuat indeks terpisah untuk indeks jarang"
 
 #: read-cache.c
 msgid "failed to convert to a sparse-index"
-msgstr ""
+msgstr "gagal mengubah ke indeks jarang"
 
 #: read-cache.c
 #, c-format
 msgid "could not stat '%s'"
-msgstr ""
+msgstr "tidak dapat men-stat '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "unable to open git dir: %s"
-msgstr ""
+msgstr "tidak dapat membuka direktori git: %s"
 
 #: read-cache.c
 #, c-format
 msgid "unable to unlink: %s"
-msgstr ""
+msgstr "tidak dapat membatal tautan: %s"
 
 #: read-cache.c
 #, c-format
 msgid "cannot fix permission bits on '%s'"
-msgstr ""
+msgstr "tidak dapat memperbaiki bit perizinan pada '%s'"
 
 #: read-cache.c
 #, c-format
 msgid "%s: cannot drop to stage #0"
-msgstr ""
+msgstr "%s: tidak dapat menurunkan ke tahap #0"
 
 #: rebase-interactive.c
 msgid ""
@@ -22313,9 +22789,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -22326,20 +22805,23 @@ msgstr ""
 "e, edit <komit> = gunakan komit, tapi berhenti untuk amandemen\n"
 "s, squash <komit> = gunakan komit, tapi lebur ke komit sebelumnya\n"
 "f, fixup [-C | -c] <komit> = seperti \"squash\" tapi hanya pertahankan\n"
-"                   pesan komit sebelumnya, kecuali -C digunakan, dimana\n"
-"                   hanya pertahankan pesan komit ini; -c sama dengan -C "
-"tapi\n"
-"                   buka penyuntingx, exec <perintah> = jalankan perintah "
-"(sisa baris) menggunakan cangkang\n"
+"                   pesan komit sebelumnya; kecuali -C digunakan, dimana\n"
+"                   hanya pertahankan pesan komit ini; -c sama dengan -C\n"
+"                   tapi buka penyunting\n"
+"x, exec <perintah> = jalankan perintah (sisa baris) menggunakan cangkang\n"
 "b, break = berhenti disini (lanjutkan pendasaran ulang nanti dengan 'git "
 "rebase --continue')\n"
 "d, drop <komit> = hapus komit\n"
 "l, label <label> = tandai HEAD saat ini dengan nama\n"
 "t, reset <label> = setel ulang HEAD ke sebuah label\n"
 "m, merge [-C <komit> | -c <komit>] <label> [# <satu baris>]\n"
-".       buat komit penggabungan dengan pesan komit penggabungan asli\n"
-".       (atau satu baris, jika tidak ada komit penggabungan asli yang\n"
-".       disebutkan); gunakan -c <komit> untuk menulis ulang pesan komit\n"
+"       buat komit penggabungan dengan pesan komit penggabungan asli\n"
+"       (atau satu baris, jika tidak ada komit penggabungan asli yang\n"
+"       disebutkan); gunakan -c <komit> untuk menulis ulang pesan komit\n"
+"u, update-ref <referensi> = lacak tempat penampung untuk <referensi> yang\n"
+"                            akan diperbarui ke posisi ini di dalam komit\n"
+"                            baru. <referensi> diperbarui pada "
+"akhir                             pendasaran ulang.\n"
 "\n"
 "Baris diatas dapat disusun ulang; hal itu dieksekusi dari atas ke bawah.\n"
 
@@ -22431,245 +22913,246 @@ msgstr "%s: 'preserve' digantikan oleh 'merges'"
 
 #: ref-filter.c wt-status.c
 msgid "gone"
-msgstr ""
+msgstr "pergi"
 
 #: ref-filter.c
 #, c-format
 msgid "ahead %d"
-msgstr ""
+msgstr "di depan %d"
 
 #: ref-filter.c
 #, c-format
 msgid "behind %d"
-msgstr ""
+msgstr "di belakang %d"
 
 #: ref-filter.c
 #, c-format
 msgid "ahead %d, behind %d"
-msgstr ""
+msgstr "di depan %d, di belakang %d"
 
 #: ref-filter.c
 #, c-format
 msgid "expected format: %%(color:<color>)"
-msgstr ""
+msgstr "format yang diharapkan: %%(color:<warna>)"
 
 #: ref-filter.c
 #, c-format
 msgid "unrecognized color: %%(color:%s)"
-msgstr ""
+msgstr "warna tidak dikenal: %%(color:%s)"
 
 #: ref-filter.c
 #, c-format
 msgid "Integer value expected refname:lstrip=%s"
-msgstr ""
+msgstr "Nilai bilangan bulat diharapkan refname:lstrip=%s"
 
 #: ref-filter.c
 #, c-format
 msgid "Integer value expected refname:rstrip=%s"
-msgstr ""
+msgstr "Nilai bilangan bulat diharapkan refname:rstrip=%s"
 
 #: ref-filter.c
 #, c-format
 msgid "unrecognized %%(%s) argument: %s"
-msgstr ""
+msgstr "argumen %%(%s) tidak dikenal: %s"
 
 #: ref-filter.c
 #, c-format
 msgid "%%(objecttype) does not take arguments"
-msgstr ""
+msgstr "%%(objecttype) tidak mengambil argumen"
 
 #: ref-filter.c
 #, c-format
 msgid "%%(deltabase) does not take arguments"
-msgstr ""
+msgstr "%%(deltabase) tidak mengambil argumen"
 
 #: ref-filter.c
 #, c-format
 msgid "%%(body) does not take arguments"
-msgstr ""
+msgstr "%%(body) tidak mengambil argumen"
 
 #: ref-filter.c
 #, c-format
 msgid "expected %%(trailers:key=<value>)"
-msgstr ""
+msgstr "diharapkan %%(trailers:key=<nilai>)"
 
 #: ref-filter.c
 #, c-format
 msgid "unknown %%(trailers) argument: %s"
-msgstr ""
+msgstr "argumen %%(trailers) tidak dikenal: %s"
 
 #: ref-filter.c
 #, c-format
 msgid "positive value expected contents:lines=%s"
-msgstr ""
+msgstr "nilai positif diharapkan contents:lines=%s"
 
 #: ref-filter.c
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
-msgstr ""
+msgstr "nilai positif '%s' diharapkan di %%(%s)"
 
 #: ref-filter.c
 #, c-format
 msgid "unrecognized email option: %s"
-msgstr ""
+msgstr "opsi surel tidak dikenal: %s"
 
 #: ref-filter.c
 #, c-format
 msgid "expected format: %%(align:<width>,<position>)"
-msgstr ""
+msgstr "format diharapkan: %%(align:<lebar>,<posisi>)"
 
 #: ref-filter.c
 #, c-format
 msgid "unrecognized position:%s"
-msgstr ""
+msgstr "posisi tidak dikenal: %s"
 
 #: ref-filter.c
 #, c-format
 msgid "unrecognized width:%s"
-msgstr ""
+msgstr "lebar tidak dikenal: %s"
 
 #: ref-filter.c
 #, c-format
 msgid "positive width expected with the %%(align) atom"
-msgstr ""
+msgstr "lebar positif diharapkan dengan atom %%(align)"
 
 #: ref-filter.c
 #, c-format
 msgid "%%(rest) does not take arguments"
-msgstr ""
+msgstr "%%(rest) tidak mengambil argumen"
 
 #: ref-filter.c
 #, c-format
 msgid "malformed field name: %.*s"
-msgstr ""
+msgstr "nama bidang rusak: %.*s"
 
 #: ref-filter.c
 #, c-format
 msgid "unknown field name: %.*s"
-msgstr ""
+msgstr "nama bidang tidak dikenal: %.*s"
 
 #: ref-filter.c
 #, c-format
 msgid ""
 "not a git repository, but the field '%.*s' requires access to object data"
 msgstr ""
+"bukan sebuah repositori git, tapi bidang '%.*s' butuh akses ke data objek"
 
 #: ref-filter.c
 #, c-format
 msgid "format: %%(%s) atom used without a %%(%s) atom"
-msgstr ""
+msgstr "format: atom %%(%s) digunakan tanpa sebuah atom %%(%s)"
 
 #: ref-filter.c
 #, c-format
 msgid "format: %%(then) atom used more than once"
-msgstr ""
+msgstr "format: atom%%(then) digunakan lebih dari sekali"
 
 #: ref-filter.c
 #, c-format
 msgid "format: %%(then) atom used after %%(else)"
-msgstr ""
+msgstr "format: atom %%(then) digunakan setelah %%(else)"
 
 #: ref-filter.c
 #, c-format
 msgid "format: %%(else) atom used more than once"
-msgstr ""
+msgstr "format: atom %%(else) digunakan lebih dari sekali"
 
 #: ref-filter.c
 #, c-format
 msgid "format: %%(end) atom used without corresponding atom"
-msgstr ""
+msgstr "format: atom %%(end) digunakan tanpa atom yang bersesuaian"
 
 #: ref-filter.c
 #, c-format
 msgid "malformed format string %s"
-msgstr ""
+msgstr "untai format %s rusak"
 
 #: ref-filter.c
 #, c-format
 msgid "this command reject atom %%(%.*s)"
-msgstr ""
+msgstr "perintah ini menolak atom %%(%.*s)"
 
 #: ref-filter.c
 #, c-format
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
-msgstr ""
+msgstr "--format=%.*s tidak dapat digunakan dengan --python, --shell, --tcl"
 
 #: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing %s)"
-msgstr ""
+msgstr "(tanpa cabang, mendasarkan ulang %s)"
 
 #: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing detached HEAD %s)"
-msgstr ""
+msgstr "(tanpa cabang, mendasarkan ulang HEAD tercopot %s)"
 
 #: ref-filter.c
 #, c-format
 msgid "(no branch, bisect started on %s)"
-msgstr ""
+msgstr "(tanpa cabang, pembagian dua dimulai pada %s)"
 
 #: ref-filter.c
 #, c-format
 msgid "(HEAD detached at %s)"
-msgstr ""
+msgstr "(HEAD tercopot pada %s)"
 
 #: ref-filter.c
 #, c-format
 msgid "(HEAD detached from %s)"
-msgstr ""
+msgstr "(HEAD tercopot dari %s)"
 
 #: ref-filter.c
 msgid "(no branch)"
-msgstr ""
+msgstr "(tanpa cabang)"
 
 #: ref-filter.c
 #, c-format
 msgid "missing object %s for %s"
-msgstr ""
+msgstr "objek %s hilang untuk %s"
 
 #: ref-filter.c
 #, c-format
 msgid "parse_object_buffer failed on %s for %s"
-msgstr ""
+msgstr "parse_object_buffer gagal pada %s untuk %s"
 
 #: ref-filter.c
 #, c-format
 msgid "malformed object at '%s'"
-msgstr ""
+msgstr "objek rusak pada '%s'"
 
 #: ref-filter.c
 #, c-format
 msgid "ignoring ref with broken name %s"
-msgstr ""
+msgstr "mengabaikan referensi dengan nama rusak %s"
 
 #: ref-filter.c refs.c
 #, c-format
 msgid "ignoring broken ref %s"
-msgstr ""
+msgstr "mengabaikan referensi rusak %s"
 
 #: ref-filter.c
 #, c-format
 msgid "format: %%(end) atom missing"
-msgstr ""
+msgstr "format: atom %%(end) hilang"
 
 #: ref-filter.c
 #, c-format
 msgid "malformed object name %s"
-msgstr ""
+msgstr "nama objek rusak %s"
 
 #: ref-filter.c
 #, c-format
 msgid "option `%s' must point to a commit"
-msgstr ""
+msgstr "opsi `%s' harus menunjuk pada sebuah komit"
 
 #: ref-filter.h
 msgid "key"
-msgstr ""
+msgstr "kunci"
 
 #: ref-filter.h
 msgid "field name to sort on"
-msgstr ""
+msgstr "nama bidang untuk diurutkan"
 
 #: reflog.c
 #, c-format
@@ -22799,139 +23282,150 @@ msgstr "spek referensi tidak valid '%s'"
 #: remote-curl.c
 #, c-format
 msgid "invalid quoting in push-option value: '%s'"
-msgstr ""
+msgstr "kuotasi tidak valid dalam nilai push-option: '%s'"
 
 #: remote-curl.c
 #, c-format
 msgid "%sinfo/refs not valid: is this a git repository?"
-msgstr ""
+msgstr "%sinfo/refs tidak valid: apakah ini sebuah repositori git?"
 
 #: remote-curl.c
 msgid "invalid server response; expected service, got flush packet"
 msgstr ""
+"tanggapan peladen tidak valid; mengharapkan layanan, dapat bilasan paket"
 
 #: remote-curl.c
 #, c-format
 msgid "invalid server response; got '%s'"
-msgstr ""
+msgstr "tanggapan peladen tidak valid; dapat '%s'"
 
 #: remote-curl.c
 #, c-format
 msgid "repository '%s' not found"
-msgstr ""
+msgstr "repositori '%s' tidak ditemukan"
 
 #: remote-curl.c
 #, c-format
 msgid "Authentication failed for '%s'"
-msgstr ""
+msgstr "Autentikasi gagal untuk '%s'"
 
 #: remote-curl.c
 #, c-format
 msgid "unable to access '%s' with http.pinnedPubkey configuration: %s"
-msgstr ""
+msgstr "tidak dapat mengakses '%s' dengan konfigurasi http.pinnedPubkey: %s"
 
 #: remote-curl.c
 #, c-format
 msgid "unable to access '%s': %s"
-msgstr ""
+msgstr "tidak dapat mengakses '%s': %s"
 
 #: remote-curl.c
 #, c-format
 msgid "redirecting to %s"
-msgstr ""
+msgstr "mengalihkan ke %s"
 
 #: remote-curl.c
 msgid "shouldn't have EOF when not gentle on EOF"
-msgstr ""
+msgstr "seharusnya tidak punya EOF ketika tidak lembut pada EOF"
 
 #: remote-curl.c
 msgid "remote server sent unexpected response end packet"
-msgstr ""
+msgstr "peladen remote mengirim paket ujung tanggapan yang tak diharapkan"
 
 #: remote-curl.c
 msgid "unable to rewind rpc post data - try increasing http.postBuffer"
 msgstr ""
+"tidak dapat memutar ulang data post rpc - coba menaikkan http.postBuffer"
 
 #: remote-curl.c
 #, c-format
 msgid "remote-curl: bad line length character: %.4s"
-msgstr ""
+msgstr "remote-curl: karakter panjang baris jelek : %.4s"
 
 #: remote-curl.c
 msgid "remote-curl: unexpected response end packet"
-msgstr ""
+msgstr "remote-curl: paket ujung tanggapan tidak diharapkan"
 
 #: remote-curl.c
 #, c-format
 msgid "RPC failed; %s"
-msgstr ""
+msgstr "RPC gagal; %s"
 
 #: remote-curl.c
 msgid "cannot handle pushes this big"
-msgstr ""
+msgstr "tidak dapat menangani dorongan sebesar ini"
 
 #: remote-curl.c
 #, c-format
 msgid "cannot deflate request; zlib deflate error %d"
-msgstr ""
+msgstr "tidak dapat mengempiskan permintaan; kesalahan mengempiskan zlib %d"
 
 #: remote-curl.c
 #, c-format
 msgid "cannot deflate request; zlib end error %d"
-msgstr ""
+msgstr "tidak dapat mengempiskan permintaan; kesalahan ujung zlib %d"
 
 #: remote-curl.c
 #, c-format
 msgid "%d bytes of length header were received"
-msgstr ""
+msgstr "%d bita dari kepala panjang diterima"
 
 #: remote-curl.c
 #, c-format
 msgid "%d bytes of body are still expected"
-msgstr ""
+msgstr "%d bita badan masih diharapkan"
 
 #: remote-curl.c
 msgid "dumb http transport does not support shallow capabilities"
-msgstr ""
+msgstr "transportasi http bodoh tidak mendukung kemampuan dangkal"
 
 #: remote-curl.c
 msgid "fetch failed."
-msgstr ""
+msgstr "pengambilan gagal."
 
 #: remote-curl.c
 msgid "cannot fetch by sha1 over smart http"
-msgstr ""
+msgstr "tidak dapat mengambil oleh sha1 melalui http pintar"
 
 #: remote-curl.c
 #, c-format
 msgid "protocol error: expected sha/ref, got '%s'"
-msgstr ""
+msgstr "kesalahan protokol: sha/referensi diharapkan, dapat '%s'"
 
 #: remote-curl.c
 #, c-format
 msgid "http transport does not support %s"
-msgstr ""
+msgstr "transportasi http tidak mendukung %s"
+
+#: remote-curl.c
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "kesalahan protokol: '<url> <jalur>' diharapkan, spasi hilang"
+
+#: remote-curl.c
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "gagal mengunduh berkas pada URL '%s'"
 
 #: remote-curl.c
 msgid "git-http-push failed"
-msgstr ""
+msgstr "git-http-push gagal"
 
 #: remote-curl.c
 msgid "remote-curl: usage: git remote-curl <remote> [<url>]"
-msgstr ""
+msgstr "remote-curl: penggunaan: git remote-curl <remote> [<url>]"
 
 #: remote-curl.c
 msgid "remote-curl: error reading command stream from git"
-msgstr ""
+msgstr "remote-curl: kesalahan membaca arus perintah dari git"
 
 #: remote-curl.c
 msgid "remote-curl: fetch attempted without a local repo"
-msgstr ""
+msgstr "remote-curl: pengambilan dicoba tanpa repositori lokal"
 
 #: remote-curl.c
 #, c-format
 msgid "remote-curl: unknown command '%s' from git"
-msgstr ""
+msgstr "remote-curl: perintah tidak dikenal '%s' dari git"
 
 #: remote.c
 #, c-format
@@ -23176,7 +23670,9 @@ msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
 msgid_plural ""
 "Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
 msgstr[0] ""
+"Cabang Anda di belakang '%s' oleh %d komit, dan bisa di maju-cepatkan.\n"
 msgstr[1] ""
+"Cabang Anda di belakan '%s' oleh %d komit, dan bisa di maju-cepatkan.\n"
 
 #: remote.c
 msgid "  (use \"git pull\" to update your local branch)\n"
@@ -23214,17 +23710,17 @@ msgstr "tidak dapat mencopot satu komponen dari url '%s'"
 #: replace-object.c
 #, c-format
 msgid "bad replace ref name: %s"
-msgstr ""
+msgstr "nama referensi pengganti jelek: %s"
 
 #: replace-object.c
 #, c-format
 msgid "duplicate replace ref: %s"
-msgstr ""
+msgstr "referensi pengganti duplikat: %s"
 
 #: replace-object.c
 #, c-format
 msgid "replace depth too high for object %s"
-msgstr ""
+msgstr "kedalaman penggantian terlalu tinggi untuk objek %s"
 
 #: rerere.c
 msgid "corrupt MERGE_RR"
@@ -23269,83 +23765,310 @@ msgstr "Resolusi direkam untuk '%s'."
 msgid "Resolved '%s' using previous resolution."
 msgstr "'%s' diselesaikan menggunakan resolusi sebelumnya."
 
-#: rerere.c
-#, c-format
-msgid "cannot unlink stray '%s'"
-msgstr "tidak dapat batal taut simpangan '%s'"
+#: rerere.c
+#, c-format
+msgid "cannot unlink stray '%s'"
+msgstr "tidak dapat batal taut simpangan '%s'"
+
+#: rerere.c
+#, c-format
+msgid "Recorded preimage for '%s'"
+msgstr "Pracitra direkam untuk '%s'"
+
+#: rerere.c
+#, c-format
+msgid "failed to update conflicted state in '%s'"
+msgstr "gagal memperbarui keadaan konflik di '%s'"
+
+#: rerere.c
+#, c-format
+msgid "no remembered resolution for '%s'"
+msgstr "tidak ada resolusi yang diingat untuk '%s'"
+
+#: rerere.c
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr "tidak dapat batal taut '%s'"
+
+#: rerere.c
+#, c-format
+msgid "Updated preimage for '%s'"
+msgstr "Pracitra diperbarui untuk '%s'"
+
+#: rerere.c
+#, c-format
+msgid "Forgot resolution for '%s'\n"
+msgstr "Resolusi dilupakan untuk '%s'\n"
+
+#: rerere.c
+msgid "unable to open rr-cache directory"
+msgstr "tidak dapat membuka direktori rr-cache"
+
+#: rerere.h
+msgid "update the index with reused conflict resolution if possible"
+msgstr ""
+"perbarui indeks dengan resolusi konflik yang digunakan kembali bila "
+"memungkinkan"
+
+#: reset.c
+msgid "could not determine HEAD revision"
+msgstr "tidak dapat menentukan revisi HEAD"
+
+#: reset.c sequencer.c
+#, c-format
+msgid "failed to find tree of %s"
+msgstr "gagal menemukan pohon %s"
+
+#: revision.c
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo merekam `%s` yang dimana hilang"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "tidak dapat mendapatkan komit untuk argumen jalur leluhur '%s'"
+
+#: revision.c
+msgid "--unpacked=<packfile> no longer supported"
+msgstr "--unpacked=<berkas pak> tidak didukung lagi"
+
+#: revision.c
+msgid "your current branch appears to be broken"
+msgstr "sepertinya cabang Anda saat ini rusak"
+
+#: revision.c
+#, c-format
+msgid "your current branch '%s' does not have any commits yet"
+msgstr "cabang Anda saat ini '%s' belum memiliki komit apapun"
+
+#: revision.c
+msgid "object filtering requires --objects"
+msgstr "penyaringan objek memerlukan --objects"
+
+#: revision.c
+msgid "-L does not yet support diff formats besides -p and -s"
+msgstr "-L belum mendukung format diff selain -p dan -s"
+
+#: run-command.c
+#, c-format
+msgid "cannot create async thread: %s"
+msgstr "tidak dapat membuat utas async: %s"
+
+#: scalar.c worktree.c
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' tidak ada"
+
+#: scalar.c
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "tidak dapat berganti ke '%s'"
+
+#: scalar.c
+msgid "need a working directory"
+msgstr "butuh sebuah direktori kerja"
+
+#: scalar.c
+msgid "Scalar enlistments require a worktree"
+msgstr "Pendaftaran scalar membutuhkan pohon kerja"
+
+#: scalar.c
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "tidak dapat menyetel %s=%s"
+
+#: scalar.c
+msgid "could not configure log.excludeDecoration"
+msgstr "tidak dapat menyetel log.excludeDecoration"
+
+#: scalar.c
+msgid "could not add enlistment"
+msgstr "tidak dapat menambah pendaftaran"
+
+#: scalar.c
+msgid "could not set recommended config"
+msgstr "tidak dapat menyetel konfigurasi yang direkomendasikan"
+
+#: scalar.c
+msgid "could not turn on maintenance"
+msgstr "tidak dapat mengaktifkan pemeliharaan"
+
+#: scalar.c
+msgid "could not start the FSMonitor daemon"
+msgstr "tidak dapat menjalankan daemon FSMonitor"
+
+#: scalar.c
+msgid "could not turn off maintenance"
+msgstr "tidak dapat menonaktifkan pemeliharaan"
+
+#: scalar.c
+msgid "could not remove enlistment"
+msgstr "tidak dapat menghapus pendaftaran"
+
+#: scalar.c
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "HEAD remote bukan sebuah cabang: '%.*s'"
+
+#: scalar.c
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"gagal mendapatkan nama cabang asali dari remote; menggunakan asali lokal"
+
+#: scalar.c
+msgid "failed to get default branch name"
+msgstr "gagal mendapatkan nama cabang asali"
+
+#: scalar.c
+msgid "failed to unregister repository"
+msgstr "gagal menghapus pendaftaran repositori"
+
+#: scalar.c
+msgid "failed to stop the FSMonitor daemon"
+msgstr "gagal menghentikan daemon FSMonitor"
+
+#: scalar.c
+msgid "failed to delete enlistment directory"
+msgstr "gagal menghapus direktori pendaftaran"
+
+#: scalar.c
+msgid "branch to checkout after clone"
+msgstr "cabang untuk dicheckout setelah kloning"
+
+#: scalar.c
+msgid "when cloning, create full working directory"
+msgstr "ketika kloning, buat direktori kerja penuh"
+
+#: scalar.c
+msgid "only download metadata for the branch that will be checked out"
+msgstr "hanya unduh metadata untuk cabang yang akan dicheckout"
+
+#: scalar.c
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<options>] [--] <repositori> [<direktori>]"
+
+#: scalar.c
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "tidak dapat menyimpulkan nama pohon kerja dari '%s'"
+
+#: scalar.c
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "direktori '%s' sudah ada"
+
+#: scalar.c
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "gagal mendapatkan cabang asali untuk '%s'"
+
+#: scalar.c
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "tidak dapat menyetel remote di '%s'"
+
+#: scalar.c
+#, c-format
+msgid "could not configure '%s'"
+msgstr "tidak dapat menyetel '%s'"
+
+#: scalar.c
+msgid "partial clone failed; attempting full clone"
+msgstr "kloning parsial gagal; mencoba kloning penuh"
+
+#: scalar.c
+msgid "could not configure for full clone"
+msgstr "tidak dapat menyetel untuk kloning penuh"
+
+#: scalar.c
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<pendaftaran>]"
+
+#: scalar.c
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` tidak mengambil argumen"
 
-#: rerere.c
-#, c-format
-msgid "Recorded preimage for '%s'"
-msgstr "Pracitra direkam untuk '%s'"
+#: scalar.c
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<pendaftaran>]"
 
-#: rerere.c
-#, c-format
-msgid "failed to update conflicted state in '%s'"
-msgstr "gagal memperbarui keadaan konflik di '%s'"
+#: scalar.c
+msgid "reconfigure all registered enlistments"
+msgstr "konfigurasi ulang semua pendaftaran yang terdaftar"
 
-#: rerere.c
-#, c-format
-msgid "no remembered resolution for '%s'"
-msgstr "tidak ada resolusi yang diingat untuk '%s'"
+#: scalar.c
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <pendaftaran>]"
 
-#: rerere.c
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr "tidak dapat batal taut '%s'"
+#: scalar.c
+msgid "--all or <enlistment>, but not both"
+msgstr "--all atau <pendaftaran>, tetapi bukan kedua-duanya"
 
-#: rerere.c
+#: scalar.c
 #, c-format
-msgid "Updated preimage for '%s'"
-msgstr "Pracitra diperbarui untuk '%s'"
+msgid "git repository gone in '%s'"
+msgstr "repositori git pergi di '%s'"
 
-#: rerere.c
+#: scalar.c
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <tugas> [<pendaftaran>]\n"
+"Tugas:\n"
+
+#: scalar.c
 #, c-format
-msgid "Forgot resolution for '%s'\n"
-msgstr "Resolusi dilupakan untuk '%s'\n"
+msgid "no such task: '%s'"
+msgstr "tidak ada tugas: '%s'"
 
-#: rerere.c
-msgid "unable to open rr-cache directory"
-msgstr "tidak dapat membuka direktori rr-cache"
+#: scalar.c
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<pendaftaran>]"
 
-#: rerere.h
-msgid "update the index with reused conflict resolution if possible"
-msgstr ""
+#: scalar.c
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <pendaftaran>"
 
-#: reset.c
-msgid "could not determine HEAD revision"
-msgstr "tidak dapat menentukan revisi HEAD"
+#: scalar.c
+msgid "refusing to delete current working directory"
+msgstr "menolak menghapus direktori kerja saat ini"
 
-#: reset.c sequencer.c
-#, c-format
-msgid "failed to find tree of %s"
-msgstr "gagal menemukan pohon %s"
+#: scalar.c
+msgid "include Git version"
+msgstr "masukkan versi Git"
 
-#: revision.c
-msgid "--unpacked=<packfile> no longer supported"
-msgstr "--unpacked=<berkas pak> tidak didukung lagi"
+#: scalar.c
+msgid "include Git's build options"
+msgstr "masukkan opsi bangun Git"
 
-#: revision.c
-msgid "your current branch appears to be broken"
-msgstr "sepertinya cabang Anda saat ini rusak"
+#: scalar.c
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
 
-#: revision.c
-#, c-format
-msgid "your current branch '%s' does not have any commits yet"
-msgstr "cabang Anda saat ini '%s' belum memiliki komit apapun"
+#: scalar.c
+msgid "-C requires a <directory>"
+msgstr "-C butuh sebuah <direktori>"
 
-#: revision.c
-msgid "object filtering requires --objects"
-msgstr "penyaringan objek memerlukan --objects"
+#: scalar.c
+#, c-format
+msgid "could not change to '%s'"
+msgstr "tidak dapat berganti ke '%s'"
 
-#: revision.c
-msgid "-L does not yet support diff formats besides -p and -s"
-msgstr "-L belum mendukung format diff selain -p dan -s"
+#: scalar.c
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c butuh argumen <kunci>=<nilai>"
 
-#: run-command.c
-#, c-format
-msgid "cannot create async thread: %s"
+#: scalar.c
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
 msgstr ""
+"scalar [-C <direktori>] [-c <kunci>=<nilai>] perintah [<opsi>]\n"
+"\n"
+"Perintah:\n"
 
 #: send-pack.c
 msgid "unexpected flush packet while reading remote unpack status"
@@ -23493,11 +24216,6 @@ msgstr "perubahan lokal Anda akan ditimpa oleh %s."
 msgid "commit your changes or stash them to proceed."
 msgstr "komit perubahan Anda atau stase untuk melanjutkan."
 
-#: sequencer.c
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: maju-cepat"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -24089,6 +24807,30 @@ msgstr "bahkan tidak dapat mencoba menggabungkan '%.*s'"
 msgid "merge: Unable to write new index file"
 msgstr "merge: Tidak dapat menulis berkas indeks baru"
 
+#: sequencer.c
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "sepertinya proses 'rebase' lainnya berjalan; '%s.lock' sudah ada"
+
+#: sequencer.c
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Referensi berikut diperbarui dengan %s:\n"
+"%s"
+
+#: sequencer.c
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Gagal memperbarui referensi berikut dengan %s:\n"
+"%s"
+
 #: sequencer.c
 msgid "Cannot autostash"
 msgstr "Tidak dapat menstase otomatis"
@@ -24293,6 +25035,11 @@ msgstr "tidak dapat melewatkan perintah pick yang tidak perlu"
 msgid "the script was already rearranged."
 msgstr "skrip sudah ditata ulang."
 
+#: sequencer.c
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "berkas update-refs pada '%s' tidak valid"
+
 #: setup.c
 #, c-format
 msgid "'%s' is outside repository at '%s'"
@@ -24438,16 +25185,22 @@ msgstr ""
 #: setup.c
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"repositori tidak aman ('%s' dimiliki oleh orang lain)\n"
-"Untuk menambahkan pengecualian untuk direktori ini, panggil:\n"
+"perizinan meragukan terdeteksi di dalam repositori pada '%s'\n"
+"%sUntuk menambahkan pengecualian untuk direktori ini, panggil:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#: setup.c
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr ""
+"tidak dapat menggunakan repositori bare '%s' (safe.bareRepository yaitu '%s')"
+
 #: setup.c
 #, c-format
 msgid ""
@@ -24890,16 +25643,16 @@ msgstr "tidak dapat menamai ulang berkas sementara ke %s"
 
 #: transport-helper.c
 msgid "full write to remote helper failed"
-msgstr ""
+msgstr "gagal menulis penuh ke pembantu remote"
 
 #: transport-helper.c
 #, c-format
 msgid "unable to find remote helper for '%s'"
-msgstr ""
+msgstr "tidak dapat menemukan pembantu remote untuk '%s'"
 
 #: transport-helper.c
 msgid "can't dup helper output fd"
-msgstr ""
+msgstr "tidak dapat menipu penjelas berkas keluaran pembantu"
 
 #: transport-helper.c
 #, c-format
@@ -24907,120 +25660,122 @@ msgid ""
 "unknown mandatory capability %s; this remote helper probably needs newer "
 "version of Git"
 msgstr ""
+"kemampuan wajib %s tidak dikenal; pembantu remote ini sepertinya butuh versi "
+"Git baru"
 
 #: transport-helper.c
 msgid "this remote helper should implement refspec capability"
-msgstr ""
+msgstr "pembantu remote ini seharusnya menerapkan kemampuan spek referensi"
 
 #: transport-helper.c
 #, c-format
 msgid "%s unexpectedly said: '%s'"
-msgstr ""
+msgstr "%s tiba-tiba berkata: '%s'"
 
 #: transport-helper.c
 #, c-format
 msgid "%s also locked %s"
-msgstr ""
+msgstr "%s juga mengunci %s"
 
 #: transport-helper.c
 msgid "couldn't run fast-import"
-msgstr ""
+msgstr "tidak dapat menjalankan fast-import"
 
 #: transport-helper.c
 msgid "error while running fast-import"
-msgstr ""
+msgstr "kesalahan ketika menjalankan fast-import"
 
 #: transport-helper.c
 #, c-format
 msgid "could not read ref %s"
-msgstr ""
+msgstr "tidak dapat membaca referensi %s"
 
 #: transport-helper.c
 #, c-format
 msgid "unknown response to connect: %s"
-msgstr ""
+msgstr "tanggapan terhadap hubungan tidak dikenal: %s"
 
 #: transport-helper.c
 msgid "setting remote service path not supported by protocol"
-msgstr ""
+msgstr "menyetel jalur layanan remote tidak didukung oleh protokol"
 
 #: transport-helper.c
 msgid "invalid remote service path"
-msgstr ""
+msgstr "jalur layanan remote tidak valid"
 
 #: transport-helper.c transport.c
 msgid "operation not supported by protocol"
-msgstr ""
+msgstr "operasi tidak didukung oleh protokol"
 
 #: transport-helper.c
 #, c-format
 msgid "can't connect to subservice %s"
-msgstr ""
+msgstr "tidak dapat menghubungkan ke sublayanan %s"
 
 #: transport-helper.c transport.c
 msgid "--negotiate-only requires protocol v2"
-msgstr ""
+msgstr "--negotiate-only butuh protokol v2"
 
 #: transport-helper.c
 msgid "'option' without a matching 'ok/error' directive"
-msgstr ""
+msgstr "'option' tanpa pengarah 'ok/error' yang bersesuaian"
 
 #: transport-helper.c
 #, c-format
 msgid "expected ok/error, helper said '%s'"
-msgstr ""
+msgstr "ok/error diharapkan, pembantu berkata '%s'"
 
 #: transport-helper.c
 #, c-format
 msgid "helper reported unexpected status of %s"
-msgstr ""
+msgstr "pembantu melaporkan status %s yang tak diharapkan"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support dry-run"
-msgstr ""
+msgstr "pembantu %s tidak mendukung latihan"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support --signed"
-msgstr ""
+msgstr "pembantu %s tidak mendukung --signed"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support --signed=if-asked"
-msgstr ""
+msgstr "pembantu %s tidak mendukung --signed=if-asked"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support --atomic"
-msgstr ""
+msgstr "pembantu %s tidak mendukung --atomic"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support --%s"
-msgstr ""
+msgstr "pembantu %s tidak mendukung --%s"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support 'push-option'"
-msgstr ""
+msgstr "pembantu %s tidak mendukung 'push-option'"
 
 #: transport-helper.c
 msgid "remote-helper doesn't support push; refspec needed"
-msgstr ""
+msgstr "pembantu tidak mendukung pendorongan; spek referensi diperlukan"
 
 #: transport-helper.c
 #, c-format
 msgid "helper %s does not support 'force'"
-msgstr ""
+msgstr "pembantu %s tidak mendukung 'force'"
 
 #: transport-helper.c
 msgid "couldn't run fast-export"
-msgstr ""
+msgstr "tidak dapat menjalankan fast-export"
 
 #: transport-helper.c
 msgid "error while running fast-export"
-msgstr ""
+msgstr "kesalahan ketika menjalankan fast-export"
 
 #: transport-helper.c
 #, c-format
@@ -25028,104 +25783,106 @@ msgid ""
 "No refs in common and none specified; doing nothing.\n"
 "Perhaps you should specify a branch.\n"
 msgstr ""
+"Tidak ada kesamaan referensi dan tidak ada yang disebutkan; tidak melakuan\n"
+"apa-apa. Mungkin Anda perlu menyebutkan sebuah cabang.\n"
 
 #: transport-helper.c
 #, c-format
 msgid "unsupported object format '%s'"
-msgstr ""
+msgstr "format objek tidak didukung '%s'"
 
 #: transport-helper.c
 #, c-format
 msgid "malformed response in ref list: %s"
-msgstr ""
+msgstr "jawaban rusak di daftar referensi: %s"
 
 #: transport-helper.c
 #, c-format
 msgid "read(%s) failed"
-msgstr ""
+msgstr "read(%s) gagal"
 
 #: transport-helper.c
 #, c-format
 msgid "write(%s) failed"
-msgstr ""
+msgstr "write(%s) gagal"
 
 #: transport-helper.c
 #, c-format
 msgid "%s thread failed"
-msgstr ""
+msgstr "utas %s gagal"
 
 #: transport-helper.c
 #, c-format
 msgid "%s thread failed to join: %s"
-msgstr ""
+msgstr "utas %s gagal bergabung: %s"
 
 #: transport-helper.c
 #, c-format
 msgid "can't start thread for copying data: %s"
-msgstr ""
+msgstr "tidak dapat memulai utas untuk menyalin data: %s"
 
 #: transport-helper.c
 #, c-format
 msgid "%s process failed to wait"
-msgstr ""
+msgstr "proses %s gagal menunggu"
 
 #: transport-helper.c
 #, c-format
 msgid "%s process failed"
-msgstr ""
+msgstr "proses %s gagal"
 
 #: transport-helper.c
 msgid "can't start thread for copying data"
-msgstr ""
+msgstr "tidak dapat memulai utas untuk menyalin data"
 
 #: transport.c
 #, c-format
 msgid "Would set upstream of '%s' to '%s' of '%s'\n"
-msgstr ""
+msgstr "Akan menyetel hulu '%s' ke '%s' dari '%s'\n"
 
 #: transport.c
 #, c-format
 msgid "could not read bundle '%s'"
-msgstr ""
+msgstr "tidak dapat membaca bundel '%s'"
 
 #: transport.c
 #, c-format
 msgid "transport: invalid depth option '%s'"
-msgstr ""
+msgstr "transport: opsi kedalaman '%s' tidak valid"
 
 #: transport.c
 msgid "see protocol.version in 'git help config' for more details"
-msgstr ""
+msgstr "lihat protocol.version di 'git help config' untuk lebih lengkapnya"
 
 #: transport.c
 msgid "server options require protocol version 2 or later"
-msgstr ""
+msgstr "opsi peladen butuh protokol versi 2 atau lebih baru"
 
 #: transport.c
 msgid "server does not support wait-for-done"
-msgstr ""
+msgstr "peladen tidak mendukung wait-for-done"
 
 #: transport.c
 msgid "could not parse transport.color.* config"
-msgstr ""
+msgstr "tidak dapat menguraikan konfigurasi transport.color.*"
 
 #: transport.c
 msgid "support for protocol v2 not implemented yet"
-msgstr ""
+msgstr "dukungan untuk protokol v2 belum diterapkan"
 
 #: transport.c
 #, c-format
 msgid "unknown value for config '%s': %s"
-msgstr ""
+msgstr "nilai tidak dikenal untuk konfigurasi '%s': %s"
 
 #: transport.c
 #, c-format
 msgid "transport '%s' not allowed"
-msgstr ""
+msgstr "transportasi '%s' tidak diperbolehkan"
 
 #: transport.c
 msgid "git-over-rsync is no longer supported"
-msgstr ""
+msgstr "git-over-rsync tidak lagi didukung"
 
 #: transport.c
 #, c-format
@@ -25133,6 +25890,8 @@ msgid ""
 "The following submodule paths contain changes that can\n"
 "not be found on any remote:\n"
 msgstr ""
+"Jalur submodul berikut berisi perubahan yang tidak dapat ditemukan\n"
+"pada remote apapun:\n"
 
 #: transport.c
 #, c-format
@@ -25149,30 +25908,40 @@ msgid ""
 "to push them to a remote.\n"
 "\n"
 msgstr ""
+"\n"
+"Mohon coba\n"
+"\n"
+"\tgit push --recurse-submodules=on-demand\n"
+"\n"
+"atau berganti direktori ke jalur dan gunakan\n"
+"\n"
+"\tgit push\n"
+"untuk mendorong ke remote.\n"
+"\n"
 
 #: transport.c
 msgid "Aborting."
-msgstr ""
+msgstr "Membatalkan."
 
 #: transport.c
 msgid "failed to push all needed submodules"
-msgstr ""
+msgstr "gagal mendorong semua submodul yang dibutuhkan"
 
 #: tree-walk.c
 msgid "too-short tree object"
-msgstr ""
+msgstr "objek pohon terlalu pendek"
 
 #: tree-walk.c
 msgid "malformed mode in tree entry"
-msgstr ""
+msgstr "mode salah di entri pohon"
 
 #: tree-walk.c
 msgid "empty filename in tree entry"
-msgstr ""
+msgstr "nama berkas kosong di entri pohon"
 
 #: tree-walk.c
 msgid "too-short tree file"
-msgstr ""
+msgstr "berkas pohon terlalu pendek"
 
 #: unpack-trees.c
 #, c-format
@@ -25180,6 +25949,8 @@ msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
 "%%sPlease commit your changes or stash them before you switch branches."
 msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh checkout:\n"
+"%%sMohon komit atau stase sebelum Anda mengganti cabang."
 
 #: unpack-trees.c
 #, c-format
@@ -25187,6 +25958,8 @@ msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
 "%%s"
 msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh checkout:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25194,6 +25967,9 @@ msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
 "%%sPlease commit your changes or stash them before you merge."
 msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh "
+"penggabungan:\n"
+"%%sMohon komit atau stase sebelum Anda gabungkan."
 
 #: unpack-trees.c
 #, c-format
@@ -25201,6 +25977,9 @@ msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
 "%%s"
 msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh "
+"penggabungan:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25208,6 +25987,8 @@ msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
 "%%sPlease commit your changes or stash them before you %s."
 msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh %s:\n"
+"%%sMohon komit atau stase sebelum Anda %s."
 
 #: unpack-trees.c
 #, c-format
@@ -25215,6 +25996,8 @@ msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
 "%%s"
 msgstr ""
+"Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh %s:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25222,6 +26005,9 @@ msgid ""
 "Updating the following directories would lose untracked files in them:\n"
 "%s"
 msgstr ""
+"Memperbarui direktori berikut akan menghilangkan berkas tak terlacak di "
+"dalam:\n"
+"%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25229,6 +26015,8 @@ msgid ""
 "Refusing to remove the current working directory:\n"
 "%s"
 msgstr ""
+"Menolak menghapus direktori kerja saat ini:\n"
+"%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25236,6 +26024,8 @@ msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
 "%%sPlease move or remove them before you switch branches."
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan dihapus oleh checkout:\n"
+"%%sMohon pindahkan atau hapus sebelum Anda berganti cabang."
 
 #: unpack-trees.c
 #, c-format
@@ -25243,6 +26033,8 @@ msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
 "%%s"
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan dihapus oleh checkout:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25250,6 +26042,8 @@ msgid ""
 "The following untracked working tree files would be removed by merge:\n"
 "%%sPlease move or remove them before you merge."
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan dihapus oleh penggabungan:\n"
+"%%sMohon pindahkan atau hapus sebelum Anda gabungkan."
 
 #: unpack-trees.c
 #, c-format
@@ -25257,6 +26051,8 @@ msgid ""
 "The following untracked working tree files would be removed by merge:\n"
 "%%s"
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan dihapus oleh penggabungan:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25264,6 +26060,8 @@ msgid ""
 "The following untracked working tree files would be removed by %s:\n"
 "%%sPlease move or remove them before you %s."
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan dihapus oleh %s:\n"
+"%%sMohon pindahkan atau hapus sebelum Anda %s."
 
 #: unpack-trees.c
 #, c-format
@@ -25271,6 +26069,8 @@ msgid ""
 "The following untracked working tree files would be removed by %s:\n"
 "%%s"
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan dihapus oleh %s:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25279,6 +26079,8 @@ msgid ""
 "checkout:\n"
 "%%sPlease move or remove them before you switch branches."
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan ditimpa oleh checkout:\n"
+"%%sMohon pindahkan atau hapus sebelum Anda berganti cabang."
 
 #: unpack-trees.c
 #, c-format
@@ -25287,6 +26089,8 @@ msgid ""
 "checkout:\n"
 "%%s"
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan ditimpa oleh checkout:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25294,6 +26098,8 @@ msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
 "%%sPlease move or remove them before you merge."
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan ditimpa oleh penggabungan:\n"
+"%%sMohon pindahkan atau hapus sebelum Anda gabungkan."
 
 #: unpack-trees.c
 #, c-format
@@ -25301,6 +26107,8 @@ msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
 "%%s"
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan ditimpa oleh penggabungan:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25308,6 +26116,8 @@ msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
 "%%sPlease move or remove them before you %s."
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan ditimpa oleh %s:\n"
+"%%sMohon pindahkan atau hapus sebelum Anda %s."
 
 #: unpack-trees.c
 #, c-format
@@ -25315,11 +26125,13 @@ msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
 "%%s"
 msgstr ""
+"Berkas pohon kerja tak terlacak berikut akan ditimpa oleh %s:\n"
+"%%s"
 
 #: unpack-trees.c
 #, c-format
 msgid "Entry '%s' overlaps with '%s'.  Cannot bind."
-msgstr ""
+msgstr "Entri '%s' tumpang tindih dengan '%s'. Tidak dapat mengikat."
 
 #: unpack-trees.c
 #, c-format
@@ -25327,6 +26139,8 @@ msgid ""
 "Cannot update submodule:\n"
 "%s"
 msgstr ""
+"Tidak dapat memperbarui submodul:\n"
+"%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25335,6 +26149,8 @@ msgid ""
 "patterns:\n"
 "%s"
 msgstr ""
+"Jalur berikut tidak diperbarui dan dibiarkan walaupun merupakan pola tipis:\n"
+"%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25342,6 +26158,9 @@ msgid ""
 "The following paths are unmerged and were left despite sparse patterns:\n"
 "%s"
 msgstr ""
+"Jalur berikut tidak digabungkan dan dibiarkan walaupun merupakan pola "
+"tipis:\n"
+"%s"
 
 #: unpack-trees.c
 #, c-format
@@ -25350,11 +26169,13 @@ msgid ""
 "patterns:\n"
 "%s"
 msgstr ""
+"Jalur berikut sudah ada dan tidak diperbarui walaupun merupakan pola tipis:\n"
+"%s"
 
 #: unpack-trees.c
 #, c-format
 msgid "Aborting\n"
-msgstr ""
+msgstr "Membatalkan\n"
 
 #: unpack-trees.c
 #, c-format
@@ -25362,10 +26183,12 @@ msgid ""
 "After fixing the above paths, you may want to run `git sparse-checkout "
 "reapply`.\n"
 msgstr ""
+"Setelah memperbarui jalur tersebut, Anda mungkin ingin menjalankan `git "
+"sparse-checkout reapply`.\n"
 
 #: unpack-trees.c
 msgid "Updating files"
-msgstr ""
+msgstr "Memperbarui berkas"
 
 #: unpack-trees.c
 msgid ""
@@ -25373,15 +26196,18 @@ msgid ""
 "on a case-insensitive filesystem) and only one from the same\n"
 "colliding group is in the working tree:\n"
 msgstr ""
+"jalur berikut bertabrakan (misalnya jalur peka huruf besar-kecil pada\n"
+"sistem berkas tidak peka huruf besar-kecil) dan hanya satu dari grup\n"
+"bertabrakan yang sama yang berada di dalam pohon kerja:\n"
 
 #: unpack-trees.c
 msgid "Updating index flags"
-msgstr ""
+msgstr "Memperbarui bendera indeks"
 
 #: unpack-trees.c
 #, c-format
 msgid "worktree and untracked commit have duplicate entries: %s"
-msgstr ""
+msgstr "pohon kerja dan komit tak terlacak punya entri duplikat: %s"
 
 #: upload-pack.c
 msgid "expected flush after fetch arguments"
@@ -25389,36 +26215,52 @@ msgstr "bilasan diharapkan setelah argumen pengambilan"
 
 #: urlmatch.c
 msgid "invalid URL scheme name or missing '://' suffix"
-msgstr ""
+msgstr "skema URL tidak valid atau kehilangan akhiran '://'"
 
 #: urlmatch.c
 #, c-format
 msgid "invalid %XX escape sequence"
-msgstr ""
+msgstr "urutan pelarian %XX tidak valid"
 
 #: urlmatch.c
 msgid "missing host and scheme is not 'file:'"
-msgstr ""
+msgstr "kehilangan host dan skema bukan 'file:'"
 
 #: urlmatch.c
 msgid "a 'file:' URL may not have a port number"
-msgstr ""
+msgstr "sebuah URL 'file:' tidak boleh punya nomor port"
 
 #: urlmatch.c
 msgid "invalid characters in host name"
-msgstr ""
+msgstr "karakter tidak valid pada nama host"
 
 #: urlmatch.c
 msgid "invalid port number"
-msgstr ""
+msgstr "nomor port tidak valid"
 
 #: urlmatch.c
 msgid "invalid '..' path segment"
-msgstr ""
+msgstr "segmen jalur '..' tidak valid"
+
+#: usage.c
+msgid "usage: "
+msgstr "penggunaan: "
+
+#: usage.c
+msgid "fatal: "
+msgstr "fatal: "
+
+#: usage.c
+msgid "error: "
+msgstr "kesalahan: "
+
+#: usage.c
+msgid "warning: "
+msgstr "peringatan: "
 
 #: walker.c
 msgid "Fetching objects"
-msgstr ""
+msgstr "Mengambil objek"
 
 #: worktree.c
 #, c-format
@@ -25524,7 +26366,7 @@ msgstr "gagal menyetel setelan extensions.worktreeConfig"
 #: wrapper.c
 #, c-format
 msgid "could not setenv '%s'"
-msgstr ""
+msgstr "tidak dapat menyetel lingkungan (setenv) '%s'"
 
 #: wrapper.c
 #, c-format
@@ -25534,16 +26376,16 @@ msgstr "tidak dapat membuat '%s'"
 #: wrapper.c
 #, c-format
 msgid "could not open '%s' for reading and writing"
-msgstr ""
+msgstr "tidak dapat membuka '%s' untuk membaca dan menulis"
 
 #: wrapper.c
 #, c-format
 msgid "unable to access '%s'"
-msgstr ""
+msgstr "tidak dapat mengakses '%s'"
 
 #: wrapper.c
 msgid "unable to get current working directory"
-msgstr ""
+msgstr "tidak dapat mendapatkan direktori kerja saat ini"
 
 #: wt-status.c
 msgid "Unmerged paths:"
@@ -25960,11 +26802,11 @@ msgstr "sedang mendasarkan ulang; ke "
 
 #: wt-status.c
 msgid "HEAD detached at "
-msgstr ""
+msgstr "HEAD terlepas pada "
 
 #: wt-status.c
 msgid "HEAD detached from "
-msgstr ""
+msgstr "HEAD terlepas dari "
 
 #: wt-status.c
 msgid "Not currently on any branch."
@@ -26093,84 +26935,86 @@ msgstr "juga indeks Anda berisi perubahan yang belum dikomit."
 msgid "cannot %s: Your index contains uncommitted changes."
 msgstr "tidak dapat %s: indeks Anda berisi perubahan yang belum dikomit."
 
-#: git-merge-octopus.sh
+#: git-merge-octopus.sh git-merge-resolve.sh
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
 msgstr ""
+"Kesalahan: Perubahan lokal Anda terhadap berkas berikut akan ditimpa oleh "
+"penggabungan"
 
 #: git-merge-octopus.sh
 msgid "Automated merge did not work."
-msgstr ""
+msgstr "Penggabungan otomatis tidak bekerja."
 
 #: git-merge-octopus.sh
 msgid "Should not be doing an octopus."
-msgstr ""
+msgstr "Seharusnya tidak melakukan gurita."
 
 #: git-merge-octopus.sh
 #, sh-format
 msgid "Unable to find common commit with $pretty_name"
-msgstr ""
+msgstr "Tidak dapat menemukan komit umum dengan $pretty_name"
 
 #: git-merge-octopus.sh
 #, sh-format
 msgid "Already up to date with $pretty_name"
-msgstr ""
+msgstr "Sudah terbaru dengan $pretty_name"
 
 #: git-merge-octopus.sh
 #, sh-format
 msgid "Fast-forwarding to: $pretty_name"
-msgstr ""
+msgstr "Memaju-cepat ke: $pretty_name"
 
 #: git-merge-octopus.sh
 #, sh-format
 msgid "Trying simple merge with $pretty_name"
-msgstr ""
+msgstr "Mencoba penggabungan sederhana dengan $pretty_name"
 
 #: git-merge-octopus.sh
 msgid "Simple merge did not work, trying automatic merge."
-msgstr ""
+msgstr "Penggabungan sederhana tidak berkerja, mencoba penggabungan otomatis."
 
 #: git-sh-setup.sh
 #, sh-format
 msgid "usage: $dashless $USAGE"
-msgstr ""
+msgstr "penggunaan: $dashless $USAGE"
 
 #: git-sh-setup.sh
 #, sh-format
 msgid "Cannot chdir to $cdup, the toplevel of the working tree"
-msgstr ""
+msgstr "tidak dapat berganti direktori ke $cdup, level atas dari pohon kerja"
 
 #: git-sh-setup.sh
 #, sh-format
 msgid "fatal: $program_name cannot be used without a working tree."
-msgstr ""
+msgstr "fatal: $program_name tidak dapat digunakan tanpa pohon kerja."
 
 #: git-sh-setup.sh
 msgid "Cannot rewrite branches: You have unstaged changes."
-msgstr ""
+msgstr "Tidak dapat menulis ulang cabang: Anda punya perubahan tak tergelar."
 
 #: git-sh-setup.sh
 #, sh-format
 msgid "Cannot $action: You have unstaged changes."
-msgstr ""
+msgstr "Tidak dapat $action: Anda punya perubahan tak tergelar."
 
 #: git-sh-setup.sh
 #, sh-format
 msgid "Cannot $action: Your index contains uncommitted changes."
-msgstr ""
+msgstr "Tidak dapat $action: Indeks Anda berisi perubahan tak terkomit."
 
 #: git-sh-setup.sh
 msgid "Additionally, your index contains uncommitted changes."
-msgstr ""
+msgstr "Selain itu, indeks Anda berisi perubahan tak terkomit."
 
 #: git-sh-setup.sh
 msgid "You need to run this command from the toplevel of the working tree."
-msgstr ""
+msgstr "Anda perlu menjalankan perintah ini dari level atas dari pohon kerja."
 
 #: git-sh-setup.sh
 msgid "Unable to determine absolute path of git directory"
-msgstr ""
+msgstr "Tidak dapat menentukan jalur absolut direktori git"
 
 #. TRANSLATORS: you can adjust this to align "git add -i" status menu
 #: git-add--interactive.perl
@@ -26328,26 +27172,6 @@ msgstr ""
 msgid "ignoring unmerged: %s\n"
 msgstr ""
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
 #: git-add--interactive.perl
 msgid "No other hunks to goto\n"
 msgstr ""
index 56db2f1bb190508bd48d00f972eb822b739efb6b..825142fde7d07ba1efbd7786c3ef76d10b08d593 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,15 +5,15 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.37.0\n"
+"Project-Id-Version: git 2.38.0\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-24 21:19+0100\n"
-"PO-Revision-Date: 2022-06-24 21:23+0100\n"
+"POT-Creation-Date: 2022-09-26 06:34+0100\n"
+"PO-Revision-Date: 2022-09-26 06:35+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: Gtranslator 3.38.0\n"
@@ -409,6 +409,22 @@ msgstr ""
 "a - applicera stycket och alla följande i filen\n"
 "d - applicera inte stycket eller något av de följande i filen\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Applicera ändrat läge på arbetskatalogen [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Applicera borttagning på arbetskatalogen [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Applicera tillägg på arbetskatalogen [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Applicera stycket på arbetskatalogen [y,n,q,a,d%s,?]? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -426,10 +442,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "kunde inte tolka styckehuvudet \"%.*s\""
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "kunde inte tolka färgat styckehuvud \"%.*s\""
-
 msgid "could not parse diff"
 msgstr "kunde inte tolka diff"
 
@@ -672,7 +684,7 @@ msgid ""
 "outside of your sparse-checkout definition, so will not be\n"
 "updated in the index:\n"
 msgstr ""
-"Följande sökvägar och/eller ökvägsangivelser motsvarar sökvägar\n"
+"Följande sökvägar och/eller sökvägsangivelser motsvarar sökvägar\n"
 "utanför din \"sparse-checkout\"-definition, så de kommer inte\n"
 "uppdateras i indexet:\n"
 
@@ -727,6 +739,25 @@ msgstr ""
 "advice.detachedHead till false\n"
 "\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Följande sökvägar har flyttats ut från din\n"
+"\"sparse-checkout\"-definition, men är inte glesa på grund av\n"
+"lokala ändringar.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"För att korrigera glesheten för dessa sökvägar, gör följande:\n"
+"* Använd \"git add --sparse <sökväg>\" för att uppdatera indexet\n"
+"* Använd \"git sparse-checkout reapply\" för att tillämpa gleshetsreglerna"
+
 msgid "cmdline ends with \\"
 msgstr "kommandorad avslutas med \\"
 
@@ -1228,6 +1259,10 @@ msgstr "kan inte strömma blob:en %s"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "filens läge stöds ej: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "fel i deflate (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "kunde inte starta filtret \"%s\""
@@ -1247,10 +1282,6 @@ msgstr "sökvägen är inte giltig UTF-8: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "sökvägen för lång (%d tecken, SHA1: %s): %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "fel i deflate (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "tidsstämpeln för stor för detta system: %<PRIuMAX>"
@@ -3014,8 +3045,12 @@ msgstr "libc-info:"
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "körs inte från ett git-arkiv - inga krokar att visa\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <fil>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <fil>] [-s|--suffix <format>] [--"
+"diagnose[=<läge>]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3052,16 +3087,29 @@ msgstr ""
 "Se över resten av felrapporten nedan.\n"
 "Du kan ta bort rader du inte vill dela.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "ange mål för buggrapporteringsfilen"
+msgid "mode"
+msgstr "läge"
 
-msgid "specify a strftime format suffix for the filename"
-msgstr "ange ett filändelse i strftime-format"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr ""
+"skapa ett ytterligare zip-arkiv med detaljerad diagnostik (förval är \"stats"
+"\")"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "ange mål för buggrapporteringsfilen/-rna"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "ange filändelse i strftime-format"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "kunde inte skapa inledande kataloger för \"%s\""
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "kunde inte skapa diagnostikarkiven %s"
+
 msgid "System Info"
 msgstr "Systeminfo"
 
@@ -3119,10 +3167,6 @@ msgstr "Behöver ett arkiv för att packa upp en bunt."
 msgid "Unbundling objects"
 msgstr "Packar upp objektbunt"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Okänt underkommando: %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "kan inte läsa objektet %s: \"%s\""
@@ -3201,6 +3245,9 @@ msgstr "visa objektstorlek"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "låter -s och -t att fungera med trasiga/sönderskrivna objekt"
 
+msgid "use mail map file"
+msgstr "använd e-postmappningsfil"
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "Buntobjekt ombeds på standard in (eller --batch-all-objects)"
 
@@ -3210,6 +3257,9 @@ msgstr "visa komplett innehåll för <objekt> eller <rev>"
 msgid "like --batch, but don't emit <contents>"
 msgstr "som --batch, men mata inte ut <innehåll>"
 
+msgid "stdin is NUL-terminated"
+msgstr "standard in är NUL-terminerad"
+
 msgid "read commands from stdin"
 msgstr "läs kommandon från standard in"
 
@@ -4078,6 +4128,12 @@ msgstr "klonade undermoduler kommer använda sin fjärrspårningsgren"
 msgid "initialize sparse-checkout file to include only files at root"
 msgstr "initiera sparse-checkout-filen till att bara ta med filer i roten"
 
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "en URI för att hämta buntar innan de hämtas från ursprungsfjärr"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: Kan inte skapa suppleant för \"%s\": %s\n"
@@ -4137,9 +4193,8 @@ msgstr "kan inte uppdatera %s"
 msgid "failed to initialize sparse-checkout"
 msgstr "misslyckades initiera sparse-checkout"
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr ""
-"HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut"
 
 msgid "unable to checkout working tree"
 msgstr "kunde inte checka ut arbetskatalogen"
@@ -4163,6 +4218,13 @@ msgstr "Du måste ange ett arkiv att klona."
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "flaggorna \"%s\" och \"%s %s\" kan inte användas samtidigt"
 
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri är inkompatibelt med --depth, --shallow-since och --shallow-"
+"exclude"
+
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "arkivet \"%s\" finns inte"
@@ -4234,6 +4296,13 @@ msgstr "--local ignoreras"
 msgid "cannot clone from filtered bundle"
 msgstr "kan inte klona från filtrerad bunt"
 
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "misslyckades initiera arkivet, hoppar över bunt-URI"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "misslyckades hämta objekt från bunt-URI \"%s\""
+
 msgid "remote transport reported error"
 msgstr "fjärrtransport rapporterade fel"
 
@@ -4348,10 +4417,6 @@ msgstr "använd som mest en av --reachable, --stdin-commits och --stdin-packs"
 msgid "Collecting commits from input"
 msgstr "Hämtar incheckningar från indata"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "okänt underkommando: %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -4705,9 +4770,6 @@ msgstr "visa status i långt format (standard)"
 msgid "terminate entries with NUL"
 msgstr "terminera poster med NUL"
 
-msgid "mode"
-msgstr "läge"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr "visa ospårade filer, valfria lägen: all, normal, no. (Standard: all)"
 
@@ -5296,6 +5358,22 @@ msgstr "Inga namn hittades, kan inte beskriva något."
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "flaggorna \"%s\" och incheckning-igter kan inte användas samtidigt"
 
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <sökväg>] [-s|--suffix <format>] [--"
+"mode=<läge>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "ange mål för diagnostikarkivet"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "ange ett filändelse i strftime-format"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "ange vilket innehåll diagnostikarkivet ska ha"
+
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base fungerar endast med två incheckningar"
 
@@ -5668,11 +5746,8 @@ msgstr "[àjour]"
 msgid "[rejected]"
 msgstr "[refuserad]"
 
-msgid "can't fetch in current branch"
-msgstr "kan inte hämta i aktuell gren"
-
-msgid "checked out in another worktree"
-msgstr "utcheckat i en annan arbetskatalog"
+msgid "can't fetch into checked-out branch"
+msgstr "kan inte hämta i utcheckad gren"
 
 msgid "[tag update]"
 msgstr "[uppdaterad tagg]"
@@ -6110,6 +6185,10 @@ msgstr "%s: ogiltig sha1-pekare i cacheträd"
 msgid "non-tree in cache-tree"
 msgstr "icke-träd i cacheträd"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s: ogiltig sha1-pekare i resolve-undo"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<flaggor>] [<objekt>...]"
 
@@ -6441,13 +6520,16 @@ msgstr "misslyckades starta schtasks"
 
 msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr ""
-"kunde inte köra \"crontab -l\"; ditt system kanske inte stöder \"cron\""
+"misslyckades köra \"crontab -l\"; ditt system kanske inte stöder \"cron\""
 
-msgid "failed to run 'crontab'; your system might not support 'cron'"
-msgstr "kunde inte köra \"crontab\"; ditt system kanske inte stöder \"cron\""
+msgid "failed to create crontab temporary file"
+msgstr "misslyckades skapa temporär crontab-fil"
+
+msgid "failed to open temporary file"
+msgstr "misslyckades öppna temporär fil"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "misslyckades öppna standard in för \"crontab\""
+msgid "failed to run 'crontab'; your system might not support 'cron'"
+msgstr "misslyckades köra \"crontab\"; ditt system kanske inte stöder \"cron\""
 
 msgid "'crontab' died"
 msgstr "\"crontab\" dog"
@@ -6495,10 +6577,6 @@ msgstr "misslyckades lägga till arkiv till global konfiguration"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <underkommando> [<flaggor>]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "felaktigt underkommando: %s"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<flaggor>] [-e] <mönster> [<rev>...] [[--] <sökväg>...]"
 
@@ -6669,6 +6747,9 @@ msgstr "visa träffade filer i filbläddraren"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "tillåt anropa grep(1) (ignoreras av detta bygge)"
 
+msgid "maximum number of results per file"
+msgstr "maximalt antal resultat per fil"
+
 msgid "no pattern given"
 msgstr "inget mönster angavs"
 
@@ -6755,11 +6836,17 @@ msgstr "visa kommandobeskrivning"
 msgid "print list of useful guides"
 msgstr "lista användbara vägledningar"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr "lista arkiv-, kommando- och filgränssnitt tänkta för användare"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr "lista filformat, protokoll och andra utvecklargränssnitt"
+
 msgid "print all configuration variable names"
 msgstr "visa namn på alla konfigurationsvariabler"
 
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<kommando>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<kommando>|<doc>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -7230,8 +7317,8 @@ msgstr "undertryck diff-utdata"
 msgid "show source"
 msgstr "visa källkod"
 
-msgid "use mail map file"
-msgstr "använd e-postmappningsfil"
+msgid "clear all previously-defined decoration filters"
+msgstr "rensa alla tidigare definierade dekorationsfilter"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "dekorera endast referenser som motsvarar <mönster>"
@@ -7482,6 +7569,9 @@ msgstr "visa ändringar mot <refspec> i omslagsbrev eller ensam patch"
 msgid "percentage by which creation is weighted"
 msgstr "procent som skapelse vägs med"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "visa From: i kroppen även om samma som i e-posthuvudet"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "ogiltig ident-rad: %s"
@@ -7540,6 +7630,18 @@ msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "Kunde inte hitta en spårad fjärrgren, ange <uppström> manuellt.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "felaktigt ls-files-format: elementet \"%s\" börjar inte med \"(\""
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "felaktigt ls-files-format: elementet \"%s\" slutar inte med \")\""
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "felaktigt ls-files-format: %%%.*s"
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<flaggor>] [<fil>...]"
 
@@ -7624,6 +7726,13 @@ msgstr "undertyck dublettposter"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "visa glesa kataloger när et glest index existerar"
 
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format kan inte användas med -s, -o, -k, -t, --resolve-undo, --"
+"deduplicate, --eol"
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url]\n"
@@ -7842,6 +7951,39 @@ msgstr "kunde inte bestämma referensen \"%s\""
 msgid "Merging %s with %s\n"
 msgstr "Slår ihop %s med %s\n"
 
+msgid "not something we can merge"
+msgstr "inte något vi kan slå ihop"
+
+msgid "refusing to merge unrelated histories"
+msgstr "vägrar slå samman orelaterad historik"
+
+msgid "failure to merge"
+msgstr "misslyckades slå ihop"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<flaggor>] <gren1> <gren2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <baseträd> <gren1> <gren2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "gör en riktig sammanslagning istället för en enkel sammanslagning"
+
+msgid "do a trivial merge only"
+msgstr "gör endast en enkel sammanslagning"
+
+msgid "also show informational/conflict messages"
+msgstr "visa även informations-/konfliktmeddelanden"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "lista filnamn utan lägen/oid/köer"
+
+msgid "allow merging unrelated histories"
+msgstr "tillåt sammanslagning av orelaterade historier"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge är inkompatibelt med andra flaggor"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<flaggor>] [<incheckning>...]"
 
@@ -7922,9 +8064,6 @@ msgstr "--abort men lämna index och arbetskatalog ensamma"
 msgid "continue the current in-progress merge"
 msgstr "fortsätt den pågående sammanslagningen"
 
-msgid "allow merging unrelated histories"
-msgstr "tillåt sammanslagning av orelaterade historier"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "förbigå pre-merge-commit- och commit-msg-krokar"
 
@@ -8045,9 +8184,6 @@ msgstr "kunde inte stänga \"%s\""
 msgid "not something we can merge in %s: %s"
 msgstr "inte något vi kan slå ihop med %s: %s"
 
-msgid "not something we can merge"
-msgstr "inte något vi kan slå ihop"
-
 msgid "--abort expects no arguments"
 msgstr "--abort tar inga argument"
 
@@ -8096,13 +8232,19 @@ msgstr "%s - inte något vi kan slå ihop"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Kan endast slå ihop en enda incheckning i ett tomt huvud"
 
-msgid "refusing to merge unrelated histories"
-msgstr "vägrar slå samman orelaterad historik"
-
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Uppdaterar %s..%s\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Dina lokala ändringar av följande filer skulle skrivas över av "
+"sammanslagning:\n"
+"  %s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Försöker riktigt enkel sammanslagning i indexet...\n"
@@ -8136,6 +8278,10 @@ msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Automatisk sammanslagning lyckades; stoppar före incheckning som önskat\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "När färdig, applicerade sparade ändringar med \"git stash pop\"\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "varning: taggindata godkänns inte av fsck: %s"
@@ -8253,6 +8399,9 @@ msgstr "Kontrollerar namnbyte av \"%s\" till \"%s\"\n"
 msgid "bad source"
 msgstr "felaktig källa"
 
+msgid "destination exists"
+msgstr "destinationen finns"
+
 msgid "can not move directory into itself"
 msgstr "kan inte flytta katalog till sig själv"
 
@@ -8268,9 +8417,6 @@ msgstr "inte versionshanterad"
 msgid "conflicted"
 msgstr "i konflikt"
 
-msgid "destination exists"
-msgstr "destinationen finns"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "skriver över \"%s\""
@@ -8284,6 +8430,9 @@ msgstr "flera källor för samma mål"
 msgid "destination directory does not exist"
 msgstr "destinationskatalogen finns inte"
 
+msgid "destination exists in the index"
+msgstr "destinationen finns i indexet"
+
 #, c-format
 msgid "%s, source=%s, destination=%s"
 msgstr "%s, källa=%s, mål=%s"
@@ -8320,7 +8469,6 @@ msgstr "ignorera referenser som motsvarar <mönster>"
 msgid "list all commits reachable from all refs"
 msgstr "lista alla incheckningar som kan nås alla referenser"
 
-#| msgid "deprecated: use annotate-stdin instead"
 msgid "deprecated: use --annotate-stdin instead"
 msgstr "avråds: använd --annotate-stdin istället"
 
@@ -8643,8 +8791,8 @@ msgid "use notes from <notes-ref>"
 msgstr "använd anteckningar från <anteckningsref>"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "okänt underkommando: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "okänt underkommando: \"%s\""
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -9527,12 +9675,17 @@ msgstr "visa endast utdata för det första intervallet"
 msgid "only emit output related to the second range"
 msgstr "visa endast utdata för det andra intervallet"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "inte en revision: \"%s\""
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "inte ett incheckningsintervall: \"%s\""
 
-msgid "single arg format must be symmetric range"
-msgstr "ensamt argument måste vara symmetriskt intervall"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "inte ett symmetriskt intervall: \"%s\""
 
 msgid "need two commit ranges"
 msgstr "behöver två incheckningsintervall"
@@ -9805,6 +9958,9 @@ msgstr "behåller incheckningar som är tomma från början"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "flytta incheckningar som börjar med squash!/fixup! under -i"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr "uppdatera grenar som pekar på incheckningar som ombaseras"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr "lägg till exec-rader efter varje incheckning i den redigerbara listan"
 
@@ -10325,6 +10481,9 @@ msgstr " ny (nästa hämtning sparar i remotes/%s)"
 msgid " tracked"
 msgstr " spårad"
 
+msgid " skipped"
+msgstr " överhoppad"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " förlegad (använd \"git remote prune\" för att ta bort)"
 
@@ -10990,6 +11149,11 @@ msgstr "Kunde inte skriva ny indexfil."
 msgid "unable to get disk usage of %s"
 msgstr "kan inte hämta diskanvändning för %s"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr ""
+"felaktigt värde för \"%s\": \"%s\", det enda tillåtna formatet är \"%s\""
+
 msgid "rev-list does not support display of notes"
 msgstr "rev-list stöder inte visning av anteckningar"
 
@@ -11015,6 +11179,9 @@ msgstr "för tidigt slut på indata"
 msgid "no usage string given before the `--' separator"
 msgstr "ingen användningssträng angavs före \"--\"-avdelaren"
 
+msgid "missing opt-spec before option flags"
+msgstr "saknar flagg-spec före alternativflaggor"
+
 msgid "Needed a single revision"
 msgstr "Behövde ensam revision"
 
@@ -11774,6 +11941,10 @@ msgstr "lägg in kommentarstecken och blanksteg först på varje rad"
 msgid "Expecting a full ref name, got %s"
 msgstr "Förväntade fullt referensnamn, fick %s"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "kunde inte få tag i arkivhandtag för undermodulen \"%s\""
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -11782,12 +11953,6 @@ msgstr ""
 "kunde inte slå upp konfigurationen \"%s\". Antar att arkivet är sin eget "
 "officiella uppström."
 
-msgid "alternative anchor for relative paths"
-msgstr "alternativa ankare för relativa sökvägar"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<sökväg>] [<sökväg>...]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr "Hittade ingen url för undermodulsökvägen \"%s\" i .gitmodules"
@@ -11820,8 +11985,8 @@ msgstr "dölj utdata från för varje undermodulskommando som startas"
 msgid "recurse into nested submodules"
 msgstr "rekursera in i nästlade undermoduler"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [--] [<kommando>]"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <kommando>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -11842,8 +12007,8 @@ msgstr "Misslyckades registrera uppdateringsläge för undermodulsökväg \"%s\"
 msgid "suppress output for initializing a submodule"
 msgstr "dölj utdata från initiering av undermodul"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<flaggor>] [<sökväg>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<flaggor>] [<sökväg>]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -11870,9 +12035,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quitet] [--cached] [--recursive] [<sökväg>...]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <sökväg>"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(blob)->%s(submodule)"
@@ -11906,9 +12068,8 @@ msgstr ""
 msgid "limit the summary size"
 msgstr "begränsa översiktsstorleken"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr ""
-"git submodule--helper summary [<flaggor>] [<incheckning>] [--] [<sökväg>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<flaggor>] [<incheckning>] [--] [<sökväg>]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "kunde inte hämta en version för HEAD"
@@ -11921,10 +12082,6 @@ msgstr "Synkroniserar undermodul-url för \"%s\"\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "misslyckades registrera url för undermodulsökväg \"%s\""
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "misslyckades hämta standardfjärr för undermodulsökväg \"%s\""
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "misslyckades uppdatera fjärr för undermodulsökväg \"%s\""
@@ -11932,8 +12089,8 @@ msgstr "misslyckades uppdatera fjärr för undermodulsökväg \"%s\""
 msgid "suppress output of synchronizing submodule url"
 msgstr "dölj utdata från synkronisering av undermodul-url"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<sökväg>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<sökväg>]"
 
 #, c-format
 msgid ""
@@ -11988,11 +12145,15 @@ msgid ""
 "submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
 "'--reference-if-able' instead of '--reference'."
 msgstr ""
-"En suppleant beräknad från överprojektets suppleant är ogiltig.\n"
+"En suppleant beräknad från huvudprojektets suppleant är ogiltig.\n"
 "För att i så fall låta Git klona utan ett suppleant, sätt\n"
 "submodule.alternateErrorStrategy till \"info\" eller, likvärdigt, klona\n"
 "med \"--reference-if-able\" istället för \"--reference\"."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "kunde inte få tag i arkivhandtag för gitkatalogen \"%s\""
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "undermodulen \"%s\" kan inte lägga till suppleant: %s"
@@ -12021,6 +12182,9 @@ msgstr "katalogen inte tom: \"%s\""
 msgid "could not get submodule directory for '%s'"
 msgstr "kunde inte få tag i undermodulkatalog för \"%s\""
 
+msgid "alternative anchor for relative paths"
+msgstr "alternativa ankare för relativa sökvägar"
+
 msgid "where the new submodule will be cloned to"
 msgstr "var den nya undermodulen ska klonas till"
 
@@ -12048,10 +12212,6 @@ msgstr ""
 "<arkiv>] [--name <namn>] [--depth <djup>] [--single-branch] [--filter "
 "<filterangivelse>] --url <url> --path <sökväg>"
 
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Ogiltigt uppdateringsläge \"%s\" för undermodulsökväg \"%s\""
-
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr ""
@@ -12124,6 +12284,10 @@ msgstr ""
 "Hämtade i undermodulssökvägen \"%s\", men den innehöll inte %s. Direkt "
 "hämtning av incheckningen misslyckades."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "kunde inte initiera undermodul i sökvägen \"%s\""
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -12132,10 +12296,6 @@ msgstr ""
 "Undermodulens (%s) gren inställd på att ärva gren från huvudprojektet, men "
 "huvudprojektet är inte på någon gren"
 
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "kunde inte få tag i arkivhandtag för undermodulen \"%s\""
-
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr "Kan inte hitta aktuell revision i undermodulsökvägen \"%s\""
@@ -12170,11 +12330,14 @@ msgstr "hämta inte nya objekt från fjärrplatsen"
 msgid "path into the working tree"
 msgstr "sökväg inuti arbetskatalogen"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "sökväg inuti arbetskatalogen, genom nästlade undermodulgränser"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "använd uppdateringsstrategin \"checkout\" (utcheckning; förval)"
 
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout eller none"
+msgid "use the 'merge' update strategy"
+msgstr "använd uppdateringsstrategin \"merge\" (sammanslagning)"
+
+msgid "use the 'rebase' update strategy"
+msgstr "använd uppdateringsstrategin \"rebase\" (ombasering)"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "skapa en grund klon trunkerad till angivet antal revisioner"
@@ -12188,6 +12351,9 @@ msgstr "om den första klonen ska följa rekommendation för grund kloning"
 msgid "don't print cloning progress"
 msgstr "skriv inte klonförlopp"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "förhindra kloning till icke-tom katalog, implicerar --init"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12199,14 +12365,11 @@ msgstr ""
 "[no-]recommend-shallow] [--reference <arkiv>] [--recursive] [--[no-]single-"
 "branch] [--] [<sökväg>...]"
 
-msgid "bad value for update parameter"
-msgstr "felaktigt värde för parametern update"
-
 msgid "recurse into submodules"
 msgstr "rekursera ner i undermoduler"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<flaggor>] [<sökväg>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<flaggor>] [<sökväg>...]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr "se om det är säkert att skriva till .gitmodules-filen"
@@ -12226,8 +12389,8 @@ msgstr "se till att .gitmodules finns i arbetskatalogen"
 msgid "suppress output for setting url of a submodule"
 msgstr "dölj utdata från inställning av url för undermodul"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <sökväg> <nyurl>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <sökväg> <nyurl>"
 
 msgid "set the default tracking branch to master"
 msgstr "välj master som förvald spårad gren"
@@ -12235,13 +12398,11 @@ msgstr "välj master som förvald spårad gren"
 msgid "set the default tracking branch"
 msgstr "välj förvald spårad gren"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <sökväg>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <sökväg>"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <gren> <sökväg>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <gren> <sökväg>"
 
 msgid "--branch or --default required"
 msgstr "--branch eller --default krävs"
@@ -12339,8 +12500,8 @@ msgstr ""
 "sätter undermodulens namn till den angivna strängen istället för att använda "
 "sökvägen"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<flaggor>] [--] <arkiv> [<sökväg>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<flaggor>] [--] <arkiv> [<sökväg>]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr "Relativ sökväg kan endast användas från arbetskatalogens toppnivå"
@@ -12546,6 +12707,16 @@ msgstr "Uppdaterad tagg \"%s\" (var %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "paket är större än tillåten maximal storlek"
 
+msgid "failed to write object in stream"
+msgstr "misslyckades skriva objekt i ström"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "inflate returnerade (%d)"
+
+msgid "invalid blob object from stream"
+msgstr "ogiltigt blob-objekt från ström"
+
 msgid "Unpacking objects"
 msgstr "Packar upp objekt"
 
@@ -13061,6 +13232,27 @@ msgstr "visa trädobjekt för underkatalogen <prefix>"
 msgid "only useful for debugging"
 msgstr "endast användbart vid felsökning"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch stöds inte på denna plattform"
+
+msgid "failed to create temporary file"
+msgstr "misslyckades skapa temporär fil"
+
+msgid "insufficient capabilities"
+msgstr "otillräckliga kapabiliteter"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "kunde inte hämta bunt från URI:en \"%s\""
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "filen på URI \"%s\" är inte en bunt"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "misslyckades packa upp bunten från URI:en \"%s\""
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "okänd hashningsalgoritm för bunt: \"%s\""
@@ -13263,6 +13455,9 @@ msgstr "En riktigt enkel server för Git-arkiv"
 msgid "Give an object a human readable name based on an available ref"
 msgstr "Ge ett objekt användarläsbara namn baserade på en tillgänglig referens"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Skapa ett zip-arkiv med diagnostisk information"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "Visa ändringar mellan incheckningar, med arbetskatalogen, osv"
 
@@ -13390,8 +13585,8 @@ msgstr "Kör en sammanslagning för filer som behöver det"
 msgid "The standard helper program to use with git-merge-index"
 msgstr "Förvalt hjälpprogram att använda tillsammans med git-merge-index"
 
-msgid "Show three-way merge without touching index"
-msgstr "Visa trevägssammanslagning utan att röra indexet"
+msgid "Perform merge without touching index or working tree"
+msgstr "Utför sammanslagning utan att röra index eller arbetskatalog"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr "Kör verktyg för lösning av sammanslagningskonflikter"
@@ -13585,6 +13780,9 @@ msgstr "Bekräfta packade Git-arkivfiler"
 msgid "Check the GPG signature of tags"
 msgstr "Kontrollera GPG-signaturer i taggar"
 
+msgid "Display version information about Git"
+msgstr "Visa versionsinformation om Git"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Visa loggar med differenser varje incheckning introducerar"
 
@@ -13618,6 +13816,24 @@ msgstr "Ett användbart minsta uppsättning kommandon för vardags-Git"
 msgid "Frequently asked questions about using Git"
 msgstr "Ofta ställda frågor om att använda Git"
 
+msgid "The bundle file format"
+msgstr "Filformat för bunt"
+
+msgid "Chunk-based file formats"
+msgstr "Styckebaserade filformat"
+
+msgid "Git commit graph format"
+msgstr "Format för Git-incheckningsgraf"
+
+msgid "Git index format"
+msgstr "Format för Git-index"
+
+msgid "Git pack format"
+msgstr "Format för Git-paket"
+
+msgid "Git cryptographic signature formats"
+msgstr "Format för kryptografiska signaturer i Git"
+
 msgid "A Git Glossary"
 msgstr "En Git-ordlista"
 
@@ -13639,6 +13855,21 @@ msgstr "Ange egenskaper för undermoduler"
 msgid "Git namespaces"
 msgstr "Git-namnrymder"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Kapabiliteter i protokoll v0 och v1"
+
+msgid "Things common to various protocols"
+msgstr "Vad är gemensamt i de olika protokollen"
+
+msgid "Git HTTP-based protocols"
+msgstr "HTTP-baserade Git-protokoll"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Hur paket överförs på linjen"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Gits linjeprotokoll, version 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Hjälpprogram för att interagera med fjärrarkiv"
 
@@ -13663,6 +13894,9 @@ msgstr "Git-webbgränssnitt (webbframända för Git-arkiv)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Översikt över rekommenderade arbetsflöden med Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Verktyg för att hantera stora Git-arkiv"
+
 msgid "commit-graph file is too small"
 msgstr "incheckningsgraffilen %s är för liten"
 
@@ -13909,6 +14143,14 @@ msgstr "ingen kompilatorinformation tillgänglig\n"
 msgid "no libc information available\n"
 msgstr "ingen libc-information tillgänglig\n"
 
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "kunde inte ta reda på ledigt diskutrymme för \"%s\""
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "kunde inte hämta info för \"%s\""
+
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
 msgstr "[GLE %ld] hälsotråden kunde inte öppna \"%ls\""
@@ -13963,6 +14205,14 @@ msgstr "GetOverlappedResult misslyckades på \"%s\" [GLE %ld]"
 msgid "could not read directory changes [GLE %ld]"
 msgstr "kunde inte läsa katalogändringar [GLE %ld]"
 
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] kunde inte öppna \"%ls\" för läsning"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] kunde inte hämta protokollinformation för \"%ls\""
+
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr "misslyckades kopiera SID (%ld)"
@@ -14507,209 +14757,34 @@ msgid "failed to close rev-list's stdin"
 msgstr "kunde inte stänga rev-list:s standard in"
 
 #, c-format
-msgid "'%s' does not exist"
-msgstr "\"%s\" finns inte"
-
-msgid "need a working directory"
-msgstr "behöver en arbetskatalog"
-
-msgid "could not find enlistment root"
-msgstr "kunde inte hitta enrolleringsroten"
+msgid "illegal crlf_action %d"
+msgstr "felaktig crlf_action %d"
 
 #, c-format
-msgid "could not switch to '%s'"
-msgstr "kunde inte växla till \"%s\""
+msgid "CRLF would be replaced by LF in %s"
+msgstr "CRLF skulle ersättas av LF i %s"
 
 #, c-format
-msgid "could not configure %s=%s"
-msgstr "kunde inte ställa in %s=%s"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "kunde inte ställa in log.excludeDecoration"
+msgid ""
+"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
+"touches it"
+msgstr ""
+"CRLF i arbetskopian av \"%s\" kommer ersättas med LF nästa gång Git rör den"
 
-msgid "Scalar enlistments require a worktree"
-msgstr "Scalar-enrolleringar kräver en arbetskatalog"
+#, c-format
+msgid "LF would be replaced by CRLF in %s"
+msgstr "LF skulle ersättas av CRLF i %s"
 
 #, c-format
-msgid "could not open directory '%s'"
-msgstr "kunde inte öppna katalogen \"%s\""
+msgid ""
+"in the working copy of '%s', LF will be replaced by CRLF the next time Git "
+"touches it"
+msgstr ""
+"LF i arbetskopian av \"%s\" kommer ersättas med CRLF nästa gång Git rör den"
 
 #, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "hoppar över \"%s\", som varken är en fil eller en katalog"
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "kunde inte ta reda på ledigt diskutrymme för \"%s\""
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "kunde inte hämta info för \"%s\""
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "HEAD hos fjärren är inte en gren: \"%.*s\""
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-"misslyckades hämta namn på standardgren för fjärr; använder lokalt förval"
-
-msgid "failed to get default branch name"
-msgstr "misslyckades hämta namn på standardgren"
-
-msgid "failed to unregister repository"
-msgstr "misslyckades avregistrera arkivet"
-
-msgid "failed to delete enlistment directory"
-msgstr "misslyckades ta bort enrolleringskatalogen"
-
-msgid "branch to checkout after clone"
-msgstr "gren att checka ut efter kloning"
-
-msgid "when cloning, create full working directory"
-msgstr "skapa komplett arbetskatalog vid kloning"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "hämta endast metadata för grenen som skall checkas ut"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<flaggor>] [--] <arkiv> [<kat>]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "Kan inte härleda arbetsträdsnamn från \"%s\""
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "katalogen \"%s\" finns redan"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "misslyckades hämta standardgren för \"%s\""
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "kunde inte ställa in fjärr i \"%s\""
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "kunde inte ställa in \"%s\""
-
-msgid "partial clone failed; attempting full clone"
-msgstr "delvis klon misslyckades; försöker med fullständig klon"
-
-msgid "could not configure for full clone"
-msgstr "kunde inte ställa in för komplett klon"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<enrollering>]"
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "kunde inte skapa katalog för \"%s\""
-
-msgid "could not duplicate stdout"
-msgstr "kunde inte duplicera standard ut"
-
-msgid "failed to write archive"
-msgstr "misslyckades skriva arkiv"
-
-msgid "`scalar list` does not take arguments"
-msgstr "\"scalar list\" tar inte argument"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<enrollering>]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "konfigurera alla registrerade enrolleringar på nytt"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <enrollering>]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "--all eller <enrollering>, men inte bägge"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git-arkiv försvunnet i \"%s\""
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <uppgift> [<enrollering>]\n"
-"Uppgifter:\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "okänd uppgift: \"%s\""
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<enrollering>]"
-
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <enrollering>"
-
-msgid "refusing to delete current working directory"
-msgstr "vägrar ta bort aktuell arbetskatalog"
-
-msgid "include Git version"
-msgstr "ta med Git-version"
-
-msgid "include Git's build options"
-msgstr "ta med Gits byggflaggor"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "-C kräver en <katalog>"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "kunde inte byta till \"%s\""
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c kräver ett argument på formen <nyckel>=<värde>"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <katalog>] [-c <nyckel>=<värde>] <kommando> [<flaggor>]\n"
-"\n"
-"Kommandon:\n"
-
-#, c-format
-msgid "illegal crlf_action %d"
-msgstr "felaktig crlf_action %d"
-
-#, c-format
-msgid "CRLF would be replaced by LF in %s"
-msgstr "CRLF skulle ersättas av LF i %s"
-
-#, c-format
-msgid ""
-"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
-"touches it"
-msgstr ""
-"CRLF i arbetskopian av \"%s\" kommer ersättas med LF nästa gång Git rör den"
-
-#, c-format
-msgid "LF would be replaced by CRLF in %s"
-msgstr "LF skulle ersättas av CRLF i %s"
-
-#, c-format
-msgid ""
-"in the working copy of '%s', LF will be replaced by CRLF the next time Git "
-"touches it"
-msgstr ""
-"LF i arbetskopian av \"%s\" kommer ersättas med CRLF nästa gång Git rör den"
-
-#, c-format
-msgid "BOM is prohibited in '%s' if encoded as %s"
-msgstr "BOM är förbjudet i \"%s\" om kodat som %s"
+msgid "BOM is prohibited in '%s' if encoded as %s"
+msgstr "BOM är förbjudet i \"%s\" om kodat som %s"
 
 #, c-format
 msgid ""
@@ -14884,6 +14959,32 @@ msgstr "ö-regex från konfiguration har för många fångstgrupper (max=%d)"
 msgid "Marked %d islands, done.\n"
 msgstr "Markerade %d öar, klar.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "ogiltigt värde för --%s: \"%s\""
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "kunde inte arkivera saknad katalog \"%s\""
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "kunde inte öppna katalogen \"%s\""
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "hoppar över \"%s\", som varken är en fil eller en katalog"
+
+msgid "could not duplicate stdout"
+msgstr "kunde inte duplicera standard ut"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "kunde inte lägga till katalogen \"%s\" till arkiveraren"
+
+msgid "failed to write archive"
+msgstr "misslyckades skriva arkiv"
+
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base fungerar inte med intervall"
 
@@ -15490,6 +15591,9 @@ msgstr "git fetch-pack: förväntade ACK/NAK, fick \"%s\""
 msgid "unable to write to remote"
 msgstr "kunde inte skriva till fjärren"
 
+msgid "Server supports filter"
+msgstr "Servern stöder filter"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "ogiltig \"shallow\"-rad: %s"
@@ -15600,9 +15704,6 @@ msgstr "servern stöder inte algoritmen \"%s\""
 msgid "Server does not support shallow requests"
 msgstr "Servern stöder inte grunda förfrågningar"
 
-msgid "Server supports filter"
-msgstr "Servern stöder filter"
-
 msgid "unable to write request to remote"
 msgstr "kunde inte skriva anrop till fjärren"
 
@@ -15948,6 +16049,12 @@ msgstr "Lågnivåkommandon / synka arkiv"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Lågnivåkommandon / interna hjälpare"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "Arkiv-, kommando- och filgränssnitt tänkta för användare"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Filformat, protokoll och andra gränssnitt tänkta för utvecklare"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "git-kommandon tillgängliga i \"%s\""
@@ -15961,6 +16068,12 @@ msgstr "Dessa vanliga Git-kommandon används i olika situationer:"
 msgid "The Git concept guides are:"
 msgstr "Vägledningar för Git-koncept:"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Arkiv-, kommando- och filgränssnitt tänkta för användare:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Filformat, protokoll och andra utvecklargränssnitt:"
+
 msgid "External commands"
 msgstr "Externa kommandon"
 
@@ -16043,10 +16156,6 @@ msgstr ""
 "Kroken \"%s\" ignorerades eftersom den inte är markerad som körbar.\n"
 "Du kan inaktivera varningen med \"git config advice.ignoredHook false\"."
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "Kunde inte starta kroken \"%s\"\n"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr ""
@@ -16229,19 +16338,14 @@ msgstr "förväntade \"flush\" efter ls-refs-argument"
 msgid "quoted CRLF detected"
 msgstr "citerad CRLF upptäcktes"
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Dina lokala ändringar av följande filer skulle skrivas över av "
-"sammanslagning:\n"
-"  %s"
-
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "Misslyckades slå ihop undermodulen %s (ej utcheckad)"
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "Misslyckades slå ihop undermodulen %s (ingen sammanslagningsbas)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "Misslyckades slå ihop undermodulen %s (incheckningar saknas)"
@@ -16262,27 +16366,8 @@ msgstr "Misslyckades slå ihop undermodulen %s"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"Misslyckades slå ihop undermodulen %s, men en möjlig lösning finns:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"Om detta är riktigt lägger du bara till det i indexet, till\n"
-"exempel så här:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"vilket godtar lösningen.\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
+msgstr "Misslyckades slå ihop undermodulen %s, men en möjlig lösning finns: %s"
 
 #, c-format
 msgid ""
@@ -16360,7 +16445,7 @@ msgid ""
 "in %s, suggesting it should perhaps be moved to %s."
 msgstr ""
 "KONFLIKT (filplacering): %s lade till %s inuti en katalog som bytte namn i "
-"%s, föreslår att den bör flyttas till%s."
+"%s, föreslår att den bör flyttas till %s."
 
 #, c-format
 msgid ""
@@ -16443,13 +16528,45 @@ msgstr ""
 "KONFLIKT (ändra/radera): %s raderad i %s och ändrad i %s. Versionen %s av %s "
 "lämnad i trädet."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - gå till undermodulen (%s), och slå antingen ihop incheckningen %s\n"
+"   eller uppdatera till en befintlig incheckning som slagit ihop "
+"ändringarna\n"
+
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
 msgstr ""
-"Observera: %s är inte à jour och i vägen för att checka ut version i "
-"konflikt; gammal upplaga har nytt namn %s"
+"Rekursiv sammanslaning med undermoduler stöder för närvarande endast enkla "
+"fall.\n"
+"Du måste hantera sammanslagning av undermoduler i konflikt manuellt.\n"
+"Detta kan göras genom att utföra följande steg:\n"
+"%s - kom tillbaka till huvudprojektet och kör:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   för att registrera sammanslagningen över eller uppdatera\n"
+" - lös eventuella andra konflikter i huvudprojektet\n"
+" - checka in det slutförda indexet i huvudprojektet\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -16524,6 +16641,22 @@ msgstr "Misslyckades slå ihop undermodulen %s (ej snabbspolning)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "Hittade en möjlig lösning av sammanslagning för undermodulen:\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Om detta är riktigt lägger du bara till det i indexet, till\n"
+"exempel så här:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"vilket godtar lösningen.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr ""
@@ -17037,6 +17170,22 @@ msgstr "\"deflateend\" på objektet %s misslyckades (%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "förvirrad av instabil objektkälldata för %s"
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "skriv strömobjektet %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "kan inte utföra \"deflate\" på nytt strömobjekt (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "\"deflateend\" på strömobjektet misslyckades (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "kunde inte skapa katalogen %s"
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr "kan inte läsa objekt för %s"
@@ -17263,6 +17412,56 @@ msgstr "kunde inte tolka objektet: %s"
 msgid "hash mismatch %s"
 msgstr "hashvärde stämmer inte överens %s"
 
+msgid "trying to write commit not in index"
+msgstr "försöker skriva incheckning som inte finns i indexet"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "misslyckade läsa in bitkarteindex (trasigt?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "trasigt bitkarteindex (för litet)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "trasigt bitkarteindex (felaktigt huvud)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "versionen \"%d\" i bitkarteindexfilen stöds inte"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr "trasigt bitkarteindex (för kort för att få plats för hash-cache)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr "trasigt bitkarteindex (för kort för att få plats för uppslagstabell)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "duplicerad post i bitkarteindex: \"%s\""
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "trasig ewah-bitkarta: avhugget huvud för post %d"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "trasig ewah-bitkarta: incheckningsindex %u utanför intervall"
+
+msgid "corrupted bitmap pack index"
+msgstr "trasigt bitkarte-packindex"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "ogiltigt XOR-offset i bitkarte-packindex"
+
+msgid "cannot fstat bitmap file"
+msgstr "kan inte utföra \"fstat\" på bitkartefil"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "ignorerar extra bitkartefil: %s"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "checksumman stämmer inte i MIDX och bitkarta"
+
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "flerpaketsbitkarta saknar nödvändigt omvänt index"
 
@@ -17274,9 +17473,58 @@ msgstr "kunde inte öppna paketfilen %s"
 msgid "preferred pack (%s) is invalid"
 msgstr "föredragen paketfil (%s) är ogiltig"
 
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "trasig bitkarteuppslagstabell: trippelposition utanför indexet"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr "trasig bitkarteuppslagstabell: xor-kedja överskrider postantalet"
+
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "kunde inte hitta %s i paketet %s på offset %<PRIuMAX>"
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr ""
+"trasig bitkarteuppslagstabell: incheckningsindexet %u utanför intervallet"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr ""
+"trasig ewah-bitkarta: avhugget huvud för bitkarta för incheckning \"%s\""
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "objektet \"%s\" hittades inte i typbitkartor"
+
+#, c-format
+msgid "object '%s' does not have a unique type"
+msgstr "objektet \"%s\" har inte en unik typ"
+
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "objektet \"%s\": riktig typ \"%s\", förväntade \"%s\""
+
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "objekt saknas i bitkarta: %s"
+
+msgid "failed to load bitmap indexes"
+msgstr "misslyckade läsa in bitkarteindex"
+
+msgid "you must specify exactly one commit to test"
+msgstr "du måste ange exakt en incheckning att testa"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "incheckningen \"%s\" har inte en indexerad bitkarta"
+
+msgid "mismatch in bitmap results"
+msgstr "bitkarteresultat stämmer inte överens"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "kunde inte hitta \"%s\" i paketet \"%s\" på offset %<PRIuMAX>"
+
+#, c-format
+msgid "unable to get disk usage of '%s'"
+msgstr "kan inte hämta diskanvändning för \"%s\""
 
 #, c-format
 msgid "mtimes file %s is too small"
@@ -17401,6 +17649,9 @@ msgstr "menade du \"--%s\" (med två bindestreck)?"
 msgid "alias of --%s"
 msgstr "alias för --%s"
 
+msgid "need a subcommand"
+msgstr "behöver ett underkommando"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "okänd flagga \"%s\""
@@ -17834,9 +18085,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -17864,9 +18118,12 @@ msgstr ""
 "l, label <etikett> = ge aktuellt HEAD ett namn\n"
 "t, reset <etikett> = återställ HEAD till en etikett\n"
 "m, merge [-C <incheckning> | -c <incheckning>] <etikett> [# <enrads>]\n"
-".       skapa en sammanslagning med ursprungligt meddelande (eller\n"
-".       enrads, om inget incheckningsmeddelande angavs); använd\n"
-".       -c <incheckning> för att skriva om meddelandet.\n"
+"        skapa en sammanslagning med ursprungligt meddelande (eller\n"
+"        enrads, om inget incheckningsmeddelande angavs); använd\n"
+"        -c <incheckning> för att skriva om meddelandet.\n"
+"u, update-ref <ref> = spåra en platshållare för <ref> att uppdatera\n"
+"                      till denna position bland nya inchecknngar.\n"
+"                      <ref> uppdateras i slutet av ombaseringen.\n"
 "\n"
 "Du kan byta ordning på raderna; de utförs uppifrån och ned.\n"
 
@@ -18335,6 +18592,13 @@ msgstr "protokollfel: förväntade sha/ref, fick \"%s\""
 msgid "http transport does not support %s"
 msgstr "http-transporten stöder inte %s"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "protokollfel: förväntade \"<url> <sökväg>\", saknar blanksteg"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "misslyckades hämta filen på URL \"%s\""
+
 msgid "git-http-push failed"
 msgstr "git-http-push misslyckades"
 
@@ -18672,6 +18936,14 @@ msgstr "kunde inte bestämma HEAD-revision"
 msgid "failed to find tree of %s"
 msgstr "kunde inte hitta trädet för %s."
 
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo registrerar \"%s\" som saknas"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "kunde inte hämta incheckning för \"ancestry-path\"-argumentet %s"
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<paketfil> stöds inte längre"
 
@@ -18692,6 +18964,173 @@ msgstr "-L stöder ännu inte andra diff-format än -p och -s"
 msgid "cannot create async thread: %s"
 msgstr "kan inte skapa asynkron tråd: %s"
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "\"%s\" finns inte"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "kunde inte växla till \"%s\""
+
+msgid "need a working directory"
+msgstr "behöver en arbetskatalog"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Scalar-enrolleringar kräver en arbetskatalog"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "kunde inte ställa in %s=%s"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "kunde inte ställa in log.excludeDecoration"
+
+msgid "could not add enlistment"
+msgstr "kunde inte lägga till enrollering"
+
+msgid "could not set recommended config"
+msgstr "kan inte ange rekommenderad konfiguration"
+
+msgid "could not turn on maintenance"
+msgstr "kunde inte aktivera underhåll"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "kunde inte starta FSMonitor-server"
+
+msgid "could not turn off maintenance"
+msgstr "kunde inte slå av underhåll"
+
+msgid "could not remove enlistment"
+msgstr "kunde inte ta bort enrollering"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "HEAD hos fjärren är inte en gren: \"%.*s\""
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"misslyckades hämta namn på standardgren för fjärr; använder lokalt förval"
+
+msgid "failed to get default branch name"
+msgstr "misslyckades hämta namn på standardgren"
+
+msgid "failed to unregister repository"
+msgstr "misslyckades avregistrera arkivet"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "misslyckades stoppa FSMonitor-server"
+
+msgid "failed to delete enlistment directory"
+msgstr "misslyckades ta bort enrolleringskatalogen"
+
+msgid "branch to checkout after clone"
+msgstr "gren att checka ut efter kloning"
+
+msgid "when cloning, create full working directory"
+msgstr "skapa komplett arbetskatalog vid kloning"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "hämta endast metadata för grenen som skall checkas ut"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<flaggor>] [--] <arkiv> [<kat>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "Kan inte härleda arbetsträdsnamn från \"%s\""
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "katalogen \"%s\" finns redan"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "misslyckades hämta standardgren för \"%s\""
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "kunde inte ställa in fjärr i \"%s\""
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "kunde inte ställa in \"%s\""
+
+msgid "partial clone failed; attempting full clone"
+msgstr "delvis klon misslyckades; försöker med fullständig klon"
+
+msgid "could not configure for full clone"
+msgstr "kunde inte ställa in för komplett klon"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<enrollering>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "\"scalar list\" tar inte argument"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<enrollering>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "konfigurera alla registrerade enrolleringar på nytt"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <enrollering>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all eller <enrollering>, men inte bägge"
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "git-arkiv försvunnet i \"%s\""
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <uppgift> [<enrollering>]\n"
+"Uppgifter:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "okänd uppgift: \"%s\""
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<enrollering>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <enrollering>"
+
+msgid "refusing to delete current working directory"
+msgstr "vägrar ta bort aktuell arbetskatalog"
+
+msgid "include Git version"
+msgstr "ta med Git-version"
+
+msgid "include Git's build options"
+msgstr "ta med Gits byggflaggor"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C kräver en <katalog>"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "kunde inte byta till \"%s\""
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c kräver ett argument på formen <nyckel>=<värde>"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <katalog>] [-c <nyckel>=<värde>] <kommando> [<flaggor>]\n"
+"\n"
+"Kommandon:\n"
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr "oväntat flush-paket vid läsning av fjärruppackningsstatus"
 
@@ -18812,10 +19251,6 @@ msgstr "dina lokala ändringar skulle skrivas över av %s."
 msgid "commit your changes or stash them to proceed."
 msgstr "checka in dina ändringar eller använd \"stash\" för att fortsätta."
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: snabbspola"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -19302,6 +19737,27 @@ msgstr "kunde inte ens försöka slå ihop \"%.*s\""
 msgid "merge: Unable to write new index file"
 msgstr "sammanslagning: Kunde inte skriva ny indexfil"
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "en annan \"rebase\"-process verkar vara aktiv; \"%s.lock\" finns redan"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Uppdaterade följande referenser med %s:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Misslyckades uppdatera följande referenser med %s:\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "Kan inte utföra \"autostash\""
 
@@ -19467,6 +19923,10 @@ msgstr "kunde inte hoppa över onödiga \"pick\"-kommandon"
 msgid "the script was already rearranged."
 msgstr "skriptet har redan omordnats."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "update-refs-filen vid \"%s\" är ogiltig"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "\"%s\" är utanför arkivet på \"%s\""
@@ -19587,16 +20047,20 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"osäkert arkiv (\"%s\" ägs av någon annan)\n"
-"För att lägga till ett undantag för denna katalog, kör:\n"
+"upptäckte tveksamt ägarskap i arkivet i \"%s\"\n"
+"%sFör att lägga till ett undantag för denna katalog, kör:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "kan inte använda naket arkiv \"%s\" (safe.bareRepository är \"%s\")"
+
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -20467,6 +20931,18 @@ msgstr "felaktigt portnummer"
 msgid "invalid '..' path segment"
 msgstr "felaktigt \"..\"-sökvägssegment"
 
+msgid "usage: "
+msgstr "användning: "
+
+msgid "fatal: "
+msgstr "ödesdigert: "
+
+msgid "error: "
+msgstr "fel: "
+
+msgid "warning: "
+msgstr "varning: "
+
 msgid "Fetching objects"
 msgstr "Hämtar objekt"
 
@@ -21257,22 +21733,6 @@ msgstr "Markerade stycken kan inte appliceras på indexet!\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "ignorerar ej sammanslagen: %s\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "Applicera ändrat läge på arbetskatalogen [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Applicera borttagning på arbetskatalogen [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Applicera tillägg på arbetskatalogen [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "Applicera stycket på arbetskatalogen [y,n,q,a,d%s,?]? "
-
 msgid "No other hunks to goto\n"
 msgstr "Inga andra stycken att gå till\n"
 
index 1e1d0318fd98ed2fe7d27341150f4e692bc1df73..484e0acf2d27435deb14cf29aa0fca78b43a7d6e 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -74,6 +74,7 @@
 # string                      | dizi                        #
 # subdirectory                | altdizin                    #
 # submodule                   | altmodül                    #
+# superproject                | üst proje                   #
 # symlink                     | sembolik bağ                #
 # symref                      | sembolik başvuru            #
 # tag                         | etiket                      #
@@ -91,8 +92,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git Turkish Localization Project\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-22 12:46+0300\n"
-"PO-Revision-Date: 2022-06-22 16:00+0300\n"
+"POT-Creation-Date: 2022-09-28 10:54+0300\n"
+"PO-Revision-Date: 2022-09-28 14:00+0300\n"
 "Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
 "Language-Team: Turkish (https://github.com/bitigchi/git-po/)\n"
 "Language: tr\n"
@@ -494,6 +495,22 @@ msgstr ""
 "a - bu parçayı ve sonraki tüm parçaları uygula\n"
 "d - bu parçayı veya sonraki parçalardan herhangi birini uygulama\n"
 
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "Kip değişimi çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "Silme çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "Ekleme çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
+
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "Bu parça çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
+
 msgid ""
 "y - apply this hunk to worktree\n"
 "n - do not apply this hunk to worktree\n"
@@ -511,10 +528,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "parça üstbilgisi '%.*s' ayrıştırılamadı"
 
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "renklendirilmiş parça üstbilgisi '%.*s' ayrıştırılamadı"
-
 msgid "could not parse diff"
 msgstr "diff ayrıştırılamadı"
 
@@ -730,7 +743,7 @@ msgid "Exiting because of an unresolved conflict."
 msgstr "Çözüme kavuşturulmamış bir çakışmadan dolayı çıkılıyor."
 
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
-msgstr "Birleştirmenizi sonuçlandırmadınız (MERGE_HEAD mevcut)."
+msgstr "Birleştirmenizi sonuçlandırmadınız (MERGE_HEAD var)."
 
 msgid "Please, commit your changes before merging."
 msgstr "Birleştirme öncesinde değişikliklerinizi işleyin."
@@ -801,6 +814,26 @@ msgstr ""
 "kapatabilirsiniz.\n"
 "\n"
 
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"Aşağıdaki yollar, aralıklı çıkış tanımının dışına\n"
+"taşındı; ancak yerel değişikliklerden dolayı\n"
+"aralıklı değiller.\n"
+
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"Bu yollardaki aralıklılığı düzeltmek için aşağıdakini yapın:\n"
+"* İndeksi güncellemek için \"git add --sparse <yollar>\" kullanın\n"
+"* Aralıklılık kurallarını uygulamak için \"git sparse-checkout reapply\" "
+"yapın"
+
 msgid "cmdline ends with \\"
 msgstr "komut satırı \\ ile bitiyor"
 
@@ -1297,6 +1330,10 @@ msgstr "%s ikili nesnesi akıtılamıyor"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "desteklenmeyen dosya kipi: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "söndürme hatası (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "'%s' süzgeci başlatılamıyor"
@@ -1316,10 +1353,6 @@ msgstr "yol geçerli UTF-8 değil: %s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "yol çok uzun (%d karakter, SHA1: %s): %s"
 
-#, c-format
-msgid "deflate error (%d)"
-msgstr "söndürme hatası (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "zaman damgası bu sistem için çok büyük: %<PRIuMAX>"
@@ -1696,7 +1729,7 @@ msgstr "izleme bilgisi ayarlanamıyor; başlangıç noktası '%s' bir dal değil
 
 #, c-format
 msgid "the requested upstream branch '%s' does not exist"
-msgstr "istenen üstkaynak dalı '%s' mevcut değil"
+msgstr "istenen üstkaynak dalı '%s' yok"
 
 msgid ""
 "\n"
@@ -1739,7 +1772,7 @@ msgid ""
 "update --init'"
 msgstr ""
 "Altmodülleri güncellemeyi 'git checkout %s && git submodule update --init' "
-"kullanarak deneyebilirsiniz."
+"kullanarak deneyebilirsiniz"
 
 #, c-format
 msgid "submodule '%s': cannot create branch '%s'"
@@ -1893,7 +1926,7 @@ msgid ""
 msgstr ""
 "Gerçekten eklemek istiyorsanız -f kullanın.\n"
 "Bu iletiyi 'git config advice.addIgnoredFile false'\n"
-"kullanarak kapatabilirsiniz."
+"yaparak kapatabilirsiniz"
 
 msgid "adding files failed"
 msgstr "dosya ekleme başarısız"
@@ -1917,10 +1950,10 @@ msgid ""
 msgstr ""
 "'git add .' mı demek istediniz?\n"
 "Bu iletiyi 'git config advice.addEmptyPathspec false'\n"
-"yaparak kapatabilirsiniz."
+"yaparak kapatabilirsiniz"
 
 msgid "index file corrupt"
-msgstr "indeks dosyası hasar görmüş"
+msgstr "indeks dosyası hasar"
 
 #, c-format
 msgid "bad action '%s' for '%s'"
@@ -2145,7 +2178,7 @@ msgid ""
 "Not rewinding to ORIG_HEAD"
 msgstr ""
 "Son 'am' başarısızlığından bu yana HEAD'i hareket ettirmiş görünüyorsunuz.\n"
-"ORIG_HEAD'e geri sarılmıyor."
+"ORIG_HEAD'e geri sarılmıyor"
 
 #, c-format
 msgid "failed to read '%s'"
@@ -2250,7 +2283,7 @@ msgid "GPG-sign commits"
 msgstr "GPG imzalı işlemeler"
 
 msgid "how to handle empty patches"
-msgstr "boş yamaların nasıl değerlendirileceği"
+msgstr "boş yamaların nasıl ele alınacağı"
 
 msgid "(internal use for git-rebase)"
 msgstr "(git-rebase için iç kullanım)"
@@ -2268,7 +2301,7 @@ msgstr "indeks okunamadı"
 #, c-format
 msgid "previous rebase directory %s still exists but mbox given."
 msgstr ""
-"Bir önceki yeniden temellendirme dizini %s hâlâ mevcut; ancak mbox verildi."
+"Bir önceki yeniden temellendirme dizini %s hâlâ var; ancak mbox verildi."
 
 #, c-format
 msgid ""
@@ -2806,11 +2839,11 @@ msgid "cannot use -a with -d"
 msgstr "-a, -d ile kullanılamıyor"
 
 msgid "Couldn't look up commit object for HEAD"
-msgstr "HEAD için işleme nesnesi aranamadı."
+msgstr "HEAD için işleme nesnesi aranamadı"
 
 #, c-format
 msgid "Cannot delete branch '%s' checked out at '%s'"
-msgstr "'%s' dalı silinemiyor, şurada çıkış yapılmış: '%s'."
+msgstr "'%s' dalı silinemiyor, şurada çıkış yapılmış: '%s'"
 
 #, c-format
 msgid "remote-tracking branch '%s' not found."
@@ -3044,7 +3077,7 @@ msgstr "'%s' diye bir dal yok"
 
 #, c-format
 msgid "branch '%s' does not exist"
-msgstr "'%s' diye bir dal mevcut değil"
+msgstr "'%s' diye bir dal yok"
 
 msgid "too many arguments to unset upstream"
 msgstr "üst kaynağı kaldırmak için çok fazla argüman"
@@ -3087,8 +3120,12 @@ msgstr "libc bilgisi: "
 msgid "not run from a git repository - no hooks to show\n"
 msgstr "bir git deposundan çalıştırılmadı - gösterilecek kanca yok\n"
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <dosya>] [-s|--suffix <biçim>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <dosya>] [-s|--suffix <biçim>] [--"
+"diagnose[=<kip>]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3124,16 +3161,27 @@ msgstr ""
 "Aşağıda hata raporunun geri kalanına bir göz atın.\n"
 "Paylaşmak istemediğiniz satırları silebilirsiniz.\n"
 
-msgid "specify a destination for the bugreport file"
-msgstr "hata raporu dosyası için bir konum belirtin"
+msgid "mode"
+msgstr "kip"
 
-msgid "specify a strftime format suffix for the filename"
-msgstr "dosya adı için bir strftime biçimli ek belirtin"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr "ayrıntılı tanıların ek bir zip arşivini oluştur (öntanımlı: 'stats')"
+
+msgid "specify a destination for the bugreport file(s)"
+msgstr "hata raporu dosyaları için bir hedef konum belirtin"
+
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "dosya adları için bir strftime biçim soneki belirtin"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "'%s' için öncü dizinler oluşturulamadı"
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "tanı arşivi %s oluşturulamadı"
+
 msgid "System Info"
 msgstr "Sistem Bilgisi"
 
@@ -3191,10 +3239,6 @@ msgstr "Demeti çözmek için bir depo gerekiyor."
 msgid "Unbundling objects"
 msgstr "Nesneler demetten çıkarılıyor"
 
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "Bilinmeyen altkomut: %s"
-
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "%s '%s' nesnesi okunamıyor"
@@ -3270,7 +3314,10 @@ msgid "show object size"
 msgstr "nesne boyutunu göster"
 
 msgid "allow -s and -t to work with broken/corrupt objects"
-msgstr "-s ve -t'nin bozuk/hasar görmüş nesnelerle çalışmasına izin ver"
+msgstr "-s ve -t'nin bozuk/hasarlı nesnelerle çalışmasına izin ver"
+
+msgid "use mail map file"
+msgstr "posta eşlem dosyasını kullan"
 
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "Toplu iş nesneleri stdin'de istendi (veya --batch-all-objects)"
@@ -3281,6 +3328,9 @@ msgstr "tam <nesne> veya <revizyon> içeriğini göster"
 msgid "like --batch, but don't emit <contents>"
 msgstr "--batch gibi; ancak <içerik> yayma"
 
+msgid "stdin is NUL-terminated"
+msgstr "stdin, NUL ile sonlandırılmış"
+
 msgid "read commands from stdin"
 msgstr "komutları stdin'den oku"
 
@@ -3433,10 +3483,10 @@ msgid "do not skip files with skip-worktree set"
 msgstr "skip-worktree kümesiyle dosyaları atlama"
 
 msgid "force overwrite of existing files"
-msgstr "mevcut dosyaların üzerine yazılmasını zorla"
+msgstr "var olan dosyaların üzerine yazılmasını zorla"
 
 msgid "no warning for existing files and files not in index"
-msgstr "mevcut dosyalar ve indekste olmayan dosyalar için uyarma"
+msgstr "var olan dosyalar ve indekste olmayan dosyalar için uyarma"
 
 msgid "don't checkout new files"
 msgstr "yeni dosyaları çıkış yapma"
@@ -3639,7 +3689,7 @@ msgid ""
 "Please use -- (and optionally --no-guess) to disambiguate"
 msgstr ""
 "'%s' hem bir yerel dosya hem de bir izleme dalı olabilir.\n"
-"Lütfen -- (ve isteğe bağlı olarak --no-guess) kullanıp belirsizliği giderin."
+"-- (ve isteğe bağlı olarak --no-guess) kullanıp belirsizliği giderin"
 
 msgid ""
 "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
@@ -4150,6 +4200,12 @@ msgstr ""
 "sparse-checkout dosyasını yalnızca kökteki dosyaları içerecek biçimde "
 "ilklendir"
 
+msgid "uri"
+msgstr "uri"
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "uzak konum kökeninden getirmeden önce demetleri indirmek için bir URI"
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "info: '%s' için alternatif eklenemedi: %s\n"
@@ -4209,9 +4265,8 @@ msgstr "%s güncellenemiyor"
 msgid "failed to initialize sparse-checkout"
 msgstr "sparse-checkout ilklendirilemedi"
 
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr ""
-"uzak konum HEAD'i var olmayan başvuruya bağlanıyor, çıkış yapılamıyor.\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "uzak konum HEAD'i, var olmayan başvuruya başvuruyor; çıkış yapılamıyor"
 
 msgid "unable to checkout working tree"
 msgstr "çalışma ağacı çıkış yapılamıyor"
@@ -4235,9 +4290,15 @@ msgstr "Klonlamak için bir depo belirtmelisiniz."
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "'%s' ve '%s %s' seçenekleri birlikte kullanılamaz"
 
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr ""
+"--bundle-uri; --depth, --shallow-since ve --shallow-exclude ile uyumsuz"
+
 #, c-format
 msgid "repository '%s' does not exist"
-msgstr "'%s' deposu mevcut değil"
+msgstr "'%s' deposu yok"
 
 #, c-format
 msgid "depth %s is not a positive number"
@@ -4245,15 +4306,15 @@ msgstr "%s derinliği pozitif bir sayı değil"
 
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
-msgstr "Hedef yolu '%s' halihazırda mevcut ve boş bir dizin değil."
+msgstr "Hedef yolu '%s' halihazırda var ve boş bir dizin değil."
 
 #, c-format
 msgid "repository path '%s' already exists and is not an empty directory."
-msgstr "Depo yolu '%s' halihazırda mevcut ve boş bir dizin değil."
+msgstr "Depo yolu '%s' halihazırda var ve boş bir dizin değil."
 
 #, c-format
 msgid "working tree '%s' already exists."
-msgstr "Çalışma ağacı '%s' halihazırda mevcut."
+msgstr "Çalışma ağacı '%s' halihazırda var."
 
 #, c-format
 msgid "could not create leading directories of '%s'"
@@ -4306,6 +4367,13 @@ msgstr "--local yok sayıldı"
 msgid "cannot clone from filtered bundle"
 msgstr "süzülmüş demetten klonlanamıyor"
 
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "depo ilklendirilemedi, demet URI'si atlanıyor"
+
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "'%s' demet URI'sinden nesneler getirilemedi"
+
 msgid "remote transport reported error"
 msgstr "uzak konum taşıması hata bildirdi"
 
@@ -4423,10 +4491,6 @@ msgstr ""
 msgid "Collecting commits from input"
 msgstr "Girdiden işlemeler toplanıyor"
 
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "tanımlanamayan altkomut: %s"
-
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
 "<file>)...] <tree>"
@@ -4584,7 +4648,7 @@ msgid ""
 "unable to select a comment character that is not used\n"
 "in the current commit message"
 msgstr ""
-"mevcut işleme iletisinde kullanılmayan bir yorum\n"
+"geçerli işleme iletisinde kullanılmayan bir yorum\n"
 "karakteri seçilemiyor"
 
 #, c-format
@@ -4707,7 +4771,7 @@ msgstr "Lütfen iletiyi -m veya -F seçeneğini kullanarak destekleyin.\n"
 #, c-format
 msgid "--author '%s' is not 'Name <email>' and matches no existing author"
 msgstr ""
-"--author '%s', 'Ad <e-posta>' biçiminde değil ve mevcut bir yazarla "
+"--author '%s', 'Ad <e-posta>' biçiminde değil ve var olan bir yazarla "
 "eşleşmiyor"
 
 #, c-format
@@ -4782,9 +4846,6 @@ msgstr "durumu uzun biçimde göster (öntanımlı)"
 msgid "terminate entries with NUL"
 msgstr "girdileri NUL ile sonlandır"
 
-msgid "mode"
-msgstr "kip"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "izlenmeyen dosyaları göster, ist. bağlı kipler: all, normal, no (Öntanım.: "
@@ -4795,7 +4856,7 @@ msgid ""
 "traditional)"
 msgstr ""
 "yok sayılan dosyaları göster, isteğe bağlı kipler: traditional (geleneksel) "
-"matching (eşleşen), no (hayır) (Öntanımlı: traditional)."
+"matching (eşleşen), no (hayır) (Öntanımlı: traditional)"
 
 msgid "when"
 msgstr "ne zaman"
@@ -4805,7 +4866,7 @@ msgid ""
 "(Default: all)"
 msgstr ""
 "altmodüllere olan değişiklikleri yok say, isteğe bağlı ne zaman: all "
-"(hepsi), dirty (kirli), untracked (izlenmeyen) (Öntanımlı: all)."
+"(hepsi), dirty (kirli), untracked (izlenmeyen) (Öntanımlı: all)"
 
 msgid "list untracked files in columns"
 msgstr "izlenmeyen dosyaları sütunlarla göster"
@@ -5173,7 +5234,7 @@ msgid ""
 msgstr ""
 "--worktree, worktreeConfig yapılandırma genişletmesi etkinleştirilmediği\n"
 "sürece birden çok çalışma ağacı ile birlikte kullanılamaz. Ayrıntılar için\n"
-"lütfen \"git help worktree\" içindeki \"CONFIGURATION FILE\" bölümünü okuyun."
+"lütfen \"git help worktree\" içindeki \"CONFIGURATION FILE\" bölümünü okuyun"
 
 msgid "--get-color and variable type are incoherent"
 msgstr "--get-color ve değişken türü tutarsız"
@@ -5272,7 +5333,7 @@ msgstr "ek açıklamalı"
 
 #, c-format
 msgid "annotated tag %s not available"
-msgstr "%s ek açıklamalı etiketi mevcut değil"
+msgstr "ek açıklamalı etiket %s kullanılamıyor"
 
 #, c-format
 msgid "tag '%s' is externally known as '%s'"
@@ -5380,6 +5441,22 @@ msgstr "Hiçbir ad bulunamadı, hiçbir şey betimlenemiyor."
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "'%s' seçeneği ve işlememsiler birlikte kullanılamaz"
 
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <yol>] [-s|--suffix <biçim>] [--"
+"mode=<kip>]"
+
+msgid "specify a destination for the diagnostics archive"
+msgstr "tanı arşivi için bir hedef konum belirtin"
+
+msgid "specify a strftime format suffix for the filename"
+msgstr "dosya adı için bir strftime biçimli ek belirtin"
+
+msgid "specify the content of the diagnostic archive"
+msgstr "tanı arşivinin içeriğini belirtin"
+
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base yalnızca iki işleme ile kullanılabilir"
 
@@ -5400,7 +5477,7 @@ msgstr "Bir git deposu değil"
 
 #, c-format
 msgid "invalid object '%s' given."
-msgstr "geçersiz nesne '%s' verildi"
+msgstr "geçersiz nesne '%s' verildi."
 
 #, c-format
 msgid "more than two blobs given: '%s'"
@@ -5408,7 +5485,7 @@ msgstr "ikiden çok ikili nesne verildi: '%s'"
 
 #, c-format
 msgid "unhandled object '%s' given."
-msgstr "ele alınmayan nesne '%s' verildi"
+msgstr "ele alınmayan nesne '%s' verildi."
 
 #, c-format
 msgid "%s...%s: multiple merge bases, using %s"
@@ -5758,11 +5835,8 @@ msgstr "[güncel]"
 msgid "[rejected]"
 msgstr "[reddedildi]"
 
-msgid "can't fetch in current branch"
-msgstr "geçerli dalda getirme yapılamıyor"
-
-msgid "checked out in another worktree"
-msgstr "başka bir çalışma ağacında çıkış yapıldı"
+msgid "can't fetch into checked-out branch"
+msgstr "çıkış yapılmış dala getirilemiyor"
 
 msgid "[tag update]"
 msgstr "[etiket güncellemesi]"
@@ -5797,9 +5871,9 @@ msgid ""
 "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
 "flag or run 'git config fetch.showForcedUpdates true'"
 msgstr ""
-"Getirme normalde hangi dallarda zorla güncelleme yapıldığını belirtir;\n"
-"ancak bu denetleme kapatılmış. Yeniden açmak için '--show-forced-updates'\n"
-"bayrağını kullanın veya 'git config fetch.showForcedUpdates true' çalıştırın."
+"Getirme, normalde hangi dallarda zorla güncelleme yapıldığını belirtir;\n"
+"ancak bu denetleme kapatılmış; yeniden açmak için '--show-forced-updates'\n"
+"bayrağını kullanın veya 'git config fetch.showForcedUpdates true' çalıştırın"
 
 #, c-format
 msgid ""
@@ -5891,8 +5965,8 @@ msgid ""
 "no source branch found;\n"
 "you need to specify exactly one branch with the --set-upstream option"
 msgstr ""
-"Kaynak dal bulunamadı.\n"
-"--set-upstream seçeneği ile tam olarak bir dal belirtmeniz gerekiyor."
+"Kaynak dal bulunamadı;\n"
+"--set-upstream seçeneği ile tam olarak bir dal belirtmeniz gerekiyor"
 
 #, c-format
 msgid "Fetching %s\n"
@@ -5910,8 +5984,8 @@ msgid ""
 "no remote repository specified; please specify either a URL or a\n"
 "remote name from which new revisions should be fetched"
 msgstr ""
-"Bir uzak dal belirtilmedi. Lütfen yeni revizyonların\n"
-"getirileceği bir URL veya uzak konum adı belirtin."
+"Bir uzak dal belirtilmedi; lütfen yeni revizyonların\n"
+"getirileceği bir URL veya uzak konum adı belirtin"
 
 msgid "you need to specify a tag name"
 msgstr "bir etiket adı belirtmeniz gerekiyor"
@@ -5949,8 +6023,8 @@ msgid ""
 "--filter can only be used with the remote configured in extensions."
 "partialclone"
 msgstr ""
-"--filter yalnızca extensions.partialclone içinde yapılandırılmış uzak konum "
-"ile kullanılabilir."
+"--filter, yalnızca extensions.partialclone içinde yapılandırılmış uzak konum "
+"ile kullanılabilir"
 
 msgid "--atomic can only be used when fetching from one remote"
 msgstr "--atomic yalnızca bir uzak konumdan getirirken kullanılabilir"
@@ -6118,7 +6192,7 @@ msgstr "%s %s (%s) şurada etiketlendi: %s"
 
 #, c-format
 msgid "%s: object corrupt or missing"
-msgstr "%s: nesne hasar görmüş veya kayıp"
+msgstr "%s: nesne hasar veya kayıp"
 
 #, c-format
 msgid "%s: invalid reflog entry %s"
@@ -6145,7 +6219,7 @@ msgstr "%s: sağlama yolu uyuşmazlığı, şurada bulundu: %s"
 
 #, c-format
 msgid "%s: object corrupt or missing: %s"
-msgstr "%s: nesne hasar görmüş veya kayıp: %s"
+msgstr "%s: nesne hasar veya kayıp: %s"
 
 #, c-format
 msgid "%s: object is of unknown type '%s': %s"
@@ -6195,6 +6269,10 @@ msgstr "%s: cache-tree içinde geçersiz sha1 işaretçisi"
 msgid "non-tree in cache-tree"
 msgstr "cache-tree içinde ağaç olmayan öge"
 
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s: resolve-undo içinde geçersiz sha1 işaretçisi"
+
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<seçenekler>] [<nesne>...]"
 
@@ -6337,7 +6415,7 @@ msgstr "geçersiz 'ipc-threads' değeri (%d)"
 
 #, c-format
 msgid "Unhandled subcommand '%s'"
-msgstr "İşlenmemiş altkomut '%s'"
+msgstr "Ele alınmamış altkomut '%s'"
 
 msgid "fsmonitor--daemon not supported on this platform"
 msgstr "fsmonitor--daemon bu platformda desteklenmiyor"
@@ -6461,7 +6539,7 @@ msgstr ""
 
 #, c-format
 msgid "lock file '%s' exists, skipping maintenance"
-msgstr "kilit dosyası '%s' mevcut, bakım atlanıyor"
+msgstr "kilit dosyası '%s' var, bakım atlanıyor"
 
 #, c-format
 msgid "task '%s' failed"
@@ -6523,12 +6601,15 @@ msgstr "schtasks başlatılamadı"
 msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr "'crontab -l' çalıştırılamadı; sisteminiz 'cron' desteklemiyor olabilir"
 
+msgid "failed to create crontab temporary file"
+msgstr "crontab geçici dosyası oluşturulamadı"
+
+msgid "failed to open temporary file"
+msgstr "geçici dosya açılamadı"
+
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr "'crontab' çalıştırılamadı; sisteminiz 'cron' desteklemiyor olabilir"
 
-msgid "failed to open stdin of 'crontab'"
-msgstr "'crontab' stdin'i açılamadı"
-
 msgid "'crontab' died"
 msgstr "'crontab' beklenmedik bir biçimde sonlandı"
 
@@ -6551,11 +6632,11 @@ msgid "unrecognized --scheduler argument '%s'"
 msgstr "tanımlanamayan --scheduler argümanı, '%s'"
 
 msgid "neither systemd timers nor crontab are available"
-msgstr "ne systemd zamanlayıcıları ne de crontab mevcut değil"
+msgstr "ne systemd zamanlayıcıları ne de crontab kullanılabiliyor"
 
 #, c-format
 msgid "%s scheduler is not available"
-msgstr "%s planlayıcısı mevcut değil"
+msgstr "%s planlayıcısı kullanılamıyor"
 
 msgid "another process is scheduling background maintenance"
 msgstr "başka bir işlem arka plan bakımı zamanını planlıyor"
@@ -6575,10 +6656,6 @@ msgstr "depo, global yapılandırmaya eklenemedi"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <altkomut> [<seçenekler>]"
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "geçersiz altkomut: %s"
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<seçenekler>] [-e] <dizgi> [<rev>...] [[--] <yol>...]"
 
@@ -6750,6 +6827,9 @@ msgstr "sayfalayıcıda eşleşen dosyaları göster"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "grep(1)'in çağrılmasına izin ver (bu yapım tarafından yok sayıldı)"
 
+msgid "maximum number of results per file"
+msgstr "dosya başına en çok sonuç sayısı"
+
 msgid "no pattern given"
 msgstr "bir dizgi verilmedi"
 
@@ -6837,11 +6917,21 @@ msgstr "komut açıklamasını yazdır"
 msgid "print list of useful guides"
 msgstr "kullanışlı kılavuzların listesini çıkar"
 
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr ""
+"kullanıcıya görünür depolar, komutlar ve dosya arayüzlerinin bir listesini "
+"yazdır"
+
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr ""
+"dosya biçimleri, protokoller ve diğer geliştirici arayüzlerinin bir "
+"listesini yazdır"
+
 msgid "print all configuration variable names"
 msgstr "tüm yapılandırma değişkenleri adlarını yazdır"
 
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<komutlar>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<komut>|<belge>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
@@ -6998,11 +7088,11 @@ msgstr "%s okunamıyor"
 
 #, c-format
 msgid "cannot read existing object info %s"
-msgstr "mevcut %s nesne bilgisi okunamıyor"
+msgstr "var olan nesne bilgisi %s okunamıyor"
 
 #, c-format
 msgid "cannot read existing object %s"
-msgstr "mevcut %s nesnesi okunamıyor"
+msgstr "var olan nesne %s okunamıyor"
 
 #, c-format
 msgid "invalid blob object %s"
@@ -7025,7 +7115,7 @@ msgid "Indexing objects"
 msgstr "Nesneler indeksleniyor"
 
 msgid "pack is corrupted (SHA1 mismatch)"
-msgstr "paket hasar görmüş (SHA1 uyumsuzluğu)"
+msgstr "paket hasar (SHA1 uyumsuzluğu)"
 
 msgid "cannot fstat packfile"
 msgstr "paket dosyası fstat yapılamıyor"
@@ -7099,7 +7189,7 @@ msgstr "Mevcut paket dosyası '%s' açılamıyor"
 
 #, c-format
 msgid "Cannot open existing pack idx file for '%s'"
-msgstr "'%s' için mevcut paket idx dosyası açılamıyor"
+msgstr "'%s' için var olan paket idx dosyası açılamıyor"
 
 #, c-format
 msgid "non delta: %d object"
@@ -7190,11 +7280,11 @@ msgstr "re-init: --initial-branch=%s yok sayıldı"
 
 #, c-format
 msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "%s%s içindeki mevcut paylaşılan Git deposu yeniden ilklendirildi\n"
+msgstr "%s%s içindeki var olan paylaşılan Git deposu yeniden ilklendirildi\n"
 
 #, c-format
 msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "%s%s içindeki mevcut Git deposu yeniden ilklendirildi\n"
+msgstr "%s%s içindeki var olan Git deposu yeniden ilklendirildi\n"
 
 #, c-format
 msgid "Initialized empty shared Git repository in %s%s\n"
@@ -7311,8 +7401,8 @@ msgstr "diff çıktısını gizle"
 msgid "show source"
 msgstr "kaynağı göster"
 
-msgid "use mail map file"
-msgstr "posta eşlem dosyasını kullan"
+msgid "clear all previously-defined decoration filters"
+msgstr "tüm önceden tanımlanmış süsleme süzgeçlerini temizle"
 
 msgid "only decorate refs that match <pattern>"
 msgstr "yalnızca <dizgi> ile eşleşen başvuruları süsle"
@@ -7408,7 +7498,7 @@ msgstr ""
 "Üstkaynak alınamadı; taban işlemesinin kaydını kendiliğinden yazmak\n"
 "istiyorsanız lütfen git branch --set-upstream-to kullanarak bir uzak dalı\n"
 "izleyin. Bunun dışında taban işlemesini kendiniz --base=<taban-işlemesi-no>\n"
-"kullanarak el ile belirtebilirsiniz."
+"kullanarak el ile belirtebilirsiniz"
 
 msgid "failed to find exact merge base"
 msgstr "kesin birleştirme temeli bulunamadı"
@@ -7566,6 +7656,9 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr "oluşumun tartıldığı yüzde"
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "e-posta üstbilgisinin aynısı dahi olsa gövde için From:'u göster"
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "geçersiz tanımlayıcı satırı: %s"
@@ -7624,6 +7717,18 @@ msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "İzlenen bir uzak dal bulunamadı, lütfen el ile <üstkaynak> belirtin.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "hatalı ls-files biçimi: '%s' ögesi, '(' ile başlamıyor"
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "hatalı ls-files biçimi: '%s' ögesi, ')' ile sonlanmıyor"
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "hatalı ls-files biçimi: %%%.*s"
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<seçenekler>] [<dosya>...]"
 
@@ -7708,6 +7813,13 @@ msgstr "yinelenen girdileri sustur"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "bir aralıklı indeks bulunurluğunda aralıklı dizinleri göster"
 
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format; -s, -o, -k, -t, --resolve-undo, --deduplicate, --eol ile birlikte "
+"kullanılamaz"
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
 "              [-q | --quiet] [--exit-code] [--get-url]\n"
@@ -7926,6 +8038,39 @@ msgstr "'%s' başvurusu çözülemedi"
 msgid "Merging %s with %s\n"
 msgstr "%s, %s ile birleştiriliyor\n"
 
+msgid "not something we can merge"
+msgstr "birleştirebileceğimiz bir şey değil"
+
+msgid "refusing to merge unrelated histories"
+msgstr "birbiriyle ilişkisi olmayan geçmişleri birleştirme reddediliyor"
+
+msgid "failure to merge"
+msgstr "birleştirilemedi"
+
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<seçenekler>] <dal1> <dal2>"
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <taban-ağaç> <dal1> <dal2>"
+
+msgid "do a real merge instead of a trivial merge"
+msgstr "bir önemsiz birleştirme yerine gerçek bir birleştirme yap"
+
+msgid "do a trivial merge only"
+msgstr "yalnızca bir önemsiz birleştirme yap"
+
+msgid "also show informational/conflict messages"
+msgstr "ayrıcı bilgi/çakışma iletilerini göster"
+
+msgid "list filenames without modes/oids/stages"
+msgstr "kipi/oid'si/hazırlığı olmayan dosya adlarını listele"
+
+msgid "allow merging unrelated histories"
+msgstr "birbiriyle ilişkisi olmayan geçmişlerin birleştirilmesine izin ver"
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge, tüm diğer seçeneklerle uyumsuz"
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<seçenekler>] [<işleme>...]"
 
@@ -8007,9 +8152,6 @@ msgstr "--abort; ancak indeksi ve çalışma ağacını değiştirmeden bırakı
 msgid "continue the current in-progress merge"
 msgstr "ilerlemekte olan geçerli birleştirmeyi sürdürün"
 
-msgid "allow merging unrelated histories"
-msgstr "birbiriyle ilişkisi olmayan geçmişlerin birleştirilmesine izin ver"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "pre-merge-commit ve commit-msg kancalarını atla"
 
@@ -8027,7 +8169,7 @@ msgid "read-tree failed"
 msgstr "read-tree başarısız oldu"
 
 msgid "Already up to date. (nothing to squash)"
-msgstr "Tümü güncel (tıkıştırılacak bir şey yok)."
+msgstr "Tümü güncel (tıkıştırılacak bir şey yok)"
 
 msgid "Already up to date."
 msgstr "Tümü güncel."
@@ -8126,9 +8268,6 @@ msgstr "'%s' kapatılamadı"
 msgid "not something we can merge in %s: %s"
 msgstr "%s içinde birleştirebileceğimiz bir şey değil: %s"
 
-msgid "not something we can merge"
-msgstr "birleştirebileceğimiz bir şey değil"
-
 msgid "--abort expects no arguments"
 msgstr "--abort bir argüman beklemez"
 
@@ -8148,18 +8287,18 @@ msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you merge."
 msgstr ""
-"Birleştirmenizi sonuçlandırmadınız (MERGE_HEAD mevcut).\n"
+"Birleştirmenizi sonuçlandırmadınız (MERGE_HEAD var).\n"
 "Lütfen birleştirmeden önce değişikliklerinizi işleyin."
 
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you merge."
 msgstr ""
-"Seç-al'ınızı sonuçlandırmadınız (CHERRY_PICK_HEAD mevcut).\n"
+"Seç-al'ınızı sonuçlandırmadınız (CHERRY_PICK_HEAD var).\n"
 "Lütfen birleştirmeden önce değişikliklerinizi işleyin."
 
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
-msgstr "Seç-al'ınızı sonuçlandırmadınız (CHERRY_PICK_HEAD mevcut)."
+msgstr "Seç-al'ınızı sonuçlandırmadınız (CHERRY_PICK_HEAD var)."
 
 msgid "No commit specified and merge.defaultToUpstream not set."
 msgstr "Belirtilen bir işleme yok ve merge.defaultToUpstream ayarlanmamış."
@@ -8178,13 +8317,18 @@ msgstr "%s - birleştirebileceğimiz bir şey değil"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "Boş dal ucuna tam olarak yalnızca bir işleme birleştirilebilir"
 
-msgid "refusing to merge unrelated histories"
-msgstr "birbiriyle ilişkisi olmayan geçmişleri birleştirme reddediliyor"
-
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Güncelleniyor: %s..%s\n"
 
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"Birleştirme ile aşağıdaki yerel değişikliklerin üzerine yazılacak:\n"
+"\t%s"
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Gerçekten önemsiz indeks içi birleştirme deneniyor...\n"
@@ -8203,7 +8347,7 @@ msgstr "%s birleştirme stratejisi deneniyor...\n"
 
 #, c-format
 msgid "No merge strategy handled the merge.\n"
-msgstr "Birleştirmeyi hiçbir birleştirme stratejisi işlemedi\n"
+msgstr "Birleştirmeyi hiçbir birleştirme stratejisi ele almadı\n"
 
 #, c-format
 msgid "Merge with strategy %s failed.\n"
@@ -8218,6 +8362,10 @@ msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr ""
 "Otomatik birleştirme iyi geçti; istendiği üzere gönderme öncesinde durdu.\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "Bittiğinde, 'git stash pop' ile zulalalan değişiklikleri uygula\n"
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr "uyarı: etiket girdisi fsck'den geçemiyor: %s"
@@ -8336,6 +8484,9 @@ msgstr "'%s'->'%s' yeniden adlandırması denetleniyor\n"
 msgid "bad source"
 msgstr "hatalı kaynak"
 
+msgid "destination exists"
+msgstr "hedef konum var"
+
 msgid "can not move directory into itself"
 msgstr "dizin kendi içine taşınamıyor"
 
@@ -8351,9 +8502,6 @@ msgstr "sürüm denetimi altında değil"
 msgid "conflicted"
 msgstr "çakışmalı"
 
-msgid "destination exists"
-msgstr "hedef mevcut"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "üzerine yazılıyor: '%s'"
@@ -8365,7 +8513,10 @@ msgid "multiple sources for the same target"
 msgstr "aynı hedef için birden çok kaynak"
 
 msgid "destination directory does not exist"
-msgstr "hedef dizin mevcut değil"
+msgstr "hedef dizin yok"
+
+msgid "destination exists in the index"
+msgstr "hedef konum indekste var"
 
 #, c-format
 msgid "%s, source=%s, destination=%s"
@@ -8517,11 +8668,11 @@ msgstr "not içeriği %s içinde bırakıldı"
 
 #, c-format
 msgid "could not open or read '%s'"
-msgstr "'%s' açılamadı veya okunamadı"
+msgstr "'%s', açılamadı veya okunamadı"
 
 #, c-format
 msgid "failed to resolve '%s' as a valid ref."
-msgstr "'%s' geçerli bir başvuru olarak çözülemedi"
+msgstr "'%s', geçerli bir başvuru olarak çözülemedi."
 
 #, c-format
 msgid "failed to read object '%s'."
@@ -8533,7 +8684,7 @@ msgstr "İkili nesne olmayan '%s' nesnesinden not verisi okunamıyor."
 
 #, c-format
 msgid "malformed input line: '%s'."
-msgstr "hatalı oluşturulmuş girdi satırı: '%s'"
+msgstr "hatalı oluşturulmuş girdi satırı: '%s'."
 
 #, c-format
 msgid "failed to copy notes from '%s' to '%s'"
@@ -8574,7 +8725,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Not eklenemiyor. %s nesnesi için halihazırda var olan notlar bulundu. Bu "
-"notların üzerine yazmak için '-f' kullanın."
+"notların üzerine yazmak için '-f' kullanın"
 
 #, c-format
 msgid "Overwriting existing notes for object %s\n"
@@ -8599,7 +8750,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Notlar kopyalanamıyor. %s nesnesi için halihazırda var olan notlar bulundu. "
-"Bu notların üzerine yazmak için '-f' kullanın."
+"Bu notların üzerine yazmak için '-f' kullanın"
 
 #, c-format
 msgid "missing notes on source object %s. Cannot copy."
@@ -8629,7 +8780,7 @@ msgid "could not find commit from NOTES_MERGE_PARTIAL."
 msgstr "işleme, NOTES_MERGE_PARTIAL ögesinden bulunamadı."
 
 msgid "could not parse commit from NOTES_MERGE_PARTIAL."
-msgstr "işleme, NOTES_MERGE_PARTIAL ögesinden ayrıştırılamadı"
+msgstr "işleme, NOTES_MERGE_PARTIAL ögesinden ayrıştırılamadı."
 
 msgid "failed to resolve NOTES_MERGE_REF"
 msgstr "NOTES_MERGE_REF çözülemedi"
@@ -8696,7 +8847,7 @@ msgstr ""
 
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
-msgstr "'%s' geçerli bir başvuru olarak çözülemiyor"
+msgstr "'%s', geçerli bir başvuru olarak çözülemiyor."
 
 #, c-format
 msgid "Object %s has no note\n"
@@ -8721,8 +8872,8 @@ msgid "use notes from <notes-ref>"
 msgstr "notları <not-bşvr>'ndan kullan"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "bilinmeyen altkomut: %s"
+msgid "unknown subcommand: `%s'"
+msgstr "bilinmeyen altkomut: '%s'"
 
 msgid ""
 "git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
@@ -8749,7 +8900,7 @@ msgstr "%s için hatalı paketlenmiş nesne CRC'si"
 
 #, c-format
 msgid "corrupt packed object for %s"
-msgstr "%s için hasar görmüş paketlenmiş nesne"
+msgstr "%s için hasar paketlenmiş nesne"
 
 #, c-format
 msgid "recursive delta detected for object %s"
@@ -9204,7 +9355,7 @@ msgid "Please specify which branch you want to merge with."
 msgstr "Lütfen hangi dal ile birleştirmek istediğinizi belirtin."
 
 msgid "See git-pull(1) for details."
-msgstr "Ayrıntılar için: git-pull(1)"
+msgstr "Ayrıntılar için git-pull(1)'a bakın."
 
 msgid "<remote>"
 msgstr "<uzak-konum>"
@@ -9250,7 +9401,7 @@ msgid ""
 "or --ff-only on the command line to override the configured default per\n"
 "invocation.\n"
 msgstr ""
-"Iraksak dallarınız mevcut ve onların nasıl uzlaştırılacağını\n"
+"Iraksak dallarınız var ve onların nasıl uzlaştırılacağını\n"
 "belirtmeniz gerekiyor. Bunu bir sonraki çekimden önce\n"
 "aşağıdaki komutlardan birini çalıştırarak yapabilirsiniz:\n"
 "\n"
@@ -9431,7 +9582,7 @@ msgid ""
 msgstr ""
 "Güncellemeler reddedildi; çünkü geçerli dalınızın ucu kendisinin\n"
 "uzak konum karşıtından geride. Yeniden itmeden önce uzak konumdaki\n"
-"değişiklikleri entegre edin (örn. 'git pull ...').\n"
+"değişiklikleri tümleştirin (örn. 'git pull ...').\n"
 "Ayrıntılar için 'git push --help' içinde 'Notes about fast-forwards'a\n"
 "bakın."
 
@@ -9443,7 +9594,7 @@ msgid ""
 msgstr ""
 "Güncellemeler reddedildi; çünkü itilmiş bir dal ucu kendisinin\n"
 "uzak konum karşıtından geride. Yeniden itmeden önce bu dalı çıkış\n"
-"yapın ve uzak konumdaki değişiklikleri entegre edin (örn. 'git pull\n"
+"yapın ve uzak konumdaki değişiklikleri tümleştirin (örn. 'git pull\n"
 "...'). Ayrıntılar için 'git push --help' içinde 'Notes about\n"
 "fast-forwards'a bakın."
 
@@ -9456,8 +9607,8 @@ msgid ""
 msgstr ""
 "Güncellemeler reddedildi; çünkü uzak konumda henüz yerelde sizde olmayan\n"
 "değişiklikler var. Bu genelde başka bir deponun aynı başvuruya itmesinden\n"
-"dolayı olur. Yeniden itmeden önce uzak konumdaki değişiklikleri entegre\n"
-"etmek isteyebilirsiniz (örn. 'git pull ...').\n"
+"dolayı olur. Yeniden itmeden önce uzak konumdaki değişiklikleri tümleş-\n"
+"tirmek isteyebilirsiniz (örn. 'git pull ...').\n"
 "Ayrıntılar için 'git push --help' içinde 'Notes about fast-forwards'a\n"
 "bakın."
 
@@ -9481,7 +9632,7 @@ msgid ""
 msgstr ""
 "Güncellemeler reddedildi; çünkü uzak izleme dalının ucu son\n"
 "çıkıştan bu yana güncellenmiş. Bir güncellemeyi zorlamadan\n"
-"önce bu değişiklikleri yerel olarak entegre etmek isteye-\n"
+"önce bu değişiklikleri yerel olarak tümleştirmek isteye-\n"
 "bilirsiniz (örn. 'git pull ...'\n"
 
 #, c-format
@@ -9521,7 +9672,7 @@ msgid "require old value of ref to be at this value"
 msgstr "başvurunun eski değerinin bu değerde olmasını gerektir"
 
 msgid "require remote updates to be integrated locally"
-msgstr "uzak güncellemelerin yerele entegre edilmesini gerektir"
+msgstr "uzak güncellemelerin yerele tümleştirilmesini gerektir"
 
 msgid "control recursive pushing of submodules"
 msgstr "altmodüllerin özyineli itilmesini denetle"
@@ -9612,12 +9763,17 @@ msgstr "yalnızca ilk erimle ilişkili çıktıyı yay"
 msgid "only emit output related to the second range"
 msgstr "yalnızca ikinci erimle ilişkili çıktıyı yay"
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "bir revizyon değil: '%s'"
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "bir işleme erimi değil: '%s'"
 
-msgid "single arg format must be symmetric range"
-msgstr "tekli argüman biçimi simetrik erim olmalı"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "bir simetrik erim değil: '%s'"
 
 msgid "need two commit ranges"
 msgstr "iki işleme erimi gerekli"
@@ -9895,6 +10051,9 @@ msgstr "boş başlayan işlemeleri tut"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "-i altındaki squash!/fixup! ile başlayan işlemeleri taşı"
 
+msgid "update branches that point to commits that are being rebased"
+msgstr "yeniden temellendirilen işlemelere işaret eden dalları güncelle"
+
 msgid "add exec lines after each commit of the editable list"
 msgstr "düzenlenebilir listenin her işlemesinden sonra exec satırları ekle"
 
@@ -9963,7 +10122,7 @@ msgid ""
 "mark them as resolved using git add"
 msgstr ""
 "Önce tüm birleştirme çakışmalarını düzenlemeli ve onları\n"
-"git add kullanarak tamamlandı olarak imlemelisiniz."
+"git add kullanarak tamamlandı olarak imlemelisiniz"
 
 msgid "could not discard worktree changes"
 msgstr "çalışma ağacı değişiklikleri atılamadı"
@@ -10292,7 +10451,7 @@ msgid ""
 "\t use --mirror=fetch or --mirror=push instead"
 msgstr ""
 "--mirror tehlikeli ve artık kullanılmamalı; lütfen\n"
-"\t yerine --mirror=fetch veya --mirror=push kullanın."
+"\t yerine --mirror=fetch veya --mirror=push kullanın"
 
 #, c-format
 msgid "unknown mirror argument: %s"
@@ -10339,7 +10498,7 @@ msgstr "birden çok %s"
 
 #, c-format
 msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
-msgstr "ilgilenilmemiş branch.%s.rebase=%s, 'true' olduğu var sayılıyor"
+msgstr "ele alınmamış branch.%s.rebase=%s, 'true' olduğu var sayılıyor"
 
 #, c-format
 msgid "Could not get fetch map for refspec %s"
@@ -10367,7 +10526,7 @@ msgid ""
 msgstr ""
 "Şuradaki %s yapılandırması remote.pushDefault:\n"
 "\t%s:%d\n"
-"artık var olmayan '%s' uzak konumunu adlandırıyor."
+"artık var olmayan '%s' uzak konumunu adlandırıyor"
 
 #, c-format
 msgid "No such remote: '%s'"
@@ -10422,6 +10581,9 @@ msgstr " yeni (bir sonraki getirme uzak konumlarda depolayacak/%s"
 msgid " tracked"
 msgstr " izlendi"
 
+msgid " skipped"
+msgstr " atlandı"
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " eskimiş (kaldırmak için 'git remote prune' kullanın)"
 
@@ -10814,7 +10976,7 @@ msgstr "'%s' geçerli bir başvuru adı değil"
 
 #, c-format
 msgid "replace ref '%s' already exists"
-msgstr "değiştirme başvurusu '%s' halihazırda mevcut"
+msgstr "değiştirme başvurusu '%s' halihazırda var"
 
 #, c-format
 msgid ""
@@ -10927,10 +11089,10 @@ msgid "change a commit's parents"
 msgstr "bir işlemenin üst ögelerini değiştir"
 
 msgid "convert existing graft file"
-msgstr "mevcut aşı dosyasını dönüştür"
+msgstr "var olan aşı dosyasını dönüştür"
 
 msgid "replace the ref if it exists"
-msgstr "başvuru mevcutsa onu değiştir"
+msgstr "başvuru varsa onu değiştir"
 
 msgid "do not pretty-print contents for --edit"
 msgstr "--edit içeriğini hoş biçimde gösterme"
@@ -11093,6 +11255,10 @@ msgstr "Yeni indeks dosyası yazılamadı."
 msgid "unable to get disk usage of %s"
 msgstr "%s ögesinin disk kullanımı alınamıyor"
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "'%s' için geçersiz değer: '%s', tek izin verilen biçim '%s'"
+
 msgid "rev-list does not support display of notes"
 msgstr "rev-list not görüntülemesini desteklemiyor"
 
@@ -11118,6 +11284,9 @@ msgstr "zamansız girdi sonu"
 msgid "no usage string given before the `--' separator"
 msgstr "'--' ayırıcısı öncesinde bir kullanım dizisi verilmedi"
 
+msgid "missing opt-spec before option flags"
+msgstr "seçenek bayraklarından önce eksik opt-spec"
+
 msgid "Needed a single revision"
 msgstr "Tek bir revizyon gerekiyordu"
 
@@ -11129,8 +11298,8 @@ msgid ""
 "Run \"git rev-parse --parseopt -h\" for more information on the first usage."
 msgstr ""
 "git rev-parse --parseopt [<seçenekler>] -- [<argümanlar>...]\n"
-"\tor: git rev-parse --sq-quote [<argümanlar>...]\n"
-"\tor: git rev-parse [<seçenekler>] [<argümanlar>...]\n"
+"   veya: git rev-parse --sq-quote [<argümanlar>...]\n"
+"   veya: git rev-parse [<seçenekler>] [<argümanlar>...]\n"
 "\n"
 "İlki hakkında ek bilgi için \"git rev-parse --parseopt -h\" çalıştırın."
 
@@ -11253,10 +11422,10 @@ msgid_plural ""
 "file and the HEAD:"
 msgstr[0] ""
 "Aşağıdaki dosyanın hem HEAD'den hem de dosyadan farklı hazırlanmış\n"
-"içeriği mevcut:"
+"içeriği var:"
 msgstr[1] ""
 "Aşağıdaki dosyaların hem HEAD'den hem de dosyadan farklı hazırlanmış\n"
-"içeriği mevcut:"
+"içeriği var:"
 
 msgid ""
 "\n"
@@ -11267,8 +11436,8 @@ msgstr ""
 
 msgid "the following file has changes staged in the index:"
 msgid_plural "the following files have changes staged in the index:"
-msgstr[0] "Aşağıdaki dosyanın indekste hazırlanmış değişiklikleri mevcut:"
-msgstr[1] "Aşağıdaki dosyaların indekste hazırlanmış değişiklikleri mevcut:"
+msgstr[0] "Aşağıdaki dosyanın indekste hazırlanmış değişiklikleri var:"
+msgstr[1] "Aşağıdaki dosyaların indekste hazırlanmış değişiklikleri var:"
 
 msgid ""
 "\n"
@@ -11575,10 +11744,10 @@ msgid "unable to unquote C-style string '%s'"
 msgstr "C biçemli '%s' dizisinin tırnakları kaldırılamıyor"
 
 msgid "unable to load existing sparse-checkout patterns"
-msgstr "mevcut aralıklı çıkış dizgileri yüklenemiyor"
+msgstr "var olan aralıklı çıkış dizgileri yüklenemiyor"
 
 msgid "existing sparse-checkout patterns do not use cone mode"
-msgstr "mevcut aralıklı çıkış dizgileri koni kipini kullanmıyor"
+msgstr "var olan aralıklı çıkış dizgileri koni kipini kullanmıyor"
 
 msgid "please run from the toplevel directory in non-cone mode"
 msgstr "koni dışı kipte en üst düzey dizinden çalıştırın"
@@ -11878,6 +12047,10 @@ msgstr "her satırın başına yorum karakteri ve boşluk koy"
 msgid "Expecting a full ref name, got %s"
 msgstr "Tam bir başvuru adı bekleniyordu, %s alındı"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "'%s' altmodülü için depo tutacağı alınamadı"
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
@@ -11886,12 +12059,6 @@ msgstr ""
 "'%s' yapılandırması aranamadı. Bu deponun kendi yetkili üstkaynağı olduğu "
 "varsayılıyor."
 
-msgid "alternative anchor for relative paths"
-msgstr "göreceli yollar için alternatif tutturucu"
-
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<yol>] [<yol>...]"
-
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
 msgstr ".gitmodules içinde '%s' altmodül yolu için url bulunamadı"
@@ -11923,8 +12090,8 @@ msgstr "her bir altmodül komutu girişinin çıktısını gizle"
 msgid "recurse into nested submodules"
 msgstr "iç içe geçmiş altmodüle özyinele"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <komut>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <komut>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -11945,8 +12112,8 @@ msgstr "'%s' altmodülü yolu için güncelleme kipi kaydı yapılamadı"
 msgid "suppress output for initializing a submodule"
 msgstr "bir altmodül ilklendirmesi çıktısını gizle"
 
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<seçenekler>] [<yol>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<seçenekler>] [<yol>]"
 
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
@@ -11973,9 +12140,6 @@ msgstr ""
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<yol>...]"
 
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <yol>"
-
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
 msgstr "* %s %s(ikili nesne)->%s(altmodül)"
@@ -12008,8 +12172,8 @@ msgstr "'ignore_config' değeri 'all' olan altmodülleri atla"
 msgid "limit the summary size"
 msgstr "özet boyutunu sınırla"
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<seçenekler>] [<işleme>] [--] [<yol>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<seçenekler>] [<işleme>] [--] [<yol>]"
 
 msgid "could not fetch a revision for HEAD"
 msgstr "HEAD için bir revizyon getirilemedi"
@@ -12022,10 +12186,6 @@ msgstr "'%s' için altmodül url'si eşitleniyor\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "'%s' altmodülü yolu için url kaydı yapılamadı"
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "'%s' altmodülü için öntanımlı uzak konum alınamadı"
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr "'%s' altmodülü için uzak konum güncellenemedi"
@@ -12033,8 +12193,8 @@ msgstr "'%s' altmodülü için uzak konum güncellenemedi"
 msgid "suppress output of synchronizing submodule url"
 msgstr "altmodül url'si eşitleme çıktısını gizle"
 
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<yol>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<yol>]"
 
 #, c-format
 msgid ""
@@ -12090,11 +12250,15 @@ msgid ""
 "submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
 "'--reference-if-able' instead of '--reference'."
 msgstr ""
-"Bir süperprojenin alternatifinden hesaplanan bir alternatif geçersiz.\n"
+"Bir üst projenin alternatifinden hesaplanan bir alternatif geçersiz.\n"
 "Böyle bir durumda Git'in alternatifsiz klonlamasına izin vermek için\n"
 "submodule.alternateErrorStrategy ayarını 'info'ya ayarlayın veya\n"
 "--reference yerine --reference-if-able kullanarak klonlayın."
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "'%s' git dizini için bir depo tutacı alınamadı"
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "'%s' altmodülü alternatif ekleyemiyor: %s"
@@ -12124,6 +12288,9 @@ msgstr "dizin boş değil: '%s'"
 msgid "could not get submodule directory for '%s'"
 msgstr "'%s' için altmodül dizini alınamadı"
 
+msgid "alternative anchor for relative paths"
+msgstr "göreceli yollar için alternatif tutturucu"
+
 msgid "where the new submodule will be cloned to"
 msgstr "yeni altmodülün nereye klonlanacağı"
 
@@ -12151,10 +12318,6 @@ msgstr ""
 "[--name <ad>] [--depth <derinlik>] [--single-branch] [--filter <süzgeç-"
 "belirteci>] --url <url> --path <yol>"
 
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "Geçersiz güncelleme kipi '%s', '%s' altmodül yolu için"
-
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr "Geçersiz güncelleme kipi '%s', '%s' altmodül yolu için yapılandırılmış"
@@ -12176,7 +12339,7 @@ msgstr "'%s' altmodülü atlanıyor"
 
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
-msgstr "'%s' klonlanamadı. Yeniden deneme zamanlandı."
+msgstr "'%s' klonlanamadı. Yeniden deneme zamanlandı"
 
 #, c-format
 msgid "Failed to clone '%s' a second time, aborting"
@@ -12228,17 +12391,17 @@ msgstr ""
 "'%s' altmodül yolunda getirme yapıldı; ancak %s içermiyor. Bu işlemenin "
 "doğrudan getirilmesi başarısız oldu."
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "'%s' konumundaki altmodül ilklendirilemedi"
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
 "the superproject is not on any branch"
 msgstr ""
-"Altmodül (%s) dalı süperproje dalından devralmak üzere yapılandırıldı; ancak "
-"süperproje herhangi bir dalda değil"
-
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "'%s' altmodülü için depo tutacağı alınamadı"
+"Altmodül (%s) dalı, üst projenin dalından devralmak üzere yapılandırıldı; "
+"ancak üst proje, herhangi bir dalda değil"
 
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
@@ -12274,11 +12437,14 @@ msgstr "yeni nesneleri uzak konumdan getirme"
 msgid "path into the working tree"
 msgstr "çalışma ağacına giden yol"
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "iç içe geçmiş altmodül sınırları üzerinden çalışma ağacına giden yol"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "'checkout' güncelleme stratejisini kullan (öntanımlı)"
+
+msgid "use the 'merge' update strategy"
+msgstr "'merge' güncelleme stratejisini kullan"
 
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout veya none"
+msgid "use the 'rebase' update strategy"
+msgstr "'rebase' güncelleme stratejisini kullan"
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr "belirli bir revizyon sayısına kısaltılmış sığ klon oluştur"
@@ -12292,6 +12458,9 @@ msgstr "ilk klonun sığlık üzerine olan tavsiyeyi izleyip izlemeyeceği"
 msgid "don't print cloning progress"
 msgstr "klonlama işlemini yazdırma"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "boş olmayan dizine klonlamaya izin verme, --init ima eder"
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12303,14 +12472,11 @@ msgstr ""
 "shallow] [--reference <depo>] [--recursive] [--[no-]single-branch] [--] "
 "[<yol>...]"
 
-msgid "bad value for update parameter"
-msgstr "güncelleme parametresi için hatalı değer"
-
 msgid "recurse into submodules"
 msgstr "altmodüllere özyinele"
 
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<seçenekler>] [<yol>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<seçenekler>] [<yol>...]"
 
 msgid "check if it is safe to write to the .gitmodules file"
 msgstr ".gitmodules dosyasına yazım güvenli mi değil mi denetle"
@@ -12330,8 +12496,8 @@ msgstr ".gitmodules dosyasının çalışma ağacında olduğundan lütfen emin
 msgid "suppress output for setting url of a submodule"
 msgstr "bir altmodül url ayarlanması çıktısını gizle"
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <yol> <yeniurl>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <yol> <yeniurl>"
 
 msgid "set the default tracking branch to master"
 msgstr "öntanımlı izleme dalını master olarak ayarla"
@@ -12339,13 +12505,11 @@ msgstr "öntanımlı izleme dalını master olarak ayarla"
 msgid "set the default tracking branch"
 msgstr "öntanımlı izleme dalını ayarla"
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <yol>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <yol>"
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <dal> <yol>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <dal> <yol>"
 
 msgid "--branch or --default required"
 msgstr "--branch veya --default gerekli"
@@ -12372,11 +12536,11 @@ msgstr "'%s' dalı oluşturuluyor"
 
 #, c-format
 msgid "Adding existing repo at '%s' to the index\n"
-msgstr "'%s' konumundaki mevcut repo indekse ekleniyor\n"
+msgstr "'%s' konumundaki var olan depo indekse ekleniyor\n"
 
 #, c-format
 msgid "'%s' already exists and is not a valid git repo"
-msgstr "'%s' halihazırda mevcut ve geçerli bir git deposu değil"
+msgstr "'%s' halihazırda var ve geçerli bir git deposu değil"
 
 #, c-format
 msgid "A git directory for '%s' is found locally with remote(s):\n"
@@ -12441,8 +12605,8 @@ msgid ""
 msgstr ""
 "altmodülün adını kendi yoluna öntanımlamak yerine verilen dizi olarak ayarlar"
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<seçenekler>] [--] <depo> [<yol>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<seçenekler>] [--] <depo> [<yol>]"
 
 msgid "Relative path can only be used from the toplevel of the working tree"
 msgstr ""
@@ -12647,6 +12811,16 @@ msgstr "'%s' etiketi güncellendi (%s idi)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "paket izin verilen en büyük boyutu aşıyor"
 
+msgid "failed to write object in stream"
+msgstr "akışta nesne yazılamadı"
+
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "şişirme programı (%d) döndürdü"
+
+msgid "invalid blob object from stream"
+msgstr "akıştan geçersiz ikili nesne"
+
 msgid "Unpacking objects"
 msgstr "Nesneler açılıyor"
 
@@ -12739,7 +12913,7 @@ msgid "add to index only; do not add content to object database"
 msgstr "yalnızca indekse ekle; içeriğe nesne veritabanına ekleme"
 
 msgid "remove named paths even if present in worktree"
-msgstr "çalışma ağacında mevcut olsa bile ad verilen yolları kaldır"
+msgstr "çalışma ağacında var olsa bile ad verilen yolları kaldır"
 
 msgid "with --stdin: input lines are terminated by null bytes"
 msgstr "--stdin ile: girdi satırları boş baytlarla sonlandırılır"
@@ -13157,6 +13331,27 @@ msgstr "bir <önek> altdizini için ağaç nesnesi yaz"
 msgid "only useful for debugging"
 msgstr "yalnızca hata ayıklama için yararlı"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch, bu platformda desteklenmiyor"
+
+msgid "failed to create temporary file"
+msgstr "geçici dosya oluşturulamadı"
+
+msgid "insufficient capabilities"
+msgstr "yetersiz yetenekler"
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "'%s' URI'sinden demet indirilemedi"
+
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "'%s' URI'sindeki dosya bir demet değil"
+
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "'%s' URI'sindeki demet çözülemedi"
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr "bilinmeyen demet sağlama algoritması: %s"
@@ -13358,6 +13553,9 @@ msgstr "Git depoları için gerçekten yalın bir sunucu"
 msgid "Give an object a human readable name based on an available ref"
 msgstr "Uygun bir başvuruyu temel alıp nesneye okunabilir ad ver"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr "Tanı bilgisinin bir zip arşivini oluştur"
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "İşlemeler, işleme ve ağaçlar vb. arası değişiklikler"
 
@@ -13368,8 +13566,7 @@ msgid "Compare a tree to the working tree or index"
 msgstr "Bir ağacı çalışma ağacı veya indeks ile karşılaştır"
 
 msgid "Compares the content and mode of blobs found via two tree objects"
-msgstr ""
-"İki ağaç nesnesi aracılığıyla bulunan ikililerin içerik ve kipini karşılaştır"
+msgstr "İki ağaç nesnesiyle bulunan ikililerin içerik/kipini karşılaştır"
 
 msgid "Show changes using common diff tools"
 msgstr "Değişiklikleri yaygın diff araçlarıyla göster"
@@ -13485,8 +13682,8 @@ msgstr "Birleştirilmesi gereken dosyaları birleştir"
 msgid "The standard helper program to use with git-merge-index"
 msgstr "Bu yardımcı program git-merge-index kullanımı içindir"
 
-msgid "Show three-way merge without touching index"
-msgstr "İndekse dokunmadan üçlü birleştirmeyi göster"
+msgid "Perform merge without touching index or working tree"
+msgstr "İndekse veya çalışma ağacına dokunmadan birleştir"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr "Çakışmaları çözmek için çözüm araçlarını çalıştır"
@@ -13531,7 +13728,7 @@ msgid "Remove extra objects that are already in pack files"
 msgstr "Halihazırda paket dosyalarında olan ek nesneleri kaldır"
 
 msgid "Fetch from and integrate with another repository or a local branch"
-msgstr "Başka bir depo veya yerel daldan getir ve entegre et"
+msgstr "Başka bir depo veya yerel daldan getir ve tümleştir"
 
 msgid "Update remote refs along with associated objects"
 msgstr "İlişkin nesnelerle birlikte uzak başvuruları da güncelle"
@@ -13618,7 +13815,7 @@ msgid "List references in a local repository"
 msgstr "Yerel bir depodaki başvuruları listele"
 
 msgid "Reduce your working tree to a subset of tracked files"
-msgstr "Çalışma ağacını izlenen dosyaların bir alt kümesine küçült"
+msgstr "Çalışma ağacını izlenen dosyaların alt kümesine küçült"
 
 msgid "Add file contents to the staging area"
 msgstr "Dosya içeriğini hazırlama alanına ekle"
@@ -13681,6 +13878,9 @@ msgstr "Paketlenmiş Git arşiv dosyalarını doğrula"
 msgid "Check the GPG signature of tags"
 msgstr "Etiketlerin GPG imzasını doğrula"
 
+msgid "Display version information about Git"
+msgstr "Git sürüm bilgisini görüntüle"
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Günlükleri her işlemenin sunduğu değişikliklerle göster"
 
@@ -13714,6 +13914,24 @@ msgstr "Günlük Git kullanımı için yararlı komutlar"
 msgid "Frequently asked questions about using Git"
 msgstr "Git kullanımı hakkında sıkça sorulan sorular"
 
+msgid "The bundle file format"
+msgstr "Demet dosya biçimi"
+
+msgid "Chunk-based file formats"
+msgstr "geçersiz gitfile biçimi: %s"
+
+msgid "Git commit graph format"
+msgstr "Git işleme grafiği biçimi"
+
+msgid "Git index format"
+msgstr "Git indeks biçimi"
+
+msgid "Git pack format"
+msgstr "Git paket biçimi"
+
+msgid "Git cryptographic signature formats"
+msgstr "Git kriptografik imza biçimleri"
+
 msgid "A Git Glossary"
 msgstr "Git Kavram Dizini"
 
@@ -13735,6 +13953,21 @@ msgstr "Altmodül özelliklerini tanımlama"
 msgid "Git namespaces"
 msgstr "Git ad alanları"
 
+msgid "Protocol v0 and v1 capabilities"
+msgstr "Protokol v0 ve v1 yetenekleri"
+
+msgid "Things common to various protocols"
+msgstr "Çeşitli protokollerde ortak olan şeyler"
+
+msgid "Git HTTP-based protocols"
+msgstr "Git HTTP tabanlı protokolleri"
+
+msgid "How packs are transferred over-the-wire"
+msgstr "Paketlerin nice aktarıldığı"
+
+msgid "Git Wire Protocol, Version 2"
+msgstr "Git Wire Protokolü, Sürüm 2"
+
 msgid "Helper programs to interact with remote repositories"
 msgstr "Uzak depolar ile etkileşim için yardımcı programlar"
 
@@ -13759,6 +13992,9 @@ msgstr "Git web arabirimi (Git depoları için web ön ucu)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Önerilen Git çalışma akışlarına genel bakış"
 
+msgid "A tool for managing large Git repositories"
+msgstr "Büyük Git depolarını yönetmek için bir araç"
+
 msgid "commit-graph file is too small"
 msgstr "commit-graph dosyası pek küçük"
 
@@ -13792,7 +14028,7 @@ msgid "unable to find all commit-graph files"
 msgstr "tüm commit-graph dosyaları bulunamıyor"
 
 msgid "invalid commit position. commit-graph is likely corrupt"
-msgstr "geçersiz işleme konumu, commit-graph büyük olasılıkla hasar görmüş"
+msgstr "geçersiz işleme konumu, commit-graph büyük olasılıkla hasar"
 
 #, c-format
 msgid "could not find commit %s"
@@ -13883,8 +14119,7 @@ msgstr "grafik yazımı için çok fazla işleme"
 
 msgid "the commit-graph file has incorrect checksum and is likely corrupt"
 msgstr ""
-"commit-graph dosyasının sağlama toplamı yanlış ve büyük olasılıkla hasar "
-"görmüş"
+"commit-graph dosyasının sağlama toplamı yanlış ve büyük olasılıkla hasarlı"
 
 #, c-format
 msgid "commit-graph has incorrect OID order: %s then %s"
@@ -13967,7 +14202,7 @@ msgstr ""
 "lütfen \"git replace --convert-graft-file\" kullanın.\n"
 "\n"
 "\"git config advice.graftFileDeprecated false\"\n"
-"kullanarak bu iletiyi kapatabilirsiniz."
+"kullanarak bu iletiyi kapatabilirsiniz"
 
 #, c-format
 msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
@@ -13997,10 +14232,18 @@ msgstr ""
 "kodlama ile değiştirmek isteyebilirsiniz.\n"
 
 msgid "no compiler information available\n"
-msgstr "derleyici bilgisi mevcut değil\n"
+msgstr "derleyici bilgisi yok\n"
 
 msgid "no libc information available\n"
-msgstr "libc bilgisi mevcut değil\n"
+msgstr "libc bilgisi yok\n"
+
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "'%s' için boş disk alanı belirlenemedi"
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "'%s' için bilgi alınamadı"
 
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
@@ -14056,6 +14299,14 @@ msgstr "GetOverlappedResult, '%s' üzerinde başarısız oldu [GLE %ld]"
 msgid "could not read directory changes [GLE %ld]"
 msgstr "dizin değişiklikleri okunamadı [GLE %ld]"
 
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] '%ls', okuma için açılamıyor"
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] '%ls' için protokol bilgisi alınamıyor"
+
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr "SID kopyalanamadı (%ld)"
@@ -14600,199 +14851,24 @@ msgid "failed to close rev-list's stdin"
 msgstr "rev-list'in stdin'i kapatılamadı"
 
 #, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' mevcut değil"
-
-msgid "need a working directory"
-msgstr "bir çalışma dizini gerekiyor"
-
-msgid "could not find enlistment root"
-msgstr "gönüllü yazılma kaydı bulunamıyor"
-
-#, c-format
-msgid "could not switch to '%s'"
-msgstr "şuraya geçilemedi: '%s'"
+msgid "illegal crlf_action %d"
+msgstr "izin verilmeyen crlf_action %d"
 
 #, c-format
-msgid "could not configure %s=%s"
-msgstr "%s=%s yapılandırılamadı"
-
-msgid "could not configure log.excludeDecoration"
-msgstr "log.excludeDecoration yapılandırılamadı"
-
-msgid "Scalar enlistments require a worktree"
-msgstr "Scalar gönüllü kayıtları bir çalışma ağacı gerektiriyor"
+msgid "CRLF would be replaced by LF in %s"
+msgstr "CRLF %s içinde LF ile değiştirilecek"
 
 #, c-format
-msgid "could not open directory '%s'"
-msgstr "'%s' dizini açılamadı"
+msgid ""
+"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
+"touches it"
+msgstr ""
+"Git'in bir sonraki dokunuşunda, '%s' çalışma kopyasındaki CRLF'ler LF ile "
+"değiştirilecektir"
 
 #, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "ne bir dosya ne de dizin olan '%s' atlanıyor"
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "'%s' için boş disk alanı belirlenemedi"
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "'%s' için bilgi alınamadı"
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "uzak konum HEAD'i bir dal değil: '%.*s'"
-
-msgid "failed to get default branch name from remote; using local default"
-msgstr ""
-"uzak konumdan öntanımlı dal adı alınamadı; yerel öntanımlı kullanılıyor"
-
-msgid "failed to get default branch name"
-msgstr "öntanımlı dal adı alınamadı"
-
-msgid "failed to unregister repository"
-msgstr "depo kaydı silinemedi"
-
-msgid "failed to delete enlistment directory"
-msgstr "gönüllü kayıt dizini silinemedi"
-
-msgid "branch to checkout after clone"
-msgstr "klonlama sonrası çıkış yapılacak dal"
-
-msgid "when cloning, create full working directory"
-msgstr "klonlama sırasında tam çalışma dizini oluştur"
-
-msgid "only download metadata for the branch that will be checked out"
-msgstr "yalnızca çıkış yapılacak dalın üstverisini indir"
-
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<seçenekler>] [--] <depo> [<dizin>]"
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "'%s' ögesinden çalışma ağacı adı ortaya çıkarılamıyor"
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "'%s' dizini halihazırda var"
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "'%s' için öntanımlı dal alınamadı"
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "'%s' içindeki uzak konum yapılandırılamadı"
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr "'%s' yapılandırılamadı"
-
-msgid "partial clone failed; attempting full clone"
-msgstr "kısımsal klonlama başarısız; tam klonlama deneniyor"
-
-msgid "could not configure for full clone"
-msgstr "tam klonlama için yapılandırılamadı"
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<gönüllükayıt>]"
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "'%s' için dizin oluşturulamadı"
-
-msgid "could not duplicate stdout"
-msgstr "stdout çoğaltılamadı"
-
-msgid "failed to write archive"
-msgstr "arşiv yazılamadı"
-
-msgid "`scalar list` does not take arguments"
-msgstr "'scalar list' argüman almıyor"
-
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<gönüllükayıt>]"
-
-msgid "reconfigure all registered enlistments"
-msgstr "tüm kaydı yapılmış gönüllü kayıtları yeniden yapılandır"
-
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <gönüllükayıt>]"
-
-msgid "--all or <enlistment>, but not both"
-msgstr "--all veya <gönüllükayıt>; ancak ikisi değil"
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git deposu '%s' içinde gitti"
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <görev> [<gönüllükayıt>]\n"
-"Görevler:\n"
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr "böyle bir görev yok: '%s'"
-
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<enlistment>]"
-
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <gönüllükayıt>"
-
-msgid "refusing to delete current working directory"
-msgstr "geçerli çalışma dizinini silme reddediliyor"
-
-msgid "include Git version"
-msgstr "Git sürümünü içer"
-
-msgid "include Git's build options"
-msgstr "Git'in yapı seçeneklerini içer"
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-msgid "-C requires a <directory>"
-msgstr "-C, bir <dizin> gerektiriyor"
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr "'%s' olarak değiştirilemedi"
-
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c, bir <anahtar>=<değer> argümanı gerektiriyor"
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <dizin>] [-c <anahtar>=<değer>] <komut> [<seçenekler>]\n"
-"\n"
-"Komutlar:\n"
-
-#, c-format
-msgid "illegal crlf_action %d"
-msgstr "izin verilmeyen crlf_action %d"
-
-#, c-format
-msgid "CRLF would be replaced by LF in %s"
-msgstr "CRLF %s içinde LF ile değiştirilecek"
-
-#, c-format
-msgid ""
-"in the working copy of '%s', CRLF will be replaced by LF the next time Git "
-"touches it"
-msgstr ""
-"Git'in bir sonraki dokunuşunda, '%s' çalışma kopyasındaki CRLF'ler LF ile "
-"değiştirilecektir"
-
-#, c-format
-msgid "LF would be replaced by CRLF in %s"
-msgstr "LF %s içinde CRLF ile değiştirilecek"
+msgid "LF would be replaced by CRLF in %s"
+msgstr "LF %s içinde CRLF ile değiştirilecek"
 
 #, c-format
 msgid ""
@@ -14980,6 +15056,32 @@ msgstr ""
 msgid "Marked %d islands, done.\n"
 msgstr "%d delta adası imlendi, bitti.\n"
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "geçersiz --%s değeri '%s'"
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "eksik dizin '%s', arşivlenemedi"
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "'%s' dizini açılamadı"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "ne bir dosya ne de dizin olan '%s' atlanıyor"
+
+msgid "could not duplicate stdout"
+msgstr "stdout çoğaltılamadı"
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "'%s' dizini, arşivleyiciye eklenemedi"
+
+msgid "failed to write archive"
+msgstr "arşiv yazılamadı"
+
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base erimlerle çalışmaz"
 
@@ -15003,7 +15105,7 @@ msgid ""
 "tree"
 msgstr ""
 "Bir git deposu değil. Bir çalışma ağacının dışındaki iki yolu karşılaştırmak "
-"için --no-index kullanın."
+"için --no-index kullanın"
 
 #, c-format
 msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
@@ -15539,7 +15641,7 @@ msgid ""
 "Please specify a directory on the command line"
 msgstr ""
 "Bir dizin adı tahmin edilemedi.\n"
-"Lütfen komut satırında bir dizin belirtin."
+"Lütfen komut satırında bir dizin belirtin"
 
 #, c-format
 msgid "index file corrupt in repo %s"
@@ -15588,6 +15690,9 @@ msgstr "git fetch-pack: ACK/NAK bekleniyordu, '%s' alındı"
 msgid "unable to write to remote"
 msgstr "uzak konuma yazılamıyor"
 
+msgid "Server supports filter"
+msgstr "Sunucu süzgeç destekliyor"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "geçersiz sığ satır: %s"
@@ -15698,9 +15803,6 @@ msgstr "sunucu '%s' algoritmasını desteklemiyor"
 msgid "Server does not support shallow requests"
 msgstr "Sunucu sığ istekleri desteklemiyor"
 
-msgid "Server supports filter"
-msgstr "Sunucu süzgeç destekliyor"
-
 msgid "unable to write request to remote"
 msgstr "uzak konuma istek yazılamıyor"
 
@@ -15870,7 +15972,7 @@ msgid ""
 "You can use '!git' in the alias to do this"
 msgstr ""
 "'%s' arması çevre değişkenlerini değiştirir.\n"
-"Bunu yapmak için armada '!git' kullanabilirsiniz."
+"Bunu yapmak için armada '!git' kullanabilirsiniz"
 
 #, c-format
 msgid "empty alias for %s"
@@ -15933,7 +16035,7 @@ msgid ""
 "verification (available in openssh version 8.2p1+)"
 msgstr ""
 "ssh-keygen -Y find-principals/verify, ssh imza doğrulaması için gerekli "
-"(openssh 8.21p1+ sürümünde mevcut)"
+"(openssh 8.21p1+ sürümünde var)"
 
 #, c-format
 msgid "ssh signing revocation file configured but not found: %s"
@@ -15982,7 +16084,7 @@ msgid ""
 "8.2p1+)"
 msgstr ""
 "ssh-keygen -Y imzası, ssh imzalaması için gerekli (openssh 8.21p1+ sürümünde "
-"mevcut)"
+"var)"
 
 #, c-format
 msgid "failed reading ssh signing data buffer from '%s'"
@@ -16047,6 +16149,12 @@ msgstr "Düşük Düzeyli Komutlar / Depo Eşitleme"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "Düşük Düzeyli Komutlar / İç Yardımcılar"
 
+msgid "User-facing repository, command and file interfaces"
+msgstr "Kullanıcı için depo, komut ve dosya arayüzleri"
+
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "Geliştirici için dosya biçimleri, protokoller ve arayüzler"
+
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "'%s' içindeki kullanılabilir git komutları"
@@ -16060,6 +16168,12 @@ msgstr "En çok kullanılan temel Git komutlarının bir listesi aşağıdadır:
 msgid "The Git concept guides are:"
 msgstr "Git konsept kılavuzları şunlardır:"
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr "Kullanıcıya görünür depo, komut ve dosya arayüzleri:"
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "Dosya biçimleri, protokoller ve diğer geliştirici arayüzleri:"
+
 msgid "External commands"
 msgstr "Dış komutlar"
 
@@ -16142,10 +16256,6 @@ msgstr ""
 "'%s' kancası yok sayıldı; çünkü bir çalıştırılabilir olarak ayarlanmamış.\n"
 "Bu uyarıyı 'git config advice.ignoredHook false' ile kapatabilirsiniz."
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "'%s' kancası başlatılamadı\n"
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr "--packfile için argüman geçerli bir sağlama olmalıdır ('%s' alındı)"
@@ -16153,6 +16263,7 @@ msgstr "--packfile için argüman geçerli bir sağlama olmalıdır ('%s' alınd
 msgid "not a git repository"
 msgstr "bir git deposu değil"
 
+#, c-format
 msgid "negative value for http.postBuffer; defaulting to %d"
 msgstr "http.postBuffer için negatif değer; %d olarak varsayılıyor"
 
@@ -16329,22 +16440,17 @@ msgstr "ls-refs argümanlarından sonra floş bekleniyordu"
 msgid "quoted CRLF detected"
 msgstr "alıntılanmış CRLF algılandı"
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"Birleştirme ile aşağıdaki dosyalardaki yerel değişikliklerin üzerine "
-"yazılacak:\n"
-"\t%s"
-
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "%s altmodülü birleştirilemedi (çıkış yapılmadı)"
 
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "%s altmodülü birleştirilemedi (birleştirme temeli yok)"
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
-msgstr "%s altmodülü birleştirilemedi (işlemeler mevcut değil)"
+msgstr "%s altmodülü birleştirilemedi (işlemeler yok)"
 
 #, c-format
 msgid "Failed to merge submodule %s (commits don't follow merge-base)"
@@ -16360,34 +16466,16 @@ msgstr "'%s' altmodülü birleştirilemedi"
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"%s altmodülü birleştirilemedi; ancak olası bir birleştirme çözümü mevcut:\n"
-"%s\n"
-
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
 msgstr ""
-"Eğer bu doğruysa yalnızca indekse ekleyin, örneğin:\n"
-"\n"
-"\tgit update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"komutu bu öneriyi kabul edecektir.\n"
+"%s altmodülü birleştirilemedi; ancak olası bir birleştirme çözümü var: %s"
 
 #, c-format
 msgid ""
 "Failed to merge submodule %s, but multiple possible merges exist:\n"
 "%s"
 msgstr ""
-"%s altmodülü birleştirilemedi; ancak birden çok olası birleştirmeler "
-"mevcut:\n"
+"%s altmodülü birleştirilemedi; ancak birden çok olası birleştirmeler var:\n"
 "%s"
 
 msgid "Failed to execute internal merge"
@@ -16406,7 +16494,7 @@ msgid ""
 "CONFLICT (implicit dir rename): Existing file/dir at %s in the way of "
 "implicit directory rename(s) putting the following path(s) there: %s."
 msgstr ""
-"ÇAKIŞMA (örtülü dizin yeniden adlandırma): %s konumundaki mevcut dosya/dizin "
+"ÇAKIŞMA (örtülü dizin yeniden adlandırma): %s konumunda var olan dosya/dizin "
 "örtülü yeniden adlandırmanın aşağıdaki yolları oraya koymasına engel oluyor: "
 "%s."
 
@@ -16417,7 +16505,7 @@ msgid ""
 msgstr ""
 "ÇAKIŞMA (örtülü dizin yeniden adlandırma): %s için birden çok yol "
 "eşlemlenemiyor; örtülü dizin yeniden adlandırmaları aşağıdaki yolları oraya "
-"koymayı denedi: %s."
+"koymayı denedi: %s"
 
 #, c-format
 msgid ""
@@ -16546,13 +16634,44 @@ msgstr ""
 "ÇAKIŞMA (değiştir/sil): %s silindi (%s içinde) ve %s içinde değiştirildi. %s "
 "sürümü (şunun: %s) ağaçta bırakıldı."
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
 msgstr ""
-"Not: %s güncel değil ve çakışmalı sürümlerin çıkışının önünde; eski kopya %s "
-"olarak yeniden adlandırıldı."
+" - altmodüle gidin (%s) ve %s işlemesini birleştirin\n"
+"   veya bu değişiklikleri birleştirmiş var olan bir işlemeye güncelleyin\n"
+
+#, c-format
+msgid ""
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
+msgstr ""
+"Altmodülle özyineli birleştirme şu anda yalnızca önemsiz durumları "
+"destekler.\n"
+"Her bir çakışan altmodülün birleştirmesini lütfen elle yapın.\n"
+"Bu, aşağıdaki adımlarla gerçekleştirilebilir:\n"
+"%s - yukarıdaki birleştirmeyi kaydetmek veya güncellemek için\n"
+"     üst projeye geri gelin ve şunu çalıştırın:\n"
+"\n"
+"      git add %s\n"
+"\n"
+" - üst projedeki kalan diğer çakışmaları çözün\n"
+" - üst projedeki sonuç olarak alınan indeksi işleyin\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -16624,6 +16743,21 @@ msgstr "%s altmodülü birleştirilemedi (ileri sarım değil)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "Şu altmodül için olası bir birleştirme çözümü bulundu:\n"
 
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"Eğer bu doğruysa yalnızca indekse ekleyin, örneğin:\n"
+"\n"
+"\tgit update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"komutu bu öneriyi kabul edecektir.\n"
+
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
 msgstr "%s altmodülü birleştirilemedi (birden çok birleştirme bulundu)"
@@ -16685,7 +16819,7 @@ msgstr ""
 msgid "CONFLICT (rename/add): Rename %s->%s in %s.  Added %s in %s"
 msgstr ""
 "ÇAKIŞMA (yeniden adlandır/ekle): %s->%s olarak adlandırıldı (%s içinde). %s "
-"eklendi (%s içinde)."
+"eklendi (%s içinde)"
 
 #, c-format
 msgid "%s is a directory in %s adding as %s instead"
@@ -16730,7 +16864,7 @@ msgid ""
 ">%s in %s"
 msgstr ""
 "ÇAKIŞMA (y. adlandır/y. adlandır): Dizini %s->%s olarak adlandır (%s "
-"içinde). Dizini %s->%s olarak adlandır (%s içinde)."
+"içinde). Dizini %s->%s olarak adlandır (%s içinde)"
 
 msgid "modify"
 msgstr "değiştir"
@@ -16740,7 +16874,7 @@ msgstr "değiştirilmiş"
 
 #, c-format
 msgid "Skipped %s (merged same as existing)"
-msgstr "%s atlandı (mevcut ile aynı biçimde birleştirildi)"
+msgstr "%s atlandı (var olan ile aynı biçimde birleştirildi)"
 
 #, c-format
 msgid "Adding as %s instead"
@@ -16759,7 +16893,7 @@ msgstr "dizin/dosya"
 #, c-format
 msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
 msgstr ""
-"ÇAKIŞMA (%s): %s adıyla bir dizin var (%s içinde). %s, %s olarak ekleniyor."
+"ÇAKIŞMA (%s): %s adıyla bir dizin var (%s içinde). %s, %s olarak ekleniyor"
 
 #, c-format
 msgid "Adding %s"
@@ -16858,7 +16992,7 @@ msgid "malformed line: %s"
 msgstr "hatalı oluşturulmuş satır: %s"
 
 msgid "ignoring existing multi-pack-index; checksum mismatch"
-msgstr "mevcut multi-pack-index yok sayılıyor; sağlama toplamı uyumsuzluğu"
+msgstr "var olan multi-pack-index yok sayılıyor; sağlama toplamı uyumsuzluğu"
 
 msgid "could not load pack"
 msgstr "paket yüklenemedi"
@@ -16903,7 +17037,7 @@ msgid "failed to clear multi-pack-index at %s"
 msgstr "multi-pack-index %s konumunda temizlenemedi"
 
 msgid "multi-pack-index file exists, but failed to parse"
-msgstr "multi-pack-index dosyası mevcut, ancak ayrıştırılamadı"
+msgstr "multi-pack-index dosyası var; ancak ayrıştırılamadı"
 
 msgid "incorrect checksum"
 msgstr "yanlış sağlama toplamı"
@@ -17070,7 +17204,7 @@ msgstr "nesne dosyası %s boş"
 
 #, c-format
 msgid "corrupt loose object '%s'"
-msgstr "hasar görmüş gevşek nesne '%s'"
+msgstr "hasar gevşek nesne '%s'"
 
 #, c-format
 msgid "garbage at end of loose object '%s'"
@@ -17101,11 +17235,11 @@ msgstr "%s yedeği %s için bulunamadı"
 
 #, c-format
 msgid "loose object %s (stored in %s) is corrupt"
-msgstr "%s gevşek nesnesi (%s içinde depolanıyor) hasar görmüş"
+msgstr "%s gevşek nesnesi (%s içinde depolanıyor) hasar"
 
 #, c-format
 msgid "packed object %s (stored in %s) is corrupt"
-msgstr "paketlenmiş nesne %s (%s içinde depolanıyor) hasar görmüş"
+msgstr "paketlenmiş nesne %s (%s içinde depolanıyor) hasar"
 
 #, c-format
 msgid "unable to write file %s"
@@ -17143,15 +17277,31 @@ msgstr "%s nesnesi üzerinde deflateEnd başarısız oldu (%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "%s için olan nesne kaynak verisinden dolayı kafa karışıklığı"
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "akış nesnesini yaz %ld != %<PRIuMAX>"
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "yeni nesne akışı söndürülemiyor (%d)"
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "akış nesnesi üzerinde deflateEnd başarısız (%d)"
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr "%s dizini oluşturulamıyor"
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr "%s için nesne okunamıyor"
 
 msgid "corrupt commit"
-msgstr "hasar görmüş işleme"
+msgstr "hasar işleme"
 
 msgid "corrupt tag"
-msgstr "hasar görmüş etiket"
+msgstr "hasar etiket"
 
 #, c-format
 msgid "read error while indexing %s"
@@ -17284,12 +17434,12 @@ msgstr ""
 "oluşturmaz; çünkü 40 onaltılı bir başvuru, onu belirlediğiniz zaman yok\n"
 "sayılacaktır. Bu başvurular yanlışlıkla oluşturulmuş olabilir. Örneğin:\n"
 "\n"
-"\tgit switch -c $br $(git rev-parse ...)\n"
+"  git switch -c $br $(git rev-parse ...)\n"
 "\n"
 "komutunda \"$br\" bir şekilde boş kalmış ve 40 onaltılı bir başvuru\n"
 "oluşturulmuş. Lütfen bu başvuruları inceleyin ve gerekirse silin. Bu "
 "iletiyi\n"
-"kapatmak için \"git config advice.objectNameWarning\" yapın."
+"kapatmak için \"git config advice.objectNameWarning\" yapın"
 
 #, c-format
 msgid "log for '%.*s' only goes back to %s"
@@ -17301,7 +17451,7 @@ msgstr "'%.*s' günlüğünde yalnızca %d girdi var"
 
 #, c-format
 msgid "path '%s' exists on disk, but not in '%.*s'"
-msgstr "'%s' yolu disk üzerinde mevcut; ancak '%.*s' içinde değil"
+msgstr "'%s' yolu disk üzerinde var; ancak '%.*s' içinde değil"
 
 #, c-format
 msgid ""
@@ -17370,6 +17520,58 @@ msgstr "nesne ayrıştırılamıyor: %s"
 msgid "hash mismatch %s"
 msgstr "sağlama uyuşmazlığı %s"
 
+msgid "trying to write commit not in index"
+msgstr "indekste olmayan işleme yazılmaya çalışılıyor"
+
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "biteşlem indeksi yüklenemedi (hasarlı mı?)"
+
+msgid "corrupted bitmap index (too small)"
+msgstr "hasarlı biteşlem indeksi (pek küçük)"
+
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "hasarlı biteşlem indeks dosyası (yanlış üstbilgi)"
+
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "biteşlem indeks dosyası için desteklenmeyen sürüm '%d'"
+
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr ""
+"hasarlı biteşlem indeks dosyası (sağlama önbelleğine sığmak için pek küçük)"
+
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr ""
+"hasarlı biteşlem indeks dosyası (arama tablosuna sığmak için pek küçük)"
+
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "biteşlem indeksinde yinelenen girdi: '%s'"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "hasarlı ewah biteşlemi: %d girdisi için kısaltılmış üstbilgi"
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "hasarlı ewah biteşlemi: işleme erimi %u, erim dışında"
+
+msgid "corrupted bitmap pack index"
+msgstr "hasarlı biteşlem paket indeksi"
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "biteşlem paket indeksinde geçersi XOR ofseti"
+
+msgid "cannot fstat bitmap file"
+msgstr "biteşlem dosyası fstat yapılamıyor"
+
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "ek biteşlem dosyası yok sayılıyor: '%s'"
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "sağlama toplamı, MIDX ve biteşlem içinde uymuyor"
+
 msgid "multi-pack bitmap is missing required reverse index"
 msgstr "çoklu paket biteşlemi gereken ters indeksi içermiyor"
 
@@ -17381,9 +17583,57 @@ msgstr "%s paketi açılamadı"
 msgid "preferred pack (%s) is invalid"
 msgstr "tercih edilen (%s) paket geçersiz"
 
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "hasarlı biteşlem arama tablosu: üçlü konum indeks dışında"
+
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr "hasarlı biteşlem arama tablosu: xor zinciri, girdi sayısını aşıyor"
+
+#, c-format
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr "hasarlı biteşlem arama tablosu: işleme indeksi %u, erim dışında"
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr ""
+"hasarlı ewah biteşlemi: \"%s\" işlemesinin biteşleminde kısaltılmış üstbilgi"
+
+#, c-format
+msgid "object '%s' not found in type bitmaps"
+msgstr "'%s' nesnesi, tür biteşlemlerinde bulunamadı"
+
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "%s, %s paketi %<PRIuMAX> ofsetinde bulunamadı"
+msgid "object '%s' does not have a unique type"
+msgstr "'%s' nesnesinin benzersiz bir türü yok"
+
+#, c-format
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "'%s' nesnesi: gerçek tür '%s', beklenen: '%s'"
+
+#, c-format
+msgid "object not in bitmap: '%s'"
+msgstr "nesne, biteşlemde değil: '%s'"
+
+msgid "failed to load bitmap indexes"
+msgstr "biteşlem indeksi yüklenemedi"
+
+msgid "you must specify exactly one commit to test"
+msgstr "sınamak için tam olarak bir işleme belirtmelisiniz"
+
+#, c-format
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "'%s' işlemesinin indekslenmiş bir biteşlemi yok"
+
+msgid "mismatch in bitmap results"
+msgstr "biteşlem sonuçlarında uyuşmazlık"
+
+#, c-format
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "öge bulunamadı: '%s'; '%s' paketinde, %<PRIuMAX> ofsetinde"
+
+#, c-format
+msgid "unable to get disk usage of '%s'"
+msgstr "'%s' ögesinin disk kullanımı alınamadı"
 
 #, c-format
 msgid "mtimes file %s is too small"
@@ -17507,6 +17757,9 @@ msgstr "şunu mu demek istediniz: '--%s' (iki tire ile)?"
 msgid "alias of --%s"
 msgstr "şunun arması: --%s"
 
+msgid "need a subcommand"
+msgstr "bir altkomut gerekli"
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr "bilinmeyen seçenek '%s'"
@@ -17939,9 +18192,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -17952,8 +18208,8 @@ msgstr ""
 "e, edit <işleme> = işlemeyi kullan; ancak değiştirmek için dur\n"
 "s, squash <işleme> = işlemeyi kullan; ancak önceki işleme içine karıştır\n"
 "f, fixup [-C | -c] <işleme> = \"squash\" gibi; ancak yalnızca bir önceki\n"
-"                   işlemenin günlük iletisini tutar (-C kullanılmadıysa,\n"
-"                   o zaman yalnızca bu işlemenin iletisini tutar; -c, -C\n"
+"                   işlemenin günlük iletisini tutar (-C kullanılmadıysa\n"
+"                   o zaman yalnızca bu işlemenin iletisini tut; -c, -C\n"
 "                   ile aynıdır; ancak ek olarak düzenleyiciyi açar)\n"
 "x, exec <komut> = komutu (satırın geri kalanı) kabuk kullanarak çalıştır\n"
 "b, break = burada dur (daha sonra sürdürmek için 'git rebase --continue')\n"
@@ -17964,7 +18220,10 @@ msgstr ""
 ".       orijinal birleştirme işlemesi iletisini kullanarak bir\n"
 ".       birleştirme işlemesi oluştur (veya teksatır, eğer bir orijinal\n"
 ".       birleştirme işlemesi belirtilmemişse). İşleme iletisini yeniden\n"
-".       yazmak için -c <işleme> kullanın.\n"
+".       yazmak için -c <işleme> kullan.\n"
+"u, update-ref <baş> = yeni iletilerde <baş>'ın bu konuma güncellenmesi için\n"
+"                      bir yer tutucu izle. <baş>, yeniden temellendirmenin\n"
+"                      sonunda güncellenir\n"
 "\n"
 "Bu satırlar yeniden sıralanabilirler, yukarıdan aşağıya çalıştırılırlar.\n"
 
@@ -18035,9 +18294,9 @@ msgid ""
 msgstr ""
 "Bu iletiden kaçınmak için, bir işlemeyi kaldırırken açıkça \"drop\" "
 "kullanın.\n"
-"Uyarıların düzeyini değiştirmek için 'git config rebase.missingCommitsCheck' "
-"kullanın.\n"
-"Kullanılabilir davranışlar: ignore, warn, error.\n"
+"Uyarıların düzeyini değiştirmek için 'git config rebase."
+"missingCommitsCheck'\n"
+"kullanın. Kullanılabilir davranışlar: ignore, warn, error.\n"
 "\n"
 
 #, c-format
@@ -18434,6 +18693,13 @@ msgstr "protokol hatası: sha/ref bekleniyordu, '%s' alındı"
 msgid "http transport does not support %s"
 msgstr "http taşıyıcısı %s desteklemiyor"
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "protokol hatası: '<url> <yol>' bekleniyordu, eksik boşluk"
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "'%s' URL'sindeki dosya indirilemedi"
+
 msgid "git-http-push failed"
 msgstr "git-http-push başarısız"
 
@@ -18460,6 +18726,7 @@ msgstr "birden fazla receivepack verildi, birincisi kullanılıyor"
 msgid "more than one uploadpack given, using the first"
 msgstr "birden fazla uploadpack verildi, birincisi kullanılıyor"
 
+#, c-format
 msgid "unrecognized value transfer.credentialsInUrl: '%s'"
 msgstr "tanımlanamayan değer transfer.credentialsInUrl: '%s'"
 
@@ -18770,6 +19037,14 @@ msgstr "HEAD revizyonu saptanamadı"
 msgid "failed to find tree of %s"
 msgstr "%s ögesinin ağacı bulunamadı"
 
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo, kayıp olan '%s' ögesini kaydetmiş"
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "soy yolu argümanı %s için işleme alınamadı"
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<paketdosyası> artık desteklenmiyor"
 
@@ -18790,6 +19065,173 @@ msgstr "-L, -p ve -s dışında başka diff biçimlerini henüz desteklemiyor"
 msgid "cannot create async thread: %s"
 msgstr "async iş parçacığı oluşturulamadı: %s"
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' yok"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "şuraya geçilemedi: '%s'"
+
+msgid "need a working directory"
+msgstr "bir çalışma dizini gerekiyor"
+
+msgid "Scalar enlistments require a worktree"
+msgstr "Scalar gönüllü kayıtları bir çalışma ağacı gerektiriyor"
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "%s=%s yapılandırılamadı"
+
+msgid "could not configure log.excludeDecoration"
+msgstr "log.excludeDecoration yapılandırılamadı"
+
+msgid "could not add enlistment"
+msgstr "gönüllü yazılma eklenemedi"
+
+msgid "could not set recommended config"
+msgstr "önerilen yapılandırma ayarlanamadı"
+
+msgid "could not turn on maintenance"
+msgstr "bakım ayarı açılamadı"
+
+msgid "could not start the FSMonitor daemon"
+msgstr "FSMonitor ardalan süreci başlatılamadı"
+
+msgid "could not turn off maintenance"
+msgstr "bakım ayarı kapatılamadı"
+
+msgid "could not remove enlistment"
+msgstr "gönüllü yazılma kaldırılamadı"
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "uzak konum HEAD'i bir dal değil: '%.*s'"
+
+msgid "failed to get default branch name from remote; using local default"
+msgstr ""
+"uzak konumdan öntanımlı dal adı alınamadı; yerel öntanımlı kullanılıyor"
+
+msgid "failed to get default branch name"
+msgstr "öntanımlı dal adı alınamadı"
+
+msgid "failed to unregister repository"
+msgstr "depo kaydı silinemedi"
+
+msgid "failed to stop the FSMonitor daemon"
+msgstr "FSMonitor ardalan süreci durdurulamadı"
+
+msgid "failed to delete enlistment directory"
+msgstr "gönüllü kayıt dizini silinemedi"
+
+msgid "branch to checkout after clone"
+msgstr "klonlama sonrası çıkış yapılacak dal"
+
+msgid "when cloning, create full working directory"
+msgstr "klonlama sırasında tam çalışma dizini oluştur"
+
+msgid "only download metadata for the branch that will be checked out"
+msgstr "yalnızca çıkış yapılacak dalın üstverisini indir"
+
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<seçenekler>] [--] <depo> [<dizin>]"
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "'%s' ögesinden çalışma ağacı adı ortaya çıkarılamıyor"
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "'%s' dizini halihazırda var"
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "'%s' için öntanımlı dal alınamadı"
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "'%s' içindeki uzak konum yapılandırılamadı"
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr "'%s' yapılandırılamadı"
+
+msgid "partial clone failed; attempting full clone"
+msgstr "kısımsal klonlama başarısız; tam klonlama deneniyor"
+
+msgid "could not configure for full clone"
+msgstr "tam klonlama için yapılandırılamadı"
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<gönüllükayıt>]"
+
+msgid "`scalar list` does not take arguments"
+msgstr "'scalar list' argüman almıyor"
+
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<gönüllükayıt>]"
+
+msgid "reconfigure all registered enlistments"
+msgstr "tüm kaydı yapılmış gönüllü kayıtları yeniden yapılandır"
+
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <gönüllükayıt>]"
+
+msgid "--all or <enlistment>, but not both"
+msgstr "--all veya <gönüllükayıt>; ancak ikisi değil"
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "git deposu '%s' içinde gitti"
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <görev> [<gönüllükayıt>]\n"
+"Görevler:\n"
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr "böyle bir görev yok: '%s'"
+
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<enlistment>]"
+
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <gönüllükayıt>"
+
+msgid "refusing to delete current working directory"
+msgstr "geçerli çalışma dizinini silme reddediliyor"
+
+msgid "include Git version"
+msgstr "Git sürümünü içer"
+
+msgid "include Git's build options"
+msgstr "Git'in yapı seçeneklerini içer"
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+msgid "-C requires a <directory>"
+msgstr "-C, bir <dizin> gerektiriyor"
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr "'%s' olarak değiştirilemedi"
+
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c, bir <anahtar>=<değer> argümanı gerektiriyor"
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <dizin>] [-c <anahtar>=<değer>] <komut> [<seçenekler>]\n"
+"\n"
+"Komutlar:\n"
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr "uzak konum açım durumu okunurken beklenmedik floş paketi"
 
@@ -18910,10 +19352,6 @@ msgstr "%s ile yerel değişikliklerinizin üzerine yazılacaktır."
 msgid "commit your changes or stash them to proceed."
 msgstr "İlerlemek için değişikliklerinizi işleyin veya zulalayın."
 
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s: ileri sar"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -18976,15 +19414,15 @@ msgstr ""
 "Eğer bu değişikliklerin bir önceki işlemeye eklenmesi\n"
 "gerekiyorsa şu komutu çalıştırın:\n"
 "\n"
-"\tgit commit --amend %s\n"
+"  git commit --amend %s\n"
 "\n"
 "Yeni bir işleme yapmak istiyorsanız şu komutu çalıştırın:\n"
 "\n"
-"\tgit commit %s\n"
+"  git commit %s\n"
 "\n"
 "Her iki durumda da işiniz bittikten sonra şu komut ile sürdürün:\n"
 "\n"
-"\tgit rebase --continue\n"
+"  git rebase --continue\n"
 
 msgid "'prepare-commit-msg' hook failed"
 msgstr "'prepare-commit-msg' başarısız oldu"
@@ -19397,6 +19835,27 @@ msgstr "şunu birleştirme girişiminde bulunulamadı bile: '%.*s'"
 msgid "merge: Unable to write new index file"
 msgstr "merge: Yeni indeks dosyası yazılamıyor"
 
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "başka bir 'rebase' süreci çalışıyor gibi; '%s.lock' halihazırda var"
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"Aşağıdaki başvurular, %s ile güncellendi:\n"
+"%s"
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"Aşağıdaki başvurular, %s ile güncellenemedi:\n"
+"%s"
+
 msgid "Cannot autostash"
 msgstr "Kendiliğinden zulalanamıyor"
 
@@ -19562,6 +20021,10 @@ msgstr "gerekli olmayan seçim komutları atlanamadı"
 msgid "the script was already rearranged."
 msgstr "betik halihazırda yeniden düzenlenmişti."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "'%s' konumundaki update-refs dosyası geçersiz"
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr "'%s', '%s' konumunda depo dışında"
@@ -19681,16 +20144,20 @@ msgstr ""
 
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"güvensiz depo ('%s' sahibi bir başkası)\n"
-"Bu dizin için bir istisna eklemek için şunu çağırın:\n"
+"'%s' konumundaki depoda belirsiz iyelik algılandı\n"
+"%sBu dizin için istisna eklemek için şunu çağırın:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "çıplak depo '%s', kullanılamaz (safe.bareRepository '%s')"
+
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -20555,6 +21022,18 @@ msgstr "geçersiz kapı numarası"
 msgid "invalid '..' path segment"
 msgstr "geçersiz '..' yol kesimi"
 
+msgid "usage: "
+msgstr "kullanım: "
+
+msgid "fatal: "
+msgstr "onulmaz: "
+
+msgid "error: "
+msgstr "hata: "
+
+msgid "warning: "
+msgstr "uyarı: "
+
 msgid "Fetching objects"
 msgstr "Nesneler getiriliyor"
 
@@ -21345,22 +21824,6 @@ msgstr "Seçili parçalar indekse uygulanamıyor!\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "birleştirilmeyenler yok sayılıyor: %s\n"
 
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "Kip değişimi çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "Silme çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "Ekleme çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
-
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "Bu parça çalışma ağacına uygulansın mı [y,n,q,a,d%s,?]? "
-
 msgid "No other hunks to goto\n"
 msgstr "Gidilecek başka parça yok\n"
 
index 7de9c72d5646191f0a825ce9d40a2aebff8bb9b1..b0832be6952b61c33f15d176985cf13ccb4fc195 100644 (file)
@@ -144,8 +144,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-22 10:25+0100\n"
-"PO-Revision-Date: 2022-06-14 20:52+0100\n"
+"POT-Creation-Date: 2022-09-28 15:50+0100\n"
+"PO-Revision-Date: 2022-09-23 14:53+0100\n"
 "Last-Translator: Fangyi Zhou <me@fangyi.io>\n"
 "Language-Team: GitHub <https://github.com/fangyi-zhou/git-po/>\n"
 "Language: zh_CN\n"
@@ -153,14 +153,14 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Gtranslator 40.0\n"
+"X-Generator: Gtranslator 42.0\n"
 
 #: add-interactive.c
 #, c-format
 msgid "Huh (%s)?"
 msgstr "嗯(%s)?"
 
-#: add-interactive.c builtin/rebase.c reset.c sequencer.c
+#: add-interactive.c builtin/merge.c builtin/rebase.c reset.c sequencer.c
 msgid "could not read index"
 msgstr "不能读取索引"
 
@@ -341,8 +341,8 @@ msgid "unstaged"
 msgstr "未缓存"
 
 #: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
-#: builtin/fetch.c builtin/merge.c builtin/pull.c builtin/submodule--helper.c
-#: git-add--interactive.perl
+#: builtin/diagnose.c builtin/fetch.c builtin/merge.c builtin/pull.c
+#: builtin/submodule--helper.c git-add--interactive.perl
 msgid "path"
 msgstr "路径"
 
@@ -623,6 +623,26 @@ msgstr ""
 "a - 应用该块和本文件中后面的全部块\n"
 "d - 不要应用该块和本文件中后面的全部块\n"
 
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "将模式变更应用到工作区 [y,n,q,a,d%s,?]? "
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "将删除操作应用到工作区 [y,n,q,a,d%s,?]? "
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "将添加操作应用到工作区 [y,n,q,a,d%s,?]? "
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "将该块应用到工作区 [y,n,q,a,d%s,?]? "
+
 #: add-patch.c
 msgid ""
 "y - apply this hunk to worktree\n"
@@ -642,11 +662,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "无法解析数据块头信息 '%.*s'"
 
-#: add-patch.c
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "无法解析彩色数据块头信息 '%.*s'"
-
 #: add-patch.c
 msgid "could not parse diff"
 msgstr "不能解析差异信息"
@@ -973,6 +988,26 @@ msgstr ""
 "通过将配置变量 advice.detachedHead 设置为 false 来关闭此建议\n"
 "\n"
 
+#: advice.c
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"下列的路径已经被移动至稀疏检出的定义之外,\n"
+"但是由于本地的修改而并非稀疏。\n"
+
+#: advice.c
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"为了修正这些的路径的稀疏性,请运行下列命令:\n"
+"* 使用 \"git add --sparse <路径>\" 来更新索引\n"
+"* 使用 \"git sparse-checkout reapply\" 来应用稀疏规则"
+
 #: alias.c
 msgid "cmdline ends with \\"
 msgstr "命令行以 \\ 结尾"
@@ -1204,7 +1239,7 @@ msgstr "到 '%s' 的二进制补丁产生了不正确的结果(应为 %s,却
 msgid "patch failed: %s:%ld"
 msgstr "打补丁失败:%s:%ld"
 
-#: apply.c
+#: apply.c builtin/mv.c
 #, c-format
 msgid "cannot checkout %s"
 msgstr "不能检出 %s"
@@ -1597,6 +1632,11 @@ msgstr "不能打开数据对象 %s"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "不支持的文件模式:0%o (SHA1: %s)"
 
+#: archive-tar.c archive-zip.c builtin/pack-objects.c
+#, c-format
+msgid "deflate error (%d)"
+msgstr "压缩错误 (%d)"
+
 #: archive-tar.c
 #, c-format
 msgid "unable to start '%s' filter"
@@ -1621,11 +1661,6 @@ msgstr "路径不是有效的 UTF-8:%s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "路径太长(%d 字符,SHA1:%s):%s"
 
-#: archive-zip.c builtin/pack-objects.c
-#, c-format
-msgid "deflate error (%d)"
-msgstr "压缩错误 (%d)"
-
 #: archive-zip.c
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
@@ -1941,10 +1976,10 @@ msgid "--reverse and --first-parent together require specified latest commit"
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c ref-filter.c
-#: remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c pack-bitmap.c
+#: ref-filter.c remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
-msgstr "版本遍历设置失败"
+msgstr "版本遍历初始化失败"
 
 #: blame.c
 msgid ""
@@ -2399,7 +2434,7 @@ msgstr "fseek 失败"
 msgid "could not open '%s' for reading"
 msgstr "无法打开 '%s' 进行读取"
 
-#: builtin/am.c builtin/rebase.c strbuf.c wrapper.c
+#: builtin/am.c builtin/rebase.c sequencer.c strbuf.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "无法打开 '%s' 进行写入"
@@ -2700,8 +2735,8 @@ msgid "n"
 msgstr "n"
 
 #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
-#: builtin/for-each-ref.c builtin/ls-tree.c builtin/replace.c builtin/tag.c
-#: builtin/verify-tag.c
+#: builtin/diagnose.c builtin/for-each-ref.c builtin/ls-files.c
+#: builtin/ls-tree.c builtin/replace.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "格式"
 
@@ -2804,7 +2839,7 @@ msgstr "交互式模式需要命令行上提供补丁"
 msgid "git apply [<options>] [<patch>...]"
 msgstr "git apply [<选项>] [<补丁>...]"
 
-#: builtin/archive.c contrib/scalar/scalar.c
+#: builtin/archive.c diagnose.c
 msgid "could not redirect output"
 msgstr "不能重定向输出"
 
@@ -3686,8 +3721,8 @@ msgstr "排序和过滤属于大小写不敏感"
 msgid "recurse through submodules"
 msgstr "在子模组中递归"
 
-#: builtin/branch.c builtin/for-each-ref.c builtin/ls-tree.c builtin/tag.c
-#: builtin/verify-tag.c
+#: builtin/branch.c builtin/for-each-ref.c builtin/ls-files.c builtin/ls-tree.c
+#: builtin/tag.c builtin/verify-tag.c
 msgid "format to use for the output"
 msgstr "输出格式"
 
@@ -3810,8 +3845,12 @@ msgid "not run from a git repository - no hooks to show\n"
 msgstr "不是在 git 仓库中执行 - 没有可显示的钩子\n"
 
 #: builtin/bugreport.c
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <文件>] [-s|--suffix <格式>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <文件>] [-s|--suffix <格式>] [--"
+"diagnose[=<模式>]"
 
 #: builtin/bugreport.c
 msgid ""
@@ -3847,19 +3886,34 @@ msgstr ""
 "请检查下面错误报告中余下的内容。\n"
 "您可以删除任何您不想共享的内容。\n"
 
+#: builtin/bugreport.c builtin/commit.c builtin/fast-export.c builtin/rebase.c
+#: parse-options.h
+msgid "mode"
+msgstr "模式"
+
+#: builtin/bugreport.c
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr "额外创建详细诊断信息的压缩包(默认 'stats')"
+
 #: builtin/bugreport.c
-msgid "specify a destination for the bugreport file"
+msgid "specify a destination for the bugreport file(s)"
 msgstr "指定错误报告文件的目标位置"
 
 #: builtin/bugreport.c
-msgid "specify a strftime format suffix for the filename"
+msgid "specify a strftime format suffix for the filename(s)"
 msgstr "指定文件的 strftime 格式后缀"
 
-#: builtin/bugreport.c
+#: builtin/bugreport.c builtin/diagnose.c
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "不能为 '%s' 创建先导目录"
 
+#: builtin/bugreport.c builtin/diagnose.c
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "不能创建诊断归档包 %s"
+
 #: builtin/bugreport.c
 msgid "System Info"
 msgstr "系统信息"
@@ -3935,11 +3989,6 @@ msgstr "需要一个仓库来解开归档包。"
 msgid "Unbundling objects"
 msgstr "解包对象中"
 
-#: builtin/bundle.c builtin/remote.c
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "未知子命令:%s"
-
 #: builtin/cat-file.c merge-recursive.c
 #, c-format
 msgid "cannot read object %s '%s'"
@@ -4037,6 +4086,10 @@ msgstr "显示对象大小"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "允许 -s 和 -t 对损坏的对象生效"
 
+#: builtin/cat-file.c builtin/log.c
+msgid "use mail map file"
+msgstr "使用邮件映射文件"
+
 #: builtin/cat-file.c
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "批量处理标准输入中请求的对象(或者 --batch-all-objects)"
@@ -4049,6 +4102,10 @@ msgstr "显示完整的 <对象> 或 <版本> 内容"
 msgid "like --batch, but don't emit <contents>"
 msgstr "类似于 --batch,但不输出 <内容>"
 
+#: builtin/cat-file.c
+msgid "stdin is NUL-terminated"
+msgstr "标准输入以 NUL 字符分隔"
+
 #: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "从标准输入读取命令"
@@ -4725,7 +4782,7 @@ msgstr ""
 
 #: builtin/checkout.c
 msgid "you must specify path(s) to restore"
-msgstr "您必须指定一个要恢复的路径"
+msgstr "您必须指定要恢复的路径"
 
 #: builtin/checkout.c builtin/clone.c builtin/remote.c
 #: builtin/submodule--helper.c builtin/worktree.c
@@ -5130,6 +5187,14 @@ msgstr "任何克隆的子模组将使用它们的远程跟踪分支"
 msgid "initialize sparse-checkout file to include only files at root"
 msgstr "初始化稀疏检出文件,只包含根目录文件"
 
+#: builtin/clone.c
+msgid "uri"
+msgstr "uri"
+
+#: builtin/clone.c
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "用于在从 origin 远程获取之前下载归档包的 URI"
+
 #: builtin/clone.c
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
@@ -5204,8 +5269,8 @@ msgid "failed to initialize sparse-checkout"
 msgstr "无法初始化稀疏检出"
 
 #: builtin/clone.c
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr "远程 HEAD 指向一个不存在的引用,无法检出。\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "远程 HEAD 指向一个不存在的引用,无法检出"
 
 #: builtin/clone.c
 msgid "unable to checkout working tree"
@@ -5227,7 +5292,7 @@ msgstr "无法删除临时的 alternates 文件"
 msgid "Too many arguments."
 msgstr "太多参数。"
 
-#: builtin/clone.c contrib/scalar/scalar.c
+#: builtin/clone.c scalar.c
 msgid "You must specify a repository to clone."
 msgstr "您必须指定一个仓库来克隆。"
 
@@ -5236,6 +5301,12 @@ msgstr "您必须指定一个仓库来克隆。"
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "选项 '%s' 和 '%s %s' 不能同时使用"
 
+#: builtin/clone.c
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr "--bundle-uri 与 --depth、--shallow-since 和 --shallow-exclude 不兼容"
+
 #: builtin/clone.c
 #, c-format
 msgid "repository '%s' does not exist"
@@ -5324,6 +5395,15 @@ msgstr "--local 被忽略"
 msgid "cannot clone from filtered bundle"
 msgstr "无法从经过过滤的归档包克隆"
 
+#: builtin/clone.c
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "无法初始化仓库,跳过归档包 URI"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "无法从归档包 URI '%s' 获取对象"
+
 #: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "远程传输报告错误"
@@ -5471,11 +5551,6 @@ msgstr "不能同时使用 --reachable、--stdin-commits 或 --stdin-packs"
 msgid "Collecting commits from input"
 msgstr "正从标准输入收集提交"
 
-#: builtin/commit-graph.c builtin/multi-pack-index.c
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "未识别的子命令:%s"
-
 #: builtin/commit-tree.c
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
@@ -5903,10 +5978,6 @@ msgstr "以长格式显示状态(默认)"
 msgid "terminate entries with NUL"
 msgstr "条目以 NUL 字符结尾"
 
-#: builtin/commit.c builtin/fast-export.c builtin/rebase.c parse-options.h
-msgid "mode"
-msgstr "模式"
-
 #: builtin/commit.c
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr "显示未跟踪的文件,“模式”的可选参数:all、normal、no。(默认:all)"
@@ -6644,6 +6715,26 @@ msgstr "没有发现名称,无法描述任何东西。"
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "选项 '%s' 和提交号不能同时使用"
 
+#: builtin/diagnose.c
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <文件>] [-s|--suffix <格式>] [--mode=<模"
+"式>]"
+
+#: builtin/diagnose.c
+msgid "specify a destination for the diagnostics archive"
+msgstr "指定诊断归档包的目标位置"
+
+#: builtin/diagnose.c
+msgid "specify a strftime format suffix for the filename"
+msgstr "指定文件的 strftime 格式后缀"
+
+#: builtin/diagnose.c
+msgid "specify the content of the diagnostic archive"
+msgstr "指定诊断信息归档包的内容"
+
 #: builtin/diff-tree.c
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base 仅适用于两个提交"
@@ -7115,12 +7206,8 @@ msgid "[rejected]"
 msgstr "[已拒绝]"
 
 #: builtin/fetch.c
-msgid "can't fetch in current branch"
-msgstr "当前分支下不能执行获取操作"
-
-#: builtin/fetch.c
-msgid "checked out in another worktree"
-msgstr "已在另一个工作树中检出"
+msgid "can't fetch into checked-out branch"
+msgstr "无法获取到已检出的分支"
 
 #: builtin/fetch.c
 msgid "[tag update]"
@@ -7658,6 +7745,11 @@ msgstr "%s:cache-tree 中无效的 sha1 指针"
 msgid "non-tree in cache-tree"
 msgstr "cache-tree 中非树对象"
 
+#: builtin/fsck.c
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s:resolve-undo 中无效的 sha1 指针"
+
 #: builtin/fsck.c
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<选项>] [<对象>...]"
@@ -8075,12 +8167,16 @@ msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr "无法执行 'crontab -l',您的系统可能不支持 'cron'"
 
 #: builtin/gc.c
-msgid "failed to run 'crontab'; your system might not support 'cron'"
-msgstr "无法运行 'crontab',您的系统可能不支持 'cron'"
+msgid "failed to create crontab temporary file"
+msgstr "无法创建 crontab 临时文件"
 
 #: builtin/gc.c
-msgid "failed to open stdin of 'crontab'"
-msgstr "无法打开 'crontab' 的标准输入"
+msgid "failed to open temporary file"
+msgstr "无法打开临时文件"
+
+#: builtin/gc.c
+msgid "failed to run 'crontab'; your system might not support 'cron'"
+msgstr "无法运行 'crontab',您的系统可能不支持 'cron'"
 
 #: builtin/gc.c
 msgid "'crontab' died"
@@ -8142,11 +8238,6 @@ msgstr "无法将仓库添加到全局配置"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <子命令> [<选项>]"
 
-#: builtin/gc.c
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "无效子命令:%s"
-
 #: builtin/grep.c
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<选项>] [-e] <模式> [<版本>...] [[--] <路径>...]"
@@ -8370,6 +8461,10 @@ msgstr "分页显示匹配的文件"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "允许调用 grep(1)(本次构建忽略)"
 
+#: builtin/grep.c
+msgid "maximum number of results per file"
+msgstr "每个文件的最大结果数量"
+
 #: builtin/grep.c
 msgid "no pattern given"
 msgstr "未提供匹配模式"
@@ -8481,13 +8576,21 @@ msgstr "打印命令描述"
 msgid "print list of useful guides"
 msgstr "显示有用的指南列表"
 
+#: builtin/help.c
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr "打印面向用户的仓库、命令和文件接口列表"
+
+#: builtin/help.c
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr "打印文件格式、协议和其他开发者接口列表"
+
 #: builtin/help.c
 msgid "print all configuration variable names"
 msgstr "打印所有配置变量名称"
 
 #: builtin/help.c
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<命令>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<命令>|<文档>]"
 
 #: builtin/help.c
 #, c-format
@@ -9078,8 +9181,8 @@ msgid "show source"
 msgstr "显示源"
 
 #: builtin/log.c
-msgid "use mail map file"
-msgstr "使用邮件映射文件"
+msgid "clear all previously-defined decoration filters"
+msgstr "清除所有之前定义的修饰过滤器"
 
 #: builtin/log.c
 msgid "only decorate refs that match <pattern>"
@@ -9404,6 +9507,10 @@ msgstr "在附函或单个补丁中显示和 <引用规格> 的差异"
 msgid "percentage by which creation is weighted"
 msgstr "创建权重的百分比"
 
+#: builtin/log.c
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "显示正文内的 From:,即使其与电子邮件头中一致"
+
 #: builtin/log.c
 #, c-format
 msgid "invalid ident line: %s"
@@ -9479,11 +9586,26 @@ msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "不能找到跟踪的远程分支,请手工指定 <上游>。\n"
 
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "坏的 ls-files 格式:元素 '%s' 没有以 '(' 开头"
+
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "坏的 ls-files 格式:元素 '%s' 没有以 ')' 结尾"
+
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "坏的 ls-files 格式: %%%.*s"
+
 #: builtin/ls-files.c
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<选项>] [<文件>...]"
 
-#: builtin/ls-files.c
+#: builtin/ls-files.c builtin/merge-tree.c
 msgid "separate paths with the NUL character"
 msgstr "用 NUL 字符分隔路径"
 
@@ -9591,6 +9713,14 @@ msgstr "抑制重复条目"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "在稀疏索引存在时显示稀疏目录"
 
+#: builtin/ls-files.c
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format 不能和 -s、-o、-k、-t、--resolve-undo、--deduplicate 和 --eol 同时使"
+"用"
+
 #: builtin/ls-remote.c
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
@@ -9874,6 +10004,50 @@ msgstr "无法解析引用 '%s'"
 msgid "Merging %s with %s\n"
 msgstr "合并 %s 和 %s\n"
 
+#: builtin/merge-tree.c builtin/merge.c
+msgid "not something we can merge"
+msgstr "不是可以合并的东西"
+
+#: builtin/merge-tree.c builtin/merge.c
+msgid "refusing to merge unrelated histories"
+msgstr "拒绝合并无关的历史"
+
+#: builtin/merge-tree.c
+msgid "failure to merge"
+msgstr "合并失败"
+
+#: builtin/merge-tree.c
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<选项>] <分支1> <分支2>"
+
+#: builtin/merge-tree.c
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <基准树> <分支1> <分支2>"
+
+#: builtin/merge-tree.c
+msgid "do a real merge instead of a trivial merge"
+msgstr "进行真正的合并而不是简单的合并"
+
+#: builtin/merge-tree.c
+msgid "do a trivial merge only"
+msgstr "只进行简单的合并"
+
+#: builtin/merge-tree.c
+msgid "also show informational/conflict messages"
+msgstr "同时显示额外信息/冲突消息"
+
+#: builtin/merge-tree.c
+msgid "list filenames without modes/oids/stages"
+msgstr "列出没有模式/对象 ID/暂存的文件名"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "allow merging unrelated histories"
+msgstr "允许合并不相关的历史"
+
+#: builtin/merge-tree.c
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge 与其他所有选项不兼容"
+
 #: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<选项>] [<提交>...]"
@@ -9980,10 +10154,6 @@ msgstr "--abort,但是保留索引和工作区"
 msgid "continue the current in-progress merge"
 msgstr "继续当前正在进行的合并"
 
-#: builtin/merge.c builtin/pull.c
-msgid "allow merging unrelated histories"
-msgstr "允许合并不相关的历史"
-
 #: builtin/merge.c
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "绕过 pre-merge-commit 和 commit-msg 钩子"
@@ -10128,10 +10298,6 @@ msgstr "不能关闭 '%s'"
 msgid "not something we can merge in %s: %s"
 msgstr "不能在 %s 中合并:%s"
 
-#: builtin/merge.c
-msgid "not something we can merge"
-msgstr "不能合并"
-
 #: builtin/merge.c
 msgid "--abort expects no arguments"
 msgstr "--abort 不带参数"
@@ -10193,15 +10359,20 @@ msgstr "%s - 不能被合并"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "只能将一个提交合并到空分支上"
 
-#: builtin/merge.c
-msgid "refusing to merge unrelated histories"
-msgstr "拒绝合并无关的历史"
-
 #: builtin/merge.c
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "更新 %s..%s\n"
 
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"您对下列文件的本地修改将被合并操作覆盖:\n"
+"  %s"
+
 #: builtin/merge.c
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
@@ -10242,6 +10413,11 @@ msgstr "使用 %s 策略以准备手工解决。\n"
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr "自动合并进展顺利,按要求在提交前停止\n"
 
+#: builtin/merge.c
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "在完成后,使用 `git stash pop` 应用贮藏的变更\n"
+
 #: builtin/mktag.c
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
@@ -10389,6 +10565,10 @@ msgstr "检查 '%s' 到 '%s' 的重命名\n"
 msgid "bad source"
 msgstr "坏的源"
 
+#: builtin/mv.c
+msgid "destination exists"
+msgstr "目标已存在"
+
 #: builtin/mv.c
 msgid "can not move directory into itself"
 msgstr "不能将目录移动到自身"
@@ -10409,10 +10589,6 @@ msgstr "不在版本控制之下"
 msgid "conflicted"
 msgstr "冲突"
 
-#: builtin/mv.c
-msgid "destination exists"
-msgstr "目标已存在"
-
 #: builtin/mv.c
 #, c-format
 msgid "overwriting '%s'"
@@ -10430,6 +10606,10 @@ msgstr "同一目标具有多个源"
 msgid "destination directory does not exist"
 msgstr "目标目录不存在"
 
+#: builtin/mv.c
+msgid "destination exists in the index"
+msgstr "目标在索引中已存在"
+
 #: builtin/mv.c
 #, c-format
 msgid "%s, source=%s, destination=%s"
@@ -10872,10 +11052,10 @@ msgstr "注解引用"
 msgid "use notes from <notes-ref>"
 msgstr "从 <注解引用> 使用注解"
 
-#: builtin/notes.c builtin/stash.c
+#: builtin/notes.c builtin/remote.c parse-options.c
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "未知子命令:%s"
+msgid "unknown subcommand: `%s'"
+msgstr "未知子命令:`%s'"
 
 #: builtin/pack-objects.c
 msgid ""
@@ -11473,7 +11653,7 @@ msgstr "详见 git-pull(1)。"
 msgid "<remote>"
 msgstr "<远程>"
 
-#: builtin/pull.c contrib/scalar/scalar.c
+#: builtin/pull.c scalar.c
 msgid "<branch>"
 msgstr "<分支>"
 
@@ -11924,14 +12104,20 @@ msgstr "仅显示与第一个范围有关的输出"
 msgid "only emit output related to the second range"
 msgstr "仅显示与第二个范围有关的输出"
 
+#: builtin/range-diff.c
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "不是版本:'%s'"
+
 #: builtin/range-diff.c
 #, c-format
 msgid "not a commit range: '%s'"
-msgstr "不是一个提交范围:'%s'"
+msgstr "不是提交范围:'%s'"
 
 #: builtin/range-diff.c
-msgid "single arg format must be symmetric range"
-msgstr "单个参数格式必须是对称范围(即包含...)"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "不是对称的范围:'%s'"
 
 #: builtin/range-diff.c
 msgid "need two commit ranges"
@@ -12265,6 +12451,10 @@ msgstr "保留初始为空的提交"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "在 -i 交互模式下,移动以 squash!/fixup! 开头的提交"
 
+#: builtin/rebase.c
+msgid "update branches that point to commits that are being rebased"
+msgstr "更新指向正在被变基的提交的分支"
+
 #: builtin/rebase.c
 msgid "add exec lines after each commit of the editable list"
 msgstr "可编辑列表的每一个提交下面增加一行 exec"
@@ -12888,6 +13078,10 @@ msgstr " 新的(下一次获取将存储于 remotes/%s)"
 msgid " tracked"
 msgstr " 已跟踪"
 
+#: builtin/remote.c
+msgid " skipped"
+msgstr " 已跳过"
+
 #: builtin/remote.c
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " 过时(使用 'git remote prune' 来移除)"
@@ -13729,11 +13923,16 @@ msgstr "不能重置索引文件至版本 '%s'。"
 msgid "Could not write new index file."
 msgstr "不能写入新的索引文件。"
 
-#: builtin/rev-list.c pack-bitmap.c
+#: builtin/rev-list.c
 #, c-format
 msgid "unable to get disk usage of %s"
 msgstr "无法得到 %s 的磁盘使用量"
 
+#: builtin/rev-list.c
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "'%s' 的值无效:'%s',唯一允许的格式是 '%s'"
+
 #: builtin/rev-list.c
 msgid "rev-list does not support display of notes"
 msgstr "rev-list 不支持显示注解"
@@ -13767,6 +13966,10 @@ msgstr "输入过早结束"
 msgid "no usage string given before the `--' separator"
 msgstr "在 `--' 分隔符之前没有给出使用方法字符串"
 
+#: builtin/rev-parse.c
+msgid "missing opt-spec before option flags"
+msgstr "选项参数之前缺少选项规格"
+
 #: builtin/rev-parse.c
 msgid "Needed a single revision"
 msgstr "需要一个单独的版本"
@@ -14317,7 +14520,7 @@ msgstr "初始化稀疏检出为锥形模式"
 msgid "toggle the use of a sparse index"
 msgstr "切换稀疏索引的使用"
 
-#: builtin/sparse-checkout.c commit-graph.c midx.c
+#: builtin/sparse-checkout.c commit-graph.c midx.c sequencer.c
 #, c-format
 msgid "unable to create leading directories of %s"
 msgstr "不能为 %s 创建先导目录"
@@ -14711,6 +14914,11 @@ msgstr "为每一行的行首添加注释符和空格"
 msgid "Expecting a full ref name, got %s"
 msgstr "期望一个完整的引用名称,却得到 %s"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "无法获得子模组 '%s' 的仓库句柄"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid ""
@@ -14718,14 +14926,6 @@ msgid ""
 "authoritative upstream."
 msgstr "无法找到配置 '%s'。假定这个仓库是其自身的官方上游。"
 
-#: builtin/submodule--helper.c
-msgid "alternative anchor for relative paths"
-msgstr "相对路径的替代锚记(anchor)"
-
-#: builtin/submodule--helper.c
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<路径>] [<路径>...]"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
@@ -14764,8 +14964,8 @@ msgid "recurse into nested submodules"
 msgstr "递归进入嵌套子模组中"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <命令>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <命令>"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14792,8 +14992,8 @@ msgid "suppress output for initializing a submodule"
 msgstr "抑制子模组初始化的输出"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<选项>] [<路径>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<选项>] [<路径>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14824,10 +15024,6 @@ msgstr "使用存储在索引中的提交,而非存储在子模组 HEAD 中的
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<路径>...]"
 
-#: builtin/submodule--helper.c
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <路径>"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
@@ -14870,8 +15066,8 @@ msgid "limit the summary size"
 msgstr "限制总结的大小"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<选项>] [<提交>] [--] [<路径>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<选项>] [<提交>] [--] [<路径>]"
 
 #: builtin/submodule--helper.c
 msgid "could not fetch a revision for HEAD"
@@ -14887,11 +15083,6 @@ msgstr "为 '%s' 同步子模组 url\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "无法为子模组路径 '%s' 注册 url"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "无法得到子模组 '%s' 的默认远程关联"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "failed to update remote for submodule '%s'"
@@ -14902,8 +15093,8 @@ msgid "suppress output of synchronizing submodule url"
 msgstr "抑制子模组 URL 同步的输出"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<路径>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<路径>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14971,6 +15162,11 @@ msgstr ""
 "Git 不使用备用仓库克隆,或者等效地使用 '--reference-if-able' 而非\n"
 "'--reference' 来克隆。"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "无法获得 git 目录 '%s' 的仓库句柄"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
@@ -15006,6 +15202,10 @@ msgstr "目录非空:'%s'"
 msgid "could not get submodule directory for '%s'"
 msgstr "无法得到 '%s' 的子模组目录"
 
+#: builtin/submodule--helper.c
+msgid "alternative anchor for relative paths"
+msgstr "相对路径的替代锚记(anchor)"
+
 #: builtin/submodule--helper.c
 msgid "where the new submodule will be cloned to"
 msgstr "新的子模组将要克隆的路径"
@@ -15040,11 +15240,6 @@ msgstr ""
 "[--name <名字>] [--depth <深度>] [--single-branch] [--filter <过滤器规格>] --"
 "url <url> --path <路径>"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "子模组路径 '%2$s' 的更新模式 '%1$s' 无效"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
@@ -15131,6 +15326,11 @@ msgid ""
 "of that commit failed."
 msgstr "获取了子模组路径 '%s',但是它没有包含 %s。直接获取该提交失败。"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "无法在路径 '%s' 初始化子模组"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid ""
@@ -15138,11 +15338,6 @@ msgid ""
 "the superproject is not on any branch"
 msgstr "子模组(%s)的分支配置为继承上级项目的分支,但是上级项目不在任何分支上"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "无法获得子模组 '%s' 的仓库句柄"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
@@ -15188,12 +15383,16 @@ msgid "path into the working tree"
 msgstr "到工作区的路径"
 
 #: builtin/submodule--helper.c
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "工作区中的路径,递归嵌套子模组"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "使用 'checkout' 更新策略(默认)"
 
 #: builtin/submodule--helper.c
-msgid "rebase, merge, checkout or none"
-msgstr "rebase、merge、checkout 或 none"
+msgid "use the 'merge' update strategy"
+msgstr "使用 'merge' 更新策略"
+
+#: builtin/submodule--helper.c
+msgid "use the 'rebase' update strategy"
+msgstr "使用 'rebase' 更新策略"
 
 #: builtin/submodule--helper.c
 msgid "create a shallow clone truncated to the specified number of revisions"
@@ -15211,6 +15410,10 @@ msgstr "初始克隆是否应该遵守推荐的浅克隆选项"
 msgid "don't print cloning progress"
 msgstr "不要输出克隆进度"
 
+#: builtin/submodule--helper.c
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "不允许克隆到一个非空目录,暗含 --init"
+
 #: builtin/submodule--helper.c
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
@@ -15223,17 +15426,13 @@ msgstr ""
 "shallow] [--reference <仓库>] [--recursive] [--[no-]single-branch] [--] [<路"
 "径>...]"
 
-#: builtin/submodule--helper.c
-msgid "bad value for update parameter"
-msgstr "update 参数取值错误"
-
 #: builtin/submodule--helper.c
 msgid "recurse into submodules"
 msgstr "在子模组中递归"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<选项>] [<路径>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<选项>] [<路径>...]"
 
 #: builtin/submodule--helper.c
 msgid "check if it is safe to write to the .gitmodules file"
@@ -15260,8 +15459,8 @@ msgid "suppress output for setting url of a submodule"
 msgstr "抑制设置子模组 URL 的输出"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <路径> <新地址>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <路径> <新地址>"
 
 #: builtin/submodule--helper.c
 msgid "set the default tracking branch to master"
@@ -15272,14 +15471,12 @@ msgid "set the default tracking branch"
 msgstr "设置默认跟踪分支"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <路径>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <路径>"
 
 #: builtin/submodule--helper.c
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <分支> <路径>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <分支> <路径>"
 
 #: builtin/submodule--helper.c
 msgid "--branch or --default required"
@@ -15394,8 +15591,8 @@ msgid ""
 msgstr "将子模组的名称设置为给定的字符串,而非默认为其路径"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<选项>] [--] <仓库> [<路径>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<选项>] [--] <仓库> [<路径>]"
 
 #: builtin/submodule--helper.c
 msgid "Relative path can only be used from the toplevel of the working tree"
@@ -15648,6 +15845,19 @@ msgstr "已更新标签 '%s'(曾为 %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "包超过了最大允许大小"
 
+#: builtin/unpack-objects.c
+msgid "failed to write object in stream"
+msgstr "无法在流中写入对象"
+
+#: builtin/unpack-objects.c
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "解压缩返回了 (%d)"
+
+#: builtin/unpack-objects.c
+msgid "invalid blob object from stream"
+msgstr "流中无效的数据对象"
+
 #: builtin/unpack-objects.c
 msgid "Unpacking objects"
 msgstr "展开对象中"
@@ -16290,6 +16500,33 @@ msgstr "将 <前缀> 子目录内容写到一个树对象"
 msgid "only useful for debugging"
 msgstr "只对调试有用"
 
+#: bulk-checkin.c
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch 不支持本平台"
+
+#: bundle-uri.c
+msgid "failed to create temporary file"
+msgstr "无法创建临时文件"
+
+#: bundle-uri.c
+msgid "insufficient capabilities"
+msgstr "缺乏能力"
+
+#: bundle-uri.c
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "无法从 URI '%s' 下载归档包"
+
+#: bundle-uri.c
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "位于 URI '%s' 的文件不是归档包"
+
+#: bundle-uri.c
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "无法从 URI '%s' 解开归档包"
+
 #: bundle.c
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
@@ -16552,6 +16789,10 @@ msgstr "一个非常简单的 Git 仓库服务器"
 msgid "Give an object a human readable name based on an available ref"
 msgstr "基于一个现存的引用为一个对象起一个可读的名称"
 
+#: command-list.h
+msgid "Generate a zip archive of diagnostic information"
+msgstr "生成诊断信息的压缩包"
+
 #: command-list.h
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "显示提交之间、提交和工作区之间等的差异"
@@ -16721,8 +16962,8 @@ msgid "The standard helper program to use with git-merge-index"
 msgstr "与 git-merge-index 一起使用的标准向导程序"
 
 #: command-list.h
-msgid "Show three-way merge without touching index"
-msgstr "在不动索引的情况下显示三路合并"
+msgid "Perform merge without touching index or working tree"
+msgstr "在不触碰索引或工作树情况下应用合并"
 
 #: command-list.h
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
@@ -16982,6 +17223,10 @@ msgstr "校验打包的Git存仓文件"
 msgid "Check the GPG signature of tags"
 msgstr "检查标签的 GPG 签名"
 
+#: command-list.h
+msgid "Display version information about Git"
+msgstr "显示关于 Git 的版本信息"
+
 #: command-list.h
 msgid "Show logs with difference each commit introduces"
 msgstr "显示每一个提交引入的差异日志"
@@ -17027,16 +17272,40 @@ msgid "Frequently asked questions about using Git"
 msgstr "关于使用 Git 的常见问题"
 
 #: command-list.h
-msgid "A Git Glossary"
-msgstr "Git 词汇表"
+msgid "The bundle file format"
+msgstr "归档包文件格式"
 
 #: command-list.h
-msgid "Hooks used by Git"
+msgid "Chunk-based file formats"
+msgstr "块式文件格式"
+
+#: command-list.h
+msgid "Git commit graph format"
+msgstr "Git 提交图格式"
+
+#: command-list.h
+msgid "Git index format"
+msgstr "Git 索引格式"
+
+#: command-list.h
+msgid "Git pack format"
+msgstr "Git 包格式"
+
+#: command-list.h
+msgid "Git cryptographic signature formats"
+msgstr "Git 密码学签名格式"
+
+#: command-list.h
+msgid "A Git Glossary"
+msgstr "Git 词汇表"
+
+#: command-list.h
+msgid "Hooks used by Git"
 msgstr "Git 使用的钩子"
 
 #: command-list.h
 msgid "Specifies intentionally untracked files to ignore"
-msgstr "忽略指定的未跟踪文件"
+msgstr "指定故意忽略的未跟踪文件"
 
 #: command-list.h
 msgid "The Git repository browser"
@@ -17054,6 +17323,26 @@ msgstr "定义子模组属性"
 msgid "Git namespaces"
 msgstr "Git 名字空间"
 
+#: command-list.h
+msgid "Protocol v0 and v1 capabilities"
+msgstr "协议 v0 和 v1 能力"
+
+#: command-list.h
+msgid "Things common to various protocols"
+msgstr "不同协议的共同部分"
+
+#: command-list.h
+msgid "Git HTTP-based protocols"
+msgstr "Git 基于 HTTP 的协议"
+
+#: command-list.h
+msgid "How packs are transferred over-the-wire"
+msgstr "包在线路中传输的方式"
+
+#: command-list.h
+msgid "Git Wire Protocol, Version 2"
+msgstr "Git 传输协议,第二版"
+
 #: command-list.h
 msgid "Helper programs to interact with remote repositories"
 msgstr "与远程仓库交互的助手程序"
@@ -17086,6 +17375,10 @@ msgstr "Git web 界面(Git 仓库的 web 前端)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Git 推荐的工作流概览"
 
+#: command-list.h
+msgid "A tool for managing large Git repositories"
+msgstr "一个管理大型 Git 仓库的工具"
+
 #: commit-graph.c
 msgid "commit-graph file is too small"
 msgstr "提交图形文件太小"
@@ -17374,6 +17667,16 @@ msgstr "编译器信息不可用\n"
 msgid "no libc information available\n"
 msgstr "libc 信息不可用\n"
 
+#: compat/disk.h
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "不能确定 '%s' 的空余磁盘空间"
+
+#: compat/disk.h
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "无法获得 '%s' 的信息"
+
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
@@ -17442,6 +17745,16 @@ msgstr "GetOverlappedResult 失败于 '%s' [GLE %ld]"
 msgid "could not read directory changes [GLE %ld]"
 msgstr "无法获取目录变更 [GLE %ld]"
 
+#: compat/fsmonitor/fsm-settings-win32.c
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] 无法打开要读取的 '%ls'"
+
+#: compat/fsmonitor/fsm-settings-win32.c
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] 无法获取 '%ls' 的协议信息 "
+
 #: compat/mingw.c
 #, c-format
 msgid "failed to copy SID (%ld)"
@@ -18115,229 +18428,6 @@ msgstr "写入 rev-list 失败"
 msgid "failed to close rev-list's stdin"
 msgstr "无法关闭 rev-list 的标准输入"
 
-#: contrib/scalar/scalar.c worktree.c
-#, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' 不存在"
-
-#: contrib/scalar/scalar.c
-msgid "need a working directory"
-msgstr "需要一个工作目录"
-
-#: contrib/scalar/scalar.c
-msgid "could not find enlistment root"
-msgstr "无法找到登记根"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not switch to '%s'"
-msgstr "无法切换到 '%s'"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure %s=%s"
-msgstr "无法配置 %s=%s"
-
-#: contrib/scalar/scalar.c
-msgid "could not configure log.excludeDecoration"
-msgstr "无法配置 log.excludeDecoration"
-
-#: contrib/scalar/scalar.c
-msgid "Scalar enlistments require a worktree"
-msgstr "Scalar 登记需要一个工作树"
-
-#: contrib/scalar/scalar.c dir.c
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "不能打开目录 '%s'"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "跳过 '%s',既不是文件又不是目录"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "不能确定 '%s' 的空余磁盘空间"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "不能获得 '%s' 的信息"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "远程 HEAD 不是一个分支:'%.*s'"
-
-#: contrib/scalar/scalar.c
-msgid "failed to get default branch name from remote; using local default"
-msgstr "无法从远程获取默认分支名称;使用本地默认值"
-
-#: contrib/scalar/scalar.c
-msgid "failed to get default branch name"
-msgstr "无法获取默认分支名称"
-
-#: contrib/scalar/scalar.c
-msgid "failed to unregister repository"
-msgstr "无法取消注册仓库"
-
-#: contrib/scalar/scalar.c
-msgid "failed to delete enlistment directory"
-msgstr "无法删除登记目录"
-
-#: contrib/scalar/scalar.c
-msgid "branch to checkout after clone"
-msgstr "克隆后要检出的分支"
-
-#: contrib/scalar/scalar.c
-msgid "when cloning, create full working directory"
-msgstr "在克隆时,创建完整的工作目录"
-
-#: contrib/scalar/scalar.c
-msgid "only download metadata for the branch that will be checked out"
-msgstr "只下载要检出的分支的元信息"
-
-#: contrib/scalar/scalar.c
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<选项>] [--] <仓库> [<目录>]"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "无法从 '%s' 猜测工作区名称"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "目录 '%s' 已存在"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "无法获取 '%s' 的默认分支"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "无法在 '%s' 中配置远程"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure '%s'"
-msgstr "无法配置 '%s'"
-
-#: contrib/scalar/scalar.c
-msgid "partial clone failed; attempting full clone"
-msgstr "部分克隆失败;尝试完整克隆"
-
-#: contrib/scalar/scalar.c
-msgid "could not configure for full clone"
-msgstr "无法配置完整克隆"
-
-#: contrib/scalar/scalar.c
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<登记>]"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "不能为 '%s' 创建目录"
-
-#: contrib/scalar/scalar.c
-msgid "could not duplicate stdout"
-msgstr "不能复制标准输出"
-
-#: contrib/scalar/scalar.c
-msgid "failed to write archive"
-msgstr "无法写入归档"
-
-#: contrib/scalar/scalar.c
-msgid "`scalar list` does not take arguments"
-msgstr "`scalar list` 不带参数"
-
-#: contrib/scalar/scalar.c
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<登记>]"
-
-#: contrib/scalar/scalar.c
-msgid "reconfigure all registered enlistments"
-msgstr "重新配置所有注册的登记"
-
-#: contrib/scalar/scalar.c
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <登记>]"
-
-#: contrib/scalar/scalar.c
-msgid "--all or <enlistment>, but not both"
-msgstr "--all 或者 <登记>,而不是两个一起"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "在 '%s' 的 git 仓库已消失"
-
-#: contrib/scalar/scalar.c
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <任务> [<登记>]\n"
-"任务:\n"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "no such task: '%s'"
-msgstr "没有此任务:'%s'"
-
-#: contrib/scalar/scalar.c
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<登记>]"
-
-#: contrib/scalar/scalar.c
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <登记>"
-
-#: contrib/scalar/scalar.c
-msgid "refusing to delete current working directory"
-msgstr "拒绝删除当前工作目录"
-
-#: contrib/scalar/scalar.c
-msgid "include Git version"
-msgstr "包括 Git 的版本"
-
-#: contrib/scalar/scalar.c
-msgid "include Git's build options"
-msgstr "包括 Git 的构建选项"
-
-#: contrib/scalar/scalar.c
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-#: contrib/scalar/scalar.c
-msgid "-C requires a <directory>"
-msgstr "-C 需要 <目录>"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not change to '%s'"
-msgstr "无法变更到 '%s'"
-
-#: contrib/scalar/scalar.c
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c 需要 <键>=<值> 参数"
-
-#: contrib/scalar/scalar.c
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <目录>] [-c <键>=<值>] <命令> [<选项>]\n"
-"\n"
-"命令:\n"
-
 #: convert.c
 #, c-format
 msgid "illegal crlf_action %d"
@@ -18578,6 +18668,39 @@ msgstr "来自 config 的数据岛正则表达式有太多的捕获组(最多
 msgid "Marked %d islands, done.\n"
 msgstr "已标记 %d 个数据岛,结束。\n"
 
+#: diagnose.c
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "无效的 --%s 值 '%s'"
+
+#: diagnose.c
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "无法归档缺失的目录 '%s'"
+
+#: diagnose.c dir.c
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "无法打开目录 '%s'"
+
+#: diagnose.c
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "跳过 '%s',既不是文件又不是目录"
+
+#: diagnose.c
+msgid "could not duplicate stdout"
+msgstr "无法复制标准输出"
+
+#: diagnose.c
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "无法添加目录 '%s' 至归档器"
+
+#: diagnose.c
+msgid "failed to write archive"
+msgstr "无法写入归档"
+
 #: diff-lib.c
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base 不适用于范围"
@@ -19327,6 +19450,10 @@ msgstr "git fetch-pack:应为 ACK/NAK,却得到 '%s'"
 msgid "unable to write to remote"
 msgstr "无法写到远程"
 
+#: fetch-pack.c
+msgid "Server supports filter"
+msgstr "服务器支持 filter"
+
 #: fetch-pack.c
 #, c-format
 msgid "invalid shallow line: %s"
@@ -19468,10 +19595,6 @@ msgstr "服务器不支持算法 '%s'"
 msgid "Server does not support shallow requests"
 msgstr "服务器不支持浅克隆请求"
 
-#: fetch-pack.c
-msgid "Server supports filter"
-msgstr "服务器支持 filter"
-
 #: fetch-pack.c
 msgid "unable to write request to remote"
 msgstr "无法将请求写到远程"
@@ -19886,6 +20009,14 @@ msgstr "低级命令/同步仓库"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "低级命令/内部助手"
 
+#: help.c
+msgid "User-facing repository, command and file interfaces"
+msgstr "面向用户的仓库、命令和文件接口"
+
+#: help.c
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "面向开发者的文件格式、协议和其他接口"
+
 #: help.c
 #, c-format
 msgid "available git commands in '%s'"
@@ -19903,6 +20034,14 @@ msgstr "这些是各种场合常见的 Git 命令:"
 msgid "The Git concept guides are:"
 msgstr "Git 概念向导有:"
 
+#: help.c
+msgid "User-facing repository, command and file interfaces:"
+msgstr "面向用户的仓库、命令和文件接口:"
+
+#: help.c
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "文件格式、协议和其他开发者接口列表:"
+
 #: help.c
 msgid "External commands"
 msgstr "外部命令"
@@ -19999,11 +20138,6 @@ msgstr ""
 "因为没有将钩子 '%s' 设置为可执行,钩子被忽略。您可以通过\n"
 "配置 `git config advice.ignoredHook false` 来关闭这条警告。"
 
-#: hook.c
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "不能启动钩子 '%s'\n"
-
 #: http-fetch.c
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
@@ -20221,20 +20355,16 @@ msgstr "在 ls-refs 参数后应该有一个 flush 包"
 msgid "quoted CRLF detected"
 msgstr "检测到被引用的 CRLF"
 
-#: merge-ort-wrappers.c merge-recursive.c
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"您对下列文件的本地修改将被合并操作覆盖:\n"
-"  %s"
-
 #: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "无法合并子模组 %s (没有检出)"
 
+#: merge-ort.c
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "无法合并子模组 %s (没有合并基线)"
+
 #: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
@@ -20258,27 +20388,8 @@ msgstr "无法合并子模组 %s"
 #: merge-ort.c
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"无法合并子模组 %s,但是存在一个可能的合并方案:\n"
-"%s\n"
-
-#: merge-ort.c merge-recursive.c
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"如果这个正确,将其添加到索引,例如使用命令:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"以接受此建议。\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
+msgstr "无法合并子模组 %s,但是存在一个可能的合并方案:%s"
 
 #: merge-ort.c
 #, c-format
@@ -20455,12 +20566,45 @@ msgstr ""
 "冲突(修改/删除):%1$s 在 %2$s 中被删除,在 %3$s 中被修改。%5$s 的 %4$s 版本"
 "在树中被保留。"
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
+#: merge-ort.c
+#, c-format
+msgid ""
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - 进入子模组(%s),要么合并提交 %s\n"
+"   要么更新至已合并这些变更的提交\n"
+
 #: merge-ort.c
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
-msgstr "注意:%s 不是最新的,并且与要检出的版本冲突。旧副本重命名为 %s"
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
+msgstr ""
+"子模组内的递归合并现在只支持简单的情况。\n"
+"请手动合并每个有冲突的子模组。\n"
+"这可以通过下列步骤完成:\n"
+"%s - 回到上级项目并运行:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   来记录上述的合并或更新\n"
+" - 解决上级项目中的其他冲突\n"
+" - 提交上级项目中的结果索引\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -20547,6 +20691,22 @@ msgstr "无法合并子模组 %s(非快进)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "找到子模组的一个可能的合并方案:\n"
 
+#: merge-recursive.c
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"如果这个正确,将其添加到索引,例如使用命令:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"以接受此建议。\n"
+
 #: merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
@@ -21182,6 +21342,26 @@ msgstr "在对象 %s 上调用 deflateEnd 失败(%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "被 %s 的不稳定对象源数据搞糊涂了"
 
+#: object-file.c
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "写入流对象 %ld != %<PRIuMAX>"
+
+#: object-file.c
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "不能流式压缩新对象(%d)"
+
+#: object-file.c
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "在流对象上调用 deflateEnd 失败(%d)"
+
+#: object-file.c
+#, c-format
+msgid "unable to create directory %s"
+msgstr "无法创建目录 %s"
+
 #: object-file.c
 #, c-format
 msgid "cannot read object for %s"
@@ -21412,59 +21592,184 @@ msgstr "路径 '%s' 不存在(既不在磁盘上,也不在索引中)"
 msgid "relative path syntax can't be used outside working tree"
 msgstr "不能在工作区之外使用相对路径语法"
 
-#: object-name.c
-#, c-format
-msgid "<object>:<path> required, only <object> '%s' given"
-msgstr "需要 <对象>:<路径>,只给出了 <对象> '%s'"
+#: object-name.c
+#, c-format
+msgid "<object>:<path> required, only <object> '%s' given"
+msgstr "需要 <对象>:<路径>,只给出了 <对象> '%s'"
+
+#: object-name.c
+#, c-format
+msgid "invalid object name '%.*s'."
+msgstr "无效的对象名 '%.*s'。"
+
+#: object.c
+#, c-format
+msgid "invalid object type \"%s\""
+msgstr "无效的对象类型 \"%s\""
+
+#: object.c
+#, c-format
+msgid "object %s is a %s, not a %s"
+msgstr "对象 %s 是一个 %s,不是一个 %s"
+
+#: object.c
+#, c-format
+msgid "object %s has unknown type id %d"
+msgstr "对象 %s 有未知的类型 id %d"
+
+#: object.c
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "不能解析对象:%s"
+
+#: object.c
+#, c-format
+msgid "hash mismatch %s"
+msgstr "哈希值与 %s 不匹配"
+
+#: pack-bitmap-write.c
+msgid "trying to write commit not in index"
+msgstr "尝试写入未在索引中的提交"
+
+#: pack-bitmap.c
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "无法载入位图索引(已损坏?)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index (too small)"
+msgstr "损坏的位图索引(太小)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "损坏的位图索引(错误的文件头)"
+
+#: pack-bitmap.c
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "不支持的位图索引文件版本 '%d'"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr "损坏的位图索引(太小,容不下哈希缓存)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr "损坏的位图索引(太小,容不下查询表)"
+
+#: pack-bitmap.c
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "位图索引中的重复条目:'%s'"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "损坏的 EWAH 位图:条目 %d 截断的文件头"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "损坏的 EWAH 位图:提交索引 %u 超出范围"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap pack index"
+msgstr "损坏的位图包索引"
+
+#: pack-bitmap.c
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "位图包索引中 XOR 偏移值无效"
+
+#: pack-bitmap.c
+msgid "cannot fstat bitmap file"
+msgstr "不能对位图文件调用 fstat"
+
+#: pack-bitmap.c
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "忽略额外的位图文件:'%s'"
+
+#: pack-bitmap.c
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "MIDX 和位图中的校验码不匹配"
+
+#: pack-bitmap.c
+msgid "multi-pack bitmap is missing required reverse index"
+msgstr "多包位图缺少必需的反向索引"
+
+#: pack-bitmap.c
+#, c-format
+msgid "could not open pack %s"
+msgstr "不能打开包 %s"
+
+#: pack-bitmap.c
+#, c-format
+msgid "preferred pack (%s) is invalid"
+msgstr "首选包 (%s) 无效"
+
+#: pack-bitmap.c
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "损坏的位图查询表:三元组位置超出索引"
+
+#: pack-bitmap.c
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr "损坏的位图查询表:xor 链超出条目数"
 
-#: object-name.c
+#: pack-bitmap.c
 #, c-format
-msgid "invalid object name '%.*s'."
-msgstr "æ\97 æ\95\88ç\9a\84对象å\90\8d '%.*s'ã\80\82"
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr "æ\8d\9få\9d\8fç\9a\84ä½\8då\9b¾æ\9f¥è¯¢è¡¨ï¼\9aæ\8f\90交索å¼\95 %u è¶\85å\87ºè\8c\83å\9b´"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "invalid object type \"%s\""
-msgstr "æ\97 æ\95\88ç\9a\84对象类å\9e\8b \"%s\""
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr "æ\8d\9få\9d\8fç\9a\84 EWAH ä½\8då\9b¾ï¼\9aæ\8f\90交 \"%s\" ä½\8då\9b¾ç\9a\84æ\96\87件头被æ\88ªæ\96­"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "object %s is a %s, not a %s"
-msgstr "对象 %s 是一个 %s,不是一个 %s"
+msgid "object '%s' not found in type bitmaps"
+msgstr "对象 %s 为在类型位图中找到"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "object %s has unknown type id %d"
-msgstr "对象 %s 有未知的类型 id %d"
+msgid "object '%s' does not have a unique type"
+msgstr "对象 '%s' 没有唯一的类型"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "unable to parse object: %s"
-msgstr "不能解析对象:%s"
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "对象 '%s':实际类型 '%s',预期:'%s'"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "hash mismatch %s"
-msgstr "å\93\88å¸\8cå\80¼ä¸\8e %s ä¸\8då\8c¹é\85\8d"
+msgid "object not in bitmap: '%s'"
+msgstr "对象ä¸\8då\9c¨ä½\8då\9b¾ä¸­ï¼\9a%s"
 
 #: pack-bitmap.c
-msgid "multi-pack bitmap is missing required reverse index"
-msgstr "多包位图缺少必需的反向索引"
+msgid "failed to load bitmap indexes"
+msgstr "无法载入位图索引"
+
+#: pack-bitmap.c
+msgid "you must specify exactly one commit to test"
+msgstr "您必须准确指定一个提交来测试"
 
 #: pack-bitmap.c
 #, c-format
-msgid "could not open pack %s"
-msgstr "不能打开包 %s"
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "提交 '%s' 没有索引位图"
+
+#: pack-bitmap.c
+msgid "mismatch in bitmap results"
+msgstr "位图结果不一致"
 
 #: pack-bitmap.c
 #, c-format
-msgid "preferred pack (%s) is invalid"
-msgstr "首选包 (%s) 无效"
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "无法在包 '%2$s' 偏移 %3$<PRIuMAX> 中找到 '%1$s'"
 
 #: pack-bitmap.c
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "在包 %2$s 偏移 %3$<PRIuMAX> 中无法找到 %1$s"
+msgid "unable to get disk usage of '%s'"
+msgstr "无法得到 '%s' 的磁盘使用量"
 
 #: pack-mtimes.c
 #, c-format
@@ -21619,6 +21924,10 @@ msgstr "您的意思是 `--%s`(有两个短线)?"
 msgid "alias of --%s"
 msgstr "--%s 的别名"
 
+#: parse-options.c
+msgid "need a subcommand"
+msgstr "需要一个子命令"
+
 #: parse-options.c
 #, c-format
 msgid "unknown option `%s'"
@@ -22147,9 +22456,12 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
@@ -22157,7 +22469,7 @@ msgstr ""
 "命令:\n"
 "p, pick <提交> = 使用提交\n"
 "r, reword <提交> = 使用提交,但编辑提交说明\n"
-"e, edit <提交> = 使用提交,但停止以便在 shell 中修补提交\n"
+"e, edit <提交> = 使用提交,但停止以便修补提交\n"
 "s, squash <提交> = 使用提交,但挤压到前一个提交\n"
 "f, fixup [-C | -c] <提交> = 类似于 \"squash\",但只保留前一个提交\n"
 "                   的提交说明,除非使用了 -C 参数,此情况下则只\n"
@@ -22172,6 +22484,9 @@ msgstr ""
 ".       创建一个合并提交,并使用原始的合并提交说明(如果没有指定\n"
 ".       原始提交,使用注释部分的 oneline 作为提交说明)。使用\n"
 ".       -c <提交> 可以编辑提交说明。\n"
+"u, update-ref <引用> = 为引用 <ref> 设置一个占位符,以将该引用更新为此处的新"
+"提交。\n"
+"                      此 <引用> 在变基结束后更新。\n"
 "\n"
 "可以对这些行重新排序,将从上至下执行。\n"
 
@@ -22737,6 +23052,15 @@ msgstr "协议错误:期望 sha/ref,却得到 '%s'"
 msgid "http transport does not support %s"
 msgstr "http 传输协议不支持 %s"
 
+#: remote-curl.c
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "协议错误:预期 '<url> <path>',缺少空格"
+
+#: remote-curl.c
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "无法下载位于 URL '%s' 的文件"
+
 #: remote-curl.c
 msgid "git-http-push failed"
 msgstr "git-http-push 失败"
@@ -23142,6 +23466,16 @@ msgstr "不能确定 HEAD 版本"
 msgid "failed to find tree of %s"
 msgstr "无法找到 %s 指向的树"
 
+#: revision.c
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo 记录 `%s`,现缺失"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "无法获得 ancestry-path 参数 %s 的提交"
+
 #: revision.c
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "不再支持 --unpacked=<packfile>"
@@ -23168,6 +23502,220 @@ msgstr "-L 尚不支持 -p 和 -s 之外的差异格式"
 msgid "cannot create async thread: %s"
 msgstr "不能创建 async 线程:%s"
 
+#: scalar.c worktree.c
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' 不存在"
+
+#: scalar.c
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "无法切换到 '%s'"
+
+#: scalar.c
+msgid "need a working directory"
+msgstr "需要一个工作目录"
+
+#: scalar.c
+msgid "Scalar enlistments require a worktree"
+msgstr "Scalar 登记需要一个工作树"
+
+#: scalar.c
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "无法配置 %s=%s"
+
+#: scalar.c
+msgid "could not configure log.excludeDecoration"
+msgstr "无法配置 log.excludeDecoration"
+
+#: scalar.c
+msgid "could not add enlistment"
+msgstr "无法添加登记"
+
+#: scalar.c
+msgid "could not set recommended config"
+msgstr "无法设置推荐的配置"
+
+#: scalar.c
+msgid "could not turn on maintenance"
+msgstr "无法打开维护模式"
+
+#: scalar.c
+msgid "could not start the FSMonitor daemon"
+msgstr "无法启动 FSMonitor 守护进程"
+
+#: scalar.c
+msgid "could not turn off maintenance"
+msgstr "无法关闭维护模式"
+
+#: scalar.c
+msgid "could not remove enlistment"
+msgstr "无法删除登记"
+
+#: scalar.c
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "远程 HEAD 不是一个分支:'%.*s'"
+
+#: scalar.c
+msgid "failed to get default branch name from remote; using local default"
+msgstr "无法从远程获取默认分支名称;使用本地默认值"
+
+#: scalar.c
+msgid "failed to get default branch name"
+msgstr "无法获取默认分支名称"
+
+#: scalar.c
+msgid "failed to unregister repository"
+msgstr "无法取消注册仓库"
+
+#: scalar.c
+msgid "failed to stop the FSMonitor daemon"
+msgstr "无法停止 FSMonitor 守护进程"
+
+#: scalar.c
+msgid "failed to delete enlistment directory"
+msgstr "无法删除登记目录"
+
+#: scalar.c
+msgid "branch to checkout after clone"
+msgstr "克隆后要检出的分支"
+
+#: scalar.c
+msgid "when cloning, create full working directory"
+msgstr "在克隆时,创建完整的工作目录"
+
+#: scalar.c
+msgid "only download metadata for the branch that will be checked out"
+msgstr "只下载要检出的分支的元信息"
+
+#: scalar.c
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<选项>] [--] <仓库> [<目录>]"
+
+#: scalar.c
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "无法从 '%s' 猜测工作区名称"
+
+#: scalar.c
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "目录 '%s' 已存在"
+
+#: scalar.c
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "无法获取 '%s' 的默认分支"
+
+#: scalar.c
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "无法在 '%s' 中配置远程"
+
+#: scalar.c
+#, c-format
+msgid "could not configure '%s'"
+msgstr "无法配置 '%s'"
+
+#: scalar.c
+msgid "partial clone failed; attempting full clone"
+msgstr "部分克隆失败;尝试完整克隆"
+
+#: scalar.c
+msgid "could not configure for full clone"
+msgstr "无法配置完整克隆"
+
+#: scalar.c
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<登记>]"
+
+#: scalar.c
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` 不带参数"
+
+#: scalar.c
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<登记>]"
+
+#: scalar.c
+msgid "reconfigure all registered enlistments"
+msgstr "重新配置所有注册的登记"
+
+#: scalar.c
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <登记>]"
+
+#: scalar.c
+msgid "--all or <enlistment>, but not both"
+msgstr "--all 或者 <登记>,而不是两个一起"
+
+#: scalar.c
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "在 '%s' 的 git 仓库已消失"
+
+#: scalar.c
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <任务> [<登记>]\n"
+"任务:\n"
+
+#: scalar.c
+#, c-format
+msgid "no such task: '%s'"
+msgstr "没有此任务:'%s'"
+
+#: scalar.c
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<登记>]"
+
+#: scalar.c
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <登记>"
+
+#: scalar.c
+msgid "refusing to delete current working directory"
+msgstr "拒绝删除当前工作目录"
+
+#: scalar.c
+msgid "include Git version"
+msgstr "包括 Git 的版本"
+
+#: scalar.c
+msgid "include Git's build options"
+msgstr "包括 Git 的构建选项"
+
+#: scalar.c
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+#: scalar.c
+msgid "-C requires a <directory>"
+msgstr "-C 需要 <目录>"
+
+#: scalar.c
+#, c-format
+msgid "could not change to '%s'"
+msgstr "无法变更到 '%s'"
+
+#: scalar.c
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c 需要 <键>=<值> 参数"
+
+#: scalar.c
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <目录>] [-c <键>=<值>] <命令> [<选项>]\n"
+"\n"
+"命令:\n"
+
 #: send-pack.c
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr "读取远程解包状态时收到意外的 flush 包"
@@ -23308,11 +23856,6 @@ msgstr "您的本地修改将被%s覆盖。"
 msgid "commit your changes or stash them to proceed."
 msgstr "提交您的修改或贮藏后再继续。"
 
-#: sequencer.c
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s:快进"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -23899,6 +24442,30 @@ msgstr "甚至不能尝试合并 '%.*s'"
 msgid "merge: Unable to write new index file"
 msgstr "合并:无法写入新索引文件"
 
+#: sequencer.c
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "另一个 'rebase' 进程似乎在运行;'%s.lock' 已存在"
+
+#: sequencer.c
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"已用 %s 更新下列引用:\n"
+"%s"
+
+#: sequencer.c
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"无法用 %s 更新下列引用:\n"
+"%s"
+
 #: sequencer.c
 msgid "Cannot autostash"
 msgstr "无法自动贮藏"
@@ -24101,6 +24668,11 @@ msgstr "无法跳过不必要的拣选"
 msgid "the script was already rearranged."
 msgstr "脚本已经重新编排。"
 
+#: sequencer.c
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "位于 '%s' 的 update-refs 文件无效"
+
 #: setup.c
 #, c-format
 msgid "'%s' is outside repository at '%s'"
@@ -24243,16 +24815,21 @@ msgstr ""
 #: setup.c
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"仓库不安全('%s' 的所有者是其他人)\n"
-"要为本仓库创建特例,请使用:\n"
+"在 '%s' 检测到可疑的仓库所有权\n"
+"%s要为本仓库创建特例,请运行:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#: setup.c
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "无法使用纯仓库 '%s' (safe.bareRepository 为 '%s')"
+
 #: setup.c
 #, c-format
 msgid ""
@@ -25278,6 +25855,22 @@ msgstr "无效的端口号"
 msgid "invalid '..' path segment"
 msgstr "无效的 '..' 路径片段"
 
+#: usage.c
+msgid "usage: "
+msgstr "用法:"
+
+#: usage.c
+msgid "fatal: "
+msgstr "致命错误:"
+
+#: usage.c
+msgid "error: "
+msgstr "错误:"
+
+#: usage.c
+msgid "warning: "
+msgstr "警告:"
+
 #: walker.c
 msgid "Fetching objects"
 msgstr "正在获取对象"
@@ -25970,7 +26563,7 @@ msgstr "另外,您的索引中包含未提交的变更。"
 msgid "cannot %s: Your index contains uncommitted changes."
 msgstr "不能%s:您的索引中包含未提交的变更。"
 
-#: git-merge-octopus.sh
+#: git-merge-octopus.sh git-merge-resolve.sh
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
@@ -26258,26 +26851,6 @@ msgstr "选中的块不能应用到索引!\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "忽略未合入的:%s\n"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "将模式变更应用到工作区 [y,n,q,a,d%s,?]? "
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "将删除操作应用到工作区 [y,n,q,a,d%s,?]? "
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "将添加操作应用到工作区 [y,n,q,a,d%s,?]? "
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "将该块应用到工作区 [y,n,q,a,d%s,?]? "
-
 #: git-add--interactive.perl
 msgid "No other hunks to goto\n"
 msgstr "没有其它可供跳转的块\n"
index 2f7d01c3031b6fe413af767346eec34f43e12969..29b80891417a91156ca25b2dffd3453d83de5883 100644 (file)
@@ -22,8 +22,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-23 21:13+0800\n"
-"PO-Revision-Date: 2022-06-23 23:02+0800\n"
+"POT-Creation-Date: 2022-09-23 21:57+0000\n"
+"PO-Revision-Date: 2022-10-01 19:02+0800\n"
 "Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n"
 "Language-Team: Chinese (Traditional) <http://weblate.slat.org/projects/git-"
 "po/git-cli/zh_Hant/>\n"
@@ -32,7 +32,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.1\n"
+"X-Generator: Poedit 3.1.1\n"
 "X-ZhConverter: 繁化姬 dict-f4bc617e-r910 @ 2019/11/16 20:23:12 | https://"
 "zhconvert.org\n"
 
@@ -41,7 +41,7 @@ msgstr ""
 msgid "Huh (%s)?"
 msgstr "嗯(%s)?"
 
-#: add-interactive.c builtin/rebase.c reset.c sequencer.c
+#: add-interactive.c builtin/merge.c builtin/rebase.c reset.c sequencer.c
 msgid "could not read index"
 msgstr "無法讀取索引"
 
@@ -219,8 +219,8 @@ msgid "unstaged"
 msgstr "未快取"
 
 #: add-interactive.c apply.c builtin/am.c builtin/bugreport.c builtin/clone.c
-#: builtin/fetch.c builtin/merge.c builtin/pull.c builtin/submodule--helper.c
-#: git-add--interactive.perl
+#: builtin/diagnose.c builtin/fetch.c builtin/merge.c builtin/pull.c
+#: builtin/submodule--helper.c git-add--interactive.perl
 msgid "path"
 msgstr "路徑"
 
@@ -501,6 +501,26 @@ msgstr ""
 "a - 套用此區塊和本檔案中後面的全部區塊\n"
 "d - 不要套用此區塊和本檔案中後面的全部區塊\n"
 
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr "將模式變更套用到工作區 [y,n,q,a,d%s,?]? "
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr "將刪除變更套用到工作區 [y,n,q,a,d%s,?]? "
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr "將新增變更套用到工作區 [y,n,q,a,d%s,?]? "
+
+#: add-patch.c git-add--interactive.perl
+#, c-format, perl-format
+msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
+msgstr "將此區塊套用到工作區 [y,n,q,a,d%s,?]? "
+
 #: add-patch.c
 msgid ""
 "y - apply this hunk to worktree\n"
@@ -520,11 +540,6 @@ msgstr ""
 msgid "could not parse hunk header '%.*s'"
 msgstr "無法解析區塊標頭 '%.*s'"
 
-#: add-patch.c
-#, c-format
-msgid "could not parse colored hunk header '%.*s'"
-msgstr "無法解析上色過的區塊標頭 '%.*s'"
-
 #: add-patch.c
 msgid "could not parse diff"
 msgstr "無法解析差異 (diff)"
@@ -589,6 +604,7 @@ msgstr ""
 "要刪除 '%c' 開始的行,刪除它們。\n"
 "以 %c 開始的行將被刪除。\n"
 
+#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
 #. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
 #: add-patch.c git-add--interactive.perl
 msgid ""
@@ -608,12 +624,14 @@ msgstr "無法解析區塊標頭"
 msgid "'git apply --cached' failed"
 msgstr "「git apply --cached」失敗"
 
+#. #-#-#-#-#  add-patch.c.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input at this point.
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
 #.
+#. #-#-#-#-#  git-add--interactive.perl.po  #-#-#-#-#
 #. TRANSLATORS: do not translate [y/n]
 #. The program will only accept that input
 #. at this point.
@@ -852,6 +870,26 @@ msgstr ""
 "將組態變數 advice.detachedHead 設定為 false,即可關閉本建議\n"
 "\n"
 
+#: advice.c
+#, c-format
+msgid ""
+"The following paths have been moved outside the\n"
+"sparse-checkout definition but are not sparse due to local\n"
+"modifications.\n"
+msgstr ""
+"以下路徑已經移到稀疏簽出定義之外的地方,\n"
+"但因為有本機更動,因此路徑不是稀疏的。\n"
+
+#: advice.c
+msgid ""
+"To correct the sparsity of these paths, do the following:\n"
+"* Use \"git add --sparse <paths>\" to update the index\n"
+"* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
+msgstr ""
+"若要更正這些路徑的稀疏狀態,請:\n"
+"* 使用 `git add --sparse <路徑>` 更新索引\n"
+"* 使用 `git sparse-checkout reapply` 套用稀疏規則"
+
 #: alias.c
 msgid "cmdline ends with \\"
 msgstr "指令列以 \\ 結尾"
@@ -1081,7 +1119,7 @@ msgstr "到 '%s' 的二進位修補檔產生了不正確的結果(應為 %s,
 msgid "patch failed: %s:%ld"
 msgstr "打修補檔失敗:%s:%ld"
 
-#: apply.c
+#: apply.c builtin/mv.c
 #, c-format
 msgid "cannot checkout %s"
 msgstr "不能簽出 %s"
@@ -1470,6 +1508,11 @@ msgstr "不能開啟資料物件 %s"
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "不支援的檔案模式:0%o (SHA1: %s)"
 
+#: archive-tar.c archive-zip.c builtin/pack-objects.c
+#, c-format
+msgid "deflate error (%d)"
+msgstr "壓縮錯誤 (%d)"
+
 #: archive-tar.c
 #, c-format
 msgid "unable to start '%s' filter"
@@ -1494,11 +1537,6 @@ msgstr "路徑不是有效的 UTF-8:%s"
 msgid "path too long (%d chars, SHA1: %s): %s"
 msgstr "路徑太長(%d 字元,SHA1:%s):%s"
 
-#: archive-zip.c builtin/pack-objects.c
-#, c-format
-msgid "deflate error (%d)"
-msgstr "壓縮錯誤 (%d)"
-
 #: archive-zip.c
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
@@ -1812,8 +1850,8 @@ msgid "--reverse and --first-parent together require specified latest commit"
 msgstr "--reverse 和 --first-parent 共用,需要指定最新的提交"
 
 #: blame.c builtin/commit.c builtin/log.c builtin/merge.c
-#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c ref-filter.c
-#: remote.c sequencer.c submodule.c
+#: builtin/pack-objects.c builtin/shortlog.c bundle.c midx.c pack-bitmap.c
+#: ref-filter.c remote.c sequencer.c submodule.c
 msgid "revision walk setup failed"
 msgstr "版本遍歷設定失敗"
 
@@ -1888,10 +1926,12 @@ msgid "not tracking: ambiguous information for ref '%s'"
 msgstr "未追蹤:「%s」引用有歧義"
 
 #  譯者:為保證在輸出中對齊,注意調整句中空格!
+#. #-#-#-#-#  branch.c.po  #-#-#-#-#
 #. TRANSLATORS: This is a line listing a remote with duplicate
 #. refspecs in the advice message below. For RTL languages you'll
 #. probably want to swap the "%s" and leading "  " space around.
 #.
+#. #-#-#-#-#  object-name.c.po  #-#-#-#-#
 #. TRANSLATORS: This is line item of ambiguous object output
 #. from describe_ambiguous_object() above. For RTL languages
 #. you'll probably want to swap the "%s" and leading " " space
@@ -2272,7 +2312,7 @@ msgstr "fseek 失敗"
 msgid "could not open '%s' for reading"
 msgstr "無法開啟 '%s' 進行讀取"
 
-#: builtin/am.c builtin/rebase.c strbuf.c wrapper.c
+#: builtin/am.c builtin/rebase.c sequencer.c strbuf.c wrapper.c
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "無法開啟 '%s' 進行寫入"
@@ -2574,8 +2614,8 @@ msgid "n"
 msgstr "n"
 
 #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c
-#: builtin/for-each-ref.c builtin/ls-tree.c builtin/replace.c builtin/tag.c
-#: builtin/verify-tag.c
+#: builtin/diagnose.c builtin/for-each-ref.c builtin/ls-files.c
+#: builtin/ls-tree.c builtin/replace.c builtin/tag.c builtin/verify-tag.c
 msgid "format"
 msgstr "格式"
 
@@ -2678,7 +2718,7 @@ msgstr "互動式模式需要指令列上提供修補檔"
 msgid "git apply [<options>] [<patch>...]"
 msgstr "git apply [<選項>] [<修補檔>...]"
 
-#: builtin/archive.c contrib/scalar/scalar.c
+#: builtin/archive.c diagnose.c
 msgid "could not redirect output"
 msgstr "不能重定向輸出"
 
@@ -3561,8 +3601,8 @@ msgstr "排序和過濾屬於大小寫不敏感"
 msgid "recurse through submodules"
 msgstr "在子模組中遞迴"
 
-#: builtin/branch.c builtin/for-each-ref.c builtin/ls-tree.c builtin/tag.c
-#: builtin/verify-tag.c
+#: builtin/branch.c builtin/for-each-ref.c builtin/ls-files.c builtin/ls-tree.c
+#: builtin/tag.c builtin/verify-tag.c
 msgid "format to use for the output"
 msgstr "輸出格式"
 
@@ -3685,8 +3725,12 @@ msgid "not run from a git repository - no hooks to show\n"
 msgstr "不是從 git 版本庫執行 - 沒有可顯示的掛鉤\n"
 
 #: builtin/bugreport.c
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
-msgstr "git bugreport [-o|--output-directory <檔案>] [-s|--suffix <格式>]"
+msgid ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
+msgstr ""
+"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--"
+"diagnose[=<mode>]"
 
 #: builtin/bugreport.c
 msgid ""
@@ -3722,19 +3766,34 @@ msgstr ""
 "請檢閱臭蟲報告下方的剩餘部分。\n"
 "您可刪除任何您不想分享的地方。\n"
 
+#: builtin/bugreport.c builtin/commit.c builtin/fast-export.c builtin/rebase.c
+#: parse-options.h
+msgid "mode"
+msgstr "模式"
+
 #: builtin/bugreport.c
-msgid "specify a destination for the bugreport file"
-msgstr "請指定 bugreport 檔案的目的地"
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
+msgstr "建立詳細診斷資訊的額外 zip 封存檔案(預設值是 “stats”)"
 
 #: builtin/bugreport.c
-msgid "specify a strftime format suffix for the filename"
-msgstr "請指定檔案名稱的 strftime 格式後綴"
+msgid "specify a destination for the bugreport file(s)"
+msgstr "指定錯誤報告檔案的目的地"
 
 #: builtin/bugreport.c
+msgid "specify a strftime format suffix for the filename(s)"
+msgstr "指定檔名,strftime 格式的後綴"
+
+#: builtin/bugreport.c builtin/diagnose.c
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr "無法建立 '%s' 的前置目錄"
 
+#: builtin/bugreport.c builtin/diagnose.c
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr "無法建立 %s 診斷封存檔"
+
 #: builtin/bugreport.c
 msgid "System Info"
 msgstr "系統資訊"
@@ -3810,11 +3869,6 @@ msgstr "需要版本庫才能拆分套件。"
 msgid "Unbundling objects"
 msgstr "正在解包物件"
 
-#: builtin/bundle.c builtin/remote.c
-#, c-format
-msgid "Unknown subcommand: %s"
-msgstr "未知子指令:%s"
-
 #: builtin/cat-file.c merge-recursive.c
 #, c-format
 msgid "cannot read object %s '%s'"
@@ -3912,6 +3966,10 @@ msgstr "顯示物件大小"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "允許 -s 和 -t 對損壞的物件生效"
 
+#: builtin/cat-file.c builtin/log.c
+msgid "use mail map file"
+msgstr "使用信件映射檔案"
+
 #: builtin/cat-file.c
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr "批次處理 stdin 上請求的物件(或 --batch-all-objects)"
@@ -3924,6 +3982,10 @@ msgstr "顯示完整的 <object> 或 <rev> 內容"
 msgid "like --batch, but don't emit <contents>"
 msgstr "類似 --batch 但不輸出 <contents>"
 
+#: builtin/cat-file.c
+msgid "stdin is NUL-terminated"
+msgstr "標準輸入的結尾是 NUL"
+
 #: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "從標準輸入讀取命令"
@@ -4991,6 +5053,14 @@ msgstr "任何複製的子模組都將使用它們的遠端追蹤分支"
 msgid "initialize sparse-checkout file to include only files at root"
 msgstr "初始化稀疏簽出檔案,只包含根目錄中的檔案"
 
+#: builtin/clone.c
+msgid "uri"
+msgstr "uri"
+
+#: builtin/clone.c
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr "在從 origin 遠端抓取前,用來下載套件的 URI"
+
 #: builtin/clone.c
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
@@ -5065,8 +5135,8 @@ msgid "failed to initialize sparse-checkout"
 msgstr "無法初始化稀疏簽出"
 
 #: builtin/clone.c
-msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr "é\81 ç«¯ HEAD æ\8c\87å\90\91ä¸\80å\80\8bä¸\8då­\98å\9c¨ç\9a\84å¼\95ç\94¨ï¼\8cç\84¡æ³\95ç°½å\87ºã\80\82\n"
+msgid "remote HEAD refers to nonexistent ref, unable to checkout"
+msgstr "é\81 ç«¯ HEAD æ\8c\87å\90\91ä¸\8då­\98å\9c¨ç\9a\84å¼\95ç\94¨ï¼\8cç\84¡æ³\95ç°½å\87º"
 
 #: builtin/clone.c
 msgid "unable to checkout working tree"
@@ -5088,7 +5158,7 @@ msgstr "無法刪除暫時的 alternates 檔案"
 msgid "Too many arguments."
 msgstr "太多參數。"
 
-#: builtin/clone.c contrib/scalar/scalar.c
+#: builtin/clone.c scalar.c
 msgid "You must specify a repository to clone."
 msgstr "您必須指定要複製的版本庫。"
 
@@ -5097,6 +5167,12 @@ msgstr "您必須指定要複製的版本庫。"
 msgid "options '%s' and '%s %s' cannot be used together"
 msgstr "「%s」和「%s %s」選項不得同時使用"
 
+#: builtin/clone.c
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
+msgstr "--bundle-uri 與 --depth、--shallow-since 和 --shallow-exclude 不相容"
+
 #: builtin/clone.c
 #, c-format
 msgid "repository '%s' does not exist"
@@ -5185,6 +5261,15 @@ msgstr "--local 被忽略"
 msgid "cannot clone from filtered bundle"
 msgstr "無法從過濾後的套件複製"
 
+#: builtin/clone.c
+msgid "failed to initialize the repo, skipping bundle URI"
+msgstr "無法初始化版本庫,略過套件 URI"
+
+#: builtin/clone.c
+#, c-format
+msgid "failed to fetch objects from bundle URI '%s'"
+msgstr "無法從套件 URL “%s” 抓取物件"
+
 #: builtin/clone.c
 msgid "remote transport reported error"
 msgstr "遠端傳輸回報錯誤"
@@ -5332,11 +5417,6 @@ msgstr "不能同時使用 --reachable、--stdin-commits 或 --stdin-packs"
 msgid "Collecting commits from input"
 msgstr "正在從輸入收集提交"
 
-#: builtin/commit-graph.c builtin/multi-pack-index.c
-#, c-format
-msgid "unrecognized subcommand: %s"
-msgstr "未識別的子指令:%s"
-
 #: builtin/commit-tree.c
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
@@ -5769,10 +5849,6 @@ msgstr "以長格式顯示狀態(預設)"
 msgid "terminate entries with NUL"
 msgstr "條目以 NUL 字元結尾"
 
-#: builtin/commit.c builtin/fast-export.c builtin/rebase.c parse-options.h
-msgid "mode"
-msgstr "模式"
-
 #: builtin/commit.c
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr "顯示未追蹤的檔案,「模式」的可選參數:all、normal、no。(預設值:all)"
@@ -6513,6 +6589,26 @@ msgstr "沒有發現名稱,無法描述任何東西。"
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr "「%s」選項和提交號不得同時使用"
 
+#: builtin/diagnose.c
+msgid ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+msgstr ""
+"git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--"
+"mode=<mode>]"
+
+#: builtin/diagnose.c
+msgid "specify a destination for the diagnostics archive"
+msgstr "指定診斷封存檔的目的地"
+
+#: builtin/diagnose.c
+msgid "specify a strftime format suffix for the filename"
+msgstr "請指定檔案名稱的 strftime 格式後綴"
+
+#: builtin/diagnose.c
+msgid "specify the content of the diagnostic archive"
+msgstr "指定診斷封存檔的內容"
+
 #: builtin/diff-tree.c
 msgid "--merge-base only works with two commits"
 msgstr "--merge-base 只對 2 個以上的提交有用"
@@ -6984,12 +7080,8 @@ msgid "[rejected]"
 msgstr "[已拒絕]"
 
 #: builtin/fetch.c
-msgid "can't fetch in current branch"
-msgstr "目前分支下不能執行取得動作"
-
-#: builtin/fetch.c
-msgid "checked out in another worktree"
-msgstr "已在其他工作區簽出"
+msgid "can't fetch into checked-out branch"
+msgstr "無法抓取至已簽出分支"
 
 #: builtin/fetch.c
 msgid "[tag update]"
@@ -7530,6 +7622,11 @@ msgstr "%s:cache-tree 中無效的 sha1 指標"
 msgid "non-tree in cache-tree"
 msgstr "cache-tree 中非樹狀物件"
 
+#: builtin/fsck.c
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo"
+msgstr "%s:resolve-undo 的 sha1 指針無效"
+
 #: builtin/fsck.c
 msgid "git fsck [<options>] [<object>...]"
 msgstr "git fsck [<選項>] [<物件>...]"
@@ -7946,12 +8043,16 @@ msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr "無法執行 “crontab -l”;您的系統可能不支援 “cron”"
 
 #: builtin/gc.c
-msgid "failed to run 'crontab'; your system might not support 'cron'"
-msgstr "無法執行 “crontab”;您的系統可能不支援 “cron”"
+msgid "failed to create crontab temporary file"
+msgstr "無法建立 crontab 暫存檔"
+
+#: builtin/gc.c
+msgid "failed to open temporary file"
+msgstr "無法開啟暫存檔"
 
 #: builtin/gc.c
-msgid "failed to open stdin of 'crontab'"
-msgstr "無法開啟 ‘crontab’ 的標準輸入"
+msgid "failed to run 'crontab'; your system might not support 'cron'"
+msgstr "無法執行 “crontab”;您的系統可能不支援 “cron”"
 
 #: builtin/gc.c
 msgid "'crontab' died"
@@ -8013,11 +8114,6 @@ msgstr "無法將版本庫加至全域設定"
 msgid "git maintenance <subcommand> [<options>]"
 msgstr "git maintenance <子命令> [<選項>]"
 
-#: builtin/gc.c
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr "無效子命令:%s"
-
 #: builtin/grep.c
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<選項>] [-e] <模式> [<版本>...] [[--] <路徑>...]"
@@ -8032,6 +8128,7 @@ msgstr "grep:無法建立執行緒:%s"
 msgid "invalid number of threads specified (%d) for %s"
 msgstr "為 %2$s 設定的執行緒數 (%1$d) 無效"
 
+#. #-#-#-#-#  grep.c.po  #-#-#-#-#
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
@@ -8241,6 +8338,10 @@ msgstr "分頁顯示符合的檔案"
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "允許呼叫 grep(1)(本次組建忽略)"
 
+#: builtin/grep.c
+msgid "maximum number of results per file"
+msgstr "每個檔案的最多結果數"
+
 #: builtin/grep.c
 msgid "no pattern given"
 msgstr "未提供符合模式"
@@ -8352,13 +8453,21 @@ msgstr "列印指令描述"
 msgid "print list of useful guides"
 msgstr "顯示有用的指南列表"
 
+#: builtin/help.c
+msgid "print list of user-facing repository, command and file interfaces"
+msgstr "輸出面向使用者的版本庫、命令,和檔案介面清單"
+
+#: builtin/help.c
+msgid "print list of file formats, protocols and other developer interfaces"
+msgstr "輸出檔案格式、通訊協定和其他開發者介面的清單"
+
 #: builtin/help.c
 msgid "print all configuration variable names"
 msgstr "列印所有設定變數名稱"
 
 #: builtin/help.c
-msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
-msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
 
 #: builtin/help.c
 #, c-format
@@ -8943,8 +9052,8 @@ msgid "show source"
 msgstr "顯示來源"
 
 #: builtin/log.c
-msgid "use mail map file"
-msgstr "使用信件映射檔案"
+msgid "clear all previously-defined decoration filters"
+msgstr "清除所有先前定義的裝飾過濾器"
 
 #: builtin/log.c
 msgid "only decorate refs that match <pattern>"
@@ -9269,6 +9378,10 @@ msgstr "在附函或單個修補檔中顯示和 <refspec> 的差異"
 msgid "percentage by which creation is weighted"
 msgstr "建立權重的百分比"
 
+#: builtin/log.c
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr "顯示內文中的 From:即便和信件標頭的值相同"
+
 #: builtin/log.c
 #, c-format
 msgid "invalid ident line: %s"
@@ -9344,11 +9457,26 @@ msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "不能找到追蹤的遠端分支,請手動指定 <上游>。\n"
 
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr "ls-files 格式錯誤:“%s” 元素不以 “(” 開頭"
+
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr "ls-files 格式錯誤:“%s” 元素不以 “)” 結尾"
+
+#: builtin/ls-files.c
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr "ls-files 格式錯誤:%%%.*s"
+
 #: builtin/ls-files.c
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<選項>] [<檔案>...]"
 
-#: builtin/ls-files.c
+#: builtin/ls-files.c builtin/merge-tree.c
 msgid "separate paths with the NUL character"
 msgstr "用 NUL 字元分隔路徑"
 
@@ -9456,6 +9584,13 @@ msgstr "不顯示重複項目"
 msgid "show sparse directories in the presence of a sparse index"
 msgstr "在稀疏索引存在時顯示稀疏目錄"
 
+#: builtin/ls-files.c
+msgid ""
+"--format cannot be used with -s, -o, -k, -t, --resolve-undo, --deduplicate, "
+"--eol"
+msgstr ""
+"--format 不能和 -s、-o、-k、-t、--resolve-undo、--deduplicate、--eol 一起使用"
+
 #: builtin/ls-remote.c
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
@@ -9738,6 +9873,50 @@ msgstr "無法解析引用 '%s'"
 msgid "Merging %s with %s\n"
 msgstr "合併 %s 和 %s\n"
 
+#: builtin/merge-tree.c builtin/merge.c
+msgid "not something we can merge"
+msgstr "不能合併"
+
+#: builtin/merge-tree.c builtin/merge.c
+msgid "refusing to merge unrelated histories"
+msgstr "拒絕合併無關的歷史"
+
+#: builtin/merge-tree.c
+msgid "failure to merge"
+msgstr "合併時發生錯誤"
+
+#: builtin/merge-tree.c
+msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+msgstr "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
+
+#: builtin/merge-tree.c
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+
+#: builtin/merge-tree.c
+msgid "do a real merge instead of a trivial merge"
+msgstr "執行真實合併,而非簡易合併"
+
+#: builtin/merge-tree.c
+msgid "do a trivial merge only"
+msgstr "只執行簡易合併"
+
+#: builtin/merge-tree.c
+msgid "also show informational/conflict messages"
+msgstr "亦顯示資訊性或衝突訊息"
+
+#: builtin/merge-tree.c
+msgid "list filenames without modes/oids/stages"
+msgstr "列出檔名,但不附加 modes/oids/stages"
+
+#: builtin/merge-tree.c builtin/merge.c builtin/pull.c
+msgid "allow merging unrelated histories"
+msgstr "允許合並不相關的歷史"
+
+#: builtin/merge-tree.c
+msgid "--trivial-merge is incompatible with all other options"
+msgstr "--trivial-merge 和其他所有選項都不相容"
+
 #: builtin/merge.c
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<選項>] [<提交>...]"
@@ -9844,10 +10023,6 @@ msgstr "--abort,但是保留索引和工作區"
 msgid "continue the current in-progress merge"
 msgstr "繼續目前正在進行的合併"
 
-#: builtin/merge.c builtin/pull.c
-msgid "allow merging unrelated histories"
-msgstr "允許合並不相關的歷史"
-
 #: builtin/merge.c
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr "繞過 pre-merge-commit 和 commit-msg 掛鉤"
@@ -9993,10 +10168,6 @@ msgstr "不能關閉 '%s'"
 msgid "not something we can merge in %s: %s"
 msgstr "不能在 %s 中合併:%s"
 
-#: builtin/merge.c
-msgid "not something we can merge"
-msgstr "不能合併"
-
 #: builtin/merge.c
 msgid "--abort expects no arguments"
 msgstr "--abort 不帶參數"
@@ -10058,15 +10229,20 @@ msgstr "%s - 不能被合併"
 msgid "Can merge only exactly one commit into empty head"
 msgstr "只能將一個提交合並到空分支上"
 
-#: builtin/merge.c
-msgid "refusing to merge unrelated histories"
-msgstr "拒絕合併無關的歷史"
-
 #: builtin/merge.c
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "更新 %s..%s\n"
 
+#: builtin/merge.c merge-ort-wrappers.c merge-recursive.c
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+"  %s"
+msgstr ""
+"您對下列檔案的本機修改將被合併動作覆蓋:\n"
+"  %s"
+
 #: builtin/merge.c
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
@@ -10107,6 +10283,11 @@ msgstr "使用 %s 策略,準備自行解決。\n"
 msgid "Automatic merge went well; stopped before committing as requested\n"
 msgstr "自動合併進展順利,按要求在提交前停止\n"
 
+#: builtin/merge.c
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr "完成時,使用 `git stash pop` 套用儲藏更改\n"
+
 #: builtin/mktag.c
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
@@ -10254,6 +10435,10 @@ msgstr "檢查 '%s' 到 '%s' 的重新命名\n"
 msgid "bad source"
 msgstr "來源損壞"
 
+#: builtin/mv.c
+msgid "destination exists"
+msgstr "目的地已存在"
+
 #: builtin/mv.c
 msgid "can not move directory into itself"
 msgstr "不能將目錄移動到自身"
@@ -10274,10 +10459,6 @@ msgstr "不在版本控制之下"
 msgid "conflicted"
 msgstr "衝突"
 
-#: builtin/mv.c
-msgid "destination exists"
-msgstr "目的地已存在"
-
 #: builtin/mv.c
 #, c-format
 msgid "overwriting '%s'"
@@ -10295,6 +10476,10 @@ msgstr "同一目標具有多個來源"
 msgid "destination directory does not exist"
 msgstr "找不到目的地目錄"
 
+#: builtin/mv.c
+msgid "destination exists in the index"
+msgstr "目的地已存在索引"
+
 #: builtin/mv.c
 #, c-format
 msgid "%s, source=%s, destination=%s"
@@ -10737,10 +10922,10 @@ msgstr "註解引用"
 msgid "use notes from <notes-ref>"
 msgstr "從 <註解引用> 使用註解"
 
-#: builtin/notes.c builtin/stash.c
+#: builtin/notes.c builtin/remote.c parse-options.c
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "未知子指令:%s"
+msgid "unknown subcommand: `%s'"
+msgstr "未知子指令:「%s」"
 
 #: builtin/pack-objects.c
 msgid ""
@@ -11339,7 +11524,7 @@ msgstr "詳見 git-pull(1)。"
 msgid "<remote>"
 msgstr "<遠端>"
 
-#: builtin/pull.c contrib/scalar/scalar.c
+#: builtin/pull.c scalar.c
 msgid "<branch>"
 msgstr "<分支>"
 
@@ -11793,14 +11978,20 @@ msgstr "只發出跟第一個範圍相關的輸出"
 msgid "only emit output related to the second range"
 msgstr "只發出跟第二個範圍相關的輸出"
 
+#: builtin/range-diff.c
+#, c-format
+msgid "not a revision: '%s'"
+msgstr "非修訂版:「%s」"
+
 #: builtin/range-diff.c
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr "不是提交範圍:「%s」"
 
 #: builtin/range-diff.c
-msgid "single arg format must be symmetric range"
-msgstr "單個參數格式必須是對稱範圍(即包含...)"
+#, c-format
+msgid "not a symmetric range: '%s'"
+msgstr "不是對稱範圍:「%s」"
 
 #: builtin/range-diff.c
 msgid "need two commit ranges"
@@ -12135,6 +12326,10 @@ msgstr "保留開頭是空白的提交"
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr "在 -i 互動模式下,移動以 squash!/fixup! 開頭的提交"
 
+#: builtin/rebase.c
+msgid "update branches that point to commits that are being rebased"
+msgstr "更新指向正在重定基底的提交之分支"
+
 #: builtin/rebase.c
 msgid "add exec lines after each commit of the editable list"
 msgstr "可編輯列表的每一個提交下面增加一行 exec"
@@ -12757,6 +12952,10 @@ msgstr " 新的(下一次取得將儲存於 remotes/%s)"
 msgid " tracked"
 msgstr " 已追蹤"
 
+#: builtin/remote.c
+msgid " skipped"
+msgstr " 略過"
+
 #: builtin/remote.c
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " 過時(使用 'git remote prune' 移除)"
@@ -13599,11 +13798,16 @@ msgstr "不能重設索引檔案至版本 '%s'。"
 msgid "Could not write new index file."
 msgstr "不能寫入新的索引檔案。"
 
-#: builtin/rev-list.c pack-bitmap.c
+#: builtin/rev-list.c
 #, c-format
 msgid "unable to get disk usage of %s"
 msgstr "無法取得 %s 的磁碟用量"
 
+#: builtin/rev-list.c
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr "「%s」的數值無效:「%s」,唯一允許的格式是「%s」"
+
 #: builtin/rev-list.c
 msgid "rev-list does not support display of notes"
 msgstr "rev-list 不支援顯示註解"
@@ -13637,6 +13841,10 @@ msgstr "輸入過早到達結尾"
 msgid "no usage string given before the `--' separator"
 msgstr "「--」分隔符號前未提供用法字串"
 
+#: builtin/rev-parse.c
+msgid "missing opt-spec before option flags"
+msgstr "選項旗標前缺少 opt-spec"
+
 #: builtin/rev-parse.c
 msgid "Needed a single revision"
 msgstr "需要一個修訂版本"
@@ -14182,7 +14390,7 @@ msgstr "以 cone 模式初始化稀疏簽出"
 msgid "toggle the use of a sparse index"
 msgstr "切換是否使用稀疏索引"
 
-#: builtin/sparse-checkout.c commit-graph.c midx.c
+#: builtin/sparse-checkout.c commit-graph.c midx.c sequencer.c
 #, c-format
 msgid "unable to create leading directories of %s"
 msgstr "不能為 %s 建立先導目錄"
@@ -14577,6 +14785,11 @@ msgstr "為每一行的行首新增備註符和空格"
 msgid "Expecting a full ref name, got %s"
 msgstr "期望一個完整的引用名稱,卻得到 %s"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr "無法獲得子模組 '%s' 的版本庫句柄"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid ""
@@ -14584,14 +14797,6 @@ msgid ""
 "authoritative upstream."
 msgstr "無法找到設定 '%s'。假定這個版本庫是其自身的官方上游。"
 
-#: builtin/submodule--helper.c
-msgid "alternative anchor for relative paths"
-msgstr "相對路徑的替代錨記(anchor)"
-
-#: builtin/submodule--helper.c
-msgid "git submodule--helper list [--prefix=<path>] [<path>...]"
-msgstr "git submodule--helper list [--prefix=<路徑>] [<路徑>...]"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
@@ -14630,8 +14835,8 @@ msgid "recurse into nested submodules"
 msgstr "遞迴進入嵌套子模組中"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
-msgstr "git submodule--helper foreach [--quiet] [--recursive] [--] <命令>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <command>"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14658,8 +14863,8 @@ msgid "suppress output for initializing a submodule"
 msgstr "隱藏初始化子模組的輸出"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper init [<options>] [<path>]"
-msgstr "git submodule--helper init [<選項>] [<路徑>]"
+msgid "git submodule init [<options>] [<path>]"
+msgstr "git submodule init [<options>] [<path>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14690,10 +14895,6 @@ msgstr "使用儲存在索引中的提交,而非儲存在子模組 HEAD 中的
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
 msgstr "git submodule status [--quiet] [--cached] [--recursive] [<路徑>...]"
 
-#: builtin/submodule--helper.c
-msgid "git submodule--helper name <path>"
-msgstr "git submodule--helper name <路徑>"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
@@ -14736,8 +14937,8 @@ msgid "limit the summary size"
 msgstr "限制摘要大小"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
-msgstr "git submodule--helper summary [<選項>] [<提交>] [--] [<路徑>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
+msgstr "git submodule summary [<options>] [<commit>] [--] [<path>]"
 
 #: builtin/submodule--helper.c
 msgid "could not fetch a revision for HEAD"
@@ -14753,11 +14954,6 @@ msgstr "為 '%s' 同步子模組 url\n"
 msgid "failed to register url for submodule path '%s'"
 msgstr "無法為子模組路徑 '%s' 註冊 url"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr "無法得到子模組 '%s' 的預設遠端關聯"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "failed to update remote for submodule '%s'"
@@ -14768,8 +14964,8 @@ msgid "suppress output of synchronizing submodule url"
 msgstr "隱藏子模組 URL 同步的輸出"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule--helper sync [--quiet] [--recursive] [<路徑>]"
+msgid "git submodule sync [--quiet] [--recursive] [<path>]"
+msgstr "git submodule sync [--quiet] [--recursive] [<path>]"
 
 #: builtin/submodule--helper.c
 #, c-format
@@ -14836,6 +15032,11 @@ msgstr ""
 "以允許 Git 不用備用版本庫複製,亦可使用等效的 '--reference-if-able'\n"
 "而非 '--reference' 複製。"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr "無法取得 gitdir “%s” 的版本庫控點"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
@@ -14871,6 +15072,10 @@ msgstr "目錄不是空的:「%s」"
 msgid "could not get submodule directory for '%s'"
 msgstr "無法得到 '%s' 的子模組目錄"
 
+#: builtin/submodule--helper.c
+msgid "alternative anchor for relative paths"
+msgstr "相對路徑的替代錨記(anchor)"
+
 #: builtin/submodule--helper.c
 msgid "where the new submodule will be cloned to"
 msgstr "新的子模組將要複製的路徑"
@@ -14905,11 +15110,6 @@ msgstr ""
 "<repository>] [--name <name>] [--depth <depth>] [--single-branch] [--filter "
 "<filter-spec>] --url <url> --path <path>"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr "子模組 '%2$s' 的更新模式 '%1$s' 無效"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
@@ -14996,6 +15196,11 @@ msgid ""
 "of that commit failed."
 msgstr "已經取得「%s」子模組路徑,這個路徑卻未包含「%s」。直接取得該提交失敗。"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr "無法在「%s」路徑初始化子模組"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid ""
@@ -15003,11 +15208,6 @@ msgid ""
 "the superproject is not on any branch"
 msgstr "子模組(%s)的分支設定為繼承上級專案的分支,但是上級專案不在任何分支上"
 
-#: builtin/submodule--helper.c
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr "無法獲得子模組 '%s' 的版本庫句柄"
-
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
@@ -15053,12 +15253,16 @@ msgid "path into the working tree"
 msgstr "到工作區的路徑"
 
 #: builtin/submodule--helper.c
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "工作區中的路徑,遞迴嵌套子模組"
+msgid "use the 'checkout' update strategy (default)"
+msgstr "使用 “checkout” 更新策略(預設值)"
+
+#: builtin/submodule--helper.c
+msgid "use the 'merge' update strategy"
+msgstr "使用 “merge” 更新策略"
 
 #: builtin/submodule--helper.c
-msgid "rebase, merge, checkout or none"
-msgstr "rebase、merge、checkout 或 none"
+msgid "use the 'rebase' update strategy"
+msgstr "使用 “rebase” 更新策略"
 
 #: builtin/submodule--helper.c
 msgid "create a shallow clone truncated to the specified number of revisions"
@@ -15076,6 +15280,10 @@ msgstr "初始複製是否應該遵循建議的淺複製選項"
 msgid "don't print cloning progress"
 msgstr "不要輸出複製進度"
 
+#: builtin/submodule--helper.c
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr "不允許複製進非空白目錄,隱含 --init"
+
 #: builtin/submodule--helper.c
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
@@ -15088,17 +15296,13 @@ msgstr ""
 "shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
 "[--] [<path>...]"
 
-#: builtin/submodule--helper.c
-msgid "bad value for update parameter"
-msgstr "update 參數取值錯誤"
-
 #: builtin/submodule--helper.c
 msgid "recurse into submodules"
 msgstr "在子模組中遞迴"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper absorb-git-dirs [<options>] [<path>...]"
-msgstr "git submodule--helper absorb-git-dirs [<選項>] [<路徑>...]"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
+msgstr "git submodule absorbgitdirs [<options>] [<path>...]"
 
 #: builtin/submodule--helper.c
 msgid "check if it is safe to write to the .gitmodules file"
@@ -15125,8 +15329,8 @@ msgid "suppress output for setting url of a submodule"
 msgstr "隱藏子模組設定 URL 的輸出"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
-msgstr "git submodule--helper set-url [--quiet] <路徑> <新 URL>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
+msgstr "git submodule set-url [--quiet] <path> <newurl>"
 
 #: builtin/submodule--helper.c
 msgid "set the default tracking branch to master"
@@ -15137,14 +15341,12 @@ msgid "set the default tracking branch"
 msgstr "設定預設追蹤分支"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
 
 #: builtin/submodule--helper.c
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
 
 #: builtin/submodule--helper.c
 msgid "--branch or --default required"
@@ -15259,8 +15461,8 @@ msgid ""
 msgstr "將子模組的名稱設為指定字串,而非預設為其路徑"
 
 #: builtin/submodule--helper.c
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
-msgstr "git submodule--helper add [<選項>] [--] <版本庫> [<路徑>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
+msgstr "git submodule add [<options>] [--] <repository> [<path>]"
 
 #: builtin/submodule--helper.c
 msgid "Relative path can only be used from the toplevel of the working tree"
@@ -15513,6 +15715,19 @@ msgstr "已更新標籤 '%s'(曾為 %s)\n"
 msgid "pack exceeds maximum allowed size"
 msgstr "包超過了最大允許值"
 
+#: builtin/unpack-objects.c
+msgid "failed to write object in stream"
+msgstr "無法在串流中寫入物件"
+
+#: builtin/unpack-objects.c
+#, c-format
+msgid "inflate returned (%d)"
+msgstr "inflate 回傳 (%d)"
+
+#: builtin/unpack-objects.c
+msgid "invalid blob object from stream"
+msgstr "源自串流的 blob 物件無效"
+
 #: builtin/unpack-objects.c
 msgid "Unpacking objects"
 msgstr "展開物件中"
@@ -16153,6 +16368,33 @@ msgstr "將 <前綴> 子目錄內容寫到一個樹狀物件"
 msgid "only useful for debugging"
 msgstr "只對除錯有用"
 
+#: bulk-checkin.c
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr "core.fsyncMethod = batch 不支援本平台"
+
+#: bundle-uri.c
+msgid "failed to create temporary file"
+msgstr "無法建立暫存檔"
+
+#: bundle-uri.c
+msgid "insufficient capabilities"
+msgstr "功能不足"
+
+#: bundle-uri.c
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr "無法從 “%s” URI 下載套件"
+
+#: bundle-uri.c
+#, c-format
+msgid "file at URI '%s' is not a bundle"
+msgstr "位於 URI “%s” 的檔案不是套件"
+
+#: bundle-uri.c
+#, c-format
+msgid "failed to unbundle bundle from URI '%s'"
+msgstr "無法解開源自 URI “%s” 的套件"
+
 #: bundle.c
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
@@ -16413,6 +16655,10 @@ msgstr "一個非常簡單的 Git 版本庫伺服器"
 msgid "Give an object a human readable name based on an available ref"
 msgstr "基於一個現存的引用為一個物件起一個可讀的名稱"
 
+#: command-list.h
+msgid "Generate a zip archive of diagnostic information"
+msgstr "產生診斷資訊的 zip 封存檔"
+
 #: command-list.h
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "顯示提交之間、提交和工作區之間等的差異"
@@ -16582,8 +16828,8 @@ msgid "The standard helper program to use with git-merge-index"
 msgstr "與 git-merge-index 一起使用的標準嚮導程式"
 
 #: command-list.h
-msgid "Show three-way merge without touching index"
-msgstr "顯示三路合併而不動索引"
+msgid "Perform merge without touching index or working tree"
+msgstr "在不接觸索引或工作區的情況下執行合併"
 
 #: command-list.h
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
@@ -16843,6 +17089,10 @@ msgstr "驗證打包的 Git 封存檔案"
 msgid "Check the GPG signature of tags"
 msgstr "檢查標籤的 GPG 簽名"
 
+#: command-list.h
+msgid "Display version information about Git"
+msgstr "顯示 Git 的版本資訊"
+
 #: command-list.h
 msgid "Show logs with difference each commit introduces"
 msgstr "顯示每一個提交引入的差異日誌"
@@ -16888,8 +17138,32 @@ msgid "Frequently asked questions about using Git"
 msgstr "Git 使用的常見問題"
 
 #: command-list.h
-msgid "A Git Glossary"
-msgstr "Git 詞彙表"
+msgid "The bundle file format"
+msgstr "套件檔案格式"
+
+#: command-list.h
+msgid "Chunk-based file formats"
+msgstr "以區塊為基礎的檔案格式"
+
+#: command-list.h
+msgid "Git commit graph format"
+msgstr "Git 提交圖格式"
+
+#: command-list.h
+msgid "Git index format"
+msgstr "Git 索引格式"
+
+#: command-list.h
+msgid "Git pack format"
+msgstr "Git 封包格式"
+
+#: command-list.h
+msgid "Git cryptographic signature formats"
+msgstr "Git 密碼編譯簽章格式"
+
+#: command-list.h
+msgid "A Git Glossary"
+msgstr "Git 詞彙表"
 
 #: command-list.h
 msgid "Hooks used by Git"
@@ -16915,6 +17189,26 @@ msgstr "定義子模組屬性"
 msgid "Git namespaces"
 msgstr "Git 名字空間"
 
+#: command-list.h
+msgid "Protocol v0 and v1 capabilities"
+msgstr "v0 和 v1 版通訊協定功能"
+
+#: command-list.h
+msgid "Things common to various protocols"
+msgstr "各種通訊協定共通的部分"
+
+#: command-list.h
+msgid "Git HTTP-based protocols"
+msgstr "Git 以 HTTP 為基礎的通訊協定"
+
+#: command-list.h
+msgid "How packs are transferred over-the-wire"
+msgstr "封包在線上傳輸的方式"
+
+#: command-list.h
+msgid "Git Wire Protocol, Version 2"
+msgstr "Git Wire 通訊協定,第 2 版"
+
 #: command-list.h
 msgid "Helper programs to interact with remote repositories"
 msgstr "用來與遠端版本庫互動的協助工具"
@@ -16947,6 +17241,10 @@ msgstr "Git web 介面(Git 版本庫的 web 前端)"
 msgid "An overview of recommended workflows with Git"
 msgstr "Git 推薦的工作流概覽"
 
+#: command-list.h
+msgid "A tool for managing large Git repositories"
+msgstr "用來管理大型 Git 版本庫的工具"
+
 #: commit-graph.c
 msgid "commit-graph file is too small"
 msgstr "提交圖形檔案太小"
@@ -17233,6 +17531,16 @@ msgstr "沒有可用的編譯器資訊\n"
 msgid "no libc information available\n"
 msgstr "沒有可用的 libc 資訊\n"
 
+#: compat/disk.h
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr "無法判斷 “%s” 的剩餘磁碟大小"
+
+#: compat/disk.h
+#, c-format
+msgid "could not get info for '%s'"
+msgstr "無法取得 “%s” 的資訊"
+
 #: compat/fsmonitor/fsm-health-win32.c
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
@@ -17301,6 +17609,16 @@ msgstr "在 “%s” 上呼叫 GetOverlappedResult 失敗 [GLE %ld]"
 msgid "could not read directory changes [GLE %ld]"
 msgstr "無法讀取目錄變化 [GLE %ld]"
 
+#: compat/fsmonitor/fsm-settings-win32.c
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr "[GLE %ld] 無法開啟以讀取「%ls」"
+
+#: compat/fsmonitor/fsm-settings-win32.c
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr "[GLE %ld] 無法取得「%ls」的通訊協定資訊"
+
 #: compat/mingw.c
 #, c-format
 msgid "failed to copy SID (%ld)"
@@ -17974,229 +18292,6 @@ msgstr "寫入 rev-list 失敗"
 msgid "failed to close rev-list's stdin"
 msgstr "關閉 rev-list 的標準輸入失敗"
 
-#: contrib/scalar/scalar.c worktree.c
-#, c-format
-msgid "'%s' does not exist"
-msgstr "'%s' 不存在"
-
-#: contrib/scalar/scalar.c
-msgid "need a working directory"
-msgstr "需要工作目錄"
-
-#: contrib/scalar/scalar.c
-msgid "could not find enlistment root"
-msgstr "找不到編列名單的根目錄"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not switch to '%s'"
-msgstr "無法切換至「%s」"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure %s=%s"
-msgstr "無法設定 %s=%s"
-
-#: contrib/scalar/scalar.c
-msgid "could not configure log.excludeDecoration"
-msgstr "無法設定 log.excludeDecoration"
-
-#: contrib/scalar/scalar.c
-msgid "Scalar enlistments require a worktree"
-msgstr "純量編列名單需要工作目錄"
-
-#: contrib/scalar/scalar.c dir.c
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "不能開啟目錄 '%s'"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr "略過 “%s”,其非檔案或目錄"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr "無法判斷 “%s” 的剩餘磁碟大小"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not get info for '%s'"
-msgstr "無法取得 “%s” 的資訊"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr "遠端 HEAD 不是分支:「%.*s」"
-
-#: contrib/scalar/scalar.c
-msgid "failed to get default branch name from remote; using local default"
-msgstr "無法從遠端取得預設分支名稱。改用本機預設名稱"
-
-#: contrib/scalar/scalar.c
-msgid "failed to get default branch name"
-msgstr "無法取得預設分支名稱"
-
-#: contrib/scalar/scalar.c
-msgid "failed to unregister repository"
-msgstr "無法取消註冊版本庫"
-
-#: contrib/scalar/scalar.c
-msgid "failed to delete enlistment directory"
-msgstr "無法刪除編列名單目錄"
-
-#: contrib/scalar/scalar.c
-msgid "branch to checkout after clone"
-msgstr "複製後要簽出的分支"
-
-#: contrib/scalar/scalar.c
-msgid "when cloning, create full working directory"
-msgstr "複製時建立完整的工作目錄"
-
-#: contrib/scalar/scalar.c
-msgid "only download metadata for the branch that will be checked out"
-msgstr "只下載會簽出的分支中介資料"
-
-#: contrib/scalar/scalar.c
-msgid "scalar clone [<options>] [--] <repo> [<dir>]"
-msgstr "scalar clone [<options>] [--] <repo> [<dir>]"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr "無法從「%s」推論工作區名稱"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "directory '%s' exists already"
-msgstr "「%s」目錄已經存在"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr "無法取得「%s」的預設分支"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr "無法設定「%s」中的遠端"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not configure '%s'"
-msgstr "無法設定「%s」"
-
-#: contrib/scalar/scalar.c
-msgid "partial clone failed; attempting full clone"
-msgstr "部分複製失敗。嘗試完整複製"
-
-#: contrib/scalar/scalar.c
-msgid "could not configure for full clone"
-msgstr "無法設定完整複製"
-
-#: contrib/scalar/scalar.c
-msgid "scalar diagnose [<enlistment>]"
-msgstr "scalar diagnose [<enlistment>]"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr "無法建立 “%s” 的目錄"
-
-#: contrib/scalar/scalar.c
-msgid "could not duplicate stdout"
-msgstr "無法複製 stdout"
-
-#: contrib/scalar/scalar.c
-msgid "failed to write archive"
-msgstr "無法寫入封存"
-
-#: contrib/scalar/scalar.c
-msgid "`scalar list` does not take arguments"
-msgstr "`scalar list` 未取引數"
-
-#: contrib/scalar/scalar.c
-msgid "scalar register [<enlistment>]"
-msgstr "scalar register [<enlistment>]"
-
-#: contrib/scalar/scalar.c
-msgid "reconfigure all registered enlistments"
-msgstr "重新設定所有註冊的編列名單"
-
-#: contrib/scalar/scalar.c
-msgid "scalar reconfigure [--all | <enlistment>]"
-msgstr "scalar reconfigure [--all | <enlistment>]"
-
-#: contrib/scalar/scalar.c
-msgid "--all or <enlistment>, but not both"
-msgstr "--all 或 <enlistment> 但不能傳入兩者"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr "git 版本庫在「%s」遺失"
-
-#: contrib/scalar/scalar.c
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-"scalar run <task> [<enlistment>]\n"
-"作業:\n"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "no such task: '%s'"
-msgstr "無此作業:「%s」"
-
-#: contrib/scalar/scalar.c
-msgid "scalar unregister [<enlistment>]"
-msgstr "scalar unregister [<enlistment>]"
-
-#: contrib/scalar/scalar.c
-msgid "scalar delete <enlistment>"
-msgstr "scalar delete <enlistment>"
-
-#: contrib/scalar/scalar.c
-msgid "refusing to delete current working directory"
-msgstr "拒絕刪除目前工作目錄"
-
-#: contrib/scalar/scalar.c
-msgid "include Git version"
-msgstr "包含 Git 版本"
-
-#: contrib/scalar/scalar.c
-msgid "include Git's build options"
-msgstr "包含 Git 組建選項"
-
-#: contrib/scalar/scalar.c
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr "scalar verbose [-v | --verbose] [--build-options]"
-
-#: contrib/scalar/scalar.c
-msgid "-C requires a <directory>"
-msgstr "-C 需要 <directory>"
-
-#: contrib/scalar/scalar.c
-#, c-format
-msgid "could not change to '%s'"
-msgstr "無法更改為「%s」"
-
-#: contrib/scalar/scalar.c
-msgid "-c requires a <key>=<value> argument"
-msgstr "-c 需要 <key>=<value> 引數"
-
-#: contrib/scalar/scalar.c
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"命令:\n"
-
 #: convert.c
 #, c-format
 msgid "illegal crlf_action %d"
@@ -18427,6 +18522,39 @@ msgstr "來自 config 的資料島常規表示式有太多的擷取群組(最
 msgid "Marked %d islands, done.\n"
 msgstr "已標記 %d 個資料島,結束。\n"
 
+#: diagnose.c
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr "無效的 --%s 值「%s」"
+
+#: diagnose.c
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr "無法封存不存在的路徑「%s」"
+
+#: diagnose.c dir.c
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "不能開啟目錄 '%s'"
+
+#: diagnose.c
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr "略過 “%s”,其非檔案或目錄"
+
+#: diagnose.c
+msgid "could not duplicate stdout"
+msgstr "無法複製 stdout"
+
+#: diagnose.c
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr "無法將「%s」路徑加入封存工具中"
+
+#: diagnose.c
+msgid "failed to write archive"
+msgstr "無法寫入封存"
+
 #: diff-lib.c
 msgid "--merge-base does not work with ranges"
 msgstr "--merge-base 跟範圍無法搭配運作"
@@ -19176,6 +19304,10 @@ msgstr "git fetch-pack:應為 ACK/NAK,卻得到 '%s'"
 msgid "unable to write to remote"
 msgstr "無法寫到遠端"
 
+#: fetch-pack.c
+msgid "Server supports filter"
+msgstr "伺服器支援 filter"
+
 #: fetch-pack.c
 #, c-format
 msgid "invalid shallow line: %s"
@@ -19317,10 +19449,6 @@ msgstr "伺服器不支援「%s」算法"
 msgid "Server does not support shallow requests"
 msgstr "伺服器不支援 shallow 請求"
 
-#: fetch-pack.c
-msgid "Server supports filter"
-msgstr "伺服器支援 filter"
-
 #: fetch-pack.c
 msgid "unable to write request to remote"
 msgstr "無法將請求寫到遠端"
@@ -19735,6 +19863,14 @@ msgstr "低級指令 / 同步版本庫"
 msgid "Low-level Commands / Internal Helpers"
 msgstr "低級指令/內部協助工具"
 
+#: help.c
+msgid "User-facing repository, command and file interfaces"
+msgstr "面向使用者的版本庫、命令和檔案介面"
+
+#: help.c
+msgid "Developer-facing file formats, protocols and other interfaces"
+msgstr "面向開發者的檔案格式、通訊協定和介面"
+
 #: help.c
 #, c-format
 msgid "available git commands in '%s'"
@@ -19752,6 +19888,14 @@ msgstr "這些是各種場合常見的 Git 指令:"
 msgid "The Git concept guides are:"
 msgstr "Git 概念嚮導有:"
 
+#: help.c
+msgid "User-facing repository, command and file interfaces:"
+msgstr "面向使用者的版本庫、命令和檔案介面:"
+
+#: help.c
+msgid "File formats, protocols and other developer interfaces:"
+msgstr "檔案格式、通訊協定和其他開發者介面:"
+
 #: help.c
 msgid "External commands"
 msgstr "外部指令"
@@ -19842,11 +19986,6 @@ msgstr ""
 "因為沒有將掛鉤 '%s' 設定為可執行,掛鉤被忽略。您可以透過\n"
 "設定 `git config advice.ignoredHook false` 來關閉這條警告。"
 
-#: hook.c
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr "無法啟動「%s」掛鉤\n"
-
 #: http-fetch.c
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
@@ -20066,20 +20205,16 @@ msgstr "在 ls-refs 引數之後應該有一個 flush 包"
 msgid "quoted CRLF detected"
 msgstr "偵測到由可列印字元 (quoted) 所組成的 CRLF"
 
-#: merge-ort-wrappers.c merge-recursive.c
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-"您對下列檔案的本機修改將被合併動作覆蓋:\n"
-"  %s"
-
 #: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
 msgstr "無法合併子模組 %s (沒有簽出)"
 
+#: merge-ort.c
+#, c-format
+msgid "Failed to merge submodule %s (no merge base)"
+msgstr "無法合併 %s 子模組(沒有合併基底)"
+
 #: merge-ort.c merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
@@ -20103,27 +20238,8 @@ msgstr "無法合併 %s 子模組"
 #: merge-ort.c
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-"無法合併 %s 子模組,但有找到一個可行的合併方案:\n"
-"%s\n"
-
-#: merge-ort.c merge-recursive.c
-#, c-format
-msgid ""
-"If this is correct simply add it to the index for example\n"
-"by using:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"which will accept this suggestion.\n"
-msgstr ""
-"正確的話,就能直接加進索引,例如執行下述命令:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"接受本建議。\n"
+"Failed to merge submodule %s, but a possible merge resolution exists: %s"
+msgstr "無法合併 %s 子模組,但存在合併可行方案:%s"
 
 #: merge-ort.c
 #, c-format
@@ -20302,12 +20418,45 @@ msgstr ""
 "衝突(修改/刪除):%1$s 已在 %2$s 刪除和在 %3$s 修改。%5$s 的 %4$s 版本留在樹"
 "上。"
 
+#. TRANSLATORS: This is a line of advice to resolve a merge
+#. conflict in a submodule. The first argument is the submodule
+#. name, and the second argument is the abbreviated id of the
+#. commit that needs to be merged.  For example:
+#.  - go to submodule (mysubmodule), and either merge commit abc1234"
+#.
 #: merge-ort.c
 #, c-format
 msgid ""
-"Note: %s not up to date and in way of checking out conflicted version; old "
-"copy renamed to %s"
-msgstr "註:%s 不是最新且干擾到簽出衝突版本。已將舊拷貝重新命名至 %s"
+" - go to submodule (%s), and either merge commit %s\n"
+"   or update to an existing commit which has merged those changes\n"
+msgstr ""
+" - 前往子模組 (%s),並合併 %s 提交或\n"
+"   更新至已經合併這些更改的提交\n"
+
+#: merge-ort.c
+#, c-format
+msgid ""
+"Recursive merging with submodules currently only supports trivial cases.\n"
+"Please manually handle the merging of each conflicted submodule.\n"
+"This can be accomplished with the following steps:\n"
+"%s - come back to superproject and run:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   to record the above merge or update\n"
+" - resolve any other conflicts in the superproject\n"
+" - commit the resulting index in the superproject\n"
+msgstr ""
+"與子模組進行遞迴合併,目前僅支援簡單的情況。\n"
+"請自行處理每個有衝突之子模組的合併問題。\n"
+"處理步驟有以下幾步:\n"
+"%s - 回到上級專案,並執行:\n"
+"\n"
+"      git add %s\n"
+"\n"
+"   來記錄上述的合併或更新\n"
+" - 解決上級專案中的其它衝突\n"
+" - 在上級專案中,提交產生之索引資訊\n"
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
@@ -20394,6 +20543,22 @@ msgstr "無法合併子模組 %s(非快轉)"
 msgid "Found a possible merge resolution for the submodule:\n"
 msgstr "找到子模組的一個可能的合併方案:\n"
 
+#: merge-recursive.c
+#, c-format
+msgid ""
+"If this is correct simply add it to the index for example\n"
+"by using:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"which will accept this suggestion.\n"
+msgstr ""
+"正確的話,就能直接加進索引,例如執行下述命令:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"接受本建議。\n"
+
 #: merge-recursive.c
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
@@ -21029,6 +21194,26 @@ msgstr "在物件 %s 上呼叫 deflateEnd 失敗(%d)"
 msgid "confused by unstable object source data for %s"
 msgstr "被 %s 的不穩定物件來源資料混淆"
 
+#: object-file.c
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr "寫入串流物件 %ld != %<PRIuMAX>"
+
+#: object-file.c
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr "不能串流壓縮新物件 (%d)"
+
+#: object-file.c
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr "串流物件上的 deflateEnd 失敗 (%d)"
+
+#: object-file.c
+#, c-format
+msgid "unable to create directory %s"
+msgstr "無法建立 %s 目錄"
+
 #: object-file.c
 #, c-format
 msgid "cannot read object for %s"
@@ -21109,7 +21294,7 @@ msgstr "%s [無效物件]"
 #. TRANSLATORS: This is a line of ambiguous commit
 #. object output. E.g.:
 #. *
-#. "deadbeef commit 2021-01-01 - Some Commit Message"
+#.    "deadbeef commit 2021-01-01 - Some Commit Message"
 #.
 #: object-name.c
 #, c-format
@@ -21119,7 +21304,7 @@ msgstr "%s 提交 %s - %s"
 #. TRANSLATORS: This is a line of ambiguous
 #. tag object output. E.g.:
 #. *
-#. "deadbeef tag 2022-01-01 - Some Tag Message"
+#.    "deadbeef tag 2022-01-01 - Some Tag Message"
 #. *
 #. The second argument is the YYYY-MM-DD found
 #. in the tag.
@@ -21136,7 +21321,7 @@ msgstr "%s 標籤 %s - %s"
 #. tag object output where we couldn't parse
 #. the tag itself. E.g.:
 #. *
-#. "deadbeef [bad tag, could not parse it]"
+#.    "deadbeef [bad tag, could not parse it]"
 #.
 #: object-name.c
 #, c-format
@@ -21260,59 +21445,184 @@ msgstr "'%s' 路徑不存在 (既不存在磁碟,也不存在索引)"
 msgid "relative path syntax can't be used outside working tree"
 msgstr "相對路徑與法不能用在工作區外"
 
-#: object-name.c
+#: object-name.c
+#, c-format
+msgid "<object>:<path> required, only <object> '%s' given"
+msgstr "需要指定 <object>:<path>,卻只指定 <object>「%s」"
+
+#: object-name.c
+#, c-format
+msgid "invalid object name '%.*s'."
+msgstr "'%.*s' 物件名稱無效。"
+
+#: object.c
+#, c-format
+msgid "invalid object type \"%s\""
+msgstr "無效的物件類型 \"%s\""
+
+#: object.c
+#, c-format
+msgid "object %s is a %s, not a %s"
+msgstr "物件 %s 是一個 %s,不是一個 %s"
+
+#: object.c
+#, c-format
+msgid "object %s has unknown type id %d"
+msgstr "物件 %s 有未知的類型 id %d"
+
+#: object.c
+#, c-format
+msgid "unable to parse object: %s"
+msgstr "不能解析物件:%s"
+
+#: object.c
+#, c-format
+msgid "hash mismatch %s"
+msgstr "雜湊值與 %s 不符合"
+
+#: pack-bitmap-write.c
+msgid "trying to write commit not in index"
+msgstr "嘗試寫入不在索引的提交"
+
+#: pack-bitmap.c
+msgid "failed to load bitmap index (corrupted?)"
+msgstr "無法載入位圖索引(損壞?)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index (too small)"
+msgstr "位圖索引損壞(過小)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (wrong header)"
+msgstr "位圖索引檔案損壞(標頭錯誤)"
+
+#: pack-bitmap.c
+#, c-format
+msgid "unsupported version '%d' for bitmap index file"
+msgstr "位圖索引檔案的版本 “%d” 不支援"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit hash cache)"
+msgstr "位圖索引檔案損壞(不夠長,無法置入雜湊快取)"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap index file (too short to fit lookup table)"
+msgstr "位圖索引檔案損壞(不夠長,無法置入查詢表)"
+
+#: pack-bitmap.c
+#, c-format
+msgid "duplicate entry in bitmap index: '%s'"
+msgstr "位圖索引中有重複項目:「%s」"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr "ewah 位圖損壞:項目 %d 的標頭遭截斷"
+
+#: pack-bitmap.c
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr "ewah 位圖損壞:提交索引 %u 超出範圍"
+
+#: pack-bitmap.c
+msgid "corrupted bitmap pack index"
+msgstr "位圖包索引損壞"
+
+#: pack-bitmap.c
+msgid "invalid XOR offset in bitmap pack index"
+msgstr "位圖包索引的 XOR 偏移無效"
+
+#: pack-bitmap.c
+msgid "cannot fstat bitmap file"
+msgstr "無法 fstat 位圖檔案"
+
+#: pack-bitmap.c
+#, c-format
+msgid "ignoring extra bitmap file: '%s'"
+msgstr "忽略多出來的位圖檔案:「%s」"
+
+#: pack-bitmap.c
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr "總和檢查碼在 MIDX 和位圖中無符合項目"
+
+#: pack-bitmap.c
+msgid "multi-pack bitmap is missing required reverse index"
+msgstr "多包位圖缺少需要的反向索引"
+
+#: pack-bitmap.c
+#, c-format
+msgid "could not open pack %s"
+msgstr "無法開啟封包 %s"
+
+#: pack-bitmap.c
+#, c-format
+msgid "preferred pack (%s) is invalid"
+msgstr "偏好的封包 (%s) 無效"
+
+#: pack-bitmap.c
+msgid "corrupt bitmap lookup table: triplet position out of index"
+msgstr "位圖查詢表損壞:三元組位置超出索引"
+
+#: pack-bitmap.c
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
+msgstr "位圖查詢表損壞:XOR 鏈超出項目數"
+
+#: pack-bitmap.c
 #, c-format
-msgid "<object>:<path> required, only <object> '%s' given"
-msgstr "é\9c\80è¦\81æ\8c\87å®\9a <object>:<path>ï¼\8cå\8d»å\8fªæ\8c\87å®\9a <object>ã\80\8c%sã\80\8d"
+msgid "corrupt bitmap lookup table: commit index %u out of range"
+msgstr "ä½\8då\9c\96æ\9f¥è©¢è¡¨æ\90\8då£\9eï¼\9aæ\8f\90交索å¼\95 %u è¶\85å\87ºç¯\84å\9c\8d"
 
-#: object-name.c
+#: pack-bitmap.c
 #, c-format
-msgid "invalid object name '%.*s'."
-msgstr "'%.*s' 物件名稱無效。"
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
+msgstr "ewah 位圖損壞:提交 “%s” 之位圖的標頭遭截斷"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "invalid object type \"%s\""
-msgstr "無效的物件類型 \"%s\""
+msgid "object '%s' not found in type bitmaps"
+msgstr "在類型位圖中,找不到「%s」物件"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "object %s is a %s, not a %s"
-msgstr "物件 %s 是一個 %s,不是一個 %s"
+msgid "object '%s' does not have a unique type"
+msgstr "「%s」物件的類型不唯一"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "object %s has unknown type id %d"
-msgstr "物件 %s 有未知的類型 id %d"
+msgid "object '%s': real type '%s', expected: '%s'"
+msgstr "「%s」物件:實際類型是「%s」,但預期是「%s」"
 
-#: object.c
+#: pack-bitmap.c
 #, c-format
-msgid "unable to parse object: %s"
-msgstr "不能解析物件:%s"
+msgid "object not in bitmap: '%s'"
+msgstr "物件不在位圖中:「%s」"
 
-#: object.c
-#, c-format
-msgid "hash mismatch %s"
-msgstr "雜湊值與 %s 不符合"
+#: pack-bitmap.c
+msgid "failed to load bitmap indexes"
+msgstr "無法載入位圖索引"
 
 #: pack-bitmap.c
-msgid "multi-pack bitmap is missing required reverse index"
-msgstr "多包位圖缺少需要的反向索引"
+msgid "you must specify exactly one commit to test"
+msgstr "您必須指定剛好一個要測試的提交"
 
 #: pack-bitmap.c
 #, c-format
-msgid "could not open pack %s"
-msgstr "無法開啟封包 %s"
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr "提交「%s」無索引過的位圖"
+
+#: pack-bitmap.c
+msgid "mismatch in bitmap results"
+msgstr "位圖結果中有不符項目"
 
 #: pack-bitmap.c
 #, c-format
-msgid "preferred pack (%s) is invalid"
-msgstr "å\81\8f好ç\9a\84å°\81å\8c\85 (%s) ç\84¡æ\95\88"
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
+msgstr "å\9c¨ã\80\8c%2$sã\80\8då°\81å\8c\85ï¼\8cä½\8d移 %3$<PRIuMAX> ç\9a\84å\9c°æ\96¹æ\89¾ä¸\8då\88°ã\80\8c%1$sã\80\8d"
 
 #: pack-bitmap.c
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
-msgstr "找不到 %2$s 包,偏移位置 %3$<PRIuMAX> 的 %1$s"
+msgid "unable to get disk usage of '%s'"
+msgstr "無法取得「%s」的磁碟用量"
 
 #: pack-mtimes.c
 #, c-format
@@ -21467,6 +21777,10 @@ msgstr "你的意思是 `--%s`(有兩個短線)嗎?"
 msgid "alias of --%s"
 msgstr "--%s 的別名"
 
+#: parse-options.c
+msgid "need a subcommand"
+msgstr "需要子命令"
+
 #: parse-options.c
 #, c-format
 msgid "unknown option `%s'"
@@ -21996,32 +22310,38 @@ msgid ""
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
 "\n"
-"令:\n"
+"令:\n"
 "p, pick <提交> = 使用提交\n"
 "r, reword <提交> = 使用提交,但編輯提交說明\n"
 "e, edit <提交> = 使用提交,但不直接修補 (amend) \n"
 "s, squash <提交> = 使用提交,但融合至上個提交\n"
-"f, fixup [-C | -c] <提交> = 跟 “squash” 相似,但除非傳入「-C」\n"
+"f, fixup [-C | -c] <提交> = 跟 “squash” 相似,但除非傳入 -C,\n"
 "                   否則只保留上一個提交的日誌訊息。傳入 -C 表示只保留這個\n"
 "                   提交的訊息;傳入 -c 與 -C 功能相同,但會開啟編輯器\n"
-"x, exec <命令> = 使用 shell 執行指令(這一行的剩餘部分)\n"
-"b, break = 在這停止(使用 'git rebase --continue' 繼續重定基底)\n"
+"x, exec <命令> = 使用 shell 執行命令(這一列的剩餘部分)\n"
+"b, break = 在此停止(使用 “git rebase --continue” 繼續重定基底)\n"
 "d, drop <提交> = 移除提交\n"
 "l, label <標籤> = 為目前 HEAD 打上指定名字標籤\n"
 "t, reset <標籤> = 重設 HEAD 到指定標籤\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       建立一個合併提交,並使用原始的合併提交說明(如果沒有指定\n"
-".       原始提交,使用備註部分的 oneline 作為提交說明)。使用\n"
-".       -c <commit> 可以編輯提交說明。\n"
+"        建立一個合併提交,並使用原始的合併提交說明(如果沒有指定\n"
+"        原始提交,則使用 <oneline> 作為提交說明)。\n"
+"        使用 -c <commit> 編輯提交說明。\n"
+"u, update-ref <ref> = 為 <ref> 引用設立佔位符號,\n"
+"                      以將這個引用更新為此處的新提交。\n"
+"                      <ref> 會在重定基底後更新。\n"
 "\n"
-"可以對這些行重新排序,會從上至下執行。\n"
+"可以對這些列重新排序;執行順序由上到下。\n"
 
 #: rebase-interactive.c
 #, c-format
@@ -22585,6 +22905,15 @@ msgstr "協定錯誤:期望 sha/ref,卻得到 '%s'"
 msgid "http transport does not support %s"
 msgstr "http 傳輸協定不支援 %s"
 
+#: remote-curl.c
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr "協定錯誤:預期是「<URL> <路徑>」,但缺少空白"
+
+#: remote-curl.c
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr "無法下載位於 URL “%s” 的檔案"
+
 #: remote-curl.c
 msgid "git-http-push failed"
 msgstr "git-http-push 失敗"
@@ -22989,6 +23318,16 @@ msgstr "不能確定 HEAD 版本"
 msgid "failed to find tree of %s"
 msgstr "無法找到 %s 指向的樹"
 
+#: revision.c
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr "resolve-undo 不存在的「%s」記錄"
+
+#: revision.c
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr "無法取得 ancestry-path 引數 %s 的提交"
+
 #: revision.c
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<packfile> 已不受支援"
@@ -23015,6 +23354,220 @@ msgstr "-L 尚不支援 -p 和 -s 之外的差異格式"
 msgid "cannot create async thread: %s"
 msgstr "不能建立 async 執行緒:%s"
 
+#: scalar.c worktree.c
+#, c-format
+msgid "'%s' does not exist"
+msgstr "'%s' 不存在"
+
+#: scalar.c
+#, c-format
+msgid "could not switch to '%s'"
+msgstr "無法切換至「%s」"
+
+#: scalar.c
+msgid "need a working directory"
+msgstr "需要工作目錄"
+
+#: scalar.c
+msgid "Scalar enlistments require a worktree"
+msgstr "純量編列名單需要工作目錄"
+
+#: scalar.c
+#, c-format
+msgid "could not configure %s=%s"
+msgstr "無法設定 %s=%s"
+
+#: scalar.c
+msgid "could not configure log.excludeDecoration"
+msgstr "無法設定 log.excludeDecoration"
+
+#: scalar.c
+msgid "could not add enlistment"
+msgstr "無法加入編列清單"
+
+#: scalar.c
+msgid "could not set recommended config"
+msgstr "無法設定建議組態"
+
+#: scalar.c
+msgid "could not turn on maintenance"
+msgstr "無法開啟維護模式"
+
+#: scalar.c
+msgid "could not start the FSMonitor daemon"
+msgstr "無法啟動 FSMonitor 守護程式"
+
+#: scalar.c
+msgid "could not turn off maintenance"
+msgstr "無法關閉維護模式"
+
+#: scalar.c
+msgid "could not remove enlistment"
+msgstr "無法移除編列清單"
+
+#: scalar.c
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr "遠端 HEAD 不是分支:「%.*s」"
+
+#: scalar.c
+msgid "failed to get default branch name from remote; using local default"
+msgstr "無法從遠端取得預設分支名稱。改用本機預設名稱"
+
+#: scalar.c
+msgid "failed to get default branch name"
+msgstr "無法取得預設分支名稱"
+
+#: scalar.c
+msgid "failed to unregister repository"
+msgstr "無法取消註冊版本庫"
+
+#: scalar.c
+msgid "failed to stop the FSMonitor daemon"
+msgstr "無法停止 FSMonitor 守護程式"
+
+#: scalar.c
+msgid "failed to delete enlistment directory"
+msgstr "無法刪除編列名單目錄"
+
+#: scalar.c
+msgid "branch to checkout after clone"
+msgstr "複製後要簽出的分支"
+
+#: scalar.c
+msgid "when cloning, create full working directory"
+msgstr "複製時建立完整的工作目錄"
+
+#: scalar.c
+msgid "only download metadata for the branch that will be checked out"
+msgstr "只下載會簽出的分支中介資料"
+
+#: scalar.c
+msgid "scalar clone [<options>] [--] <repo> [<dir>]"
+msgstr "scalar clone [<options>] [--] <repo> [<dir>]"
+
+#: scalar.c
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr "無法從「%s」推論工作區名稱"
+
+#: scalar.c
+#, c-format
+msgid "directory '%s' exists already"
+msgstr "「%s」目錄已經存在"
+
+#: scalar.c
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr "無法取得「%s」的預設分支"
+
+#: scalar.c
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr "無法設定「%s」中的遠端"
+
+#: scalar.c
+#, c-format
+msgid "could not configure '%s'"
+msgstr "無法設定「%s」"
+
+#: scalar.c
+msgid "partial clone failed; attempting full clone"
+msgstr "部分複製失敗。嘗試完整複製"
+
+#: scalar.c
+msgid "could not configure for full clone"
+msgstr "無法設定完整複製"
+
+#: scalar.c
+msgid "scalar diagnose [<enlistment>]"
+msgstr "scalar diagnose [<enlistment>]"
+
+#: scalar.c
+msgid "`scalar list` does not take arguments"
+msgstr "`scalar list` 未取引數"
+
+#: scalar.c
+msgid "scalar register [<enlistment>]"
+msgstr "scalar register [<enlistment>]"
+
+#: scalar.c
+msgid "reconfigure all registered enlistments"
+msgstr "重新設定所有註冊的編列名單"
+
+#: scalar.c
+msgid "scalar reconfigure [--all | <enlistment>]"
+msgstr "scalar reconfigure [--all | <enlistment>]"
+
+#: scalar.c
+msgid "--all or <enlistment>, but not both"
+msgstr "--all 或 <enlistment> 但不能傳入兩者"
+
+#: scalar.c
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr "git 版本庫在「%s」遺失"
+
+#: scalar.c
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+"scalar run <task> [<enlistment>]\n"
+"作業:\n"
+
+#: scalar.c
+#, c-format
+msgid "no such task: '%s'"
+msgstr "無此作業:「%s」"
+
+#: scalar.c
+msgid "scalar unregister [<enlistment>]"
+msgstr "scalar unregister [<enlistment>]"
+
+#: scalar.c
+msgid "scalar delete <enlistment>"
+msgstr "scalar delete <enlistment>"
+
+#: scalar.c
+msgid "refusing to delete current working directory"
+msgstr "拒絕刪除目前工作目錄"
+
+#: scalar.c
+msgid "include Git version"
+msgstr "包含 Git 版本"
+
+#: scalar.c
+msgid "include Git's build options"
+msgstr "包含 Git 組建選項"
+
+#: scalar.c
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
+
+#: scalar.c
+msgid "-C requires a <directory>"
+msgstr "-C 需要 <directory>"
+
+#: scalar.c
+#, c-format
+msgid "could not change to '%s'"
+msgstr "無法更改為「%s」"
+
+#: scalar.c
+msgid "-c requires a <key>=<value> argument"
+msgstr "-c 需要 <key>=<value> 引數"
+
+#: scalar.c
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"命令:\n"
+
 #: send-pack.c
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr "讀取遠端解包狀態時收到意外的 flush 包"
@@ -23159,11 +23712,6 @@ msgstr "您的本機修改將被%s覆蓋。"
 msgid "commit your changes or stash them to proceed."
 msgstr "提交您的修改或儲藏後再繼續。"
 
-#: sequencer.c
-#, c-format
-msgid "%s: fast-forward"
-msgstr "%s:快轉"
-
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
 #.
@@ -23751,6 +24299,30 @@ msgstr "甚至不能嘗試合併 '%.*s'"
 msgid "merge: Unable to write new index file"
 msgstr "合併:無法寫入新索引檔案"
 
+#: sequencer.c
+#, c-format
+msgid ""
+"another 'rebase' process appears to be running; '%s.lock' already exists"
+msgstr "似乎有另一個 “rebase” 程序正在進行;“%s.lock” 已經存在"
+
+#: sequencer.c
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+"已使用 %s 更新下述引用:\n"
+"%s"
+
+#: sequencer.c
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+"無法使用 %s 更新下述引用:\n"
+"%s"
+
 #: sequencer.c
 msgid "Cannot autostash"
 msgstr "無法 autostash"
@@ -23953,6 +24525,11 @@ msgstr "無法略過不必要的揀選"
 msgid "the script was already rearranged."
 msgstr "腳本已經重新編排。"
 
+#: sequencer.c
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr "位於「%s」的 update-refs 檔案無效"
+
 #: setup.c
 #, c-format
 msgid "'%s' is outside repository at '%s'"
@@ -24093,16 +24670,21 @@ msgstr ""
 #: setup.c
 #, c-format
 msgid ""
-"unsafe repository ('%s' is owned by someone else)\n"
-"To add an exception for this directory, call:\n"
+"detected dubious ownership in repository at '%s'\n"
+"%sTo add an exception for this directory, call:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 msgstr ""
-"不安全版本庫(「%s」由其他人所有)\n"
-"若要放行本目錄,請呼叫:\n"
+"在位於「%s」的版本庫偵測到可疑所有權\n"
+"%s若要放行本目錄,請呼叫:\n"
 "\n"
 "\tgit config --global --add safe.directory %s"
 
+#: setup.c
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr "無法使用 “%s” 純版本庫(safe.bareRepository 是 “%s”)"
+
 #: setup.c
 #, c-format
 msgid ""
@@ -25126,6 +25708,22 @@ msgstr "無效的埠號"
 msgid "invalid '..' path segment"
 msgstr "無效的 '..' 路徑區塊"
 
+#: usage.c
+msgid "usage: "
+msgstr "用法:"
+
+#: usage.c
+msgid "fatal: "
+msgstr "致命錯誤:"
+
+#: usage.c
+msgid "error: "
+msgstr "錯誤:"
+
+#: usage.c
+msgid "warning: "
+msgstr "警告:"
+
 #: walker.c
 msgid "Fetching objects"
 msgstr "正在抓取物件"
@@ -25818,7 +26416,7 @@ msgstr "另外,您的索引中包含未提交的變更。"
 msgid "cannot %s: Your index contains uncommitted changes."
 msgstr "不能%s:您的索引中包含未提交的變更。"
 
-#: git-merge-octopus.sh
+#: git-merge-octopus.sh git-merge-resolve.sh
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
@@ -26105,26 +26703,6 @@ msgstr "選取區塊不能套用到索引!\n"
 msgid "ignoring unmerged: %s\n"
 msgstr "忽略未套用的:%s\n"
 
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr "將模式變更套用到工作區 [y,n,q,a,d%s,?]? "
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr "將刪除變更套用到工作區 [y,n,q,a,d%s,?]? "
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr "將新增變更套用到工作區 [y,n,q,a,d%s,?]? "
-
-#: git-add--interactive.perl
-#, perl-format
-msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
-msgstr "將此區塊套用到工作區 [y,n,q,a,d%s,?]? "
-
 #: git-add--interactive.perl
 msgid "No other hunks to goto\n"
 msgstr "沒有其它可供跳轉的區塊\n"
diff --git a/ppc/sha1.c b/ppc/sha1.c
deleted file mode 100644 (file)
index 1b705ce..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SHA-1 implementation.
- *
- * Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
- *
- * This version assumes we are running on a big-endian machine.
- * It calls an external sha1_core() to process blocks of 64 bytes.
- */
-#include <stdio.h>
-#include <string.h>
-#include "sha1.h"
-
-void ppc_sha1_core(uint32_t *hash, const unsigned char *p,
-                  unsigned int nblocks);
-
-int ppc_SHA1_Init(ppc_SHA_CTX *c)
-{
-       c->hash[0] = 0x67452301;
-       c->hash[1] = 0xEFCDAB89;
-       c->hash[2] = 0x98BADCFE;
-       c->hash[3] = 0x10325476;
-       c->hash[4] = 0xC3D2E1F0;
-       c->len = 0;
-       c->cnt = 0;
-       return 0;
-}
-
-int ppc_SHA1_Update(ppc_SHA_CTX *c, const void *ptr, unsigned long n)
-{
-       unsigned long nb;
-       const unsigned char *p = ptr;
-
-       c->len += (uint64_t) n << 3;
-       while (n != 0) {
-               if (c->cnt || n < 64) {
-                       nb = 64 - c->cnt;
-                       if (nb > n)
-                               nb = n;
-                       memcpy(&c->buf.b[c->cnt], p, nb);
-                       if ((c->cnt += nb) == 64) {
-                               ppc_sha1_core(c->hash, c->buf.b, 1);
-                               c->cnt = 0;
-                       }
-               } else {
-                       nb = n >> 6;
-                       ppc_sha1_core(c->hash, p, nb);
-                       nb <<= 6;
-               }
-               n -= nb;
-               p += nb;
-       }
-       return 0;
-}
-
-int ppc_SHA1_Final(unsigned char *hash, ppc_SHA_CTX *c)
-{
-       unsigned int cnt = c->cnt;
-
-       c->buf.b[cnt++] = 0x80;
-       if (cnt > 56) {
-               if (cnt < 64)
-                       memset(&c->buf.b[cnt], 0, 64 - cnt);
-               ppc_sha1_core(c->hash, c->buf.b, 1);
-               cnt = 0;
-       }
-       if (cnt < 56)
-               memset(&c->buf.b[cnt], 0, 56 - cnt);
-       c->buf.l[7] = c->len;
-       ppc_sha1_core(c->hash, c->buf.b, 1);
-       memcpy(hash, c->hash, 20);
-       return 0;
-}
diff --git a/ppc/sha1.h b/ppc/sha1.h
deleted file mode 100644 (file)
index 9b24b32..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SHA-1 implementation.
- *
- * Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
- */
-#include <stdint.h>
-
-typedef struct {
-       uint32_t hash[5];
-       uint32_t cnt;
-       uint64_t len;
-       union {
-               unsigned char b[64];
-               uint64_t l[8];
-       } buf;
-} ppc_SHA_CTX;
-
-int ppc_SHA1_Init(ppc_SHA_CTX *c);
-int ppc_SHA1_Update(ppc_SHA_CTX *c, const void *p, unsigned long n);
-int ppc_SHA1_Final(unsigned char *hash, ppc_SHA_CTX *c);
-
-#define platform_SHA_CTX       ppc_SHA_CTX
-#define platform_SHA1_Init     ppc_SHA1_Init
-#define platform_SHA1_Update   ppc_SHA1_Update
-#define platform_SHA1_Final    ppc_SHA1_Final
diff --git a/ppc/sha1ppc.S b/ppc/sha1ppc.S
deleted file mode 100644 (file)
index 1711eef..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * SHA-1 implementation for PowerPC.
- *
- * Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
- */
-
-/*
- * PowerPC calling convention:
- * %r0 - volatile temp
- * %r1 - stack pointer.
- * %r2 - reserved
- * %r3-%r12 - Incoming arguments & return values; volatile.
- * %r13-%r31 - Callee-save registers
- * %lr - Return address, volatile
- * %ctr - volatile
- *
- * Register usage in this routine:
- * %r0 - temp
- * %r3 - argument (pointer to 5 words of SHA state)
- * %r4 - argument (pointer to data to hash)
- * %r5 - Constant K in SHA round (initially number of blocks to hash)
- * %r6-%r10 - Working copies of SHA variables A..E (actually E..A order)
- * %r11-%r26 - Data being hashed W[].
- * %r27-%r31 - Previous copies of A..E, for final add back.
- * %ctr - loop count
- */
-
-
-/*
- * We roll the registers for A, B, C, D, E around on each
- * iteration; E on iteration t is D on iteration t+1, and so on.
- * We use registers 6 - 10 for this.  (Registers 27 - 31 hold
- * the previous values.)
- */
-#define RA(t)  (((t)+4)%5+6)
-#define RB(t)  (((t)+3)%5+6)
-#define RC(t)  (((t)+2)%5+6)
-#define RD(t)  (((t)+1)%5+6)
-#define RE(t)  (((t)+0)%5+6)
-
-/* We use registers 11 - 26 for the W values */
-#define W(t)   ((t)%16+11)
-
-/* Register 5 is used for the constant k */
-
-/*
- * The basic SHA-1 round function is:
- * E += ROTL(A,5) + F(B,C,D) + W[i] + K;  B = ROTL(B,30)
- * Then the variables are renamed: (A,B,C,D,E) = (E,A,B,C,D).
- *
- * Every 20 rounds, the function F() and the constant K changes:
- * - 20 rounds of f0(b,c,d) = "bit wise b ? c : d" =  (^b & d) + (b & c)
- * - 20 rounds of f1(b,c,d) = b^c^d = (b^d)^c
- * - 20 rounds of f2(b,c,d) = majority(b,c,d) = (b&d) + ((b^d)&c)
- * - 20 more rounds of f1(b,c,d)
- *
- * These are all scheduled for near-optimal performance on a G4.
- * The G4 is a 3-issue out-of-order machine with 3 ALUs, but it can only
- * *consider* starting the oldest 3 instructions per cycle.  So to get
- * maximum performance out of it, you have to treat it as an in-order
- * machine.  Which means interleaving the computation round t with the
- * computation of W[t+4].
- *
- * The first 16 rounds use W values loaded directly from memory, while the
- * remaining 64 use values computed from those first 16.  We preload
- * 4 values before starting, so there are three kinds of rounds:
- * - The first 12 (all f0) also load the W values from memory.
- * - The next 64 compute W(i+4) in parallel. 8*f0, 20*f1, 20*f2, 16*f1.
- * - The last 4 (all f1) do not do anything with W.
- *
- * Therefore, we have 6 different round functions:
- * STEPD0_LOAD(t,s) - Perform round t and load W(s).  s < 16
- * STEPD0_UPDATE(t,s) - Perform round t and compute W(s).  s >= 16.
- * STEPD1_UPDATE(t,s)
- * STEPD2_UPDATE(t,s)
- * STEPD1(t) - Perform round t with no load or update.
- *
- * The G5 is more fully out-of-order, and can find the parallelism
- * by itself.  The big limit is that it has a 2-cycle ALU latency, so
- * even though it's 2-way, the code has to be scheduled as if it's
- * 4-way, which can be a limit.  To help it, we try to schedule the
- * read of RA(t) as late as possible so it doesn't stall waiting for
- * the previous round's RE(t-1), and we try to rotate RB(t) as early
- * as possible while reading RC(t) (= RB(t-1)) as late as possible.
- */
-
-/* the initial loads. */
-#define LOADW(s) \
-       lwz     W(s),(s)*4(%r4)
-
-/*
- * Perform a step with F0, and load W(s).  Uses W(s) as a temporary
- * before loading it.
- * This is actually 10 instructions, which is an awkward fit.
- * It can execute grouped as listed, or delayed one instruction.
- * (If delayed two instructions, there is a stall before the start of the
- * second line.)  Thus, two iterations take 7 cycles, 3.5 cycles per round.
- */
-#define STEPD0_LOAD(t,s) \
-add RE(t),RE(t),W(t); andc   %r0,RD(t),RB(t);  and    W(s),RC(t),RB(t); \
-add RE(t),RE(t),%r0;  rotlwi %r0,RA(t),5;      rotlwi RB(t),RB(t),30;   \
-add RE(t),RE(t),W(s); add    %r0,%r0,%r5;      lwz    W(s),(s)*4(%r4);  \
-add RE(t),RE(t),%r0
-
-/*
- * This is likewise awkward, 13 instructions.  However, it can also
- * execute starting with 2 out of 3 possible moduli, so it does 2 rounds
- * in 9 cycles, 4.5 cycles/round.
- */
-#define STEPD0_UPDATE(t,s,loadk...) \
-add RE(t),RE(t),W(t); andc   %r0,RD(t),RB(t); xor    W(s),W((s)-16),W((s)-3); \
-add RE(t),RE(t),%r0;  and    %r0,RC(t),RB(t); xor    W(s),W(s),W((s)-8);      \
-add RE(t),RE(t),%r0;  rotlwi %r0,RA(t),5;     xor    W(s),W(s),W((s)-14);     \
-add RE(t),RE(t),%r5;  loadk; rotlwi RB(t),RB(t),30;  rotlwi W(s),W(s),1;     \
-add RE(t),RE(t),%r0
-
-/* Nicely optimal.  Conveniently, also the most common. */
-#define STEPD1_UPDATE(t,s,loadk...) \
-add RE(t),RE(t),W(t); xor    %r0,RD(t),RB(t); xor    W(s),W((s)-16),W((s)-3); \
-add RE(t),RE(t),%r5;  loadk; xor %r0,%r0,RC(t);  xor W(s),W(s),W((s)-8);      \
-add RE(t),RE(t),%r0;  rotlwi %r0,RA(t),5;     xor    W(s),W(s),W((s)-14);     \
-add RE(t),RE(t),%r0;  rotlwi RB(t),RB(t),30;  rotlwi W(s),W(s),1
-
-/*
- * The naked version, no UPDATE, for the last 4 rounds.  3 cycles per.
- * We could use W(s) as a temp register, but we don't need it.
- */
-#define STEPD1(t) \
-                        add   RE(t),RE(t),W(t); xor    %r0,RD(t),RB(t); \
-rotlwi RB(t),RB(t),30;  add   RE(t),RE(t),%r5;  xor    %r0,%r0,RC(t);   \
-add    RE(t),RE(t),%r0; rotlwi %r0,RA(t),5;     /* spare slot */        \
-add    RE(t),RE(t),%r0
-
-/*
- * 14 instructions, 5 cycles per.  The majority function is a bit
- * awkward to compute.  This can execute with a 1-instruction delay,
- * but it causes a 2-instruction delay, which triggers a stall.
- */
-#define STEPD2_UPDATE(t,s,loadk...) \
-add RE(t),RE(t),W(t); and    %r0,RD(t),RB(t); xor    W(s),W((s)-16),W((s)-3); \
-add RE(t),RE(t),%r0;  xor    %r0,RD(t),RB(t); xor    W(s),W(s),W((s)-8);      \
-add RE(t),RE(t),%r5;  loadk; and %r0,%r0,RC(t);  xor W(s),W(s),W((s)-14);     \
-add RE(t),RE(t),%r0;  rotlwi %r0,RA(t),5;     rotlwi W(s),W(s),1;             \
-add RE(t),RE(t),%r0;  rotlwi RB(t),RB(t),30
-
-#define STEP0_LOAD4(t,s)               \
-       STEPD0_LOAD(t,s);               \
-       STEPD0_LOAD((t+1),(s)+1);       \
-       STEPD0_LOAD((t)+2,(s)+2);       \
-       STEPD0_LOAD((t)+3,(s)+3)
-
-#define STEPUP4(fn, t, s, loadk...)            \
-       STEP##fn##_UPDATE(t,s,);                \
-       STEP##fn##_UPDATE((t)+1,(s)+1,);        \
-       STEP##fn##_UPDATE((t)+2,(s)+2,);        \
-       STEP##fn##_UPDATE((t)+3,(s)+3,loadk)
-
-#define STEPUP20(fn, t, s, loadk...)   \
-       STEPUP4(fn, t, s,);             \
-       STEPUP4(fn, (t)+4, (s)+4,);     \
-       STEPUP4(fn, (t)+8, (s)+8,);     \
-       STEPUP4(fn, (t)+12, (s)+12,);   \
-       STEPUP4(fn, (t)+16, (s)+16, loadk)
-
-       .globl  ppc_sha1_core
-ppc_sha1_core:
-       stwu    %r1,-80(%r1)
-       stmw    %r13,4(%r1)
-
-       /* Load up A - E */
-       lmw     %r27,0(%r3)
-
-       mtctr   %r5
-
-1:
-       LOADW(0)
-       lis     %r5,0x5a82
-       mr      RE(0),%r31
-       LOADW(1)
-       mr      RD(0),%r30
-       mr      RC(0),%r29
-       LOADW(2)
-       ori     %r5,%r5,0x7999  /* K0-19 */
-       mr      RB(0),%r28
-       LOADW(3)
-       mr      RA(0),%r27
-
-       STEP0_LOAD4(0, 4)
-       STEP0_LOAD4(4, 8)
-       STEP0_LOAD4(8, 12)
-       STEPUP4(D0, 12, 16,)
-       STEPUP4(D0, 16, 20, lis %r5,0x6ed9)
-
-       ori     %r5,%r5,0xeba1  /* K20-39 */
-       STEPUP20(D1, 20, 24, lis %r5,0x8f1b)
-
-       ori     %r5,%r5,0xbcdc  /* K40-59 */
-       STEPUP20(D2, 40, 44, lis %r5,0xca62)
-
-       ori     %r5,%r5,0xc1d6  /* K60-79 */
-       STEPUP4(D1, 60, 64,)
-       STEPUP4(D1, 64, 68,)
-       STEPUP4(D1, 68, 72,)
-       STEPUP4(D1, 72, 76,)
-       addi    %r4,%r4,64
-       STEPD1(76)
-       STEPD1(77)
-       STEPD1(78)
-       STEPD1(79)
-
-       /* Add results to original values */
-       add     %r31,%r31,RE(0)
-       add     %r30,%r30,RD(0)
-       add     %r29,%r29,RC(0)
-       add     %r28,%r28,RB(0)
-       add     %r27,%r27,RA(0)
-
-       bdnz    1b
-
-       /* Save final hash, restore registers, and return */
-       stmw    %r27,0(%r3)
-       lmw     %r13,4(%r1)
-       addi    %r1,%r1,80
-       blr
index ee6114e3f0aa1dcf8737794bbe8dc8f6e23f5f7b..6cb363ae1c9e90e47e2002fb7e89a1f03a12f23c 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -43,7 +43,8 @@ static void save_user_format(struct rev_info *rev, const char *cp, int is_tforma
        rev->commit_format = CMIT_FMT_USERFORMAT;
 }
 
-static int git_pretty_formats_config(const char *var, const char *value, void *cb)
+static int git_pretty_formats_config(const char *var, const char *value,
+                                    void *cb UNUSED)
 {
        struct cmt_fmt_map *commit_format = NULL;
        const char *name;
@@ -477,6 +478,16 @@ end:
        }
 }
 
+static int use_in_body_from(const struct pretty_print_context *pp,
+                           const struct ident_split *ident)
+{
+       if (pp->rev && pp->rev->force_in_body_from)
+               return 1;
+       if (ident_cmp(pp->from_ident, ident))
+               return 1;
+       return 0;
+}
+
 void pp_user_info(struct pretty_print_context *pp,
                  const char *what, struct strbuf *sb,
                  const char *line, const char *encoding)
@@ -503,7 +514,7 @@ void pp_user_info(struct pretty_print_context *pp,
                map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
 
        if (cmit_fmt_is_mail(pp->fmt)) {
-               if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
+               if (pp->from_ident && use_in_body_from(pp, &ident)) {
                        struct strbuf buf = STRBUF_INIT;
 
                        strbuf_addstr(&buf, "From: ");
@@ -1575,23 +1586,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                strbuf_addstr(sb, c->signature_check.primary_key_fingerprint);
                        break;
                case 'T':
-                       switch (c->signature_check.trust_level) {
-                       case TRUST_UNDEFINED:
-                               strbuf_addstr(sb, "undefined");
-                               break;
-                       case TRUST_NEVER:
-                               strbuf_addstr(sb, "never");
-                               break;
-                       case TRUST_MARGINAL:
-                               strbuf_addstr(sb, "marginal");
-                               break;
-                       case TRUST_FULLY:
-                               strbuf_addstr(sb, "fully");
-                               break;
-                       case TRUST_ULTIMATE:
-                               strbuf_addstr(sb, "ultimate");
-                               break;
-                       }
+                       strbuf_addstr(sb, gpg_trust_level_to_str(c->signature_check.trust_level));
                        break;
                default:
                        return 0;
index f63b3ffc200a8b71df3d7287322321ac70be2595..8b7d81adc1be09d91a1551c370c08058766f76f6 100644 (file)
@@ -57,9 +57,9 @@ static int read_patches(const char *range, struct string_list *list,
                     "--pretty=medium",
                     "--notes",
                     NULL);
+       strvec_push(&cp.args, range);
        if (other_arg)
                strvec_pushv(&cp.args, other_arg->v);
-       strvec_push(&cp.args, range);
        cp.out = -1;
        cp.no_stdin = 1;
        cp.git_cmd = 1;
@@ -224,8 +224,10 @@ cleanup:
        return ret;
 }
 
-static int patch_util_cmp(const void *dummy, const struct patch_util *a,
-                         const struct patch_util *b, const char *keydata)
+static int patch_util_cmp(const void *cmp_data UNUSED,
+                         const struct patch_util *a,
+                         const struct patch_util *b,
+                         const char *keydata)
 {
        return strcmp(a->diff, keydata ? keydata : b->diff);
 }
index b09128b188431857450336481898f27f8894a241..32024029274828c12654e3c256de3d8d08f37734 100644 (file)
@@ -1873,9 +1873,20 @@ static int read_index_extension(struct index_state *istate,
        return 0;
 }
 
+/*
+ * Parses the contents of the cache entry contained within the 'ondisk' buffer
+ * into a new incore 'cache_entry'.
+ *
+ * Note that 'char *ondisk' may not be aligned to a 4-byte address interval in
+ * index v4, so we cannot cast it to 'struct ondisk_cache_entry *' and access
+ * its members. Instead, we use the byte offsets of members within the struct to
+ * identify where 'get_be16()', 'get_be32()', and 'oidread()' (which can all
+ * read from an unaligned memory buffer) should read from the 'ondisk' buffer
+ * into the corresponding incore 'cache_entry' members.
+ */
 static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
                                            unsigned int version,
-                                           struct ondisk_cache_entry *ondisk,
+                                           const char *ondisk,
                                            unsigned long *ent_size,
                                            const struct cache_entry *previous_ce)
 {
@@ -1883,7 +1894,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
        size_t len;
        const char *name;
        const unsigned hashsz = the_hash_algo->rawsz;
-       const uint16_t *flagsp = (const uint16_t *)(ondisk->data + hashsz);
+       const char *flagsp = ondisk + offsetof(struct ondisk_cache_entry, data) + hashsz;
        unsigned int flags;
        size_t copy_len = 0;
        /*
@@ -1901,15 +1912,15 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
 
        if (flags & CE_EXTENDED) {
                int extended_flags;
-               extended_flags = get_be16(flagsp + 1) << 16;
+               extended_flags = get_be16(flagsp + sizeof(uint16_t)) << 16;
                /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
                if (extended_flags & ~CE_EXTENDED_FLAGS)
                        die(_("unknown index entry format 0x%08x"), extended_flags);
                flags |= extended_flags;
-               name = (const char *)(flagsp + 2);
+               name = (const char *)(flagsp + 2 * sizeof(uint16_t));
        }
        else
-               name = (const char *)(flagsp + 1);
+               name = (const char *)(flagsp + sizeof(uint16_t));
 
        if (expand_name_field) {
                const unsigned char *cp = (const unsigned char *)name;
@@ -1935,20 +1946,32 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
 
        ce = mem_pool__ce_alloc(ce_mem_pool, len);
 
-       ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
-       ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
-       ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
-       ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
-       ce->ce_stat_data.sd_dev   = get_be32(&ondisk->dev);
-       ce->ce_stat_data.sd_ino   = get_be32(&ondisk->ino);
-       ce->ce_mode  = get_be32(&ondisk->mode);
-       ce->ce_stat_data.sd_uid   = get_be32(&ondisk->uid);
-       ce->ce_stat_data.sd_gid   = get_be32(&ondisk->gid);
-       ce->ce_stat_data.sd_size  = get_be32(&ondisk->size);
+       /*
+        * NEEDSWORK: using 'offsetof()' is cumbersome and should be replaced
+        * with something more akin to 'load_bitmap_entries_v1()'s use of
+        * 'read_be16'/'read_be32'. For consistency with the corresponding
+        * ondisk entry write function ('copy_cache_entry_to_ondisk()'), this
+        * should be done at the same time as removing references to
+        * 'ondisk_cache_entry' there.
+        */
+       ce->ce_stat_data.sd_ctime.sec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, ctime)
+                                                       + offsetof(struct cache_time, sec));
+       ce->ce_stat_data.sd_mtime.sec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, mtime)
+                                                       + offsetof(struct cache_time, sec));
+       ce->ce_stat_data.sd_ctime.nsec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, ctime)
+                                                        + offsetof(struct cache_time, nsec));
+       ce->ce_stat_data.sd_mtime.nsec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, mtime)
+                                                        + offsetof(struct cache_time, nsec));
+       ce->ce_stat_data.sd_dev   = get_be32(ondisk + offsetof(struct ondisk_cache_entry, dev));
+       ce->ce_stat_data.sd_ino   = get_be32(ondisk + offsetof(struct ondisk_cache_entry, ino));
+       ce->ce_mode  = get_be32(ondisk + offsetof(struct ondisk_cache_entry, mode));
+       ce->ce_stat_data.sd_uid   = get_be32(ondisk + offsetof(struct ondisk_cache_entry, uid));
+       ce->ce_stat_data.sd_gid   = get_be32(ondisk + offsetof(struct ondisk_cache_entry, gid));
+       ce->ce_stat_data.sd_size  = get_be32(ondisk + offsetof(struct ondisk_cache_entry, size));
        ce->ce_flags = flags & ~CE_NAMEMASK;
        ce->ce_namelen = len;
        ce->index = 0;
-       oidread(&ce->oid, ondisk->data);
+       oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data));
 
        if (expand_name_field) {
                if (copy_len)
@@ -2117,12 +2140,12 @@ static unsigned long load_cache_entry_block(struct index_state *istate,
        unsigned long src_offset = start_offset;
 
        for (i = offset; i < offset + nr; i++) {
-               struct ondisk_cache_entry *disk_ce;
                struct cache_entry *ce;
                unsigned long consumed;
 
-               disk_ce = (struct ondisk_cache_entry *)(mmap + src_offset);
-               ce = create_from_disk(ce_mem_pool, istate->version, disk_ce, &consumed, previous_ce);
+               ce = create_from_disk(ce_mem_pool, istate->version,
+                                     mmap + src_offset,
+                                     &consumed, previous_ce);
                set_index_entry(istate, i, ce);
 
                src_offset += consumed;
index 87649d0c016a371f83710a04140909d54a553aa7..7407c593191679c757573e567a28f35c65c9cb33 100644 (file)
@@ -54,9 +54,12 @@ void append_todo_help(int command_count,
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
-".       create a merge commit using the original merge commit's\n"
-".       message (or the oneline, if no original merge commit was\n"
-".       specified); use -c <commit> to reword the commit message\n"
+"        create a merge commit using the original merge commit's\n"
+"        message (or the oneline, if no original merge commit was\n"
+"        specified); use -c <commit> to reword the commit message\n"
+"u, update-ref <ref> = track a placeholder for the <ref> to be updated\n"
+"                      to this position in the new commits. The <ref> is\n"
+"                      updated at the end of the rebase\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n");
        unsigned edit_todo = !(shortrevisions && shortonto);
@@ -143,6 +146,12 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
                return -4;
        }
 
+       /*
+        * See if branches need to be added or removed from the update-refs
+        * file based on the new todo list.
+        */
+       todo_list_filter_update_refs(r, new_todo);
+
        return 0;
 }
 
index d3c90e5dbe2fdb4cdbad6b93290e27b46e205fbb..fd1cb14b0f131de522cd60c71127c9369fe84648 100644 (file)
@@ -89,7 +89,7 @@ struct ref_to_worktree_entry {
        struct worktree *wt; /* key is wt->head_ref */
 };
 
-static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+static int ref_to_worktree_map_cmpfnc(const void *lookupdata UNUSED,
                                      const struct hashmap_entry *eptr,
                                      const struct hashmap_entry *kptr,
                                      const void *keydata_aka_refname)
@@ -2405,6 +2405,7 @@ static void reach_filter(struct ref_array *array,
 int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
 {
        struct ref_filter_cbdata ref_cbdata;
+       int save_commit_buffer_orig;
        int ret = 0;
 
        ref_cbdata.array = array;
@@ -2412,6 +2413,9 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
 
        filter->kind = type & FILTER_REFS_KIND_MASK;
 
+       save_commit_buffer_orig = save_commit_buffer;
+       save_commit_buffer = 0;
+
        init_contains_cache(&ref_cbdata.contains_cache);
        init_contains_cache(&ref_cbdata.no_contains_cache);
 
@@ -2444,6 +2448,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
        reach_filter(array, filter->reachable_from, INCLUDE_REACHED);
        reach_filter(array, filter->unreachable_from, EXCLUDE_REACHED);
 
+       save_commit_buffer = save_commit_buffer_orig;
        return ret;
 }
 
index 135a1a6e41cf51afaf2ffc730a225409147f81b0..d258fd31995fbb4f8a198ba0bd275564182fe43c 100644 (file)
--- a/reflog.c
+++ b/reflog.c
@@ -240,8 +240,9 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit
  * Return true iff the specified reflog entry should be expired.
  */
 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)
+                            const char *email UNUSED,
+                            timestamp_t timestamp, int tz UNUSED,
+                            const char *message UNUSED, void *cb_data)
 {
        struct expire_reflog_policy_cb *cb = cb_data;
        struct commit *old_commit, *new_commit;
@@ -294,7 +295,8 @@ int should_expire_reflog_ent_verbose(struct object_id *ooid,
        return expire;
 }
 
-static int push_tip_to_list(const char *refname, const struct object_id *oid,
+static int push_tip_to_list(const char *refname UNUSED,
+                           const struct object_id *oid,
                            int flags, void *cb_data)
 {
        struct commit_list **list = cb_data;
@@ -378,9 +380,11 @@ void reflog_expiry_cleanup(void *cb_data)
        }
 }
 
-int count_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 UNUSED,
+                    struct object_id *noid UNUSED,
+                    const char *email UNUSED,
+                    timestamp_t timestamp, int tz UNUSED,
+                    const char *message UNUSED, void *cb_data)
 {
        struct cmd_reflog_expire_cb *cb = cb_data;
        if (!cb->expire_total || timestamp < cb->expire_total)
diff --git a/refs.c b/refs.c
index 90bcb2716873592864e2496951f913618521cb45..c89d558892569b6326d092eb61a7bba28ef4b3d4 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -20,6 +20,7 @@
 #include "repository.h"
 #include "sigchain.h"
 #include "date.h"
+#include "commit.h"
 
 /*
  * List of all available backends
@@ -56,6 +57,88 @@ static unsigned char refname_disposition[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
 };
 
+struct ref_namespace_info ref_namespace[] = {
+       [NAMESPACE_HEAD] = {
+               .ref = "HEAD",
+               .decoration = DECORATION_REF_HEAD,
+               .exact = 1,
+       },
+       [NAMESPACE_BRANCHES] = {
+               .ref = "refs/heads/",
+               .decoration = DECORATION_REF_LOCAL,
+       },
+       [NAMESPACE_TAGS] = {
+               .ref = "refs/tags/",
+               .decoration = DECORATION_REF_TAG,
+       },
+       [NAMESPACE_REMOTE_REFS] = {
+               /*
+                * The default refspec for new remotes copies refs from
+                * refs/heads/ on the remote into refs/remotes/<remote>/.
+                * As such, "refs/remotes/" has special handling.
+                */
+               .ref = "refs/remotes/",
+               .decoration = DECORATION_REF_REMOTE,
+       },
+       [NAMESPACE_STASH] = {
+               /*
+                * The single ref "refs/stash" stores the latest stash.
+                * Older stashes can be found in the reflog.
+                */
+               .ref = "refs/stash",
+               .exact = 1,
+               .decoration = DECORATION_REF_STASH,
+       },
+       [NAMESPACE_REPLACE] = {
+               /*
+                * This namespace allows Git to act as if one object ID
+                * points to the content of another. Unlike the other
+                * ref namespaces, this one can be changed by the
+                * GIT_REPLACE_REF_BASE environment variable. This
+                * .namespace value will be overwritten in setup_git_env().
+                */
+               .ref = "refs/replace/",
+               .decoration = DECORATION_GRAFTED,
+       },
+       [NAMESPACE_NOTES] = {
+               /*
+                * The refs/notes/commit ref points to the tip of a
+                * parallel commit history that adds metadata to commits
+                * in the normal history. This ref can be overwritten
+                * by the core.notesRef config variable or the
+                * GIT_NOTES_REFS environment variable.
+                */
+               .ref = "refs/notes/commit",
+               .exact = 1,
+       },
+       [NAMESPACE_PREFETCH] = {
+               /*
+                * Prefetch refs are written by the background 'fetch'
+                * maintenance task. It allows faster foreground fetches
+                * by advertising these previously-downloaded tips without
+                * updating refs/remotes/ without user intervention.
+                */
+               .ref = "refs/prefetch/",
+       },
+       [NAMESPACE_REWRITTEN] = {
+               /*
+                * Rewritten refs are used by the 'label' command in the
+                * sequencer. These are particularly useful during an
+                * interactive rebase that uses the 'merge' command.
+                */
+               .ref = "refs/rewritten/",
+       },
+};
+
+void update_ref_namespace(enum ref_namespace namespace, char *ref)
+{
+       struct ref_namespace_info *info = &ref_namespace[namespace];
+       if (info->ref_updated)
+               free(info->ref);
+       info->ref = ref;
+       info->ref_updated = 1;
+}
+
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -358,7 +441,8 @@ struct warn_if_dangling_data {
        const char *msg_fmt;
 };
 
-static int warn_if_dangling_symref(const char *refname, const struct object_id *oid,
+static int warn_if_dangling_symref(const char *refname,
+                                  const struct object_id *oid UNUSED,
                                   int flags, void *cb_data)
 {
        struct warn_if_dangling_data *d = cb_data;
@@ -455,11 +539,16 @@ void normalize_glob_ref(struct string_list_item *item, const char *prefix,
        if (*pattern == '/')
                BUG("pattern must not start with '/'");
 
-       if (prefix) {
+       if (prefix)
                strbuf_addstr(&normalized_pattern, prefix);
-       }
-       else if (!starts_with(pattern, "refs/"))
+       else if (!starts_with(pattern, "refs/") &&
+                  strcmp(pattern, "HEAD"))
                strbuf_addstr(&normalized_pattern, "refs/");
+       /*
+        * NEEDSWORK: Special case other symrefs such as REBASE_HEAD,
+        * MERGE_HEAD, etc.
+        */
+
        strbuf_addstr(&normalized_pattern, pattern);
        strbuf_strip_suffix(&normalized_pattern, "/");
 
@@ -893,8 +982,9 @@ static void set_read_ref_cutoffs(struct read_ref_at_cb *cb,
 }
 
 static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
-               const char *email, timestamp_t timestamp, int tz,
-               const char *message, void *cb_data)
+                          const char *email UNUSED,
+                          timestamp_t timestamp, int tz,
+                          const char *message, void *cb_data)
 {
        struct read_ref_at_cb *cb = cb_data;
        int reached_count;
@@ -934,9 +1024,11 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
        return cb->found_it;
 }
 
-static int read_ref_at_ent_newest(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_ref_at_ent_newest(struct object_id *ooid UNUSED,
+                                 struct object_id *noid,
+                                 const char *email UNUSED,
+                                 timestamp_t timestamp, int tz,
+                                 const char *message, void *cb_data)
 {
        struct read_ref_at_cb *cb = cb_data;
 
@@ -947,8 +1039,9 @@ static int read_ref_at_ent_newest(struct object_id *ooid, struct object_id *noid
 }
 
 static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
-                                 const char *email, timestamp_t timestamp,
-                                 int tz, const char *message, void *cb_data)
+                                 const char *email UNUSED,
+                                 timestamp_t timestamp, int tz,
+                                 const char *message, void *cb_data)
 {
        struct read_ref_at_cb *cb = cb_data;
 
@@ -1524,6 +1617,7 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
 
 int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
 {
+       const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
        return do_for_each_repo_ref(r, git_replace_ref_base, fn,
                                    strlen(git_replace_ref_base),
                                    DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
@@ -1810,7 +1904,7 @@ struct ref_store_hash_entry
        char name[FLEX_ARRAY];
 };
 
-static int ref_store_hash_cmp(const void *unused_cmp_data,
+static int ref_store_hash_cmp(const void *cmp_data UNUSED,
                              const struct hashmap_entry *eptr,
                              const struct hashmap_entry *entry_or_key,
                              const void *keydata)
diff --git a/refs.h b/refs.h
index 47cb9edbaa8913c3af721d347744beefacb1e754..d6575b8c2bdf0d3e9021f7000b42308ff33203af 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -2,6 +2,7 @@
 #define REFS_H
 
 #include "cache.h"
+#include "commit.h"
 
 struct object_id;
 struct ref_store;
@@ -930,4 +931,49 @@ struct ref_store *get_main_ref_store(struct repository *r);
 struct ref_store *get_submodule_ref_store(const char *submodule);
 struct ref_store *get_worktree_ref_store(const struct worktree *wt);
 
+/*
+ * Some of the names specified by refs have special meaning to Git.
+ * Organize these namespaces in a comon 'ref_namespace' array for
+ * reference from multiple places in the codebase.
+ */
+
+struct ref_namespace_info {
+       char *ref;
+       enum decoration_type decoration;
+
+       /*
+        * If 'exact' is true, then we must match the 'ref' exactly.
+        * Otherwise, use a prefix match.
+        *
+        * 'ref_updated' is for internal use. It represents whether the
+        * 'ref' value was replaced from its original literal version.
+        */
+       unsigned exact:1,
+                ref_updated:1;
+};
+
+enum ref_namespace {
+       NAMESPACE_HEAD,
+       NAMESPACE_BRANCHES,
+       NAMESPACE_TAGS,
+       NAMESPACE_REMOTE_REFS,
+       NAMESPACE_STASH,
+       NAMESPACE_REPLACE,
+       NAMESPACE_NOTES,
+       NAMESPACE_PREFETCH,
+       NAMESPACE_REWRITTEN,
+
+       /* Must be last */
+       NAMESPACE__COUNT
+};
+
+/* See refs.c for the contents of this array. */
+extern struct ref_namespace_info ref_namespace[NAMESPACE__COUNT];
+
+/*
+ * Some ref namespaces can be modified by config values or environment
+ * variables. Modify a namespace as specified by its ref_namespace key.
+ */
+void update_ref_namespace(enum ref_namespace namespace, char *ref);
+
 #endif /* REFS_H */
index 8db7882aacb533ebf6635a0457c8b2ac7855c392..e4009b3c421f5bddf9b3480a9fc881cee0d2307b 100644 (file)
@@ -2202,8 +2202,8 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
        return ok;
 }
 
-static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
-                                     struct object_id *peeled)
+static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
+                                     struct object_id *peeled UNUSED)
 {
        BUG("ref_iterator_peel() called for reflog_iterator");
 }
@@ -2257,7 +2257,7 @@ static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
 static enum iterator_selection reflog_iterator_select(
        struct ref_iterator *iter_worktree,
        struct ref_iterator *iter_common,
-       void *cb_data)
+       void *cb_data UNUSED)
 {
        if (iter_worktree) {
                /*
@@ -2985,7 +2985,7 @@ cleanup:
 
 static int files_transaction_abort(struct ref_store *ref_store,
                                   struct ref_transaction *transaction,
-                                  struct strbuf *err)
+                                  struct strbuf *err UNUSED)
 {
        struct files_ref_store *refs =
                files_downcast(ref_store, 0, "ref_transaction_abort");
@@ -2995,7 +2995,9 @@ static int files_transaction_abort(struct ref_store *ref_store,
 }
 
 static int ref_present(const char *refname,
-                      const struct object_id *oid, int flags, void *cb_data)
+                      const struct object_id *oid UNUSED,
+                      int flags UNUSED,
+                      void *cb_data)
 {
        struct string_list *affected_refnames = cb_data;
 
@@ -3259,7 +3261,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
        return -1;
 }
 
-static int files_init_db(struct ref_store *ref_store, struct strbuf *err)
+static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
 {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE, "init_db");
index b2e56bae1c6408bccf66729b8b09f76907b984d9..c9fd0bcaf90c753031a1624f593c607a4549bf5a 100644 (file)
@@ -51,8 +51,8 @@ static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator)
        return ref_iterator_abort(ref_iterator);
 }
 
-static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator,
-                                  struct object_id *peeled)
+static int empty_ref_iterator_peel(struct ref_iterator *ref_iterator UNUSED,
+                                  struct object_id *peeled UNUSED)
 {
        BUG("peel called for empty iterator");
 }
@@ -238,7 +238,7 @@ struct ref_iterator *merge_ref_iterator_begin(
  */
 static enum iterator_selection overlay_iterator_select(
                struct ref_iterator *front, struct ref_iterator *back,
-               void *cb_data)
+               void *cb_data UNUSED)
 {
        int cmp;
 
index 97b68377673067d3a28d60e01f2b4532433750f2..43cdb97f8b37756ee2f62fcf2dc285ec3116f5b4 100644 (file)
@@ -726,7 +726,7 @@ static struct snapshot *get_snapshot(struct packed_ref_store *refs)
 }
 
 static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname,
-                              struct object_id *oid, struct strbuf *referent,
+                              struct object_id *oid, struct strbuf *referent UNUSED,
                               unsigned int *type, int *failure_errno)
 {
        struct packed_ref_store *refs =
@@ -1078,7 +1078,8 @@ int packed_refs_is_locked(struct ref_store *ref_store)
 static const char PACKED_REFS_HEADER[] =
        "# pack-refs with: peeled fully-peeled sorted \n";
 
-static int packed_init_db(struct ref_store *ref_store, struct strbuf *err)
+static int packed_init_db(struct ref_store *ref_store UNUSED,
+                         struct strbuf *err UNUSED)
 {
        /* Nothing to do. */
        return 0;
@@ -1473,7 +1474,7 @@ failure:
 
 static int packed_transaction_abort(struct ref_store *ref_store,
                                    struct ref_transaction *transaction,
-                                   struct strbuf *err)
+                                   struct strbuf *err UNUSED)
 {
        struct packed_ref_store *refs = packed_downcast(
                        ref_store,
@@ -1512,7 +1513,7 @@ cleanup:
        return ret;
 }
 
-static int packed_initial_transaction_commit(struct ref_store *ref_store,
+static int packed_initial_transaction_commit(struct ref_store *ref_store UNUSED,
                                            struct ref_transaction *transaction,
                                            struct strbuf *err)
 {
@@ -1568,7 +1569,8 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
        return ret;
 }
 
-static int packed_pack_refs(struct ref_store *ref_store, unsigned int flags)
+static int packed_pack_refs(struct ref_store *ref_store UNUSED,
+                           unsigned int flags UNUSED)
 {
        /*
         * Packed refs are already packed. It might be that loose refs
@@ -1578,7 +1580,7 @@ static int packed_pack_refs(struct ref_store *ref_store, unsigned int flags)
        return 0;
 }
 
-static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
+static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store UNUSED)
 {
        return empty_ref_iterator_begin();
 }
index 8b79891d3218d526ef1216bc1525b6040730185a..8c0c44699335e65af07ee2ea3ebd4fb266db32a5 100644 (file)
--- a/refspec.h
+++ b/refspec.h
@@ -69,7 +69,7 @@ int valid_remote_name(const char *name);
 struct strvec;
 /*
  * Determine what <prefix> values to pass to the peer in ref-prefix lines
- * (see Documentation/technical/protocol-v2.txt).
+ * (see linkgit:gitprotocol-v2[5]).
  */
 void refspec_ref_prefixes(const struct refspec *rs,
                          struct strvec *ref_prefixes);
index 2a6efa110d5dfaf0f4971a69f7b9e81a9fe04d68..5ded470c086c92760083dc16c08e7bdff821e9bf 100644 (file)
@@ -36,7 +36,7 @@ static int merged_iter_init(struct merged_iter *mi)
                                .rec = rec,
                                .index = i,
                        };
-                       merged_iter_pqueue_add(&mi->pq, e);
+                       merged_iter_pqueue_add(&mi->pq, &e);
                }
        }
 
@@ -71,7 +71,7 @@ static int merged_iter_advance_nonnull_subiter(struct merged_iter *mi,
                return 0;
        }
 
-       merged_iter_pqueue_add(&mi->pq, e);
+       merged_iter_pqueue_add(&mi->pq, &e);
        return 0;
 }
 
index 96ca6dd37b3ac0b881781403806d30e52edff46a..dcefeb793a9051b75a276732a32d88809bb86d94 100644 (file)
@@ -71,7 +71,7 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq)
        return e;
 }
 
-void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e)
+void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e)
 {
        int i = 0;
 
@@ -81,7 +81,7 @@ void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e)
                                            pq->cap * sizeof(struct pq_entry));
        }
 
-       pq->heap[pq->len++] = e;
+       pq->heap[pq->len++] = *e;
        i = pq->len - 1;
        while (i > 0) {
                int j = (i - 1) / 2;
index 56fc1b6d873e6bf4b49f324ccd9476702e4fcd39..e85bac9b52e0039bd378cb1073215af4d48196c7 100644 (file)
@@ -26,7 +26,7 @@ struct pq_entry merged_iter_pqueue_top(struct merged_iter_pqueue pq);
 int merged_iter_pqueue_is_empty(struct merged_iter_pqueue pq);
 void merged_iter_pqueue_check(struct merged_iter_pqueue pq);
 struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq);
-void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, struct pq_entry e);
+void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e);
 void merged_iter_pqueue_release(struct merged_iter_pqueue *pq);
 int pq_less(struct pq_entry *a, struct pq_entry *b);
 
index 7de5e886f35236eff6b7e033813ea2f7b403b9c8..011b5c75028a9d8dbad15f23ddb99d39e09ca9cb 100644 (file)
@@ -46,7 +46,7 @@ static void test_pq(void)
                                               .u.ref = {
                                                       .refname = names[i],
                                               } } };
-               merged_iter_pqueue_add(&pq, e);
+               merged_iter_pqueue_add(&pq, &e);
                merged_iter_pqueue_check(pq);
                i = (i * 7) % N;
        } while (i != 1);
index 54b4025105cfd6dc53821d366a1dd20bc8d11004..b4db23ce1880794a937b841e28ffa27e8869d2c7 100644 (file)
@@ -443,7 +443,7 @@ static int reader_start(struct reftable_reader *r, struct table_iter *ti,
        return reader_table_iter_at(r, ti, off, typ);
 }
 
-static int reader_seek_linear(struct reftable_reader *r, struct table_iter *ti,
+static int reader_seek_linear(struct table_iter *ti,
                              struct reftable_record *want)
 {
        struct reftable_record rec =
@@ -510,7 +510,7 @@ static int reader_seek_indexed(struct reftable_reader *r,
        if (err < 0)
                goto done;
 
-       err = reader_seek_linear(r, &index_iter, &want_index);
+       err = reader_seek_linear(&index_iter, &want_index);
        while (1) {
                err = table_iter_next(&index_iter, &index_result);
                table_iter_block_done(&index_iter);
@@ -570,7 +570,7 @@ static int reader_seek_internal(struct reftable_reader *r,
        err = reader_start(r, &ti, reftable_record_type(rec), 0);
        if (err < 0)
                return err;
-       err = reader_seek_linear(r, &ti, rec);
+       err = reader_seek_linear(&ti, rec);
        if (err < 0)
                return err;
        else {
index 67f178b1120bd9167cef21382141ab96b8ff3514..72dfb8fb86aab0e93780416049cf8f8bfae157bc 100644 (file)
@@ -580,6 +580,7 @@ struct rpc_state {
        char *service_url;
        char *hdr_content_type;
        char *hdr_accept;
+       char *hdr_accept_language;
        char *protocol_header;
        char *buf;
        size_t alloc;
@@ -607,6 +608,8 @@ struct rpc_state {
        unsigned flush_read_but_not_sent : 1;
 };
 
+#define RPC_STATE_INIT { 0 }
+
 /*
  * Appends the result of reading from rpc->out to the string represented by
  * rpc->buf and rpc->len if there is enough space. Returns 1 if there was
@@ -932,6 +935,10 @@ static int post_rpc(struct rpc_state *rpc, int stateless_connect, int flush_rece
        headers = curl_slist_append(headers, needs_100_continue ?
                "Expect: 100-continue" : "Expect:");
 
+       /* Add Accept-Language header */
+       if (rpc->hdr_accept_language)
+               headers = curl_slist_append(headers, rpc->hdr_accept_language);
+
        /* Add the extra Git-Protocol header */
        if (rpc->protocol_header)
                headers = curl_slist_append(headers, rpc->protocol_header);
@@ -1080,6 +1087,8 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads,
        strbuf_addf(&buf, "%s%s", url.buf, svc);
        rpc->service_url = strbuf_detach(&buf, NULL);
 
+       rpc->hdr_accept_language = xstrdup_or_null(http_get_accept_language_header());
+
        strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
        rpc->hdr_content_type = strbuf_detach(&buf, NULL);
 
@@ -1118,6 +1127,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads,
        free(rpc->service_url);
        free(rpc->hdr_content_type);
        free(rpc->hdr_accept);
+       free(rpc->hdr_accept_language);
        free(rpc->protocol_header);
        free(rpc->buf);
        strbuf_release(&buf);
@@ -1153,7 +1163,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
 static int fetch_git(struct discovery *heads,
        int nr_heads, struct ref **to_fetch)
 {
-       struct rpc_state rpc;
+       struct rpc_state rpc = RPC_STATE_INIT;
        struct strbuf preamble = STRBUF_INIT;
        int i, err;
        struct strvec args = STRVEC_INIT;
@@ -1276,6 +1286,29 @@ static void parse_fetch(struct strbuf *buf)
        strbuf_reset(buf);
 }
 
+static void parse_get(const char *arg)
+{
+       struct strbuf url = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       const char *space;
+
+       space = strchr(arg, ' ');
+
+       if (!space)
+               die(_("protocol error: expected '<url> <path>', missing space"));
+
+       strbuf_add(&url, arg, space - arg);
+       strbuf_addstr(&path, space + 1);
+
+       if (http_get_file(url.buf, path.buf, NULL))
+               die(_("failed to download file at URL '%s'"), url.buf);
+
+       strbuf_release(&url);
+       strbuf_release(&path);
+       printf("\n");
+       fflush(stdout);
+}
+
 static int push_dav(int nr_spec, const char **specs)
 {
        struct child_process child = CHILD_PROCESS_INIT;
@@ -1299,7 +1332,7 @@ static int push_dav(int nr_spec, const char **specs)
 
 static int push_git(struct discovery *heads, int nr_spec, const char **specs)
 {
-       struct rpc_state rpc;
+       struct rpc_state rpc = RPC_STATE_INIT;
        int i, err;
        struct strvec args;
        struct string_list_item *cas_option;
@@ -1398,8 +1431,9 @@ free_specs:
 static int stateless_connect(const char *service_name)
 {
        struct discovery *discover;
-       struct rpc_state rpc;
+       struct rpc_state rpc = RPC_STATE_INIT;
        struct strbuf buf = STRBUF_INIT;
+       const char *accept_language;
 
        /*
         * Run the info/refs request and see if the server supports protocol
@@ -1418,6 +1452,9 @@ static int stateless_connect(const char *service_name)
                printf("\n");
                fflush(stdout);
        }
+       accept_language = http_get_accept_language_header();
+       if (accept_language)
+               rpc.hdr_accept_language = xstrfmt("%s", accept_language);
 
        rpc.service_name = service_name;
        rpc.service_url = xstrfmt("%s%s", url.buf, rpc.service_name);
@@ -1467,6 +1504,7 @@ static int stateless_connect(const char *service_name)
        free(rpc.service_url);
        free(rpc.hdr_content_type);
        free(rpc.hdr_accept);
+       free(rpc.hdr_accept_language);
        free(rpc.protocol_header);
        free(rpc.buf);
        strbuf_release(&buf);
@@ -1549,9 +1587,14 @@ int cmd_main(int argc, const char **argv)
                                printf("unsupported\n");
                        fflush(stdout);
 
+               } else if (skip_prefix(buf.buf, "get ", &arg)) {
+                       parse_get(arg);
+                       fflush(stdout);
+
                } else if (!strcmp(buf.buf, "capabilities")) {
                        printf("stateless-connect\n");
                        printf("fetch\n");
+                       printf("get\n");
                        printf("option\n");
                        printf("push\n");
                        printf("check-connectivity\n");
index b19e3a2f015a7215df4227ae85368e11d8b1e962..60869beebe7364a594cd45938d4ed97dcdd28840 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -11,7 +11,6 @@
 #include "dir.h"
 #include "tag.h"
 #include "string-list.h"
-#include "mergesort.h"
 #include "strvec.h"
 #include "commit-reach.h"
 #include "advice.h"
@@ -87,7 +86,7 @@ struct remotes_hash_key {
        int len;
 };
 
-static int remotes_hash_cmp(const void *unused_cmp_data,
+static int remotes_hash_cmp(const void *cmp_data UNUSED,
                            const struct hashmap_entry *eptr,
                            const struct hashmap_entry *entry_or_key,
                            const void *keydata)
@@ -171,7 +170,7 @@ struct branches_hash_key {
        int len;
 };
 
-static int branches_hash_cmp(const void *unused_cmp_data,
+static int branches_hash_cmp(const void *cmp_data UNUSED,
                             const struct hashmap_entry *eptr,
                             const struct hashmap_entry *entry_or_key,
                             const void *keydata)
@@ -850,7 +849,7 @@ static int refspec_match(const struct refspec_item *refspec,
        return !strcmp(refspec->src, name);
 }
 
-static int omit_name_by_refspec(const char *name, struct refspec *rs)
+int omit_name_by_refspec(const char *name, struct refspec *rs)
 {
        int i;
 
@@ -1082,27 +1081,6 @@ void free_refs(struct ref *ref)
        }
 }
 
-int ref_compare_name(const void *va, const void *vb)
-{
-       const struct ref *a = va, *b = vb;
-       return strcmp(a->name, b->name);
-}
-
-static void *ref_list_get_next(const void *a)
-{
-       return ((const struct ref *)a)->next;
-}
-
-static void ref_list_set_next(void *a, void *next)
-{
-       ((struct ref *)a)->next = next;
-}
-
-void sort_ref_list(struct ref **l, int (*cmp)(const void *, const void *))
-{
-       *l = llist_mergesort(*l, ref_list_get_next, ref_list_set_next, cmp);
-}
-
 int count_refspec_match(const char *pattern,
                        struct ref *refs,
                        struct ref **matched_ref)
@@ -2169,6 +2147,9 @@ static int stat_branch_pair(const char *branch_name, const char *base,
        struct object_id oid;
        struct commit *ours, *theirs;
        struct rev_info revs;
+       struct setup_revision_opt opt = {
+               .free_removed_argv_elements = 1,
+       };
        struct strvec argv = STRVEC_INIT;
 
        /* Cannot stat if what we used to build on no longer exists */
@@ -2203,7 +2184,7 @@ static int stat_branch_pair(const char *branch_name, const char *base,
        strvec_push(&argv, "--");
 
        repo_init_revisions(the_repository, &revs, NULL);
-       setup_revisions(argv.nr, argv.v, &revs, NULL);
+       setup_revisions(argv.nr, argv.v, &revs, &opt);
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
 
@@ -2339,7 +2320,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
 }
 
 static int one_local_ref(const char *refname, const struct object_id *oid,
-                        int flag, void *cb_data)
+                        int flag UNUSED,
+                        void *cb_data)
 {
        struct ref ***local_tail = cb_data;
        struct ref *ref;
@@ -2595,19 +2577,22 @@ struct check_and_collect_until_cb_data {
 };
 
 /* Get the timestamp of the latest entry. */
-static int peek_reflog(struct object_id *o_oid, struct object_id *n_oid,
-                      const char *ident, timestamp_t timestamp,
-                      int tz, const char *message, void *cb_data)
+static int peek_reflog(struct object_id *o_oid UNUSED,
+                      struct object_id *n_oid UNUSED,
+                      const char *ident UNUSED,
+                      timestamp_t timestamp, int tz UNUSED,
+                      const char *message UNUSED, void *cb_data)
 {
        timestamp_t *ts = cb_data;
        *ts = timestamp;
        return 1;
 }
 
-static int check_and_collect_until(struct object_id *o_oid,
+static int check_and_collect_until(struct object_id *o_oid UNUSED,
                                   struct object_id *n_oid,
-                                  const char *ident, timestamp_t timestamp,
-                                  int tz, const char *message, void *cb_data)
+                                  const char *ident UNUSED,
+                                  timestamp_t timestamp, int tz UNUSED,
+                                  const char *message UNUSED, void *cb_data)
 {
        struct commit *commit;
        struct check_and_collect_until_cb_data *cb = cb_data;
index dd4402436f1f2e1bb06d37c932ca8f9e3afcf48a..1c4621b414bdc0372613e58c3b2133b84004d1e7 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -207,9 +207,7 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name);
 struct ref *alloc_ref(const char *name);
 struct ref *copy_ref(const struct ref *ref);
 struct ref *copy_ref_list(const struct ref *ref);
-void sort_ref_list(struct ref **, int (*cmp)(const void *, const void *));
 int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref);
-int ref_compare_name(const void *, const void *);
 
 int check_ref_type(const struct ref *ref, int flags);
 
@@ -247,6 +245,12 @@ int resolve_remote_symref(struct ref *ref, struct ref *list);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
+/*
+ * Check whether a name matches any negative refspec in rs. Returns 1 if the
+ * name matches at least one negative refspec, and 0 otherwise.
+ */
+int omit_name_by_refspec(const char *name, struct refspec *rs);
+
 /*
  * Remove all entries in the input list which match any negative refspec in
  * the refspec list.
index 7bd9aba6ee6c339e02c6fe25262a75a19bfc6e68..320be2522d80a87fdb1569a97c5e24b77fd4a525 100644 (file)
@@ -9,7 +9,8 @@
 static int register_replace_ref(struct repository *r,
                                const char *refname,
                                const struct object_id *oid,
-                               int flag, void *cb_data)
+                               int flag UNUSED,
+                               void *cb_data UNUSED)
 {
        /* Get sha1 from refname */
        const char *slash = strrchr(refname, '/');
index 2dfcb2b6542f2cbe75d4575e8b707cf1676679a3..e8b58151bc4a01d0a90ba49d89ddf52d3d780995 100644 (file)
@@ -11,11 +11,18 @@ static void repo_cfg_bool(struct repository *r, const char *key, int *dest,
                *dest = def;
 }
 
+static void repo_cfg_int(struct repository *r, const char *key, int *dest,
+                        int def)
+{
+       if (repo_config_get_int(r, key, dest))
+               *dest = def;
+}
+
 void prepare_repo_settings(struct repository *r)
 {
        int experimental;
        int value;
-       char *strval;
+       const char *strval;
        int manyfiles;
 
        if (!r->gitdir)
@@ -42,11 +49,14 @@ void prepare_repo_settings(struct repository *r)
                r->settings.core_untracked_cache = UNTRACKED_CACHE_WRITE;
        }
 
-       /* Boolean config or default, does not cascade (simple)  */
+       /* Commit graph config or default, does not cascade (simple) */
        repo_cfg_bool(r, "core.commitgraph", &r->settings.core_commit_graph, 1);
+       repo_cfg_int(r, "commitgraph.generationversion", &r->settings.commit_graph_generation_version, 2);
        repo_cfg_bool(r, "commitgraph.readchangedpaths", &r->settings.commit_graph_read_changed_paths, 1);
        repo_cfg_bool(r, "gc.writecommitgraph", &r->settings.gc_write_commit_graph, 1);
        repo_cfg_bool(r, "fetch.writecommitgraph", &r->settings.fetch_write_commit_graph, 0);
+
+       /* Boolean config or default, does not cascade (simple)  */
        repo_cfg_bool(r, "pack.usesparse", &r->settings.pack_use_sparse, 1);
        repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
        repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
@@ -67,7 +77,7 @@ void prepare_repo_settings(struct repository *r)
        if (!repo_config_get_int(r, "index.version", &value))
                r->settings.index_version = value;
 
-       if (!repo_config_get_string(r, "core.untrackedcache", &strval)) {
+       if (!repo_config_get_string_tmp(r, "core.untrackedcache", &strval)) {
                int v = git_parse_maybe_bool(strval);
 
                /*
@@ -78,10 +88,9 @@ void prepare_repo_settings(struct repository *r)
                if (v >= 0)
                        r->settings.core_untracked_cache = v ?
                                UNTRACKED_CACHE_WRITE : UNTRACKED_CACHE_REMOVE;
-               free(strval);
        }
 
-       if (!repo_config_get_string(r, "fetch.negotiationalgorithm", &strval)) {
+       if (!repo_config_get_string_tmp(r, "fetch.negotiationalgorithm", &strval)) {
                int fetch_default = r->settings.fetch_negotiation_algorithm;
                if (!strcasecmp(strval, "skipping"))
                        r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
index 6cc661e5a43b82022ca171a43c015db2f278116e..24316ac944edcd5827de279d14fef7dea9334c74 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef REPOSITORY_H
 #define REPOSITORY_H
 
+#include "git-compat-util.h"
 #include "path.h"
 
 struct config_set;
@@ -30,6 +31,7 @@ struct repo_settings {
        int initialized;
 
        int core_commit_graph;
+       int commit_graph_generation_version;
        int commit_graph_read_changed_paths;
        int gc_write_commit_graph;
        int fetch_write_commit_graph;
@@ -185,6 +187,7 @@ void repo_set_gitdir(struct repository *repo, const char *root,
 void repo_set_worktree(struct repository *repo, const char *path);
 void repo_set_hash_algo(struct repository *repo, int algo);
 void initialize_the_repository(void);
+RESULT_MUST_BE_USED
 int repo_init(struct repository *r, const char *gitdir, const char *worktree);
 
 /*
@@ -196,6 +199,7 @@ int repo_init(struct repository *r, const char *gitdir, const char *worktree);
  * Return 0 upon success and a non-zero value upon failure.
  */
 struct object_id;
+RESULT_MUST_BE_USED
 int repo_submodule_init(struct repository *subrepo,
                        struct repository *superproject,
                        const char *path,
index 0c6e26cd9c8ff8d4f6fdb6050d7df57be460256e..36e31942ceec3c43c8dc690c273937aaf4d29b2c 100644 (file)
@@ -119,10 +119,10 @@ struct path_and_oids_entry {
        struct oidset trees;
 };
 
-static int path_and_oids_cmp(const void *hashmap_cmp_fn_data,
+static int path_and_oids_cmp(const void *hashmap_cmp_fn_data UNUSED,
                             const struct hashmap_entry *eptr,
                             const struct hashmap_entry *entry_or_key,
-                            const void *keydata)
+                            const void *keydata UNUSED)
 {
        const struct path_and_oids_entry *e1, *e2;
 
@@ -373,18 +373,10 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
                                    unsigned int flags)
 {
        struct object *object;
-       struct commit *commit;
 
-       /*
-        * If the repository has commit graphs, we try to opportunistically
-        * look up the object ID in those graphs. Like this, we can avoid
-        * parsing commit data from disk.
-        */
-       commit = lookup_commit_in_graph(revs->repo, oid);
-       if (commit)
-               object = &commit->object;
-       else
-               object = parse_object(revs->repo, oid);
+       object = parse_object_with_flags(revs->repo, oid,
+                                        revs->verify_objects ? 0 :
+                                        PARSE_OBJECT_SKIP_HASH_CHECK);
 
        if (!object) {
                if (revs->ignore_missing)
@@ -1105,7 +1097,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
                           struct commit_list **list, struct prio_queue *queue)
 {
        struct commit_list *parent = commit->parents;
-       unsigned left_flag;
+       unsigned pass_flags;
 
        if (commit->object.flags & ADDED)
                return 0;
@@ -1160,7 +1152,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
        if (revs->no_walk)
                return 0;
 
-       left_flag = (commit->object.flags & SYMMETRIC_LEFT);
+       pass_flags = (commit->object.flags & (SYMMETRIC_LEFT | ANCESTRY_PATH));
 
        for (parent = commit->parents; parent; parent = parent->next) {
                struct commit *p = parent->item;
@@ -1181,7 +1173,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
                        if (!*slot)
                                *slot = *revision_sources_at(revs->sources, commit);
                }
-               p->object.flags |= left_flag;
+               p->object.flags |= pass_flags;
                if (!(p->object.flags & SEEN)) {
                        p->object.flags |= (SEEN | NOT_USER_GIVEN);
                        if (list)
@@ -1304,13 +1296,24 @@ static int still_interesting(struct commit_list *src, timestamp_t date, int slop
 }
 
 /*
- * "rev-list --ancestry-path A..B" computes commits that are ancestors
- * of B but not ancestors of A but further limits the result to those
- * that are descendants of A.  This takes the list of bottom commits and
- * the result of "A..B" without --ancestry-path, and limits the latter
- * further to the ones that can reach one of the commits in "bottom".
+ * "rev-list --ancestry-path=C_0 [--ancestry-path=C_1 ...] A..B"
+ * computes commits that are ancestors of B but not ancestors of A but
+ * further limits the result to those that have any of C in their
+ * ancestry path (i.e. are either ancestors of any of C, descendants
+ * of any of C, or are any of C). If --ancestry-path is specified with
+ * no commit, we use all bottom commits for C.
+ *
+ * Before this function is called, ancestors of C will have already
+ * been marked with ANCESTRY_PATH previously.
+ *
+ * This takes the list of bottom commits and the result of "A..B"
+ * without --ancestry-path, and limits the latter further to the ones
+ * that have any of C in their ancestry path. Since the ancestors of C
+ * have already been marked (a prerequisite of this function), we just
+ * need to mark the descendants, then exclude any commit that does not
+ * have any of these marks.
  */
-static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *list)
+static void limit_to_ancestry(struct commit_list *bottoms, struct commit_list *list)
 {
        struct commit_list *p;
        struct commit_list *rlist = NULL;
@@ -1323,7 +1326,7 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li
        for (p = list; p; p = p->next)
                commit_list_insert(p->item, &rlist);
 
-       for (p = bottom; p; p = p->next)
+       for (p = bottoms; p; p = p->next)
                p->item->object.flags |= TMP_MARK;
 
        /*
@@ -1356,38 +1359,39 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li
         */
 
        /*
-        * The ones that are not marked with TMP_MARK are uninteresting
+        * The ones that are not marked with either TMP_MARK or
+        * ANCESTRY_PATH are uninteresting
         */
        for (p = list; p; p = p->next) {
                struct commit *c = p->item;
-               if (c->object.flags & TMP_MARK)
+               if (c->object.flags & (TMP_MARK | ANCESTRY_PATH))
                        continue;
                c->object.flags |= UNINTERESTING;
        }
 
-       /* We are done with the TMP_MARK */
+       /* We are done with TMP_MARK and ANCESTRY_PATH */
        for (p = list; p; p = p->next)
-               p->item->object.flags &= ~TMP_MARK;
-       for (p = bottom; p; p = p->next)
-               p->item->object.flags &= ~TMP_MARK;
+               p->item->object.flags &= ~(TMP_MARK | ANCESTRY_PATH);
+       for (p = bottoms; p; p = p->next)
+               p->item->object.flags &= ~(TMP_MARK | ANCESTRY_PATH);
        free_commit_list(rlist);
 }
 
 /*
- * Before walking the history, keep the set of "negative" refs the
- * caller has asked to exclude.
+ * Before walking the history, add the set of "negative" refs the
+ * caller has asked to exclude to the bottom list.
  *
  * This is used to compute "rev-list --ancestry-path A..B", as we need
  * to filter the result of "A..B" further to the ones that can actually
  * reach A.
  */
-static struct commit_list *collect_bottom_commits(struct commit_list *list)
+static void collect_bottom_commits(struct commit_list *list,
+                                  struct commit_list **bottom)
 {
-       struct commit_list *elem, *bottom = NULL;
+       struct commit_list *elem;
        for (elem = list; elem; elem = elem->next)
                if (elem->item->object.flags & BOTTOM)
-                       commit_list_insert(elem->item, &bottom);
-       return bottom;
+                       commit_list_insert(elem->item, bottom);
 }
 
 /* Assumes either left_only or right_only is set */
@@ -1414,12 +1418,12 @@ static int limit_list(struct rev_info *revs)
        struct commit_list *original_list = revs->commits;
        struct commit_list *newlist = NULL;
        struct commit_list **p = &newlist;
-       struct commit_list *bottom = NULL;
        struct commit *interesting_cache = NULL;
 
-       if (revs->ancestry_path) {
-               bottom = collect_bottom_commits(original_list);
-               if (!bottom)
+       if (revs->ancestry_path_implicit_bottoms) {
+               collect_bottom_commits(original_list,
+                                      &revs->ancestry_path_bottoms);
+               if (!revs->ancestry_path_bottoms)
                        die("--ancestry-path given but there are no bottom commits");
        }
 
@@ -1464,9 +1468,8 @@ static int limit_list(struct rev_info *revs)
        if (revs->left_only || revs->right_only)
                limit_left_right(newlist, revs);
 
-       if (bottom)
-               limit_to_ancestry(bottom, newlist);
-       free_commit_list(bottom);
+       if (revs->ancestry_path)
+               limit_to_ancestry(revs->ancestry_path_bottoms, newlist);
 
        /*
         * Check if any commits have become TREESAME by some of their parents
@@ -1543,7 +1546,8 @@ int ref_excluded(struct string_list *ref_excludes, const char *path)
 }
 
 static int handle_one_ref(const char *path, const struct object_id *oid,
-                         int flag, void *cb_data)
+                         int flag UNUSED,
+                         void *cb_data)
 {
        struct all_refs_cb *cb = cb_data;
        struct object *object;
@@ -1618,8 +1622,11 @@ 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,
-               const char *email, timestamp_t timestamp, int tz,
-               const char *message, void *cb_data)
+                                const char *email UNUSED,
+                                timestamp_t timestamp UNUSED,
+                                int tz UNUSED,
+                                const char *message UNUSED,
+                                void *cb_data)
 {
        handle_one_reflog_commit(ooid, cb_data);
        handle_one_reflog_commit(noid, cb_data);
@@ -1627,8 +1634,8 @@ static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
 }
 
 static int handle_one_reflog(const char *refname_in_wt,
-                            const struct object_id *oid,
-                            int flag, void *cb_data)
+                            const struct object_id *oid UNUSED,
+                            int flag UNUSED, void *cb_data)
 {
        struct all_refs_cb *cb = cb_data;
        struct strbuf refname = STRBUF_INIT;
@@ -1900,6 +1907,7 @@ void repo_init_revisions(struct repository *r,
        }
 
        init_display_notes(&revs->notes_opt);
+       list_objects_filter_init(&revs->filter);
 }
 
 static void add_pending_commit_list(struct rev_info *revs,
@@ -2213,7 +2221,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                               const struct setup_revision_opt* opt)
 {
        const char *arg = argv[0];
-       const char *optarg;
+       const char *optarg = NULL;
        int argcount;
        const unsigned hexsz = the_hash_algo->hexsz;
 
@@ -2284,6 +2292,23 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->ancestry_path = 1;
                revs->simplify_history = 0;
                revs->limited = 1;
+               revs->ancestry_path_implicit_bottoms = 1;
+       } else if (skip_prefix(arg, "--ancestry-path=", &optarg)) {
+               struct commit *c;
+               struct object_id oid;
+               const char *msg = _("could not get commit for ancestry-path argument %s");
+
+               revs->ancestry_path = 1;
+               revs->simplify_history = 0;
+               revs->limited = 1;
+
+               if (repo_get_oid_committish(revs->repo, optarg, &oid))
+                       return error(msg, optarg);
+               get_reference(revs, optarg, &oid, ANCESTRY_PATH);
+               c = lookup_commit_reference(revs->repo, &oid);
+               if (!c)
+                       return error(msg, optarg);
+               commit_list_insert(c, &revs->ancestry_path_bottoms);
        } else if (!strcmp(arg, "-g") || !strcmp(arg, "--walk-reflogs")) {
                init_reflog_walk(&revs->reflog_info);
        } else if (!strcmp(arg, "--default")) {
@@ -2398,6 +2423,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->tree_objects = 1;
                revs->blob_objects = 1;
                revs->verify_objects = 1;
+               disable_commit_graph(revs->repo);
        } else if (!strcmp(arg, "--unpacked")) {
                revs->unpacked = 1;
        } else if (starts_with(arg, "--unpacked=")) {
@@ -2784,6 +2810,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        const char *arg = argv[i];
                        if (strcmp(arg, "--"))
                                continue;
+                       if (opt && opt->free_removed_argv_elements)
+                               free((char *)argv[i]);
                        argv[i] = NULL;
                        argc = i;
                        if (argv[i + 1])
@@ -2991,6 +3019,7 @@ static void release_revisions_topo_walk_info(struct topo_walk_info *info);
 void release_revisions(struct rev_info *revs)
 {
        free_commit_list(revs->commits);
+       free_commit_list(revs->ancestry_path_bottoms);
        object_array_clear(&revs->pending);
        object_array_clear(&revs->boundary_commits);
        release_revisions_cmdline(&revs->cmdline);
@@ -3791,51 +3820,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,
        return 0;
 }
 
-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)
-{
-       char *person, *endp;
-       size_t len, namelen, maillen;
-       const char *name;
-       const char *mail;
-       struct ident_split ident;
-
-       person = strstr(buf->buf, what);
-       if (!person)
-               return 0;
-
-       person += strlen(what);
-       endp = strchr(person, '\n');
-       if (!endp)
-               return 0;
-
-       len = endp - person;
-
-       if (split_ident_line(&ident, person, len))
-               return 0;
-
-       mail = ident.mail_begin;
-       maillen = ident.mail_end - ident.mail_begin;
-       name = ident.name_begin;
-       namelen = ident.name_end - ident.name_begin;
-
-       if (map_user(mailmap, &mail, &maillen, &name, &namelen)) {
-               struct strbuf namemail = STRBUF_INIT;
-
-               strbuf_addf(&namemail, "%.*s <%.*s>",
-                           (int)namelen, name, (int)maillen, mail);
-
-               strbuf_splice(buf, ident.name_begin - buf->buf,
-                             ident.mail_end - ident.name_begin + 1,
-                             namemail.buf, namemail.len);
-
-               strbuf_release(&namemail);
-
-               return 1;
-       }
-
-       return 0;
-}
-
 static int commit_match(struct commit *commit, struct rev_info *opt)
 {
        int retval;
@@ -3868,11 +3852,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                strbuf_addstr(&buf, message);
 
        if (opt->grep_filter.header_list && opt->mailmap) {
+               const char *commit_headers[] = { "author ", "committer ", NULL };
+
                if (!buf.len)
                        strbuf_addstr(&buf, message);
 
-               commit_rewrite_person(&buf, "\nauthor ", opt->mailmap);
-               commit_rewrite_person(&buf, "\ncommitter ", opt->mailmap);
+               apply_mailmap_to_header(&buf, commit_headers, opt->mailmap);
        }
 
        /* Append "fake" message parts as needed */
index e576845cdd103731f3e8d3ea1a4b0eefb21e2063..afe1b77985faf5caeea507dad6639441013587c2 100644 (file)
@@ -48,6 +48,7 @@
  */
 #define NOT_USER_GIVEN (1u<<25)
 #define TRACK_LINEAR   (1u<<26)
+#define ANCESTRY_PATH  (1u<<27)
 #define ALL_REV_FLAGS  (((1u<<11)-1) | NOT_USER_GIVEN | TRACK_LINEAR | PULL_MERGE)
 
 #define DECORATE_SHORT_REFS    1
@@ -164,6 +165,13 @@ struct rev_info {
                        cherry_mark:1,
                        bisect:1,
                        ancestry_path:1,
+
+                       /* True if --ancestry-path was specified without an
+                        * argument. The bottom revisions are implicitly
+                        * the arguments in this case.
+                        */
+                       ancestry_path_implicit_bottoms:1,
+
                        first_parent_only:1,
                        exclude_first_parent_only:1,
                        line_level_traverse:1,
@@ -221,6 +229,7 @@ struct rev_info {
                        missing_newline:1,
                        date_mode_explicit:1,
                        preserve_subject:1,
+                       force_in_body_from:1,
                        encode_email_headers:1,
                        include_header:1;
        unsigned int    disable_stdin:1;
@@ -306,6 +315,7 @@ struct rev_info {
        struct saved_parents *saved_parents_slab;
 
        struct commit_list *previous_parents;
+       struct commit_list *ancestry_path_bottoms;
        const char *break_bar;
 
        struct revision_sources *sources;
@@ -375,7 +385,8 @@ struct setup_revision_opt {
        const char *def;
        void (*tweak)(struct rev_info *, struct setup_revision_opt *);
        unsigned int    assume_dashdash:1,
-                       allow_exclude_promisor_objects:1;
+                       allow_exclude_promisor_objects:1,
+                       free_removed_argv_elements:1;
        unsigned revarg_opt;
 };
 int setup_revisions(int argc, const char **argv, struct rev_info *revs,
similarity index 65%
rename from contrib/scalar/scalar.c
rename to scalar.c
index 28176914e57b91e823d6197a926909a87cfe1d16..c5c1ce689199083a9eb47ff6161ce6b1bcd7be64 100644 (file)
+++ b/scalar.c
@@ -7,27 +7,13 @@
 #include "parse-options.h"
 #include "config.h"
 #include "run-command.h"
+#include "simple-ipc.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
 #include "refs.h"
 #include "dir.h"
 #include "packfile.h"
 #include "help.h"
-#include "archive.h"
-#include "object-store.h"
-
-/*
- * Remove the deepest subdirectory in the provided path string. Path must not
- * include a trailing path separator. Returns 1 if parent directory found,
- * otherwise 0.
- */
-static int strbuf_parent_directory(struct strbuf *buf)
-{
-       size_t len = buf->len;
-       size_t offset = offset_1st_component(buf->buf);
-       char *path_sep = find_last_dir_sep(buf->buf + offset);
-       strbuf_setlen(buf, path_sep ? path_sep - buf->buf : offset);
-
-       return buf->len < len;
-}
 
 static void setup_enlistment_directory(int argc, const char **argv,
                                       const char * const *usagestr,
@@ -35,8 +21,8 @@ static void setup_enlistment_directory(int argc, const char **argv,
                                       struct strbuf *enlistment_root)
 {
        struct strbuf path = STRBUF_INIT;
-       char *root;
-       int enlistment_found = 0;
+       int enlistment_is_repo_parent = 0;
+       size_t len;
 
        if (startup_info->have_repository)
                BUG("gitdir already set up?!?");
@@ -49,51 +35,36 @@ static void setup_enlistment_directory(int argc, const char **argv,
                strbuf_add_absolute_path(&path, argv[0]);
                if (!is_directory(path.buf))
                        die(_("'%s' does not exist"), path.buf);
+               if (chdir(path.buf) < 0)
+                       die_errno(_("could not switch to '%s'"), path.buf);
        } else if (strbuf_getcwd(&path) < 0)
                die(_("need a working directory"));
 
        strbuf_trim_trailing_dir_sep(&path);
-       do {
-               const size_t len = path.len;
-
-               /* check if currently in enlistment root with src/ workdir */
-               strbuf_addstr(&path, "/src");
-               if (is_nonbare_repository_dir(&path)) {
-                       if (enlistment_root)
-                               strbuf_add(enlistment_root, path.buf, len);
-
-                       enlistment_found = 1;
-                       break;
-               }
 
-               /* reset to original path */
-               strbuf_setlen(&path, len);
-
-               /* check if currently in workdir */
-               if (is_nonbare_repository_dir(&path)) {
-                       if (enlistment_root) {
-                               /*
-                                * If the worktree's directory's name is `src`, the enlistment is the
-                                * parent directory, otherwise it is identical to the worktree.
-                                */
-                               root = strip_path_suffix(path.buf, "src");
-                               strbuf_addstr(enlistment_root, root ? root : path.buf);
-                               free(root);
-                       }
+       /* check if currently in enlistment root with src/ workdir */
+       len = path.len;
+       strbuf_addstr(&path, "/src");
+       if (is_nonbare_repository_dir(&path)) {
+               enlistment_is_repo_parent = 1;
+               if (chdir(path.buf) < 0)
+                       die_errno(_("could not switch to '%s'"), path.buf);
+       }
+       strbuf_setlen(&path, len);
 
-                       enlistment_found = 1;
-                       break;
-               }
-       } while (strbuf_parent_directory(&path));
+       setup_git_directory();
 
-       if (!enlistment_found)
-               die(_("could not find enlistment root"));
+       if (!the_repository->worktree)
+               die(_("Scalar enlistments require a worktree"));
 
-       if (chdir(path.buf) < 0)
-               die_errno(_("could not switch to '%s'"), path.buf);
+       if (enlistment_root) {
+               if (enlistment_is_repo_parent)
+                       strbuf_addbuf(enlistment_root, &path);
+               else
+                       strbuf_addstr(enlistment_root, the_repository->worktree);
+       }
 
        strbuf_release(&path);
-       setup_git_directory();
 }
 
 static int run_git(const char *arg, ...)
@@ -115,13 +86,39 @@ static int run_git(const char *arg, ...)
        return res;
 }
 
+struct scalar_config {
+       const char *key;
+       const char *value;
+       int overwrite_on_reconfigure;
+};
+
+static int set_scalar_config(const struct scalar_config *config, int reconfigure)
+{
+       char *value = NULL;
+       int res;
+
+       if ((reconfigure && config->overwrite_on_reconfigure) ||
+           git_config_get_string(config->key, &value)) {
+               trace2_data_string("scalar", the_repository, config->key, "created");
+               res = git_config_set_gently(config->key, config->value);
+       } else {
+               trace2_data_string("scalar", the_repository, config->key, "exists");
+               res = 0;
+       }
+
+       free(value);
+       return res;
+}
+
+static int have_fsmonitor_support(void)
+{
+       return fsmonitor_ipc__is_supported() &&
+              fsm_settings__get_reason(the_repository) == FSMONITOR_REASON_OK;
+}
+
 static int set_recommended_config(int reconfigure)
 {
-       struct {
-               const char *key;
-               const char *value;
-               int overwrite_on_reconfigure;
-       } config[] = {
+       struct scalar_config config[] = {
                /* Required */
                { "am.keepCR", "true", 1 },
                { "core.FSCache", "true", 1 },
@@ -175,17 +172,16 @@ static int set_recommended_config(int reconfigure)
        char *value;
 
        for (i = 0; config[i].key; i++) {
-               if ((reconfigure && config[i].overwrite_on_reconfigure) ||
-                   git_config_get_string(config[i].key, &value)) {
-                       trace2_data_string("scalar", the_repository, config[i].key, "created");
-                       if (git_config_set_gently(config[i].key,
-                                                 config[i].value) < 0)
-                               return error(_("could not configure %s=%s"),
-                                            config[i].key, config[i].value);
-               } else {
-                       trace2_data_string("scalar", the_repository, config[i].key, "exists");
-                       free(value);
-               }
+               if (set_scalar_config(config + i, reconfigure))
+                       return error(_("could not configure %s=%s"),
+                                    config[i].key, config[i].value);
+       }
+
+       if (have_fsmonitor_support()) {
+               struct scalar_config fsmonitor = { "core.fsmonitor", "true" };
+               if (set_scalar_config(&fsmonitor, reconfigure))
+                       return error(_("could not configure %s=%s"),
+                                    fsmonitor.key, fsmonitor.value);
        }
 
        /*
@@ -236,123 +232,55 @@ static int add_or_remove_enlistment(int add)
                       "scalar.repo", the_repository->worktree, NULL);
 }
 
-static int register_dir(void)
+static int start_fsmonitor_daemon(void)
 {
-       int res = add_or_remove_enlistment(1);
+       assert(have_fsmonitor_support());
 
-       if (!res)
-               res = set_recommended_config(0);
+       if (fsmonitor_ipc__get_state() != IPC_STATE__LISTENING)
+               return run_git("fsmonitor--daemon", "start", NULL);
 
-       if (!res)
-               res = toggle_maintenance(1);
-
-       return res;
+       return 0;
 }
 
-static int unregister_dir(void)
+static int stop_fsmonitor_daemon(void)
 {
-       int res = 0;
+       assert(have_fsmonitor_support());
 
-       if (toggle_maintenance(0) < 0)
-               res = -1;
+       if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+               return run_git("fsmonitor--daemon", "stop", NULL);
 
-       if (add_or_remove_enlistment(0) < 0)
-               res = -1;
-
-       return res;
+       return 0;
 }
 
-static int add_directory_to_archiver(struct strvec *archiver_args,
-                                         const char *path, int recurse)
+static int register_dir(void)
 {
-       int at_root = !*path;
-       DIR *dir = opendir(at_root ? "." : path);
-       struct dirent *e;
-       struct strbuf buf = STRBUF_INIT;
-       size_t len;
-       int res = 0;
+       if (add_or_remove_enlistment(1))
+               return error(_("could not add enlistment"));
 
-       if (!dir)
-               return error_errno(_("could not open directory '%s'"), path);
-
-       if (!at_root)
-               strbuf_addf(&buf, "%s/", path);
-       len = buf.len;
-       strvec_pushf(archiver_args, "--prefix=%s", buf.buf);
-
-       while (!res && (e = readdir(dir))) {
-               if (!strcmp(".", e->d_name) || !strcmp("..", e->d_name))
-                       continue;
-
-               strbuf_setlen(&buf, len);
-               strbuf_addstr(&buf, e->d_name);
-
-               if (e->d_type == DT_REG)
-                       strvec_pushf(archiver_args, "--add-file=%s", buf.buf);
-               else if (e->d_type != DT_DIR)
-                       warning(_("skipping '%s', which is neither file nor "
-                                 "directory"), buf.buf);
-               else if (recurse &&
-                        add_directory_to_archiver(archiver_args,
-                                                  buf.buf, recurse) < 0)
-                       res = -1;
+       if (set_recommended_config(0))
+               return error(_("could not set recommended config"));
+
+       if (toggle_maintenance(1))
+               return error(_("could not turn on maintenance"));
+
+       if (have_fsmonitor_support() && start_fsmonitor_daemon()) {
+               return error(_("could not start the FSMonitor daemon"));
        }
 
-       closedir(dir);
-       strbuf_release(&buf);
-       return res;
+       return 0;
 }
 
-#ifndef WIN32
-#include <sys/statvfs.h>
-#endif
-
-static int get_disk_info(struct strbuf *out)
+static int unregister_dir(void)
 {
-#ifdef WIN32
-       struct strbuf buf = STRBUF_INIT;
-       char volume_name[MAX_PATH], fs_name[MAX_PATH];
-       DWORD serial_number, component_length, flags;
-       ULARGE_INTEGER avail2caller, total, avail;
-
-       strbuf_realpath(&buf, ".", 1);
-       if (!GetDiskFreeSpaceExA(buf.buf, &avail2caller, &total, &avail)) {
-               error(_("could not determine free disk size for '%s'"),
-                     buf.buf);
-               strbuf_release(&buf);
-               return -1;
-       }
+       int res = 0;
 
-       strbuf_setlen(&buf, offset_1st_component(buf.buf));
-       if (!GetVolumeInformationA(buf.buf, volume_name, sizeof(volume_name),
-                                  &serial_number, &component_length, &flags,
-                                  fs_name, sizeof(fs_name))) {
-               error(_("could not get info for '%s'"), buf.buf);
-               strbuf_release(&buf);
-               return -1;
-       }
-       strbuf_addf(out, "Available space on '%s': ", buf.buf);
-       strbuf_humanise_bytes(out, avail2caller.QuadPart);
-       strbuf_addch(out, '\n');
-       strbuf_release(&buf);
-#else
-       struct strbuf buf = STRBUF_INIT;
-       struct statvfs stat;
+       if (toggle_maintenance(0))
+               res = error(_("could not turn off maintenance"));
 
-       strbuf_realpath(&buf, ".", 1);
-       if (statvfs(buf.buf, &stat) < 0) {
-               error_errno(_("could not determine free disk size for '%s'"),
-                           buf.buf);
-               strbuf_release(&buf);
-               return -1;
-       }
+       if (add_or_remove_enlistment(0))
+               res = error(_("could not remove enlistment"));
 
-       strbuf_addf(out, "Available space on '%s': ", buf.buf);
-       strbuf_humanise_bytes(out, st_mult(stat.f_bsize, stat.f_bavail));
-       strbuf_addf(out, " (mount flags 0x%lx)\n", stat.f_flag);
-       strbuf_release(&buf);
-#endif
-       return 0;
+       return res;
 }
 
 /* printf-style interface, expects `<key>=<value>` argument */
@@ -431,25 +359,35 @@ static int delete_enlistment(struct strbuf *enlistment)
 {
 #ifdef WIN32
        struct strbuf parent = STRBUF_INIT;
+       size_t offset;
+       char *path_sep;
 #endif
 
        if (unregister_dir())
-               die(_("failed to unregister repository"));
+               return error(_("failed to unregister repository"));
 
 #ifdef WIN32
        /*
         * Change the current directory to one outside of the enlistment so
         * that we may delete everything underneath it.
         */
-       strbuf_addbuf(&parent, enlistment);
-       strbuf_parent_directory(&parent);
-       if (chdir(parent.buf) < 0)
-               die_errno(_("could not switch to '%s'"), parent.buf);
+       offset = offset_1st_component(enlistment->buf);
+       path_sep = find_last_dir_sep(enlistment->buf + offset);
+       strbuf_add(&parent, enlistment->buf,
+                  path_sep ? path_sep - enlistment->buf : offset);
+       if (chdir(parent.buf) < 0) {
+               int res = error_errno(_("could not switch to '%s'"), parent.buf);
+               strbuf_release(&parent);
+               return res;
+       }
        strbuf_release(&parent);
 #endif
 
+       if (have_fsmonitor_support() && stop_fsmonitor_daemon())
+               return error(_("failed to stop the FSMonitor daemon"));
+
        if (remove_dir_recursively(enlistment, 0))
-               die(_("failed to delete enlistment directory"));
+               return error(_("failed to delete enlistment directory"));
 
        return 0;
 }
@@ -595,83 +533,6 @@ cleanup:
        return res;
 }
 
-static void dir_file_stats_objects(const char *full_path, size_t full_path_len,
-                                  const char *file_name, void *data)
-{
-       struct strbuf *buf = data;
-       struct stat st;
-
-       if (!stat(full_path, &st))
-               strbuf_addf(buf, "%-70s %16" PRIuMAX "\n", file_name,
-                           (uintmax_t)st.st_size);
-}
-
-static int dir_file_stats(struct object_directory *object_dir, void *data)
-{
-       struct strbuf *buf = data;
-
-       strbuf_addf(buf, "Contents of %s:\n", object_dir->path);
-
-       for_each_file_in_pack_dir(object_dir->path, dir_file_stats_objects,
-                                 data);
-
-       return 0;
-}
-
-static int count_files(char *path)
-{
-       DIR *dir = opendir(path);
-       struct dirent *e;
-       int count = 0;
-
-       if (!dir)
-               return 0;
-
-       while ((e = readdir(dir)) != NULL)
-               if (!is_dot_or_dotdot(e->d_name) && e->d_type == DT_REG)
-                       count++;
-
-       closedir(dir);
-       return count;
-}
-
-static void loose_objs_stats(struct strbuf *buf, const char *path)
-{
-       DIR *dir = opendir(path);
-       struct dirent *e;
-       int count;
-       int total = 0;
-       unsigned char c;
-       struct strbuf count_path = STRBUF_INIT;
-       size_t base_path_len;
-
-       if (!dir)
-               return;
-
-       strbuf_addstr(buf, "Object directory stats for ");
-       strbuf_add_absolute_path(buf, path);
-       strbuf_addstr(buf, ":\n");
-
-       strbuf_add_absolute_path(&count_path, path);
-       strbuf_addch(&count_path, '/');
-       base_path_len = count_path.len;
-
-       while ((e = readdir(dir)) != NULL)
-               if (!is_dot_or_dotdot(e->d_name) &&
-                   e->d_type == DT_DIR && strlen(e->d_name) == 2 &&
-                   !hex_to_bytes(&c, e->d_name, 1)) {
-                       strbuf_setlen(&count_path, base_path_len);
-                       strbuf_addstr(&count_path, e->d_name);
-                       total += (count = count_files(count_path.buf));
-                       strbuf_addf(buf, "%s : %7d files\n", e->d_name, count);
-               }
-
-       strbuf_addf(buf, "Total: %d loose objects", total);
-
-       strbuf_release(&count_path);
-       closedir(dir);
-}
-
 static int cmd_diagnose(int argc, const char **argv)
 {
        struct option options[] = {
@@ -681,107 +542,19 @@ static int cmd_diagnose(int argc, const char **argv)
                N_("scalar diagnose [<enlistment>]"),
                NULL
        };
-       struct strbuf zip_path = STRBUF_INIT;
-       struct strvec archiver_args = STRVEC_INIT;
-       char **argv_copy = NULL;
-       int stdout_fd = -1, archiver_fd = -1;
-       time_t now = time(NULL);
-       struct tm tm;
-       struct strbuf path = STRBUF_INIT, buf = STRBUF_INIT;
+       struct strbuf diagnostics_root = STRBUF_INIT;
        int res = 0;
 
        argc = parse_options(argc, argv, NULL, options,
                             usage, 0);
 
-       setup_enlistment_directory(argc, argv, usage, options, &zip_path);
-
-       strbuf_addstr(&zip_path, "/.scalarDiagnostics/scalar_");
-       strbuf_addftime(&zip_path,
-                       "%Y%m%d_%H%M%S", localtime_r(&now, &tm), 0, 0);
-       strbuf_addstr(&zip_path, ".zip");
-       switch (safe_create_leading_directories(zip_path.buf)) {
-       case SCLD_EXISTS:
-       case SCLD_OK:
-               break;
-       default:
-               error_errno(_("could not create directory for '%s'"),
-                           zip_path.buf);
-               goto diagnose_cleanup;
-       }
-       stdout_fd = dup(1);
-       if (stdout_fd < 0) {
-               res = error_errno(_("could not duplicate stdout"));
-               goto diagnose_cleanup;
-       }
-
-       archiver_fd = xopen(zip_path.buf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
-       if (archiver_fd < 0 || dup2(archiver_fd, 1) < 0) {
-               res = error_errno(_("could not redirect output"));
-               goto diagnose_cleanup;
-       }
-
-       init_zip_archiver();
-       strvec_pushl(&archiver_args, "scalar-diagnose", "--format=zip", NULL);
-
-       strbuf_reset(&buf);
-       strbuf_addstr(&buf, "Collecting diagnostic info\n\n");
-       get_version_info(&buf, 1);
-
-       strbuf_addf(&buf, "Enlistment root: %s\n", the_repository->worktree);
-       get_disk_info(&buf);
-       write_or_die(stdout_fd, buf.buf, buf.len);
-       strvec_pushf(&archiver_args,
-                    "--add-virtual-file=diagnostics.log:%.*s",
-                    (int)buf.len, buf.buf);
-
-       strbuf_reset(&buf);
-       strbuf_addstr(&buf, "--add-virtual-file=packs-local.txt:");
-       dir_file_stats(the_repository->objects->odb, &buf);
-       foreach_alt_odb(dir_file_stats, &buf);
-       strvec_push(&archiver_args, buf.buf);
+       setup_enlistment_directory(argc, argv, usage, options, &diagnostics_root);
+       strbuf_addstr(&diagnostics_root, "/.scalarDiagnostics");
 
-       strbuf_reset(&buf);
-       strbuf_addstr(&buf, "--add-virtual-file=objects-local.txt:");
-       loose_objs_stats(&buf, ".git/objects");
-       strvec_push(&archiver_args, buf.buf);
-
-       if ((res = add_directory_to_archiver(&archiver_args, ".git", 0)) ||
-           (res = add_directory_to_archiver(&archiver_args, ".git/hooks", 0)) ||
-           (res = add_directory_to_archiver(&archiver_args, ".git/info", 0)) ||
-           (res = add_directory_to_archiver(&archiver_args, ".git/logs", 1)) ||
-           (res = add_directory_to_archiver(&archiver_args, ".git/objects/info", 0)))
-               goto diagnose_cleanup;
-
-       strvec_pushl(&archiver_args, "--prefix=",
-                    oid_to_hex(the_hash_algo->empty_tree), "--", NULL);
-
-       /* `write_archive()` modifies the `argv` passed to it. Let it. */
-       argv_copy = xmemdupz(archiver_args.v,
-                            sizeof(char *) * archiver_args.nr);
-       res = write_archive(archiver_args.nr, (const char **)argv_copy, NULL,
-                           the_repository, NULL, 0);
-       if (res) {
-               error(_("failed to write archive"));
-               goto diagnose_cleanup;
-       }
-
-       if (!res)
-               fprintf(stderr, "\n"
-                      "Diagnostics complete.\n"
-                      "All of the gathered info is captured in '%s'\n",
-                      zip_path.buf);
-
-diagnose_cleanup:
-       if (archiver_fd >= 0) {
-               close(1);
-               dup2(stdout_fd, 1);
-       }
-       free(argv_copy);
-       strvec_clear(&archiver_args);
-       strbuf_release(&zip_path);
-       strbuf_release(&path);
-       strbuf_release(&buf);
+       res = run_git("diagnose", "--mode=all", "-s", "%Y%m%d_%H%M%S",
+                     "-o", diagnostics_root.buf, NULL);
 
+       strbuf_release(&diagnostics_root);
        return res;
 }
 
@@ -1046,6 +819,25 @@ static int cmd_delete(int argc, const char **argv)
        return res;
 }
 
+static int cmd_help(int argc, const char **argv)
+{
+       struct option options[] = {
+               OPT_END(),
+       };
+       const char * const usage[] = {
+               "scalar help",
+               NULL
+       };
+
+       argc = parse_options(argc, argv, NULL, options,
+                            usage, 0);
+
+       if (argc != 0)
+               usage_with_options(usage, options);
+
+       return run_git("help", "scalar", NULL);
+}
+
 static int cmd_version(int argc, const char **argv)
 {
        int verbose = 0, build_options = 0;
@@ -1085,6 +877,7 @@ static struct {
        { "run", cmd_run },
        { "reconfigure", cmd_reconfigure },
        { "delete", cmd_delete },
+       { "help", cmd_help },
        { "version", cmd_version },
        { "diagnose", cmd_diagnose },
        { NULL, NULL},
index bc0fcdbb000769935e9f080164d8e02e81dbb8b3..f2e19838c9c342b3b9d6df5e9bf24d0add0d47d1 100644 (file)
@@ -84,6 +84,8 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised,
                strvec_push(&po.args, "--progress");
        if (is_repository_shallow(the_repository))
                strvec_push(&po.args, "--shallow");
+       if (args->disable_bitmaps)
+               strvec_push(&po.args, "--no-use-bitmap-index");
        po.in = -1;
        po.out = args->stateless_rpc ? -1 : fd;
        po.git_cmd = 1;
@@ -264,7 +266,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
        return ret;
 }
 
-static int sideband_demux(int in, int out, void *data)
+static int sideband_demux(int in UNUSED, int out, void *data)
 {
        int *fd = data, ret;
        if (async_with_fork())
@@ -487,6 +489,7 @@ int send_pack(struct send_pack_args *args,
        struct async demux;
        const char *push_cert_nonce = NULL;
        struct packet_reader reader;
+       int use_bitmaps;
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -498,6 +501,9 @@ int send_pack(struct send_pack_args *args,
        if (push_negotiate)
                get_commons_through_negotiation(args->url, remote_refs, &commons);
 
+       if (!git_config_get_bool("push.usebitmaps", &use_bitmaps))
+               args->disable_bitmaps = !use_bitmaps;
+
        git_config_get_bool("transfer.advertisesid", &advertise_sid);
 
        /* Does the other end support the reporting? */
index e148fcd960994b1724f8d09c4ea4897b1cf069f0..7edb80596c7b0edf607ea5cd0f01315106d02b73 100644 (file)
@@ -26,7 +26,8 @@ struct send_pack_args {
                /* One of the SEND_PACK_PUSH_CERT_* constants. */
                push_cert:2,
                stateless_rpc:1,
-               atomic:1;
+               atomic:1,
+               disable_bitmaps:1;
        const struct string_list *push_options;
 };
 
index 61a8e0020d596de550127d5b66f076034636239c..d26ede83c4b2beb1f14ee368bfc30958c4db6d07 100644 (file)
@@ -35,6 +35,8 @@
 #include "commit-reach.h"
 #include "rebase-interactive.h"
 #include "reset.h"
+#include "branch.h"
+#include "log-tree.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -147,6 +149,20 @@ static GIT_PATH_FUNC(rebase_path_squash_onto, "rebase-merge/squash-onto")
  */
 static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
 
+/*
+ * The update-refs file stores a list of refs that will be updated at the end
+ * of the rebase sequence. The 'update-ref <ref>' commands in the todo file
+ * update the OIDs for the refs in this file, but the refs are not updated
+ * until the end of the rebase sequence.
+ *
+ * rebase_path_update_refs() returns the path to this file for a given
+ * worktree directory. For the current worktree, pass the_repository->gitdir.
+ */
+static char *rebase_path_update_refs(const char *wt_git_dir)
+{
+       return xstrfmt("%s/rebase-merge/update-refs", wt_git_dir);
+}
+
 /*
  * The following files are written by git-rebase just after parsing the
  * command-line.
@@ -169,6 +185,30 @@ static GIT_PATH_FUNC(rebase_path_no_reschedule_failed_exec, "rebase-merge/no-res
 static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
 static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
 
+/**
+ * A 'struct update_refs_record' represents a value in the update-refs
+ * list. We use a string_list to map refs to these (before, after) pairs.
+ */
+struct update_ref_record {
+       struct object_id before;
+       struct object_id after;
+};
+
+static struct update_ref_record *init_update_ref_record(const char *ref)
+{
+       struct update_ref_record *rec;
+
+       CALLOC_ARRAY(rec, 1);
+
+       oidcpy(&rec->before, null_oid());
+       oidcpy(&rec->after, null_oid());
+
+       /* This may fail, but that's fine, we will keep the null OID. */
+       read_ref(ref, &rec->before);
+
+       return rec;
+}
+
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
        struct replay_opts *opts = cb;
@@ -497,7 +537,7 @@ static struct tree *empty_tree(struct repository *r)
 static int error_dirty_index(struct repository *repo, struct replay_opts *opts)
 {
        if (repo_read_index_unmerged(repo))
-               return error_resolve_conflict(_(action_name(opts)));
+               return error_resolve_conflict(action_name(opts));
 
        error(_("your local changes would be overwritten by %s."),
                _(action_name(opts)));
@@ -535,7 +575,7 @@ static int fast_forward_to(struct repository *r,
        if (checkout_fast_forward(r, from, to, 1))
                return -1; /* the callee should have complained already */
 
-       strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
+       strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
@@ -1689,20 +1729,21 @@ static struct {
        char c;
        const char *str;
 } todo_command_info[] = {
-       { 'p', "pick" },
-       { 0,   "revert" },
-       { 'e', "edit" },
-       { 'r', "reword" },
-       { 'f', "fixup" },
-       { 's', "squash" },
-       { 'x', "exec" },
-       { 'b', "break" },
-       { 'l', "label" },
-       { 't', "reset" },
-       { 'm', "merge" },
-       { 0,   "noop" },
-       { 'd', "drop" },
-       { 0,   NULL }
+       [TODO_PICK] = { 'p', "pick" },
+       [TODO_REVERT] = { 0,   "revert" },
+       [TODO_EDIT] = { 'e', "edit" },
+       [TODO_REWORD] = { 'r', "reword" },
+       [TODO_FIXUP] = { 'f', "fixup" },
+       [TODO_SQUASH] = { 's', "squash" },
+       [TODO_EXEC] = { 'x', "exec" },
+       [TODO_BREAK] = { 'b', "break" },
+       [TODO_LABEL] = { 'l', "label" },
+       [TODO_RESET] = { 't', "reset" },
+       [TODO_MERGE] = { 'm', "merge" },
+       [TODO_UPDATE_REF] = { 'u', "update-ref" },
+       [TODO_NOOP] = { 0,   "noop" },
+       [TODO_DROP] = { 'd', "drop" },
+       [TODO_COMMENT] = { 0,   NULL },
 };
 
 static const char *command_to_string(const enum todo_command command)
@@ -2381,7 +2422,7 @@ static int read_and_refresh_cache(struct repository *r,
        if (repo_read_index(r) < 0) {
                rollback_lock_file(&index_lock);
                return error(_("git %s: failed to read the index"),
-                       _(action_name(opts)));
+                       action_name(opts));
        }
        refresh_index(r->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
 
@@ -2389,7 +2430,7 @@ static int read_and_refresh_cache(struct repository *r,
                if (write_locked_index(r->index, &index_lock,
                                       COMMIT_LOCK | SKIP_IF_UNCHANGED)) {
                        return error(_("git %s: failed to refresh the index"),
-                               _(action_name(opts)));
+                               action_name(opts));
                }
        }
 
@@ -2481,7 +2522,7 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
                             command_to_string(item->command));
 
        if (item->command == TODO_EXEC || item->command == TODO_LABEL ||
-           item->command == TODO_RESET) {
+           item->command == TODO_RESET || item->command == TODO_UPDATE_REF) {
                item->commit = NULL;
                item->arg_offset = bol - buf;
                item->arg_len = (int)(eol - bol);
@@ -3712,7 +3753,7 @@ static int do_reset(struct repository *r,
        init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
 
        if (repo_read_index_unmerged(r)) {
-               ret = error_resolve_conflict(_(action_name(opts)));
+               ret = error_resolve_conflict(action_name(opts));
                goto cleanup;
        }
 
@@ -4081,6 +4122,221 @@ leave_merge:
        return ret;
 }
 
+static int write_update_refs_state(struct string_list *refs_to_oids)
+{
+       int result = 0;
+       struct lock_file lock = LOCK_INIT;
+       FILE *fp = NULL;
+       struct string_list_item *item;
+       char *path;
+
+       if (!refs_to_oids->nr)
+               return 0;
+
+       path = rebase_path_update_refs(the_repository->gitdir);
+
+       if (safe_create_leading_directories(path)) {
+               result = error(_("unable to create leading directories of %s"),
+                              path);
+               goto cleanup;
+       }
+
+       if (hold_lock_file_for_update(&lock, path, 0) < 0) {
+               result = error(_("another 'rebase' process appears to be running; "
+                                "'%s.lock' already exists"),
+                              path);
+               goto cleanup;
+       }
+
+       fp = fdopen_lock_file(&lock, "w");
+       if (!fp) {
+               result = error_errno(_("could not open '%s' for writing"), path);
+               rollback_lock_file(&lock);
+               goto cleanup;
+       }
+
+       for_each_string_list_item(item, refs_to_oids) {
+               struct update_ref_record *rec = item->util;
+               fprintf(fp, "%s\n%s\n%s\n", item->string,
+                       oid_to_hex(&rec->before), oid_to_hex(&rec->after));
+       }
+
+       result = commit_lock_file(&lock);
+
+cleanup:
+       free(path);
+       return result;
+}
+
+/*
+ * Parse the update-refs file for the current rebase, then remove the
+ * refs that do not appear in the todo_list (and have not had updated
+ * values stored) and add refs that are in the todo_list but not
+ * represented in the update-refs file.
+ *
+ * If there are changes to the update-refs list, then write the new state
+ * to disk.
+ */
+void todo_list_filter_update_refs(struct repository *r,
+                                 struct todo_list *todo_list)
+{
+       int i;
+       int updated = 0;
+       struct string_list update_refs = STRING_LIST_INIT_DUP;
+
+       sequencer_get_update_refs_state(r->gitdir, &update_refs);
+
+       /*
+        * For each item in the update_refs list, if it has no updated
+        * value and does not appear in the todo_list, then remove it
+        * from the update_refs list.
+        */
+       for (i = 0; i < update_refs.nr; i++) {
+               int j;
+               int found = 0;
+               const char *ref = update_refs.items[i].string;
+               size_t reflen = strlen(ref);
+               struct update_ref_record *rec = update_refs.items[i].util;
+
+               /* OID already stored as updated. */
+               if (!is_null_oid(&rec->after))
+                       continue;
+
+               for (j = 0; !found && j < todo_list->total_nr; j++) {
+                       struct todo_item *item = &todo_list->items[j];
+                       const char *arg = todo_list->buf.buf + item->arg_offset;
+
+                       if (item->command != TODO_UPDATE_REF)
+                               continue;
+
+                       if (item->arg_len != reflen ||
+                           strncmp(arg, ref, reflen))
+                               continue;
+
+                       found = 1;
+               }
+
+               if (!found) {
+                       free(update_refs.items[i].string);
+                       free(update_refs.items[i].util);
+
+                       update_refs.nr--;
+                       MOVE_ARRAY(update_refs.items + i, update_refs.items + i + 1, update_refs.nr - i);
+
+                       updated = 1;
+                       i--;
+               }
+       }
+
+       /*
+        * For each todo_item, check if its ref is in the update_refs list.
+        * If not, then add it as an un-updated ref.
+        */
+       for (i = 0; i < todo_list->total_nr; i++) {
+               struct todo_item *item = &todo_list->items[i];
+               const char *arg = todo_list->buf.buf + item->arg_offset;
+               int j, found = 0;
+
+               if (item->command != TODO_UPDATE_REF)
+                       continue;
+
+               for (j = 0; !found && j < update_refs.nr; j++) {
+                       const char *ref = update_refs.items[j].string;
+
+                       found = strlen(ref) == item->arg_len &&
+                               !strncmp(ref, arg, item->arg_len);
+               }
+
+               if (!found) {
+                       struct string_list_item *inserted;
+                       struct strbuf argref = STRBUF_INIT;
+
+                       strbuf_add(&argref, arg, item->arg_len);
+                       inserted = string_list_insert(&update_refs, argref.buf);
+                       inserted->util = init_update_ref_record(argref.buf);
+                       strbuf_release(&argref);
+                       updated = 1;
+               }
+       }
+
+       if (updated)
+               write_update_refs_state(&update_refs);
+       string_list_clear(&update_refs, 1);
+}
+
+static int do_update_ref(struct repository *r, const char *refname)
+{
+       struct string_list_item *item;
+       struct string_list list = STRING_LIST_INIT_DUP;
+
+       if (sequencer_get_update_refs_state(r->gitdir, &list))
+               return -1;
+
+       for_each_string_list_item(item, &list) {
+               if (!strcmp(item->string, refname)) {
+                       struct update_ref_record *rec = item->util;
+                       if (read_ref("HEAD", &rec->after))
+                               return -1;
+                       break;
+               }
+       }
+
+       write_update_refs_state(&list);
+       string_list_clear(&list, 1);
+       return 0;
+}
+
+static int do_update_refs(struct repository *r, int quiet)
+{
+       int res = 0;
+       struct string_list_item *item;
+       struct string_list refs_to_oids = STRING_LIST_INIT_DUP;
+       struct ref_store *refs = get_main_ref_store(r);
+       struct strbuf update_msg = STRBUF_INIT;
+       struct strbuf error_msg = STRBUF_INIT;
+
+       if ((res = sequencer_get_update_refs_state(r->gitdir, &refs_to_oids)))
+               return res;
+
+       for_each_string_list_item(item, &refs_to_oids) {
+               struct update_ref_record *rec = item->util;
+               int loop_res;
+
+               loop_res = refs_update_ref(refs, "rewritten during rebase",
+                                          item->string,
+                                          &rec->after, &rec->before,
+                                          0, UPDATE_REFS_MSG_ON_ERR);
+               res |= loop_res;
+
+               if (quiet)
+                       continue;
+
+               if (loop_res)
+                       strbuf_addf(&error_msg, "\t%s\n", item->string);
+               else
+                       strbuf_addf(&update_msg, "\t%s\n", item->string);
+       }
+
+       if (!quiet &&
+           (update_msg.len || error_msg.len)) {
+               fprintf(stderr,
+                       _("Updated the following refs with %s:\n%s"),
+                       "--update-refs",
+                       update_msg.buf);
+
+               if (res)
+                       fprintf(stderr,
+                               _("Failed to update the following refs with %s:\n%s"),
+                               "--update-refs",
+                               error_msg.buf);
+       }
+
+       string_list_clear(&refs_to_oids, 1);
+       strbuf_release(&update_msg);
+       strbuf_release(&error_msg);
+       return res;
+}
+
 static int is_final_fixup(struct todo_list *todo_list)
 {
        int i = todo_list->current;
@@ -4456,6 +4712,12 @@ static int pick_commits(struct repository *r,
                                return error_with_patch(r, item->commit,
                                                        arg, item->arg_len,
                                                        opts, res, 0);
+               } else if (item->command == TODO_UPDATE_REF) {
+                       struct strbuf ref = STRBUF_INIT;
+                       strbuf_add(&ref, arg, item->arg_len);
+                       if ((res = do_update_ref(r, ref.buf)))
+                               reschedule = 1;
+                       strbuf_release(&ref);
                } else if (!is_noop(item->command))
                        return error(_("unknown command %d"), item->command);
 
@@ -4591,6 +4853,9 @@ cleanup_head_ref:
 
                strbuf_release(&buf);
                strbuf_release(&head_ref);
+
+               if (do_update_refs(r, opts->quiet))
+                       return -1;
        }
 
        /*
@@ -4989,7 +5254,8 @@ struct labels_entry {
        char label[FLEX_ARRAY];
 };
 
-static int labels_cmp(const void *fndata, const struct hashmap_entry *eptr,
+static int labels_cmp(const void *fndata UNUSED,
+                     const struct hashmap_entry *eptr,
                      const struct hashmap_entry *entry_or_key, const void *key)
 {
        const struct labels_entry *a, *b;
@@ -5638,10 +5904,135 @@ static int skip_unnecessary_picks(struct repository *r,
        return 0;
 }
 
+struct todo_add_branch_context {
+       struct todo_item *items;
+       size_t items_nr;
+       size_t items_alloc;
+       struct strbuf *buf;
+       struct commit *commit;
+       struct string_list refs_to_oids;
+};
+
+static int add_decorations_to_list(const struct commit *commit,
+                                  struct todo_add_branch_context *ctx)
+{
+       const struct name_decoration *decoration = get_name_decoration(&commit->object);
+       const char *head_ref = resolve_ref_unsafe("HEAD",
+                                                 RESOLVE_REF_READING,
+                                                 NULL,
+                                                 NULL);
+
+       while (decoration) {
+               struct todo_item *item;
+               const char *path;
+               size_t base_offset = ctx->buf->len;
+
+               /*
+                * If the branch is the current HEAD, then it will be
+                * updated by the default rebase behavior.
+                */
+               if (head_ref && !strcmp(head_ref, decoration->name)) {
+                       decoration = decoration->next;
+                       continue;
+               }
+
+               ALLOC_GROW(ctx->items,
+                       ctx->items_nr + 1,
+                       ctx->items_alloc);
+               item = &ctx->items[ctx->items_nr];
+               memset(item, 0, sizeof(*item));
+
+               /* If the branch is checked out, then leave a comment instead. */
+               if ((path = branch_checked_out(decoration->name))) {
+                       item->command = TODO_COMMENT;
+                       strbuf_addf(ctx->buf, "# Ref %s checked out at '%s'\n",
+                                   decoration->name, path);
+               } else {
+                       struct string_list_item *sti;
+                       item->command = TODO_UPDATE_REF;
+                       strbuf_addf(ctx->buf, "%s\n", decoration->name);
+
+                       sti = string_list_insert(&ctx->refs_to_oids,
+                                                decoration->name);
+                       sti->util = init_update_ref_record(decoration->name);
+               }
+
+               item->offset_in_buf = base_offset;
+               item->arg_offset = base_offset;
+               item->arg_len = ctx->buf->len - base_offset;
+               ctx->items_nr++;
+
+               decoration = decoration->next;
+       }
+
+       return 0;
+}
+
+/*
+ * For each 'pick' command, find out if the commit has a decoration in
+ * refs/heads/. If so, then add a 'label for-update-refs/' command.
+ */
+static int todo_list_add_update_ref_commands(struct todo_list *todo_list)
+{
+       int i, res;
+       static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
+       static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
+       static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
+       struct decoration_filter decoration_filter = {
+               .include_ref_pattern = &decorate_refs_include,
+               .exclude_ref_pattern = &decorate_refs_exclude,
+               .exclude_ref_config_pattern = &decorate_refs_exclude_config,
+       };
+       struct todo_add_branch_context ctx = {
+               .buf = &todo_list->buf,
+               .refs_to_oids = STRING_LIST_INIT_DUP,
+       };
+
+       ctx.items_alloc = 2 * todo_list->nr + 1;
+       ALLOC_ARRAY(ctx.items, ctx.items_alloc);
+
+       string_list_append(&decorate_refs_include, "refs/heads/");
+       load_ref_decorations(&decoration_filter, 0);
+
+       for (i = 0; i < todo_list->nr; ) {
+               struct todo_item *item = &todo_list->items[i];
+
+               /* insert ith item into new list */
+               ALLOC_GROW(ctx.items,
+                          ctx.items_nr + 1,
+                          ctx.items_alloc);
+
+               ctx.items[ctx.items_nr++] = todo_list->items[i++];
+
+               if (item->commit) {
+                       ctx.commit = item->commit;
+                       add_decorations_to_list(item->commit, &ctx);
+               }
+       }
+
+       res = write_update_refs_state(&ctx.refs_to_oids);
+
+       string_list_clear(&ctx.refs_to_oids, 1);
+
+       if (res) {
+               /* we failed, so clean up the new list. */
+               free(ctx.items);
+               return res;
+       }
+
+       free(todo_list->items);
+       todo_list->items = ctx.items;
+       todo_list->nr = ctx.items_nr;
+       todo_list->alloc = ctx.items_alloc;
+
+       return 0;
+}
+
 int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
                    const char *shortrevisions, const char *onto_name,
                    struct commit *onto, const struct object_id *orig_head,
                    struct string_list *commands, unsigned autosquash,
+                   unsigned update_refs,
                    struct todo_list *todo_list)
 {
        char shortonto[GIT_MAX_HEXSZ + 1];
@@ -5660,6 +6051,9 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
                item->arg_len = item->arg_offset = item->flags = item->offset_in_buf = 0;
        }
 
+       if (update_refs && todo_list_add_update_ref_commands(todo_list))
+               return -1;
+
        if (autosquash && todo_list_rearrange_squash(todo_list))
                return -1;
 
@@ -5738,7 +6132,7 @@ struct subject2item_entry {
        char subject[FLEX_ARRAY];
 };
 
-static int subject2item_cmp(const void *fndata,
+static int subject2item_cmp(const void *fndata UNUSED,
                            const struct hashmap_entry *eptr,
                            const struct hashmap_entry *entry_or_key,
                            const void *key)
@@ -5936,3 +6330,54 @@ int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
 
        return 0;
 }
+
+int sequencer_get_update_refs_state(const char *wt_dir,
+                                   struct string_list *refs)
+{
+       int result = 0;
+       FILE *fp = NULL;
+       struct strbuf ref = STRBUF_INIT;
+       struct strbuf hash = STRBUF_INIT;
+       struct update_ref_record *rec = NULL;
+
+       char *path = rebase_path_update_refs(wt_dir);
+
+       fp = fopen(path, "r");
+       if (!fp)
+               goto cleanup;
+
+       while (strbuf_getline(&ref, fp) != EOF) {
+               struct string_list_item *item;
+
+               CALLOC_ARRAY(rec, 1);
+
+               if (strbuf_getline(&hash, fp) == EOF ||
+                   get_oid_hex(hash.buf, &rec->before)) {
+                       warning(_("update-refs file at '%s' is invalid"),
+                                 path);
+                       result = -1;
+                       goto cleanup;
+               }
+
+               if (strbuf_getline(&hash, fp) == EOF ||
+                   get_oid_hex(hash.buf, &rec->after)) {
+                       warning(_("update-refs file at '%s' is invalid"),
+                                 path);
+                       result = -1;
+                       goto cleanup;
+               }
+
+               item = string_list_insert(refs, ref.buf);
+               item->util = rec;
+               rec = NULL;
+       }
+
+cleanup:
+       if (fp)
+               fclose(fp);
+       free(path);
+       free(rec);
+       strbuf_release(&ref);
+       strbuf_release(&hash);
+       return result;
+}
index 698599fe4e915ed4acbbf17995b0df201b723321..563fe5993340a0d0a18b148d4280c1d5a3f8d307 100644 (file)
@@ -96,6 +96,7 @@ enum todo_command {
        TODO_LABEL,
        TODO_RESET,
        TODO_MERGE,
+       TODO_UPDATE_REF,
        /* commands that do nothing but are counted for reporting progress */
        TODO_NOOP,
        TODO_DROP,
@@ -132,6 +133,18 @@ void todo_list_release(struct todo_list *todo_list);
 const char *todo_item_get_arg(struct todo_list *todo_list,
                              struct todo_item *item);
 
+/*
+ * Parse the update-refs file for the current rebase, then remove the
+ * refs that do not appear in the todo_list (and have not had updated
+ * values stored) and add refs that are in the todo_list but not
+ * represented in the update-refs file.
+ *
+ * If there are changes to the update-refs list, then write the new state
+ * to disk.
+ */
+void todo_list_filter_update_refs(struct repository *r,
+                                 struct todo_list *todo_list);
+
 /* Call this to setup defaults before parsing command line options */
 void sequencer_init_config(struct replay_opts *opts);
 int sequencer_pick_revisions(struct repository *repo,
@@ -167,6 +180,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
                    const char *shortrevisions, const char *onto_name,
                    struct commit *onto, const struct object_id *orig_head,
                    struct string_list *commands, unsigned autosquash,
+                   unsigned update_refs,
                    struct todo_list *todo_list);
 int todo_list_rearrange_squash(struct todo_list *todo_list);
 
@@ -233,4 +247,13 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose);
 int sequencer_get_last_command(struct repository* r,
                               enum replay_action *action);
 int sequencer_determine_whence(struct repository *r, enum commit_whence *whence);
+
+/**
+ * Append the set of ref-OID pairs that are currently stored for the 'git
+ * rebase --update-refs' feature if such a rebase is currently happening.
+ *
+ * Localized to a worktree's git dir.
+ */
+int sequencer_get_update_refs_state(const char *wt_dir, struct string_list *refs);
+
 #endif /* SEQUENCER_H */
index 7701d7c20a12af53d2f91737f12f3dfb97ac59e9..0ec6c0c16546a7a2ebb45a8e8a03e3270cedf214 100644 (file)
@@ -147,7 +147,8 @@ out:
 }
 
 static int add_info_ref(const char *path, const struct object_id *oid,
-                       int flag, void *cb_data)
+                       int flag UNUSED,
+                       void *cb_data)
 {
        struct update_info_ctx *uic = cb_data;
        struct object *o = parse_object(the_repository, oid);
diff --git a/setup.c b/setup.c
index 640f6ea4d03f58147fa51e59d213adac9c37d3ba..cefd5f63c4680f7f656084ef72f74784f86e4562 100644 (file)
--- a/setup.c
+++ b/setup.c
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 static int work_tree_config_is_bogus;
+enum allowed_bare_repo {
+       ALLOWED_BARE_REPO_EXPLICIT = 0,
+       ALLOWED_BARE_REPO_ALL,
+};
 
 static struct startup_info the_startup_info;
 struct startup_info *startup_info = &the_startup_info;
@@ -1156,11 +1160,51 @@ static int ensure_valid_ownership(const char *gitfile,
         * constant regardless of what failed above. data.is_safe should be
         * initialized to false, and might be changed by the callback.
         */
-       read_very_early_config(safe_directory_cb, &data);
+       git_protected_config(safe_directory_cb, &data);
 
        return data.is_safe;
 }
 
+static int allowed_bare_repo_cb(const char *key, const char *value, void *d)
+{
+       enum allowed_bare_repo *allowed_bare_repo = d;
+
+       if (strcasecmp(key, "safe.bareRepository"))
+               return 0;
+
+       if (!strcmp(value, "explicit")) {
+               *allowed_bare_repo = ALLOWED_BARE_REPO_EXPLICIT;
+               return 0;
+       }
+       if (!strcmp(value, "all")) {
+               *allowed_bare_repo = ALLOWED_BARE_REPO_ALL;
+               return 0;
+       }
+       return -1;
+}
+
+static enum allowed_bare_repo get_allowed_bare_repo(void)
+{
+       enum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL;
+       git_protected_config(allowed_bare_repo_cb, &result);
+       return result;
+}
+
+static const char *allowed_bare_repo_to_string(
+       enum allowed_bare_repo allowed_bare_repo)
+{
+       switch (allowed_bare_repo) {
+       case ALLOWED_BARE_REPO_EXPLICIT:
+               return "explicit";
+       case ALLOWED_BARE_REPO_ALL:
+               return "all";
+       default:
+               BUG("invalid allowed_bare_repo %d",
+                   allowed_bare_repo);
+       }
+       return NULL;
+}
+
 enum discovery_result {
        GIT_DIR_NONE = 0,
        GIT_DIR_EXPLICIT,
@@ -1170,7 +1214,8 @@ enum discovery_result {
        GIT_DIR_HIT_CEILING = -1,
        GIT_DIR_HIT_MOUNT_POINT = -2,
        GIT_DIR_INVALID_GITFILE = -3,
-       GIT_DIR_INVALID_OWNERSHIP = -4
+       GIT_DIR_INVALID_OWNERSHIP = -4,
+       GIT_DIR_DISALLOWED_BARE = -5,
 };
 
 /*
@@ -1300,6 +1345,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
                }
 
                if (is_git_directory(dir->buf)) {
+                       if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
+                               return GIT_DIR_DISALLOWED_BARE;
                        if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
                                return GIT_DIR_INVALID_OWNERSHIP;
                        strbuf_addstr(gitdir, ".");
@@ -1448,6 +1495,14 @@ const char *setup_git_directory_gently(int *nongit_ok)
                }
                *nongit_ok = 1;
                break;
+       case GIT_DIR_DISALLOWED_BARE:
+               if (!nongit_ok) {
+                       die(_("cannot use bare repository '%s' (safe.bareRepository is '%s')"),
+                           dir.buf,
+                           allowed_bare_repo_to_string(get_allowed_bare_repo()));
+               }
+               *nongit_ok = 1;
+               break;
        case GIT_DIR_NONE:
                /*
                 * As a safeguard against setup_git_directory_gently_1 returning
diff --git a/sha256/nettle.h b/sha256/nettle.h
new file mode 100644 (file)
index 0000000..b63e1c8
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SHA256_NETTLE_H
+#define SHA256_NETTLE_H
+
+#include <nettle/sha2.h>
+
+typedef struct sha256_ctx nettle_SHA256_CTX;
+
+static inline void nettle_SHA256_Init(nettle_SHA256_CTX *ctx)
+{
+       sha256_init(ctx);
+}
+
+static inline void nettle_SHA256_Update(nettle_SHA256_CTX *ctx,
+                                       const void *data,
+                                       size_t len)
+{
+       sha256_update(ctx, len, data);
+}
+
+static inline void nettle_SHA256_Final(unsigned char *digest,
+                                      nettle_SHA256_CTX *ctx)
+{
+       sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
+}
+
+#define platform_SHA256_CTX nettle_SHA256_CTX
+#define platform_SHA256_Init nettle_SHA256_Init
+#define platform_SHA256_Update nettle_SHA256_Update
+#define platform_SHA256_Final nettle_SHA256_Final
+
+#endif
index 8cb768ee5f886fdafcf16221e5878b8fc080f253..17f9bcdb5f38270c4f5910a2e1c930432ba350e5 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -604,8 +604,10 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
        free(tmp);
 }
 
-static int mark_uninteresting(const char *refname, const struct object_id *oid,
-                             int flags, void *cb_data)
+static int mark_uninteresting(const char *refname UNUSED,
+                             const struct object_id *oid,
+                             int flags UNUSED,
+                             void *cb_data UNUSED)
 {
        struct commit *commit = lookup_commit_reference_gently(the_repository,
                                                               oid, 1);
@@ -715,8 +717,10 @@ struct commit_array {
        int nr, alloc;
 };
 
-static int add_ref(const char *refname, const struct object_id *oid,
-                  int flags, void *cb_data)
+static int add_ref(const char *refname UNUSED,
+                  const struct object_id *oid,
+                  int flags UNUSED,
+                  void *cb_data)
 {
        struct commit_array *ca = cb_data;
        ALLOC_GROW(ca->commits, ca->nr + 1, ca->alloc);
index 4330192e9c363df8103e27d5ccb06769adfbc0b8..33f43edbf9a6b2e156f15628869c1d6c1755cd6f 100644 (file)
@@ -70,6 +70,7 @@ ifndef V
        QUIET_HDR      = @echo '   ' HDR $(<:hcc=h);
        QUIET_RC       = @echo '   ' RC $@;
        QUIET_SPATCH   = @echo '   ' SPATCH $<;
+       QUIET_SPATCH_T = @echo '   ' SPATCH TEST $(@:.build/%=%);
 
 ## Used in "Documentation/Makefile"
        QUIET_ASCIIDOC  = @echo '   ' ASCIIDOC $@;
index dd9eb85527ab5a2f5007907b2cb3ce76ed5ccc3f..0890b1405c5cc6888396bac8558549ebdb2e2977 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -436,7 +436,7 @@ void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
 
 size_t strbuf_expand_literal_cb(struct strbuf *sb,
                                const char *placeholder,
-                               void *context)
+                               void *context UNUSED)
 {
        int ch;
 
index fe54665d86e72a3400a6f60f610a5264bc0f0667..7b2f8b2b9384b8c9c516be005c9b9f811348b0c7 100644 (file)
@@ -328,9 +328,9 @@ static int close_istream_pack_non_delta(struct git_istream *st)
 }
 
 static int open_istream_pack_non_delta(struct git_istream *st,
-                                      struct repository *r,
-                                      const struct object_id *oid,
-                                      enum object_type *type)
+                                      struct repository *r UNUSED,
+                                      const struct object_id *oid UNUSED,
+                                      enum object_type *type UNUSED)
 {
        struct pack_window *window;
        enum object_type in_pack_type;
index ee48635708219e66bf03bad6f5e9100c766d2fb7..c7b9c52174c54c5bc1986e927e0be67bf1983625 100644 (file)
--- a/strmap.c
+++ b/strmap.c
@@ -2,10 +2,10 @@
 #include "strmap.h"
 #include "mem-pool.h"
 
-int cmp_strmap_entry(const void *hashmap_cmp_fn_data,
+int cmp_strmap_entry(const void *hashmap_cmp_fn_data UNUSED,
                     const struct hashmap_entry *entry1,
                     const struct hashmap_entry *entry2,
-                    const void *keydata)
+                    const void *keydata UNUSED)
 {
        const struct strmap_entry *e1, *e2;
 
index cae56ae6b8077547a35eda62bb3d250ca6d6510b..6d4232294dbee7ad2928b0ac12e1860dcf04a12d 100644 (file)
@@ -5,10 +5,10 @@
 #include "sigchain.h"
 #include "pkt-line.h"
 
-int cmd2process_cmp(const void *unused_cmp_data,
+int cmd2process_cmp(const void *cmp_data UNUSED,
                    const struct hashmap_entry *eptr,
                    const struct hashmap_entry *entry_or_key,
-                   const void *unused_keydata)
+                   const void *keydata UNUSED)
 {
        const struct subprocess_entry *e1, *e2;
 
index c2ac7e7bf39b2eb9c273a11fb457b0dbc7369aa6..cd7ee236a120bc99d91ec615e94a6cd4240937f0 100644 (file)
@@ -38,10 +38,10 @@ enum lookup_type {
        lookup_path
 };
 
-static int config_path_cmp(const void *unused_cmp_data,
+static int config_path_cmp(const void *cmp_data UNUSED,
                           const struct hashmap_entry *eptr,
                           const struct hashmap_entry *entry_or_key,
-                          const void *unused_keydata)
+                          const void *keydata UNUSED)
 {
        const struct submodule_entry *a, *b;
 
@@ -52,10 +52,10 @@ static int config_path_cmp(const void *unused_cmp_data,
               !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
 }
 
-static int config_name_cmp(const void *unused_cmp_data,
+static int config_name_cmp(const void *cmp_data UNUSED,
                           const struct hashmap_entry *eptr,
                           const struct hashmap_entry *entry_or_key,
-                          const void *unused_keydata)
+                          const void *keydata UNUSED)
 {
        const struct submodule_entry *a, *b;
 
index 4e299f578f96f17110114f441e6370085c452e40..bf7a2c79183e17eb3b6c4c8487938de6c01be565 100644 (file)
@@ -213,7 +213,8 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
 }
 
 /* Cheap function that only determines if we're interested in submodules at all */
-int git_default_submodule_config(const char *var, const char *value, void *cb)
+int git_default_submodule_config(const char *var, const char *value,
+                                void *cb UNUSED)
 {
        if (!strcmp(var, "submodule.recurse")) {
                int v = git_config_bool(var, value) ?
@@ -415,10 +416,9 @@ int parse_submodule_update_strategy(const char *value,
        return 0;
 }
 
-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)
+const char *submodule_update_type_to_string(enum submodule_update_type type)
 {
-       struct strbuf sb = STRBUF_INIT;
-       switch (s->type) {
+       switch (type) {
        case SM_UPDATE_CHECKOUT:
                return "checkout";
        case SM_UPDATE_MERGE:
@@ -428,12 +428,11 @@ const char *submodule_strategy_to_string(const struct submodule_update_strategy
        case SM_UPDATE_NONE:
                return "none";
        case SM_UPDATE_UNSPECIFIED:
-               return NULL;
        case SM_UPDATE_COMMAND:
-               strbuf_addf(&sb, "!%s", s->command);
-               return strbuf_detach(&sb, NULL);
+               BUG("init_submodule() should handle type %d", type);
+       default:
+               BUG("unexpected update strategy type: %d", type);
        }
-       return NULL;
 }
 
 void handle_ignore_submodules_arg(struct diff_options *diffopt,
@@ -940,8 +939,9 @@ static void free_submodules_data(struct string_list *submodules)
        string_list_clear(submodules, 1);
 }
 
-static int has_remote(const char *refname, const struct object_id *oid,
-                     int flags, void *cb_data)
+static int has_remote(const char *refname UNUSED,
+                     const struct object_id *oid UNUSED,
+                     int flags UNUSED, void *cb_data UNUSED)
 {
        return 1;
 }
@@ -1243,8 +1243,9 @@ int push_unpushed_submodules(struct repository *r,
        return ret;
 }
 
-static int append_oid_to_array(const char *ref, const struct object_id *oid,
-                              int flags, void *data)
+static int append_oid_to_array(const char *ref UNUSED,
+                              const struct object_id *oid,
+                              int flags UNUSED, void *data)
 {
        struct oid_array *array = data;
        oid_array_append(array, oid);
@@ -2374,7 +2375,7 @@ void absorb_git_dir_into_superproject(const char *path,
                cp.no_stdin = 1;
                strvec_pushl(&cp.args, "--super-prefix", sb.buf,
                             "submodule--helper",
-                            "absorb-git-dirs", NULL);
+                            "absorbgitdirs", NULL);
                prepare_submodule_repo_env(&cp.env);
                if (run_command(&cp))
                        die(_("could not recurse into submodule '%s'"), path);
@@ -2388,7 +2389,7 @@ int get_superproject_working_tree(struct strbuf *buf)
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf sb = STRBUF_INIT;
        struct strbuf one_up = STRBUF_INIT;
-       const char *cwd = xgetcwd();
+       char *cwd = xgetcwd();
        int ret = 0;
        const char *subpath;
        int code;
@@ -2451,6 +2452,7 @@ int get_superproject_working_tree(struct strbuf *buf)
                ret = 1;
                free(super_wt);
        }
+       free(cwd);
        strbuf_release(&sb);
 
        code = finish_command(&cp);
index bfaa9da1868af5e201db3a831b283924cf7c8a89..6a9fec6de1159f0389df2391c2d18e8d5fd7d297 100644 (file)
@@ -72,7 +72,7 @@ void die_path_inside_submodule(struct index_state *istate,
 enum submodule_update_type parse_submodule_update_type(const char *value);
 int parse_submodule_update_strategy(const char *value,
                                    struct submodule_update_strategy *dst);
-const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
+const char *submodule_update_type_to_string(enum submodule_update_type type);
 void handle_ignore_submodules_arg(struct diff_options *, const char *);
 void show_submodule_diff_summary(struct diff_options *o, const char *path,
                            struct object_id *one, struct object_id *two,
index 056ce55dcc92c923ce560ef61a0b2888d799c450..882782a519c97b65d2a6d487ac6849a540015fe4 100644 (file)
@@ -35,16 +35,22 @@ TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY))
 CHAINLINTTMP_SQ = $(subst ','\'',$(CHAINLINTTMP))
 
 T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
-TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh))
 THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh)))
+TLIBS = $(sort $(wildcard lib-*.sh)) annotate-tests.sh
 TPERF = $(sort $(wildcard perf/p[0-9][0-9][0-9][0-9]-*.sh))
+TINTEROP = $(sort $(wildcard interop/i[0-9][0-9][0-9][0-9]-*.sh))
 CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.test)))
-CHAINLINT = sed -f chainlint.sed
+CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl
+
+# `test-chainlint` (which is a dependency of `test-lint`, `test` and `prove`)
+# checks all tests in all scripts via a single invocation, so tell individual
+# scripts not to "chainlint" themselves
+CHAINLINTSUPPRESS = GIT_TEST_CHAIN_LINT=0 && export GIT_TEST_CHAIN_LINT &&
 
 all: $(DEFAULT_TEST_TARGET)
 
 test: pre-clean check-chainlint $(TEST_LINT)
-       $(MAKE) aggregate-results-and-cleanup
+       $(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup
 
 failed:
        @failed=$$(cd '$(TEST_RESULTS_DIRECTORY_SQ)' && \
@@ -53,7 +59,7 @@ failed:
        test -z "$$failed" || $(MAKE) $$failed
 
 prove: pre-clean check-chainlint $(TEST_LINT)
-       @echo "*** prove ***"; $(PROVE) --exec '$(TEST_SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
+       @echo "*** prove ***"; $(CHAINLINTSUPPRESS) $(PROVE) --exec '$(TEST_SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
        $(MAKE) clean-except-prove-cache
 
 $(T):
@@ -63,10 +69,11 @@ pre-clean:
        $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
 
 clean-except-prove-cache: clean-chainlint
-       $(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
+       $(RM) -r 'trash directory'.*
        $(RM) -r valgrind/bin
 
 clean: clean-except-prove-cache
+       $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
        $(RM) .prove
 
 clean-chainlint:
@@ -74,13 +81,35 @@ clean-chainlint:
 
 check-chainlint:
        @mkdir -p '$(CHAINLINTTMP_SQ)' && \
-       sed -e '/^# LINT: /d' $(patsubst %,chainlint/%.test,$(CHAINLINTTESTS)) >'$(CHAINLINTTMP_SQ)'/tests && \
-       sed -e '/^[     ]*$$/d' $(patsubst %,chainlint/%.expect,$(CHAINLINTTESTS)) >'$(CHAINLINTTMP_SQ)'/expect && \
-       $(CHAINLINT) '$(CHAINLINTTMP_SQ)'/tests | grep -v '^[   ]*$$' >'$(CHAINLINTTMP_SQ)'/actual && \
-       diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual
+       for i in $(CHAINLINTTESTS); do \
+               echo "test_expect_success '$$i' '" && \
+               sed -e '/^# LINT: /d' chainlint/$$i.test && \
+               echo "'"; \
+       done >'$(CHAINLINTTMP_SQ)'/tests && \
+       { \
+               echo "# chainlint: $(CHAINLINTTMP_SQ)/tests" && \
+               for i in $(CHAINLINTTESTS); do \
+                       echo "# chainlint: $$i" && \
+                       sed -e '/^[     ]*$$/d' chainlint/$$i.expect; \
+               done \
+       } >'$(CHAINLINTTMP_SQ)'/expect && \
+       $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests | \
+               grep -v '^[     ]*$$' >'$(CHAINLINTTMP_SQ)'/actual && \
+       if test -f ../GIT-BUILD-OPTIONS; then \
+               . ../GIT-BUILD-OPTIONS; \
+       fi && \
+       if test -x ../git$$X; then \
+               DIFFW="../git$$X --no-pager diff -w --no-index"; \
+       else \
+               DIFFW="diff -w -u"; \
+       fi && \
+       $$DIFFW '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual
 
 test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \
        test-lint-filenames
+ifneq ($(GIT_TEST_CHAIN_LINT),0)
+test-lint: test-chainlint
+endif
 
 test-lint-duplicates:
        @dups=`echo $(T) $(TPERF) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \
@@ -103,6 +132,9 @@ test-lint-filenames:
                test -z "$$bad" || { \
                echo >&2 "non-portable file name(s): $$bad"; exit 1; }
 
+test-chainlint:
+       @$(CHAINLINT) $(T) $(TLIBS) $(TPERF) $(TINTEROP)
+
 aggregate-results-and-cleanup: $(T)
        $(MAKE) aggregate-results
        $(MAKE) clean
@@ -112,13 +144,11 @@ aggregate-results:
                echo "$$f"; \
        done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh
 
-gitweb-test:
-       $(MAKE) $(TGITWEB)
-
 valgrind:
        $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind"
 
 perf:
        $(MAKE) -C perf/ all
 
-.PHONY: pre-clean $(T) aggregate-results clean valgrind perf check-chainlint clean-chainlint
+.PHONY: pre-clean $(T) aggregate-results clean valgrind perf \
+       check-chainlint clean-chainlint test-chainlint
index 4f9981cf5e3c29d255ed0d2a3f399cd992e961c7..979b2d4833d983ef50a71c3a9394bd9c8b6e4051 100644 (file)
--- a/t/README
+++ b/t/README
@@ -196,11 +196,6 @@ appropriately before running "make". Short options can be bundled, i.e.
        this feature by setting the GIT_TEST_CHAIN_LINT environment
        variable to "1" or "0", respectively.
 
-       A few test scripts disable some of the more advanced
-       chain-linting detection in the name of efficiency. You can
-       override this by setting the GIT_TEST_CHAIN_LINT_HARDER
-       environment variable to "1".
-
 --stress::
        Run the test script repeatedly in multiple parallel jobs until
        one of them fails.  Useful for reproducing rare failures in
@@ -366,12 +361,47 @@ excluded as so much relies on it, but this might change in the future.
 GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole
 test suite. Accept any boolean values that are accepted by git-config.
 
-GIT_TEST_PASSING_SANITIZE_LEAK=<boolean> when compiled with
-SANITIZE=leak will run only those tests that have whitelisted
-themselves as passing with no memory leaks. Tests can be whitelisted
-by setting "TEST_PASSES_SANITIZE_LEAK=true" before sourcing
-"test-lib.sh" itself at the top of the test script. This test mode is
-used by the "linux-leaks" CI target.
+GIT_TEST_PASSING_SANITIZE_LEAK=true skips those tests that haven't
+declared themselves as leak-free by setting
+"TEST_PASSES_SANITIZE_LEAK=true" before sourcing "test-lib.sh". This
+test mode is used by the "linux-leaks" CI target.
+
+GIT_TEST_PASSING_SANITIZE_LEAK=check checks that our
+"TEST_PASSES_SANITIZE_LEAK=true" markings are current. Rather than
+skipping those tests that haven't set "TEST_PASSES_SANITIZE_LEAK=true"
+before sourcing "test-lib.sh" this mode runs them with
+"--invert-exit-code". This is used to check that there's a one-to-one
+mapping between "TEST_PASSES_SANITIZE_LEAK=true" and those tests that
+pass under "SANITIZE=leak". This is especially useful when testing a
+series that fixes various memory leaks with "git rebase -x".
+
+GIT_TEST_SANITIZE_LEAK_LOG=true will log memory leaks to
+"test-results/$TEST_NAME.leak/trace.*" files. The logs include a
+"dedup_token" (see +"ASAN_OPTIONS=help=1 ./git") and other options to
+make logs +machine-readable.
+
+With GIT_TEST_SANITIZE_LEAK_LOG=true we'll look at the leak logs
+before exiting and exit on failure if the logs showed that we had a
+memory leak, even if the test itself would have otherwise passed. This
+allows us to catch e.g. missing &&-chaining. This is especially useful
+when combined with "GIT_TEST_PASSING_SANITIZE_LEAK", see below.
+
+GIT_TEST_PASSING_SANITIZE_LEAK=check when combined with "--immediate"
+will run to completion faster, and result in the same failing
+tests. The only practical reason to run
+GIT_TEST_PASSING_SANITIZE_LEAK=check without "--immediate" is to
+combine it with "GIT_TEST_SANITIZE_LEAK_LOG=true". If we stop at the
+first failing test case our leak logs won't show subsequent leaks we
+might have run into.
+
+GIT_TEST_PASSING_SANITIZE_LEAK=(true|check) will not catch all memory
+leaks unless combined with GIT_TEST_SANITIZE_LEAK_LOG=true. Some tests
+run "git" (or "test-tool" etc.) without properly checking the exit
+code, or git will invoke itself and fail to ferry the abort() exit
+code to the original caller. When the two modes are combined we'll
+look at the "test-results/$TEST_NAME.leak/trace.*" files at the end of
+the test run to see if had memory leaks which the test itself didn't
+catch.
 
 GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version'
 default to n.
@@ -935,32 +965,6 @@ see test-lib-functions.sh for the full list and their options.
            test_done
        fi
 
- - test_external [<prereq>] <message> <external> <script>
-
-   Execute a <script> with an <external> interpreter (like perl). This
-   was added for tests like t9700-perl-git.sh which do most of their
-   work in an external test script.
-
-       test_external \
-           'GitwebCache::*FileCache*' \
-           perl "$TEST_DIRECTORY"/t9503/test_cache_interface.pl
-
-   If the test is outputting its own TAP you should set the
-   test_external_has_tap variable somewhere before calling the first
-   test_external* function. See t9700-perl-git.sh for an example.
-
-       # The external test will outputs its own plan
-       test_external_has_tap=1
-
- - test_external_without_stderr [<prereq>] <message> <external> <script>
-
-   Like test_external but fail if there's any output on stderr,
-   instead of checking the exit code.
-
-       test_external_without_stderr \
-           'Perl API' \
-           perl "$TEST_DIRECTORY"/t9700/test.pl
-
  - test_expect_code <exit-code> <command>
 
    Run a command and ensure that it exits with the given exit code.
index cc01d891504eb117eb9c367ebc4e89b516157012..f1b9a6ce4daee67c7aadfd2a9d19cb1c4033224c 100644 (file)
@@ -153,7 +153,7 @@ test_expect_success 'blame evil merge' '
 
 test_expect_success 'blame huge graft' '
        test_when_finished "git checkout branch2" &&
-       test_when_finished "rm -f .git/info/grafts" &&
+       test_when_finished "rm -rf .git/info" &&
        graft= &&
        for i in 0 1 2
        do
@@ -168,6 +168,7 @@ test_expect_success 'blame huge graft' '
                        graft="$graft$commit " || return 1
                done
        done &&
+       mkdir .git/info &&
        printf "%s " $graft >.git/info/grafts &&
        check_count -h 00 01 1 10 1
 '
diff --git a/t/chainlint.pl b/t/chainlint.pl
new file mode 100755 (executable)
index 0000000..976db4b
--- /dev/null
@@ -0,0 +1,770 @@
+#!/usr/bin/env perl
+#
+# Copyright (c) 2021-2022 Eric Sunshine <sunshine@sunshineco.com>
+#
+# This tool scans shell scripts for test definitions and checks those tests for
+# problems, such as broken &&-chains, which might hide bugs in the tests
+# themselves or in behaviors being exercised by the tests.
+#
+# Input arguments are pathnames of shell scripts containing test definitions,
+# or globs referencing a collection of scripts. For each problem discovered,
+# the pathname of the script containing the test is printed along with the test
+# name and the test body with a `?!FOO?!` annotation at the location of each
+# detected problem, where "FOO" is a tag such as "AMP" which indicates a broken
+# &&-chain. Returns zero if no problems are discovered, otherwise non-zero.
+
+use warnings;
+use strict;
+use Config;
+use File::Glob;
+use Getopt::Long;
+
+my $jobs = -1;
+my $show_stats;
+my $emit_all;
+
+# Lexer tokenizes POSIX shell scripts. It is roughly modeled after section 2.3
+# "Token Recognition" of POSIX chapter 2 "Shell Command Language". Although
+# similar to lexical analyzers for other languages, this one differs in a few
+# substantial ways due to quirks of the shell command language.
+#
+# For instance, in many languages, newline is just whitespace like space or
+# TAB, but in shell a newline is a command separator, thus a distinct lexical
+# token. A newline is significant and returned as a distinct token even at the
+# end of a shell comment.
+#
+# In other languages, `1+2` would typically be scanned as three tokens
+# (`1`, `+`, and `2`), but in shell it is a single token. However, the similar
+# `1 + 2`, which embeds whitepace, is scanned as three token in shell, as well.
+# In shell, several characters with special meaning lose that meaning when not
+# surrounded by whitespace. For instance, the negation operator `!` is special
+# when standing alone surrounded by whitespace; whereas in `foo!uucp` it is
+# just a plain character in the longer token "foo!uucp". In many other
+# languages, `"string"/foo:'string'` might be scanned as five tokens ("string",
+# `/`, `foo`, `:`, and 'string'), but in shell, it is just a single token.
+#
+# The lexical analyzer for the shell command language is also somewhat unusual
+# in that it recursively invokes the parser to handle the body of `$(...)`
+# expressions which can contain arbitrary shell code. Such expressions may be
+# encountered both inside and outside of double-quoted strings.
+#
+# The lexical analyzer is responsible for consuming shell here-doc bodies which
+# extend from the line following a `<<TAG` operator until a line consisting
+# solely of `TAG`. Here-doc consumption begins when a newline is encountered.
+# It is legal for multiple here-doc `<<TAG` operators to be present on a single
+# line, in which case their bodies must be present one following the next, and
+# are consumed in the (left-to-right) order the `<<TAG` operators appear on the
+# line. A special complication is that the bodies of all here-docs must be
+# consumed when the newline is encountered even if the parse context depth has
+# changed. For instance, in `cat <<A && x=$(cat <<B &&\n`, bodies of here-docs
+# "A" and "B" must be consumed even though "A" was introduced outside the
+# recursive parse context in which "B" was introduced and in which the newline
+# is encountered.
+package Lexer;
+
+sub new {
+       my ($class, $parser, $s) = @_;
+       bless {
+               parser => $parser,
+               buff => $s,
+               heretags => []
+       } => $class;
+}
+
+sub scan_heredoc_tag {
+       my $self = shift @_;
+       ${$self->{buff}} =~ /\G(-?)/gc;
+       my $indented = $1;
+       my $tag = $self->scan_token();
+       $tag =~ s/['"\\]//g;
+       push(@{$self->{heretags}}, $indented ? "\t$tag" : "$tag");
+       return "<<$indented$tag";
+}
+
+sub scan_op {
+       my ($self, $c) = @_;
+       my $b = $self->{buff};
+       return $c unless $$b =~ /\G(.)/sgc;
+       my $cc = $c . $1;
+       return scan_heredoc_tag($self) if $cc eq '<<';
+       return $cc if $cc =~ /^(?:&&|\|\||>>|;;|<&|>&|<>|>\|)$/;
+       pos($$b)--;
+       return $c;
+}
+
+sub scan_sqstring {
+       my $self = shift @_;
+       ${$self->{buff}} =~ /\G([^']*'|.*\z)/sgc;
+       return "'" . $1;
+}
+
+sub scan_dqstring {
+       my $self = shift @_;
+       my $b = $self->{buff};
+       my $s = '"';
+       while (1) {
+               # slurp up non-special characters
+               $s .= $1 if $$b =~ /\G([^"\$\\]+)/gc;
+               # handle special characters
+               last unless $$b =~ /\G(.)/sgc;
+               my $c = $1;
+               $s .= '"', last if $c eq '"';
+               $s .= '$' . $self->scan_dollar(), next if $c eq '$';
+               if ($c eq '\\') {
+                       $s .= '\\', last unless $$b =~ /\G(.)/sgc;
+                       $c = $1;
+                       next if $c eq "\n"; # line splice
+                       # backslash escapes only $, `, ", \ in dq-string
+                       $s .= '\\' unless $c =~ /^[\$`"\\]$/;
+                       $s .= $c;
+                       next;
+               }
+               die("internal error scanning dq-string '$c'\n");
+       }
+       return $s;
+}
+
+sub scan_balanced {
+       my ($self, $c1, $c2) = @_;
+       my $b = $self->{buff};
+       my $depth = 1;
+       my $s = $c1;
+       while ($$b =~ /\G([^\Q$c1$c2\E]*(?:[\Q$c1$c2\E]|\z))/gc) {
+               $s .= $1;
+               $depth++, next if $s =~ /\Q$c1\E$/;
+               $depth--;
+               last if $depth == 0;
+       }
+       return $s;
+}
+
+sub scan_subst {
+       my $self = shift @_;
+       my @tokens = $self->{parser}->parse(qr/^\)$/);
+       $self->{parser}->next_token(); # closing ")"
+       return @tokens;
+}
+
+sub scan_dollar {
+       my $self = shift @_;
+       my $b = $self->{buff};
+       return $self->scan_balanced('(', ')') if $$b =~ /\G\((?=\()/gc; # $((...))
+       return '(' . join(' ', $self->scan_subst()) . ')' if $$b =~ /\G\(/gc; # $(...)
+       return $self->scan_balanced('{', '}') if $$b =~ /\G\{/gc; # ${...}
+       return $1 if $$b =~ /\G(\w+)/gc; # $var
+       return $1 if $$b =~ /\G([@*#?$!0-9-])/gc; # $*, $1, $$, etc.
+       return '';
+}
+
+sub swallow_heredocs {
+       my $self = shift @_;
+       my $b = $self->{buff};
+       my $tags = $self->{heretags};
+       while (my $tag = shift @$tags) {
+               my $indent = $tag =~ s/^\t// ? '\\s*' : '';
+               $$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc;
+       }
+}
+
+sub scan_token {
+       my $self = shift @_;
+       my $b = $self->{buff};
+       my $token = '';
+RESTART:
+       $$b =~ /\G[ \t]+/gc; # skip whitespace (but not newline)
+       return "\n" if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment
+       while (1) {
+               # slurp up non-special characters
+               $token .= $1 if $$b =~ /\G([^\\;&|<>(){}'"\$\s]+)/gc;
+               # handle special characters
+               last unless $$b =~ /\G(.)/sgc;
+               my $c = $1;
+               last if $c =~ /^[ \t]$/; # whitespace ends token
+               pos($$b)--, last if length($token) && $c =~ /^[;&|<>(){}\n]$/;
+               $token .= $self->scan_sqstring(), next if $c eq "'";
+               $token .= $self->scan_dqstring(), next if $c eq '"';
+               $token .= $c . $self->scan_dollar(), next if $c eq '$';
+               $self->swallow_heredocs(), $token = $c, last if $c eq "\n";
+               $token = $self->scan_op($c), last if $c =~ /^[;&|<>]$/;
+               $token = $c, last if $c =~ /^[(){}]$/;
+               if ($c eq '\\') {
+                       $token .= '\\', last unless $$b =~ /\G(.)/sgc;
+                       $c = $1;
+                       next if $c eq "\n" && length($token); # line splice
+                       goto RESTART if $c eq "\n"; # line splice
+                       $token .= '\\' . $c;
+                       next;
+               }
+               die("internal error scanning character '$c'\n");
+       }
+       return length($token) ? $token : undef;
+}
+
+# ShellParser parses POSIX shell scripts (with minor extensions for Bash). It
+# is a recursive descent parser very roughly modeled after section 2.10 "Shell
+# Grammar" of POSIX chapter 2 "Shell Command Language".
+package ShellParser;
+
+sub new {
+       my ($class, $s) = @_;
+       my $self = bless {
+               buff => [],
+               stop => [],
+               output => []
+       } => $class;
+       $self->{lexer} = Lexer->new($self, $s);
+       return $self;
+}
+
+sub next_token {
+       my $self = shift @_;
+       return pop(@{$self->{buff}}) if @{$self->{buff}};
+       return $self->{lexer}->scan_token();
+}
+
+sub untoken {
+       my $self = shift @_;
+       push(@{$self->{buff}}, @_);
+}
+
+sub peek {
+       my $self = shift @_;
+       my $token = $self->next_token();
+       return undef unless defined($token);
+       $self->untoken($token);
+       return $token;
+}
+
+sub stop_at {
+       my ($self, $token) = @_;
+       return 1 unless defined($token);
+       my $stop = ${$self->{stop}}[-1] if @{$self->{stop}};
+       return defined($stop) && $token =~ $stop;
+}
+
+sub expect {
+       my ($self, $expect) = @_;
+       my $token = $self->next_token();
+       return $token if defined($token) && $token eq $expect;
+       push(@{$self->{output}}, "?!ERR?! expected '$expect' but found '" . (defined($token) ? $token : "<end-of-input>") . "'\n");
+       $self->untoken($token) if defined($token);
+       return ();
+}
+
+sub optional_newlines {
+       my $self = shift @_;
+       my @tokens;
+       while (my $token = $self->peek()) {
+               last unless $token eq "\n";
+               push(@tokens, $self->next_token());
+       }
+       return @tokens;
+}
+
+sub parse_group {
+       my $self = shift @_;
+       return ($self->parse(qr/^}$/),
+               $self->expect('}'));
+}
+
+sub parse_subshell {
+       my $self = shift @_;
+       return ($self->parse(qr/^\)$/),
+               $self->expect(')'));
+}
+
+sub parse_case_pattern {
+       my $self = shift @_;
+       my @tokens;
+       while (defined(my $token = $self->next_token())) {
+               push(@tokens, $token);
+               last if $token eq ')';
+       }
+       return @tokens;
+}
+
+sub parse_case {
+       my $self = shift @_;
+       my @tokens;
+       push(@tokens,
+            $self->next_token(), # subject
+            $self->optional_newlines(),
+            $self->expect('in'),
+            $self->optional_newlines());
+       while (1) {
+               my $token = $self->peek();
+               last unless defined($token) && $token ne 'esac';
+               push(@tokens,
+                    $self->parse_case_pattern(),
+                    $self->optional_newlines(),
+                    $self->parse(qr/^(?:;;|esac)$/)); # item body
+               $token = $self->peek();
+               last unless defined($token) && $token ne 'esac';
+               push(@tokens,
+                    $self->expect(';;'),
+                    $self->optional_newlines());
+       }
+       push(@tokens, $self->expect('esac'));
+       return @tokens;
+}
+
+sub parse_for {
+       my $self = shift @_;
+       my @tokens;
+       push(@tokens,
+            $self->next_token(), # variable
+            $self->optional_newlines());
+       my $token = $self->peek();
+       if (defined($token) && $token eq 'in') {
+               push(@tokens,
+                    $self->expect('in'),
+                    $self->optional_newlines());
+       }
+       push(@tokens,
+            $self->parse(qr/^do$/), # items
+            $self->expect('do'),
+            $self->optional_newlines(),
+            $self->parse_loop_body(),
+            $self->expect('done'));
+       return @tokens;
+}
+
+sub parse_if {
+       my $self = shift @_;
+       my @tokens;
+       while (1) {
+               push(@tokens,
+                    $self->parse(qr/^then$/), # if/elif condition
+                    $self->expect('then'),
+                    $self->optional_newlines(),
+                    $self->parse(qr/^(?:elif|else|fi)$/)); # if/elif body
+               my $token = $self->peek();
+               last unless defined($token) && $token eq 'elif';
+               push(@tokens, $self->expect('elif'));
+       }
+       my $token = $self->peek();
+       if (defined($token) && $token eq 'else') {
+               push(@tokens,
+                    $self->expect('else'),
+                    $self->optional_newlines(),
+                    $self->parse(qr/^fi$/)); # else body
+       }
+       push(@tokens, $self->expect('fi'));
+       return @tokens;
+}
+
+sub parse_loop_body {
+       my $self = shift @_;
+       return $self->parse(qr/^done$/);
+}
+
+sub parse_loop {
+       my $self = shift @_;
+       return ($self->parse(qr/^do$/), # condition
+               $self->expect('do'),
+               $self->optional_newlines(),
+               $self->parse_loop_body(),
+               $self->expect('done'));
+}
+
+sub parse_func {
+       my $self = shift @_;
+       return ($self->expect('('),
+               $self->expect(')'),
+               $self->optional_newlines(),
+               $self->parse_cmd()); # body
+}
+
+sub parse_bash_array_assignment {
+       my $self = shift @_;
+       my @tokens = $self->expect('(');
+       while (defined(my $token = $self->next_token())) {
+               push(@tokens, $token);
+               last if $token eq ')';
+       }
+       return @tokens;
+}
+
+my %compound = (
+       '{' => \&parse_group,
+       '(' => \&parse_subshell,
+       'case' => \&parse_case,
+       'for' => \&parse_for,
+       'if' => \&parse_if,
+       'until' => \&parse_loop,
+       'while' => \&parse_loop);
+
+sub parse_cmd {
+       my $self = shift @_;
+       my $cmd = $self->next_token();
+       return () unless defined($cmd);
+       return $cmd if $cmd eq "\n";
+
+       my $token;
+       my @tokens = $cmd;
+       if ($cmd eq '!') {
+               push(@tokens, $self->parse_cmd());
+               return @tokens;
+       } elsif (my $f = $compound{$cmd}) {
+               push(@tokens, $self->$f());
+       } elsif (defined($token = $self->peek()) && $token eq '(') {
+               if ($cmd !~ /\w=$/) {
+                       push(@tokens, $self->parse_func());
+                       return @tokens;
+               }
+               $tokens[-1] .= join(' ', $self->parse_bash_array_assignment());
+       }
+
+       while (defined(my $token = $self->next_token())) {
+               $self->untoken($token), last if $self->stop_at($token);
+               push(@tokens, $token);
+               last if $token =~ /^(?:[;&\n|]|&&|\|\|)$/;
+       }
+       push(@tokens, $self->next_token()) if $tokens[-1] ne "\n" && defined($token = $self->peek()) && $token eq "\n";
+       return @tokens;
+}
+
+sub accumulate {
+       my ($self, $tokens, $cmd) = @_;
+       push(@$tokens, @$cmd);
+}
+
+sub parse {
+       my ($self, $stop) = @_;
+       push(@{$self->{stop}}, $stop);
+       goto DONE if $self->stop_at($self->peek());
+       my @tokens;
+       while (my @cmd = $self->parse_cmd()) {
+               $self->accumulate(\@tokens, \@cmd);
+               last if $self->stop_at($self->peek());
+       }
+DONE:
+       pop(@{$self->{stop}});
+       return @tokens;
+}
+
+# TestParser is a subclass of ShellParser which, beyond parsing shell script
+# code, is also imbued with semantic knowledge of test construction, and checks
+# tests for common problems (such as broken &&-chains) which might hide bugs in
+# the tests themselves or in behaviors being exercised by the tests. As such,
+# TestParser is only called upon to parse test bodies, not the top-level
+# scripts in which the tests are defined.
+package TestParser;
+
+use base 'ShellParser';
+
+sub find_non_nl {
+       my $tokens = shift @_;
+       my $n = shift @_;
+       $n = $#$tokens if !defined($n);
+       $n-- while $n >= 0 && $$tokens[$n] eq "\n";
+       return $n;
+}
+
+sub ends_with {
+       my ($tokens, $needles) = @_;
+       my $n = find_non_nl($tokens);
+       for my $needle (reverse(@$needles)) {
+               return undef if $n < 0;
+               $n = find_non_nl($tokens, $n), next if $needle eq "\n";
+               return undef if $$tokens[$n] !~ $needle;
+               $n--;
+       }
+       return 1;
+}
+
+sub match_ending {
+       my ($tokens, $endings) = @_;
+       for my $needles (@$endings) {
+               next if @$tokens < scalar(grep {$_ ne "\n"} @$needles);
+               return 1 if ends_with($tokens, $needles);
+       }
+       return undef;
+}
+
+sub parse_loop_body {
+       my $self = shift @_;
+       my @tokens = $self->SUPER::parse_loop_body(@_);
+       # did loop signal failure via "|| return" or "|| exit"?
+       return @tokens if !@tokens || grep(/^(?:return|exit|\$\?)$/, @tokens);
+       # did loop upstream of a pipe signal failure via "|| echo 'impossible
+       # text'" as the final command in the loop body?
+       return @tokens if ends_with(\@tokens, [qr/^\|\|$/, "\n", qr/^echo$/, qr/^.+$/]);
+       # flag missing "return/exit" handling explicit failure in loop body
+       my $n = find_non_nl(\@tokens);
+       splice(@tokens, $n + 1, 0, '?!LOOP?!');
+       return @tokens;
+}
+
+my @safe_endings = (
+       [qr/^(?:&&|\|\||\||&)$/],
+       [qr/^(?:exit|return)$/, qr/^(?:\d+|\$\?)$/],
+       [qr/^(?:exit|return)$/, qr/^(?:\d+|\$\?)$/, qr/^;$/],
+       [qr/^(?:exit|return|continue)$/],
+       [qr/^(?:exit|return|continue)$/, qr/^;$/]);
+
+sub accumulate {
+       my ($self, $tokens, $cmd) = @_;
+       goto DONE unless @$tokens;
+       goto DONE if @$cmd == 1 && $$cmd[0] eq "\n";
+
+       # did previous command end with "&&", "|", "|| return" or similar?
+       goto DONE if match_ending($tokens, \@safe_endings);
+
+       # if this command handles "$?" specially, then okay for previous
+       # command to be missing "&&"
+       for my $token (@$cmd) {
+               goto DONE if $token =~ /\$\?/;
+       }
+
+       # if this command is "false", "return 1", or "exit 1" (which signal
+       # failure explicitly), then okay for all preceding commands to be
+       # missing "&&"
+       if ($$cmd[0] =~ /^(?:false|return|exit)$/) {
+               @$tokens = grep(!/^\?!AMP\?!$/, @$tokens);
+               goto DONE;
+       }
+
+       # flag missing "&&" at end of previous command
+       my $n = find_non_nl($tokens);
+       splice(@$tokens, $n + 1, 0, '?!AMP?!') unless $n < 0;
+
+DONE:
+       $self->SUPER::accumulate($tokens, $cmd);
+}
+
+# ScriptParser is a subclass of ShellParser which identifies individual test
+# definitions within test scripts, and passes each test body through TestParser
+# to identify possible problems. ShellParser detects test definitions not only
+# at the top-level of test scripts but also within compound commands such as
+# loops and function definitions.
+package ScriptParser;
+
+use base 'ShellParser';
+
+sub new {
+       my $class = shift @_;
+       my $self = $class->SUPER::new(@_);
+       $self->{ntests} = 0;
+       return $self;
+}
+
+# extract the raw content of a token, which may be a single string or a
+# composition of multiple strings and non-string character runs; for instance,
+# `"test body"` unwraps to `test body`; `word"a b"42'c d'` to `worda b42c d`
+sub unwrap {
+       my $token = @_ ? shift @_ : $_;
+       # simple case: 'sqstring' or "dqstring"
+       return $token if $token =~ s/^'([^']*)'$/$1/;
+       return $token if $token =~ s/^"([^"]*)"$/$1/;
+
+       # composite case
+       my ($s, $q, $escaped);
+       while (1) {
+               # slurp up non-special characters
+               $s .= $1 if $token =~ /\G([^\\'"]*)/gc;
+               # handle special characters
+               last unless $token =~ /\G(.)/sgc;
+               my $c = $1;
+               $q = undef, next if defined($q) && $c eq $q;
+               $q = $c, next if !defined($q) && $c =~ /^['"]$/;
+               if ($c eq '\\') {
+                       last unless $token =~ /\G(.)/sgc;
+                       $c = $1;
+                       $s .= '\\' if $c eq "\n"; # preserve line splice
+               }
+               $s .= $c;
+       }
+       return $s
+}
+
+sub check_test {
+       my $self = shift @_;
+       my ($title, $body) = map(unwrap, @_);
+       $self->{ntests}++;
+       my $parser = TestParser->new(\$body);
+       my @tokens = $parser->parse();
+       return unless $emit_all || grep(/\?![^?]+\?!/, @tokens);
+       my $c = main::fd_colors(1);
+       my $checked = join(' ', @tokens);
+       $checked =~ s/^\n//;
+       $checked =~ s/^ //mg;
+       $checked =~ s/ $//mg;
+       $checked =~ s/(\?![^?]+\?!)/$c->{rev}$c->{red}$1$c->{reset}/mg;
+       $checked .= "\n" unless $checked =~ /\n$/;
+       push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked");
+}
+
+sub parse_cmd {
+       my $self = shift @_;
+       my @tokens = $self->SUPER::parse_cmd();
+       return @tokens unless @tokens && $tokens[0] =~ /^test_expect_(?:success|failure)$/;
+       my $n = $#tokens;
+       $n-- while $n >= 0 && $tokens[$n] =~ /^(?:[;&\n|]|&&|\|\|)$/;
+       $self->check_test($tokens[1], $tokens[2]) if $n == 2; # title body
+       $self->check_test($tokens[2], $tokens[3]) if $n > 2;  # prereq title body
+       return @tokens;
+}
+
+# main contains high-level functionality for processing command-line switches,
+# feeding input test scripts to ScriptParser, and reporting results.
+package main;
+
+my $getnow = sub { return time(); };
+my $interval = sub { return time() - shift; };
+if (eval {require Time::HiRes; Time::HiRes->import(); 1;}) {
+       $getnow = sub { return [Time::HiRes::gettimeofday()]; };
+       $interval = sub { return Time::HiRes::tv_interval(shift); };
+}
+
+# Restore TERM if test framework set it to "dumb" so 'tput' will work; do this
+# outside of get_colors() since under 'ithreads' all threads use %ENV of main
+# thread and ignore %ENV changes in subthreads.
+$ENV{TERM} = $ENV{USER_TERM} if $ENV{USER_TERM};
+
+my @NOCOLORS = (bold => '', rev => '', reset => '', blue => '', green => '', red => '');
+my %COLORS = ();
+sub get_colors {
+       return \%COLORS if %COLORS;
+       if (exists($ENV{NO_COLOR}) ||
+           system("tput sgr0 >/dev/null 2>&1") != 0 ||
+           system("tput bold >/dev/null 2>&1") != 0 ||
+           system("tput rev  >/dev/null 2>&1") != 0 ||
+           system("tput setaf 1 >/dev/null 2>&1") != 0) {
+               %COLORS = @NOCOLORS;
+               return \%COLORS;
+       }
+       %COLORS = (bold  => `tput bold`,
+                  rev   => `tput rev`,
+                  reset => `tput sgr0`,
+                  blue  => `tput setaf 4`,
+                  green => `tput setaf 2`,
+                  red   => `tput setaf 1`);
+       chomp(%COLORS);
+       return \%COLORS;
+}
+
+my %FD_COLORS = ();
+sub fd_colors {
+       my $fd = shift;
+       return $FD_COLORS{$fd} if exists($FD_COLORS{$fd});
+       $FD_COLORS{$fd} = -t $fd ? get_colors() : {@NOCOLORS};
+       return $FD_COLORS{$fd};
+}
+
+sub ncores {
+       # Windows
+       return $ENV{NUMBER_OF_PROCESSORS} if exists($ENV{NUMBER_OF_PROCESSORS});
+       # Linux / MSYS2 / Cygwin / WSL
+       do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor\s*:/, <>)); } if -r '/proc/cpuinfo';
+       # macOS & BSD
+       return qx/sysctl -n hw.ncpu/ if $^O =~ /(?:^darwin$|bsd)/;
+       return 1;
+}
+
+sub show_stats {
+       my ($start_time, $stats) = @_;
+       my $walltime = $interval->($start_time);
+       my ($usertime) = times();
+       my ($total_workers, $total_scripts, $total_tests, $total_errs) = (0, 0, 0, 0);
+       my $c = fd_colors(2);
+       print(STDERR $c->{green});
+       for (@$stats) {
+               my ($worker, $nscripts, $ntests, $nerrs) = @$_;
+               print(STDERR "worker $worker: $nscripts scripts, $ntests tests, $nerrs errors\n");
+               $total_workers++;
+               $total_scripts += $nscripts;
+               $total_tests += $ntests;
+               $total_errs += $nerrs;
+       }
+       printf(STDERR "total: %d workers, %d scripts, %d tests, %d errors, %.2fs/%.2fs (wall/user)$c->{reset}\n", $total_workers, $total_scripts, $total_tests, $total_errs, $walltime, $usertime);
+}
+
+sub check_script {
+       my ($id, $next_script, $emit) = @_;
+       my ($nscripts, $ntests, $nerrs) = (0, 0, 0);
+       while (my $path = $next_script->()) {
+               $nscripts++;
+               my $fh;
+               unless (open($fh, "<", $path)) {
+                       $emit->("?!ERR?! $path: $!\n");
+                       next;
+               }
+               my $s = do { local $/; <$fh> };
+               close($fh);
+               my $parser = ScriptParser->new(\$s);
+               1 while $parser->parse_cmd();
+               if (@{$parser->{output}}) {
+                       my $c = fd_colors(1);
+                       my $s = join('', @{$parser->{output}});
+                       $emit->("$c->{bold}$c->{blue}# chainlint: $path$c->{reset}\n" . $s);
+                       $nerrs += () = $s =~ /\?![^?]+\?!/g;
+               }
+               $ntests += $parser->{ntests};
+       }
+       return [$id, $nscripts, $ntests, $nerrs];
+}
+
+sub exit_code {
+       my $stats = shift @_;
+       for (@$stats) {
+               my ($worker, $nscripts, $ntests, $nerrs) = @$_;
+               return 1 if $nerrs;
+       }
+       return 0;
+}
+
+Getopt::Long::Configure(qw{bundling});
+GetOptions(
+       "emit-all!" => \$emit_all,
+       "jobs|j=i" => \$jobs,
+       "stats|show-stats!" => \$show_stats) or die("option error\n");
+$jobs = ncores() if $jobs < 1;
+
+my $start_time = $getnow->();
+my @stats;
+
+my @scripts;
+push(@scripts, File::Glob::bsd_glob($_)) for (@ARGV);
+unless (@scripts) {
+       show_stats($start_time, \@stats) if $show_stats;
+       exit;
+}
+
+unless ($Config{useithreads} && eval {
+       require threads; threads->import();
+       require Thread::Queue; Thread::Queue->import();
+       1;
+       }) {
+       push(@stats, check_script(1, sub { shift(@scripts); }, sub { print(@_); }));
+       show_stats($start_time, \@stats) if $show_stats;
+       exit(exit_code(\@stats));
+}
+
+my $script_queue = Thread::Queue->new();
+my $output_queue = Thread::Queue->new();
+
+sub next_script { return $script_queue->dequeue(); }
+sub emit { $output_queue->enqueue(@_); }
+
+sub monitor {
+       while (my $s = $output_queue->dequeue()) {
+               print($s);
+       }
+}
+
+my $mon = threads->create({'context' => 'void'}, \&monitor);
+threads->create({'context' => 'list'}, \&check_script, $_, \&next_script, \&emit) for 1..$jobs;
+
+$script_queue->enqueue(@scripts);
+$script_queue->end();
+
+for (threads->list()) {
+       push(@stats, $_->join()) unless $_ == $mon;
+}
+
+$output_queue->end();
+$mon->join();
+
+show_stats($start_time, \@stats) if $show_stats;
+exit(exit_code(\@stats));
diff --git a/t/chainlint.sed b/t/chainlint.sed
deleted file mode 100644 (file)
index dc4ce37..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-#------------------------------------------------------------------------------
-# Detect broken &&-chains in tests.
-#
-# At present, only &&-chains in subshells are examined by this linter;
-# top-level &&-chains are instead checked directly by the test framework. Like
-# the top-level &&-chain linter, the subshell linter (intentionally) does not
-# check &&-chains within {...} blocks.
-#
-# Checking for &&-chain breakage is done line-by-line by pure textual
-# inspection.
-#
-# Incomplete lines (those ending with "\") are stitched together with following
-# lines to simplify processing, particularly of "one-liner" statements.
-# Top-level here-docs are swallowed to avoid false positives within the
-# here-doc body, although the statement to which the here-doc is attached is
-# retained.
-#
-# Heuristics are used to detect end-of-subshell when the closing ")" is cuddled
-# with the final subshell statement on the same line:
-#
-#    (cd foo &&
-#        bar)
-#
-# in order to avoid misinterpreting the ")" in constructs such as "x=$(...)"
-# and "case $x in *)" as ending the subshell.
-#
-# Lines missing a final "&&" are flagged with "?!AMP?!", as are lines which
-# chain commands with ";" internally rather than "&&". A line may be flagged
-# for both violations.
-#
-# Detection of a missing &&-link in a multi-line subshell is complicated by the
-# fact that the last statement before the closing ")" must not end with "&&".
-# Since processing is line-by-line, it is not known whether a missing "&&" is
-# legitimate or not until the _next_ line is seen. To accommodate this, within
-# multi-line subshells, each line is stored in sed's "hold" area until after
-# the next line is seen and processed. If the next line is a stand-alone ")",
-# then a missing "&&" on the previous line is legitimate; otherwise a missing
-# "&&" is a break in the &&-chain.
-#
-#    (
-#         cd foo &&
-#         bar
-#    )
-#
-# In practical terms, when "bar" is encountered, it is flagged with "?!AMP?!",
-# but when the stand-alone ")" line is seen which closes the subshell, the
-# "?!AMP?!" violation is removed from the "bar" line (retrieved from the "hold"
-# area) since the final statement of a subshell must not end with "&&". The
-# final line of a subshell may still break the &&-chain by using ";" internally
-# to chain commands together rather than "&&", but an internal "?!AMP?!" is
-# never removed from a line even though a line-ending "?!AMP?!" might be.
-#
-# Care is taken to recognize the last _statement_ of a multi-line subshell, not
-# necessarily the last textual _line_ within the subshell, since &&-chaining
-# applies to statements, not to lines. Consequently, blank lines, comment
-# lines, and here-docs are swallowed (but not the command to which the here-doc
-# is attached), leaving the last statement in the "hold" area, not the last
-# line, thus simplifying &&-link checking.
-#
-# The final statement before "done" in for- and while-loops, and before "elif",
-# "else", and "fi" in if-then-else likewise must not end with "&&", thus
-# receives similar treatment.
-#
-# Swallowing here-docs with arbitrary tags requires a bit of finesse. When a
-# line such as "cat <<EOF" is seen, the here-doc tag is copied to the front of
-# the line enclosed in angle brackets as a sentinel, giving "<EOF>cat <<EOF".
-# As each subsequent line is read, it is appended to the target line and a
-# (whitespace-loose) back-reference match /^<(.*)>\n\1$/ is attempted to see if
-# the content inside "<...>" matches the entirety of the newly-read line. For
-# instance, if the next line read is "some data", when concatenated with the
-# target line, it becomes "<EOF>cat <<EOF\nsome data", and a match is attempted
-# to see if "EOF" matches "some data". Since it doesn't, the next line is
-# attempted. When a line consisting of only "EOF" (and possible whitespace) is
-# encountered, it is appended to the target line giving "<EOF>cat <<EOF\nEOF",
-# in which case the "EOF" inside "<...>" does match the text following the
-# newline, thus the closing here-doc tag has been found. The closing tag line
-# and the "<...>" prefix on the target line are then discarded, leaving just
-# the target line "cat <<EOF".
-#------------------------------------------------------------------------------
-
-# incomplete line -- slurp up next line
-:squash
-/\\$/ {
-       N
-       s/\\\n//
-       bsquash
-}
-
-# here-doc -- swallow it to avoid false hits within its body (but keep the
-# command to which it was attached)
-/<<-*[         ]*[\\'"]*[A-Za-z0-9_]/ {
-       /"[^"]*<<[^"]*"/bnotdoc
-       s/^\(.*<<-*[    ]*\)[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1\2/
-       :hered
-       N
-       /^<\([^>]*\)>.*\n[      ]*\1[   ]*$/!{
-               s/\n.*$//
-               bhered
-       }
-       s/^<[^>]*>//
-       s/\n.*$//
-}
-:notdoc
-
-# one-liner "(...) &&"
-/^[    ]*!*[   ]*(..*)[        ]*&&[   ]*$/boneline
-
-# same as above but without trailing "&&"
-/^[    ]*!*[   ]*(..*)[        ]*$/boneline
-
-# one-liner "(...) >x" (or "2>x" or "<x" or "|x" or "&"
-/^[    ]*!*[   ]*(..*)[        ]*[0-9]*[<>|&]/boneline
-
-# multi-line "(...\n...)"
-/^[    ]*(/bsubsh
-
-# innocuous line -- print it and advance to next line
-b
-
-# found one-liner "(...)" -- mark suspect if it uses ";" internally rather than
-# "&&" (but not ";" in a string)
-:oneline
-/;/{
-       /"[^"]*;[^"]*"/!s/;/; ?!AMP?!/
-}
-b
-
-:subsh
-# bare "(" line? -- stash for later printing
-/^[    ]*([    ]*$/ {
-       h
-       bnextln
-}
-# "(..." line -- "(" opening subshell cuddled with command; temporarily replace
-# "(" with sentinel "^" and process the line as if "(" had been seen solo on
-# the preceding line; this temporary replacement prevents several rules from
-# accidentally thinking "(" introduces a nested subshell; "^" is changed back
-# to "(" at output time
-x
-s/.*//
-x
-s/(/^/
-bslurp
-
-:nextln
-N
-s/.*\n//
-
-:slurp
-# incomplete line "...\"
-/\\$/bicmplte
-# multi-line quoted string "...\n..."?
-/"/bdqstr
-# multi-line quoted string '...\n...'? (but not contraction in string "it's")
-/'/{
-       /"[^'"]*'[^'"]*"/!bsqstr
-}
-:folded
-# here-doc -- swallow it (but not "<<" in a string)
-/<<-*[         ]*[\\'"]*[A-Za-z0-9_]/{
-       /"[^"]*<<[^"]*"/!bheredoc
-}
-# comment or empty line -- discard since final non-comment, non-empty line
-# before closing ")", "done", "elsif", "else", or "fi" will need to be
-# re-visited to drop "suspect" marking since final line of those constructs
-# legitimately lacks "&&", so "suspect" mark must be removed
-/^[    ]*#/bnextln
-/^[    ]*$/bnextln
-# in-line comment -- strip it (but not "#" in a string, Bash ${#...} array
-# length, or Perforce "//depot/path#42" revision in filespec)
-/[     ]#/{
-       /"[^"]*#[^"]*"/!s/[     ]#.*$//
-}
-# one-liner "case ... esac"
-/^[    ^]*case[        ]*..*esac/bchkchn
-# multi-line "case ... esac"
-/^[    ^]*case[        ]..*[   ]in/bcase
-# multi-line "for ... done" or "while ... done"
-/^[    ^]*for[         ]..*[   ]in/bcont
-/^[    ^]*while[       ]/bcont
-/^[    ]*do[   ]/bcont
-/^[    ]*do[   ]*$/bcont
-/;[    ]*do/bcont
-/^[    ]*done[         ]*&&[   ]*$/bdone
-/^[    ]*done[         ]*$/bdone
-/^[    ]*done[         ]*[<>|]/bdone
-/^[    ]*done[         ]*)/bdone
-/||[   ]*exit[         ]/bcont
-/||[   ]*exit[         ]*$/bcont
-# multi-line "if...elsif...else...fi"
-/^[    ^]*if[  ]/bcont
-/^[    ]*then[         ]/bcont
-/^[    ]*then[         ]*$/bcont
-/;[    ]*then/bcont
-/^[    ]*elif[         ]/belse
-/^[    ]*elif[         ]*$/belse
-/^[    ]*else[         ]/belse
-/^[    ]*else[         ]*$/belse
-/^[    ]*fi[   ]*&&[   ]*$/bdone
-/^[    ]*fi[   ]*$/bdone
-/^[    ]*fi[   ]*[<>|]/bdone
-/^[    ]*fi[   ]*)/bdone
-# nested one-liner "(...) &&"
-/^[    ^]*(.*)[        ]*&&[   ]*$/bchkchn
-# nested one-liner "(...)"
-/^[    ^]*(.*)[        ]*$/bchkchn
-# nested one-liner "(...) >x" (or "2>x" or "<x" or "|x")
-/^[    ^]*(.*)[        ]*[0-9]*[<>|]/bchkchn
-# nested multi-line "(...\n...)"
-/^[    ^]*(/bnest
-# multi-line "{...\n...}"
-/^[    ^]*{/bblock
-# closing ")" on own line -- exit subshell
-/^[    ]*)/bclssolo
-# "$((...))" -- arithmetic expansion; not closing ")"
-/\$(([^)][^)]*))[^)]*$/bchkchn
-# "$(...)" -- command substitution; not closing ")"
-/\$([^)][^)]*)[^)]*$/bchkchn
-# multi-line "$(...\n...)" -- command substitution; treat as nested subshell
-/\$([^)]*$/bnest
-# "=(...)" -- Bash array assignment; not closing ")"
-/=(/bchkchn
-# closing "...) &&"
-/)[    ]*&&[   ]*$/bclose
-# closing "...)"
-/)[    ]*$/bclose
-# closing "...) >x" (or "2>x" or "<x" or "|x")
-/)[    ]*[<>|]/bclose
-:chkchn
-# mark suspect if line uses ";" internally rather than "&&" (but not ";" in a
-# string and not ";;" in one-liner "case...esac")
-/;/{
-       /;;/!{
-               /"[^"]*;[^"]*"/!s/;/; ?!AMP?!/
-       }
-}
-# line ends with pipe "...|" -- valid; not missing "&&"
-/|[    ]*$/bcont
-# missing end-of-line "&&" -- mark suspect
-/&&[   ]*$/!s/$/ ?!AMP?!/
-:cont
-# retrieve and print previous line
-x
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-n
-bslurp
-
-# found incomplete line "...\" -- slurp up next line
-:icmplte
-N
-s/\\\n//
-bslurp
-
-# check for multi-line double-quoted string "...\n..." -- fold to one line
-:dqstr
-# remove all quote pairs
-s/"\([^"]*\)"/@!\1@!/g
-# done if no dangling quote
-/"/!bdqdone
-# otherwise, slurp next line and try again
-N
-s/\n//
-bdqstr
-:dqdone
-s/@!/"/g
-bfolded
-
-# check for multi-line single-quoted string '...\n...' -- fold to one line
-:sqstr
-# remove all quote pairs
-s/'\([^']*\)'/@!\1@!/g
-# done if no dangling quote
-/'/!bsqdone
-# otherwise, slurp next line and try again
-N
-s/\n//
-bsqstr
-:sqdone
-s/@!/'/g
-bfolded
-
-# found here-doc -- swallow it to avoid false hits within its body (but keep
-# the command to which it was attached)
-:heredoc
-s/^\(.*\)<<\(-*[       ]*\)[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\3>\1?!HERE?!\2\3/
-:hdocsub
-N
-/^<\([^>]*\)>.*\n[     ]*\1[   ]*$/!{
-       s/\n.*$//
-       bhdocsub
-}
-s/^<[^>]*>//
-s/\n.*$//
-bfolded
-
-# found "case ... in" -- pass through untouched
-:case
-x
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-n
-:cascom
-/^[    ]*#/{
-       N
-       s/.*\n//
-       bcascom
-}
-/^[    ]*esac/bslurp
-bcase
-
-# found "else" or "elif" -- drop "suspect" from final line before "else" since
-# that line legitimately lacks "&&"
-:else
-x
-s/\( ?!AMP?!\)* ?!AMP?!$//
-x
-bcont
-
-# found "done" closing for-loop or while-loop, or "fi" closing if-then -- drop
-# "suspect" from final contained line since that line legitimately lacks "&&"
-:done
-x
-s/\( ?!AMP?!\)* ?!AMP?!$//
-x
-# is 'done' or 'fi' cuddled with ")" to close subshell?
-/done.*)/bclose
-/fi.*)/bclose
-bchkchn
-
-# found nested multi-line "(...\n...)" -- pass through untouched
-:nest
-x
-:nstslrp
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-n
-:nstcom
-# comment -- not closing ")" if in comment
-/^[    ]*#/{
-       N
-       s/.*\n//
-       bnstcom
-}
-# closing ")" on own line -- stop nested slurp
-/^[    ]*)/bnstcl
-# "$((...))" -- arithmetic expansion; not closing ")"
-/\$(([^)][^)]*))[^)]*$/bnstcnt
-# "$(...)" -- command substitution; not closing ")"
-/\$([^)][^)]*)[^)]*$/bnstcnt
-# closing "...)" -- stop nested slurp
-/)/bnstcl
-:nstcnt
-x
-bnstslrp
-:nstcl
-# is it "))" which closes nested and parent subshells?
-/)[    ]*)/bslurp
-bchkchn
-
-# found multi-line "{...\n...}" block -- pass through untouched
-:block
-x
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-n
-:blkcom
-/^[    ]*#/{
-       N
-       s/.*\n//
-       bblkcom
-}
-# closing "}" -- stop block slurp
-/}/bchkchn
-bblock
-
-# found closing ")" on own line -- drop "suspect" from final line of subshell
-# since that line legitimately lacks "&&" and exit subshell loop
-:clssolo
-x
-s/\( ?!AMP?!\)* ?!AMP?!$//
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-p
-x
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-b
-
-# found closing "...)" -- exit subshell loop
-:close
-x
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-p
-x
-s/^\([         ]*\)^/\1(/
-s/?!HERE?!/<</g
-b
diff --git a/t/chainlint/blank-line-before-esac.expect b/t/chainlint/blank-line-before-esac.expect
new file mode 100644 (file)
index 0000000..48ed4eb
--- /dev/null
@@ -0,0 +1,18 @@
+test_done ( ) {
+       case "$test_failure" in
+       0 )
+               test_at_end_hook_
+
+               exit 0 ;;
+
+       * )
+               if test $test_external_has_tap -eq 0
+               then
+                       say_color error "# failed $test_failure among $msg"
+                       say "1..$test_count"
+               fi
+
+               exit 1 ;;
+
+               esac
+}
diff --git a/t/chainlint/blank-line-before-esac.test b/t/chainlint/blank-line-before-esac.test
new file mode 100644 (file)
index 0000000..cecccad
--- /dev/null
@@ -0,0 +1,19 @@
+# LINT: blank line before "esac"
+test_done () {
+       case "$test_failure" in
+       0)
+               test_at_end_hook_
+
+               exit 0 ;;
+
+       *)
+               if test $test_external_has_tap -eq 0
+               then
+                       say_color error "# failed $test_failure among $msg"
+                       say "1..$test_count"
+               fi
+
+               exit 1 ;;
+
+       esac
+}
index da60257ebc4e1d2e019e2b8fee8da3742849ddd7..a3bcea492a915f62cc6870a3e194fd86c19344a7 100644 (file)
@@ -1,7 +1,7 @@
 (
        foo &&
        {
-               echo a
+               echo a ?!AMP?!
                echo b
        } &&
        bar &&
@@ -9,4 +9,15 @@
                echo c
        } ?!AMP?!
        baz
-)
+) &&
+
+{
+       echo a ; ?!AMP?! echo b
+} &&
+{ echo a ; ?!AMP?! echo b ; } &&
+
+{
+       echo "${var}9" &&
+       echo "done"
+} &&
+finis
index 0a82fd579f6751a8ed7a88505d2c7988eaf3ae5c..4ab69a4afc40381561b0ccd2a4d7f1abe96c80d1 100644 (file)
                echo c
        }
        baz
-)
+) &&
+
+# LINT: ";" not allowed in place of "&&"
+{
+       echo a; echo b
+} &&
+{ echo a; echo b; } &&
+
+# LINT: "}" inside string not mistaken as end of block
+{
+       echo "${var}9" &&
+       echo "done"
+} &&
+finis
diff --git a/t/chainlint/chain-break-background.expect b/t/chainlint/chain-break-background.expect
new file mode 100644 (file)
index 0000000..28f9114
--- /dev/null
@@ -0,0 +1,9 @@
+JGIT_DAEMON_PID= &&
+git init --bare empty.git &&
+> empty.git/git-daemon-export-ok &&
+mkfifo jgit_daemon_output &&
+{
+       jgit daemon --port="$JGIT_DAEMON_PORT" . > jgit_daemon_output &
+       JGIT_DAEMON_PID=$!
+} &&
+test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
diff --git a/t/chainlint/chain-break-background.test b/t/chainlint/chain-break-background.test
new file mode 100644 (file)
index 0000000..e10f656
--- /dev/null
@@ -0,0 +1,10 @@
+JGIT_DAEMON_PID= &&
+git init --bare empty.git &&
+>empty.git/git-daemon-export-ok &&
+mkfifo jgit_daemon_output &&
+{
+# LINT: exit status of "&" is always 0 so &&-chaining immaterial
+       jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output &
+       JGIT_DAEMON_PID=$!
+} &&
+test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
diff --git a/t/chainlint/chain-break-continue.expect b/t/chainlint/chain-break-continue.expect
new file mode 100644 (file)
index 0000000..47a3457
--- /dev/null
@@ -0,0 +1,12 @@
+git ls-tree --name-only -r refs/notes/many_notes |
+while read path
+do
+       test "$path" = "foobar/non-note.txt" && continue
+       test "$path" = "deadbeef" && continue
+       test "$path" = "de/adbeef" && continue
+
+       if test $(expr length "$path") -ne $hexsz
+       then
+               return 1
+       fi
+done
diff --git a/t/chainlint/chain-break-continue.test b/t/chainlint/chain-break-continue.test
new file mode 100644 (file)
index 0000000..f0af71d
--- /dev/null
@@ -0,0 +1,13 @@
+git ls-tree --name-only -r refs/notes/many_notes |
+while read path
+do
+# LINT: broken &&-chain okay if explicit "continue"
+       test "$path" = "foobar/non-note.txt" && continue
+       test "$path" = "deadbeef" && continue
+       test "$path" = "de/adbeef" && continue
+
+       if test $(expr length "$path") -ne $hexsz
+       then
+               return 1
+       fi
+done
diff --git a/t/chainlint/chain-break-false.expect b/t/chainlint/chain-break-false.expect
new file mode 100644 (file)
index 0000000..989766f
--- /dev/null
@@ -0,0 +1,9 @@
+if condition not satisified
+then
+       echo it did not work...
+       echo failed!
+       false
+else
+       echo it went okay ?!AMP?!
+       congratulate user
+fi
diff --git a/t/chainlint/chain-break-false.test b/t/chainlint/chain-break-false.test
new file mode 100644 (file)
index 0000000..a5aaff8
--- /dev/null
@@ -0,0 +1,10 @@
+# LINT: broken &&-chain okay if explicit "false" signals failure
+if condition not satisified
+then
+       echo it did not work...
+       echo failed!
+       false
+else
+       echo it went okay
+       congratulate user
+fi
diff --git a/t/chainlint/chain-break-return-exit.expect b/t/chainlint/chain-break-return-exit.expect
new file mode 100644 (file)
index 0000000..1732d22
--- /dev/null
@@ -0,0 +1,19 @@
+case "$(git ls-files)" in
+one ) echo pass one ;;
+* ) echo bad one ; return 1 ;;
+esac &&
+(
+       case "$(git ls-files)" in
+       two ) echo pass two ;;
+       * ) echo bad two ; exit 1 ;;
+esac
+) &&
+case "$(git ls-files)" in
+dir/two"$LF"one ) echo pass both ;;
+* ) echo bad ; return 1 ;;
+esac &&
+
+for i in 1 2 3 4 ; do
+       git checkout main -b $i || return $?
+       test_commit $i $i $i tag$i || return $?
+done
diff --git a/t/chainlint/chain-break-return-exit.test b/t/chainlint/chain-break-return-exit.test
new file mode 100644 (file)
index 0000000..46542ed
--- /dev/null
@@ -0,0 +1,23 @@
+case "$(git ls-files)" in
+one) echo pass one ;;
+# LINT: broken &&-chain okay if explicit "return 1" signals failuire
+*) echo bad one; return 1 ;;
+esac &&
+(
+       case "$(git ls-files)" in
+       two) echo pass two ;;
+# LINT: broken &&-chain okay if explicit "exit 1" signals failuire
+       *) echo bad two; exit 1 ;;
+       esac
+) &&
+case "$(git ls-files)" in
+dir/two"$LF"one) echo pass both ;;
+# LINT: broken &&-chain okay if explicit "return 1" signals failuire
+*) echo bad; return 1 ;;
+esac &&
+
+for i in 1 2 3 4 ; do
+# LINT: broken &&-chain okay if explicit "return $?" signals failure
+       git checkout main -b $i || return $?
+       test_commit $i $i $i tag$i || return $?
+done
diff --git a/t/chainlint/chain-break-status.expect b/t/chainlint/chain-break-status.expect
new file mode 100644 (file)
index 0000000..f4bada9
--- /dev/null
@@ -0,0 +1,9 @@
+OUT=$(( ( large_git ; echo $? 1 >& 3 ) | : ) 3 >& 1) &&
+test_match_signal 13 "$OUT" &&
+
+{ test-tool sigchain > actual ; ret=$? ; } &&
+{
+       test_match_signal 15 "$ret" ||
+       test "$ret" = 3
+} &&
+test_cmp expect actual
diff --git a/t/chainlint/chain-break-status.test b/t/chainlint/chain-break-status.test
new file mode 100644 (file)
index 0000000..a6602a7
--- /dev/null
@@ -0,0 +1,11 @@
+# LINT: broken &&-chain okay if next command handles "$?" explicitly
+OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) &&
+test_match_signal 13 "$OUT" &&
+
+# LINT: broken &&-chain okay if next command handles "$?" explicitly
+{ test-tool sigchain >actual; ret=$?; } &&
+{
+       test_match_signal 15 "$ret" ||
+       test "$ret" = 3
+} &&
+test_cmp expect actual
diff --git a/t/chainlint/chained-block.expect b/t/chainlint/chained-block.expect
new file mode 100644 (file)
index 0000000..574cdce
--- /dev/null
@@ -0,0 +1,9 @@
+echo nobody home && {
+       test the doohicky ?!AMP?!
+       right now
+} &&
+
+GIT_EXTERNAL_DIFF=echo git diff | {
+       read path oldfile oldhex oldmode newfile newhex newmode &&
+       test "z$oh" = "z$oldhex"
+}
diff --git a/t/chainlint/chained-block.test b/t/chainlint/chained-block.test
new file mode 100644 (file)
index 0000000..86f81ec
--- /dev/null
@@ -0,0 +1,11 @@
+# LINT: start of block chained to preceding command
+echo nobody home && {
+       test the doohicky
+       right now
+} &&
+
+# LINT: preceding command pipes to block on same line
+GIT_EXTERNAL_DIFF=echo git diff | {
+       read path oldfile oldhex oldmode newfile newhex newmode &&
+       test "z$oh" = "z$oldhex"
+}
diff --git a/t/chainlint/chained-subshell.expect b/t/chainlint/chained-subshell.expect
new file mode 100644 (file)
index 0000000..af0369d
--- /dev/null
@@ -0,0 +1,10 @@
+mkdir sub && (
+       cd sub &&
+       foo the bar ?!AMP?!
+       nuff said
+) &&
+
+cut "-d " -f actual | ( read s1 s2 s3 &&
+test -f $s1 ?!AMP?!
+test $(cat $s2) = tree2path1 &&
+test $(cat $s3) = tree3path1 )
diff --git a/t/chainlint/chained-subshell.test b/t/chainlint/chained-subshell.test
new file mode 100644 (file)
index 0000000..4ff6ddd
--- /dev/null
@@ -0,0 +1,13 @@
+# LINT: start of subshell chained to preceding command
+mkdir sub && (
+       cd sub &&
+       foo the bar
+       nuff said
+) &&
+
+# LINT: preceding command pipes to subshell on same line
+cut "-d " -f actual | (read s1 s2 s3 &&
+test -f $s1
+test $(cat $s2) = tree2path1 &&
+# LINT: closing subshell ")" correctly detected on same line as "$(...)"
+test $(cat $s3) = tree3path1)
diff --git a/t/chainlint/command-substitution-subsubshell.expect b/t/chainlint/command-substitution-subsubshell.expect
new file mode 100644 (file)
index 0000000..ab2f79e
--- /dev/null
@@ -0,0 +1,2 @@
+OUT=$(( ( large_git 1 >& 3 ) | : ) 3 >& 1) &&
+test_match_signal 13 "$OUT"
diff --git a/t/chainlint/command-substitution-subsubshell.test b/t/chainlint/command-substitution-subsubshell.test
new file mode 100644 (file)
index 0000000..321de29
--- /dev/null
@@ -0,0 +1,3 @@
+# LINT: subshell nested in subshell nested in command substitution
+OUT=$( ((large_git 1>&3) | :) 3>&1 ) &&
+test_match_signal 13 "$OUT"
index 2fca1834095817a0aba1bce38a5a837dea0debae..dac2d0fd1d9037e9ebed8be9439bbafe334a1960 100644 (file)
@@ -4,6 +4,6 @@
      :
    else
      echo >file
-   fi
+   fi ?!LOOP?!
  done) &&
 test ! -f file
diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect
new file mode 100644 (file)
index 0000000..75477bb
--- /dev/null
@@ -0,0 +1,2 @@
+run_sub_test_lib_test_err run-inv-range-start "--run invalid range start" --run="a-5" <<-EOF &&
+check_sub_test_lib_test_err run-inv-range-start <<-EOF_OUT 3 <<-EOF_ERR
diff --git a/t/chainlint/double-here-doc.test b/t/chainlint/double-here-doc.test
new file mode 100644 (file)
index 0000000..cd584a4
--- /dev/null
@@ -0,0 +1,12 @@
+run_sub_test_lib_test_err run-inv-range-start \
+       "--run invalid range start" \
+       --run="a-5" <<-\EOF &&
+test_expect_success "passing test #1" "true"
+test_done
+EOF
+check_sub_test_lib_test_err run-inv-range-start \
+       <<-\EOF_OUT 3<<-EOF_ERR
+> FATAL: Unexpected exit with code 1
+EOF_OUT
+> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ}
+EOF_ERR
diff --git a/t/chainlint/dqstring-line-splice.expect b/t/chainlint/dqstring-line-splice.expect
new file mode 100644 (file)
index 0000000..bf9ced6
--- /dev/null
@@ -0,0 +1,3 @@
+echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' > expect &&
+test_must_fail git commit --fixup=reword:HEAD~ $1 2 > actual &&
+test_cmp expect actual
diff --git a/t/chainlint/dqstring-line-splice.test b/t/chainlint/dqstring-line-splice.test
new file mode 100644 (file)
index 0000000..b407144
--- /dev/null
@@ -0,0 +1,7 @@
+# LINT: line-splice within DQ-string
+'"
+echo 'fatal: reword option of --fixup is mutually exclusive with'\
+       '--patch/--interactive/--all/--include/--only' >expect &&
+test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual &&
+test_cmp expect actual
+"'
diff --git a/t/chainlint/dqstring-no-interpolate.expect b/t/chainlint/dqstring-no-interpolate.expect
new file mode 100644 (file)
index 0000000..1072498
--- /dev/null
@@ -0,0 +1,11 @@
+grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out &&
+
+grep "^\.git$" output.txt &&
+
+
+(
+       cd client$version &&
+       GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input)
+) > output &&
+       cut -d ' ' -f 2 < output | sort > actual &&
+       test_cmp expect actual
diff --git a/t/chainlint/dqstring-no-interpolate.test b/t/chainlint/dqstring-no-interpolate.test
new file mode 100644 (file)
index 0000000..d2f4219
--- /dev/null
@@ -0,0 +1,15 @@
+# LINT: regex dollar-sign eol anchor in double-quoted string not special
+grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out &&
+
+# LINT: escaped "$" not mistaken for variable expansion
+grep "^\\.git\$" output.txt &&
+
+'"
+(
+       cd client$version &&
+# LINT: escaped dollar-sign in double-quoted test body
+       GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. \$(cat ../input)
+) >output &&
+       cut -d ' ' -f 2 <output | sort >actual &&
+       test_cmp expect actual
+"'
diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect
new file mode 100644 (file)
index 0000000..f42f2d4
--- /dev/null
@@ -0,0 +1,3 @@
+git ls-tree $tree path > current &&
+cat > expected <<EOF &&
+test_output
diff --git a/t/chainlint/empty-here-doc.test b/t/chainlint/empty-here-doc.test
new file mode 100644 (file)
index 0000000..24fc165
--- /dev/null
@@ -0,0 +1,5 @@
+git ls-tree $tree path >current &&
+# LINT: empty here-doc
+cat >expected <<\EOF &&
+EOF
+test_output
diff --git a/t/chainlint/exclamation.expect b/t/chainlint/exclamation.expect
new file mode 100644 (file)
index 0000000..2d961a5
--- /dev/null
@@ -0,0 +1,4 @@
+if ! condition ; then echo nope ; else yep ; fi &&
+test_prerequisite !MINGW &&
+mail uucp!address &&
+echo !whatever!
diff --git a/t/chainlint/exclamation.test b/t/chainlint/exclamation.test
new file mode 100644 (file)
index 0000000..323595b
--- /dev/null
@@ -0,0 +1,8 @@
+# LINT: "! word" is two tokens
+if ! condition; then echo nope; else yep; fi &&
+# LINT: "!word" is single token, not two tokens "!" and "word"
+test_prerequisite !MINGW &&
+# LINT: "word!word" is single token, not three tokens "word", "!", and "word"
+mail uucp!address &&
+# LINT: "!word!" is single token, not three tokens "!", "word", and "!"
+echo !whatever!
diff --git a/t/chainlint/for-loop-abbreviated.expect b/t/chainlint/for-loop-abbreviated.expect
new file mode 100644 (file)
index 0000000..a21007a
--- /dev/null
@@ -0,0 +1,5 @@
+for it
+do
+       path=$(expr "$it" : ( [^:]*) ) &&
+       git update-index --add "$path" || exit
+done
diff --git a/t/chainlint/for-loop-abbreviated.test b/t/chainlint/for-loop-abbreviated.test
new file mode 100644 (file)
index 0000000..1084ecc
--- /dev/null
@@ -0,0 +1,6 @@
+# LINT: for-loop lacking optional "in [word...]" before "do"
+for it
+do
+       path=$(expr "$it" : '\([^:]*\)') &&
+       git update-index --add "$path" || exit
+done
index 6671b8cd842de110882342fc4ee359eb7e4d1375..a5810c9bddd8352c74f3213be1fd54d1986a72f4 100644 (file)
@@ -2,10 +2,10 @@
        for i in a b c
        do
                echo $i ?!AMP?!
-               cat <<-EOF
+               cat <<-EOF ?!LOOP?!
        done ?!AMP?!
        for i in a b c; do
                echo $i &&
-               cat $i
+               cat $i ?!LOOP?!
        done
 )
diff --git a/t/chainlint/function.expect b/t/chainlint/function.expect
new file mode 100644 (file)
index 0000000..a14388e
--- /dev/null
@@ -0,0 +1,11 @@
+sha1_file ( ) {
+       echo "$*" | sed "s#..#.git/objects/&/#"
+} &&
+
+remove_object ( ) {
+       file=$(sha1_file "$*") &&
+       test -e "$file" ?!AMP?!
+       rm -f "$file"
+} ?!AMP?!
+
+sha1_file arg && remove_object arg
diff --git a/t/chainlint/function.test b/t/chainlint/function.test
new file mode 100644 (file)
index 0000000..5ee5956
--- /dev/null
@@ -0,0 +1,13 @@
+# LINT: "()" in function definition not mistaken for subshell
+sha1_file() {
+       echo "$*" | sed "s#..#.git/objects/&/#"
+} &&
+
+# LINT: broken &&-chain in function and after function
+remove_object() {
+       file=$(sha1_file "$*") &&
+       test -e "$file"
+       rm -f "$file"
+}
+
+sha1_file arg && remove_object arg
diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect
new file mode 100644 (file)
index 0000000..fb6cf72
--- /dev/null
@@ -0,0 +1,5 @@
+cat > expect <<-EOF &&
+
+cat > expect <<-EOF ?!AMP?!
+
+cleanup
diff --git a/t/chainlint/here-doc-indent-operator.test b/t/chainlint/here-doc-indent-operator.test
new file mode 100644 (file)
index 0000000..c8a6f18
--- /dev/null
@@ -0,0 +1,13 @@
+# LINT: whitespace between operator "<<-" and tag legal
+cat >expect <<- EOF &&
+header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
+num_commits: $1
+chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
+EOF
+
+# LINT: not an indented here-doc; just a plain here-doc with tag named "-EOF"
+cat >expect << -EOF
+this is not indented
+-EOF
+
+cleanup
index 2578191ca8a809c8bbc271c9f1b8b744d9d8444e..be64b26869ada1f4d7d9715cb754c2aa826c6978 100644 (file)
@@ -1,4 +1,5 @@
 (
-       cat <<-TXT && echo "multi-line  string" ?!AMP?!
+       cat <<-TXT && echo "multi-line
+       string" ?!AMP?!
        bap
 )
diff --git a/t/chainlint/if-condition-split.expect b/t/chainlint/if-condition-split.expect
new file mode 100644 (file)
index 0000000..ee745ef
--- /dev/null
@@ -0,0 +1,7 @@
+if bob &&
+   marcia ||
+   kevin
+then
+       echo "nomads" ?!AMP?!
+       echo "for sure"
+fi
diff --git a/t/chainlint/if-condition-split.test b/t/chainlint/if-condition-split.test
new file mode 100644 (file)
index 0000000..240daa9
--- /dev/null
@@ -0,0 +1,8 @@
+# LINT: "if" condition split across multiple lines at "&&" or "||"
+if bob &&
+   marcia ||
+   kevin
+then
+       echo "nomads"
+       echo "for sure"
+fi
index 03b82a3e58c21e1300befb317f19c7f063fba3ec..d6514ae74927ff4336279112d5570499a71d6b53 100644 (file)
@@ -3,7 +3,7 @@
        do
                if false
                then
-                       echo "err" ?!AMP?!
+                       echo "err"
                        exit 1
                fi ?!AMP?!
                foo
index f0cf19cfadac8c1ae9d09a668bafc99517c50cdf..90c23976feccdd3f3851a39cf7b12cb5f643f628 100644 (file)
@@ -3,7 +3,7 @@
        do
                if false
                then
-# LINT: missing "&&" on "echo"
+# LINT: missing "&&" on "echo" okay since "exit 1" signals error explicitly
                        echo "err"
                        exit 1
 # LINT: missing "&&" on "fi"
diff --git a/t/chainlint/loop-detect-failure.expect b/t/chainlint/loop-detect-failure.expect
new file mode 100644 (file)
index 0000000..a66025c
--- /dev/null
@@ -0,0 +1,15 @@
+git init r1 &&
+for n in 1 2 3 4 5
+do
+       echo "This is file: $n" > r1/file.$n &&
+       git -C r1 add file.$n &&
+       git -C r1 commit -m "$n" || return 1
+done &&
+
+git init r2 &&
+for n in 1000 10000
+do
+       printf "%"$n"s" X > r2/large.$n &&
+       git -C r2 add large.$n &&
+       git -C r2 commit -m "$n" ?!LOOP?!
+done
diff --git a/t/chainlint/loop-detect-failure.test b/t/chainlint/loop-detect-failure.test
new file mode 100644 (file)
index 0000000..b9791cc
--- /dev/null
@@ -0,0 +1,17 @@
+git init r1 &&
+# LINT: loop handles failure explicitly with "|| return 1"
+for n in 1 2 3 4 5
+do
+       echo "This is file: $n" > r1/file.$n &&
+       git -C r1 add file.$n &&
+       git -C r1 commit -m "$n" || return 1
+done &&
+
+git init r2 &&
+# LINT: loop fails to handle failure explicitly with "|| return 1"
+for n in 1000 10000
+do
+       printf "%"$n"s" X > r2/large.$n &&
+       git -C r2 add large.$n &&
+       git -C r2 commit -m "$n"
+done
diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect
new file mode 100644 (file)
index 0000000..0ad23bb
--- /dev/null
@@ -0,0 +1,18 @@
+( while test $i -le $blobcount
+do
+       printf "Generating blob $i/$blobcount\r" >& 2 &&
+       printf "blob\nmark :$i\ndata $blobsize\n" &&
+
+       printf "%-${blobsize}s" $i &&
+       echo "M 100644 :$i $i" >> commit &&
+       i=$(($i+1)) ||
+       echo $? > exit-status
+done &&
+echo "commit refs/heads/main" &&
+echo "author A U Thor <author@email.com> 123456789 +0000" &&
+echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
+echo "data 5" &&
+echo ">2gb" &&
+cat commit ) |
+git fast-import --big-file-threshold=2 &&
+test ! -f exit-status
diff --git a/t/chainlint/loop-detect-status.test b/t/chainlint/loop-detect-status.test
new file mode 100644 (file)
index 0000000..1c6c23c
--- /dev/null
@@ -0,0 +1,19 @@
+# LINT: "$?" handled explicitly within loop body
+(while test $i -le $blobcount
+ do
+       printf "Generating blob $i/$blobcount\r" >&2 &&
+       printf "blob\nmark :$i\ndata $blobsize\n" &&
+       #test-tool genrandom $i $blobsize &&
+       printf "%-${blobsize}s" $i &&
+       echo "M 100644 :$i $i" >> commit &&
+       i=$(($i+1)) ||
+       echo $? > exit-status
+ done &&
+ echo "commit refs/heads/main" &&
+ echo "author A U Thor <author@email.com> 123456789 +0000" &&
+ echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
+ echo "data 5" &&
+ echo ">2gb" &&
+ cat commit) |
+git fast-import --big-file-threshold=2 &&
+test ! -f exit-status
index e1be42376c5ef480c791222dc0cc75d4d01fe1ce..6c5d6e5b2438ef826b15b45de67544f72f633543 100644 (file)
@@ -4,7 +4,7 @@
                while true
                do
                        echo "pop" ?!AMP?!
-                       echo "glup"
+                       echo "glup" ?!LOOP?!
                done ?!AMP?!
                foo
        fi ?!AMP?!
diff --git a/t/chainlint/loop-upstream-pipe.expect b/t/chainlint/loop-upstream-pipe.expect
new file mode 100644 (file)
index 0000000..0b82ecc
--- /dev/null
@@ -0,0 +1,10 @@
+(
+       git rev-list --objects --no-object-names base..loose |
+       while read oid
+       do
+               path="$objdir/$(test_oid_to_path "$oid")" &&
+               printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" ||
+               echo "object list generation failed for $oid"
+       done |
+       sort -k1
+) >expect &&
diff --git a/t/chainlint/loop-upstream-pipe.test b/t/chainlint/loop-upstream-pipe.test
new file mode 100644 (file)
index 0000000..efb77da
--- /dev/null
@@ -0,0 +1,11 @@
+(
+       git rev-list --objects --no-object-names base..loose |
+       while read oid
+       do
+# LINT: "|| echo" signals failure in loop upstream of a pipe
+               path="$objdir/$(test_oid_to_path "$oid")" &&
+               printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" ||
+               echo "object list generation failed for $oid"
+       done |
+       sort -k1
+) >expect &&
index ab0dadf748e859968e654cf8d6a28a3a5882460b..27ff95218e7f64ec7f4e816ba73174b77cb98ef2 100644 (file)
@@ -1,9 +1,14 @@
 (
-       x="line 1               line 2          line 3" &&
-       y="line 1               line2" ?!AMP?!
+       x="line 1
+               line 2
+               line 3" &&
+       y="line 1
+               line2" ?!AMP?!
        foobar
 ) &&
 (
-       echo "xyz" "abc         def             ghi" &&
+       echo "xyz" "abc
+               def
+               ghi" &&
        barfoo
 )
diff --git a/t/chainlint/nested-loop-detect-failure.expect b/t/chainlint/nested-loop-detect-failure.expect
new file mode 100644 (file)
index 0000000..4793a0e
--- /dev/null
@@ -0,0 +1,31 @@
+for i in 0 1 2 3 4 5 6 7 8 9 ;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9 ;
+       do
+               echo "$i$j" > "path$i$j" ?!LOOP?!
+       done ?!LOOP?!
+done &&
+
+for i in 0 1 2 3 4 5 6 7 8 9 ;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9 ;
+       do
+               echo "$i$j" > "path$i$j" || return 1
+       done
+done &&
+
+for i in 0 1 2 3 4 5 6 7 8 9 ;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9 ;
+       do
+               echo "$i$j" > "path$i$j" ?!LOOP?!
+       done || return 1
+done &&
+
+for i in 0 1 2 3 4 5 6 7 8 9 ;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9 ;
+       do
+               echo "$i$j" > "path$i$j" || return 1
+       done || return 1
+done
diff --git a/t/chainlint/nested-loop-detect-failure.test b/t/chainlint/nested-loop-detect-failure.test
new file mode 100644 (file)
index 0000000..e6f0c1a
--- /dev/null
@@ -0,0 +1,35 @@
+# LINT: neither loop handles failure explicitly with "|| return 1"
+for i in 0 1 2 3 4 5 6 7 8 9;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9;
+       do
+               echo "$i$j" >"path$i$j"
+       done
+done &&
+
+# LINT: inner loop handles failure explicitly with "|| return 1"
+for i in 0 1 2 3 4 5 6 7 8 9;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9;
+       do
+               echo "$i$j" >"path$i$j" || return 1
+       done
+done &&
+
+# LINT: outer loop handles failure explicitly with "|| return 1"
+for i in 0 1 2 3 4 5 6 7 8 9;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9;
+       do
+               echo "$i$j" >"path$i$j"
+       done || return 1
+done &&
+
+# LINT: inner & outer loops handles failure explicitly with "|| return 1"
+for i in 0 1 2 3 4 5 6 7 8 9;
+do
+       for j in 0 1 2 3 4 5 6 7 8 9;
+       do
+               echo "$i$j" >"path$i$j" || return 1
+       done || return 1
+done
index 41a48adaa2b8ff62784f9fe022281e094063e96a..02e0a9f1bb5f302a2903817b5d8ef7ff25b2efa7 100644 (file)
@@ -6,7 +6,7 @@
        ) >file &&
        cd foo &&
        (
-               echo a
+               echo a ?!AMP?!
                echo b
        ) >file
 )
diff --git a/t/chainlint/one-liner-for-loop.expect b/t/chainlint/one-liner-for-loop.expect
new file mode 100644 (file)
index 0000000..51a3dc7
--- /dev/null
@@ -0,0 +1,9 @@
+git init dir-rename-and-content &&
+(
+       cd dir-rename-and-content &&
+       test_write_lines 1 2 3 4 5 >foo &&
+       mkdir olddir &&
+       for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?!
+       git add foo olddir &&
+       git commit -m "original" &&
+)
diff --git a/t/chainlint/one-liner-for-loop.test b/t/chainlint/one-liner-for-loop.test
new file mode 100644 (file)
index 0000000..4bd8c06
--- /dev/null
@@ -0,0 +1,10 @@
+git init dir-rename-and-content &&
+(
+       cd dir-rename-and-content &&
+       test_write_lines 1 2 3 4 5 >foo &&
+       mkdir olddir &&
+# LINT: one-liner for-loop missing "|| exit"; also broken &&-chain
+       for i in a b c; do echo $i >olddir/$i; done
+       git add foo olddir &&
+       git commit -m "original" &&
+)
diff --git a/t/chainlint/return-loop.expect b/t/chainlint/return-loop.expect
new file mode 100644 (file)
index 0000000..cfc0549
--- /dev/null
@@ -0,0 +1,5 @@
+while test $i -lt $((num - 5))
+do
+       git notes add -m "notes for commit$i" HEAD~$i || return 1
+       i=$((i + 1))
+done
diff --git a/t/chainlint/return-loop.test b/t/chainlint/return-loop.test
new file mode 100644 (file)
index 0000000..f90b171
--- /dev/null
@@ -0,0 +1,6 @@
+while test $i -lt $((num - 5))
+do
+# LINT: "|| return {n}" valid loop escape outside subshell; no "&&" needed
+       git notes add -m "notes for commit$i" HEAD~$i || return 1
+       i=$((i + 1))
+done
index ed0b3707ae90139de0aec8e4ccd8d08301cff1dc..3aa2259f36c172b1da6e67d6a533da8238db7830 100644 (file)
@@ -15,5 +15,5 @@
 ) &&
 (cd foo &&
        for i in a b c; do
-               echo;
+               echo; ?!LOOP?!
        done)
diff --git a/t/chainlint/sqstring-in-sqstring.expect b/t/chainlint/sqstring-in-sqstring.expect
new file mode 100644 (file)
index 0000000..cf0b591
--- /dev/null
@@ -0,0 +1,4 @@
+perl -e '
+       defined($_ = -s $_) or die for @ARGV;
+       exit 1 if $ARGV[0] <= $ARGV[1];
+' test-2-$packname_2.pack test-3-$packname_3.pack
diff --git a/t/chainlint/sqstring-in-sqstring.test b/t/chainlint/sqstring-in-sqstring.test
new file mode 100644 (file)
index 0000000..77a425e
--- /dev/null
@@ -0,0 +1,5 @@
+# LINT: SQ-string Perl code fragment within SQ-string
+perl -e '\''
+       defined($_ = -s $_) or die for @ARGV;
+       exit 1 if $ARGV[0] <= $ARGV[1];
+'\'' test-2-$packname_2.pack test-3-$packname_3.pack
index 1cccc7bf7e1a47d9a922dda821b9eac513c83104..69167da2f27a3098297191c6cbfc737eacb91e8a 100644 (file)
@@ -1,10 +1,17 @@
 (
-       chks="sub1sub2sub3sub4" &&
+       chks="sub1
+sub2
+sub3
+sub4" &&
        chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
 ) &&
-       chkms="main-sub1main-sub2main-sub3main-sub4" &&
+       chkms="main-sub1
+main-sub2
+main-sub3
+main-sub4" &&
        chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
 ) &&
        subfiles=$(git ls-files) &&
-       check_equal "$subfiles" "$chkms$chks"
+       check_equal "$subfiles" "$chkms
+$chks"
 )
diff --git a/t/chainlint/token-pasting.expect b/t/chainlint/token-pasting.expect
new file mode 100644 (file)
index 0000000..342360b
--- /dev/null
@@ -0,0 +1,27 @@
+git config filter.rot13.smudge ./rot13.sh &&
+git config filter.rot13.clean ./rot13.sh &&
+
+{
+    echo "*.t filter=rot13" ?!AMP?!
+    echo "*.i ident"
+} > .gitattributes &&
+
+{
+    echo a b c d e f g h i j k l m ?!AMP?!
+    echo n o p q r s t u v w x y z ?!AMP?!
+    echo '$Id$'
+} > test &&
+cat test > test.t &&
+cat test > test.o &&
+cat test > test.i &&
+git add test test.t test.i &&
+rm -f test test.t test.i &&
+git checkout -- test test.t test.i &&
+
+echo "content-test2" > test2.o &&
+echo "content-test3 - filename with special characters" > "test3 'sq',$x=.o" ?!AMP?!
+
+downstream_url_for_sed=$(
+       printf "%sn" "$downstream_url" |
+       sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g'
+)
diff --git a/t/chainlint/token-pasting.test b/t/chainlint/token-pasting.test
new file mode 100644 (file)
index 0000000..b4610ce
--- /dev/null
@@ -0,0 +1,32 @@
+# LINT: single token; composite of multiple strings
+git config filter.rot13.smudge ./rot13.sh &&
+git config filter.rot13.clean ./rot13.sh &&
+
+{
+    echo "*.t filter=rot13"
+    echo "*.i ident"
+} >.gitattributes &&
+
+{
+    echo a b c d e f g h i j k l m
+    echo n o p q r s t u v w x y z
+# LINT: exit/enter string context and escaped-quote outside of string
+    echo '\''$Id$'\''
+} >test &&
+cat test >test.t &&
+cat test >test.o &&
+cat test >test.i &&
+git add test test.t test.i &&
+rm -f test test.t test.i &&
+git checkout -- test test.t test.i &&
+
+echo "content-test2" >test2.o &&
+# LINT: exit/enter string context and escaped-quote outside of string
+echo "content-test3 - filename with special characters" >"test3 '\''sq'\'',\$x=.o"
+
+# LINT: single token; composite of multiple strings
+downstream_url_for_sed=$(
+       printf "%s\n" "$downstream_url" |
+# LINT: exit/enter string context; "&" inside string not command terminator
+       sed -e '\''s/\\/\\\\/g'\'' -e '\''s/[[/.*^$]/\\&/g'\''
+)
index 0d3a9b3d128940a9515d9924964e9efeeaf48152..f272aa21fee1950a97a9eeddee9436a11c4e1f3f 100644 (file)
@@ -2,10 +2,10 @@
        while true
        do
                echo foo ?!AMP?!
-               cat <<-EOF
+               cat <<-EOF ?!LOOP?!
        done ?!AMP?!
        while true; do
                echo foo &&
-               cat bar
+               cat bar ?!LOOP?!
        done
 )
index fd3303552bec0d3ca243845634179eb35890866a..dd8107cd7da24b01541f0bccf4cff332940f31e9 100755 (executable)
@@ -45,6 +45,7 @@ while (<>) {
        /\bhead\s+-c\b/ and err 'head -c is not portable (use test_copy_bytes BYTES <file >out)';
        /(?:\$\(seq|^\s*seq\b)/ and err 'seq is not portable (use test_seq)';
        /\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)';
+       /\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)';
        /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)';
        /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and
                err '"FOO=bar shell_func" assignment extends beyond "shell_func"';
index ad3ef1cd77ae1b98db3c46980d1439f1ca5f56e7..6c900ca668467dcdbc92c6544ad173565c3a5f08 100644 (file)
@@ -16,6 +16,7 @@ static void add_string_to_filter(const char *data, struct bloom_filter *filter)
                }
                printf("\n");
                add_key_to_filter(&key, filter, &settings);
+               clear_bloom_key(&key);
 }
 
 static void print_bloom_filter(struct bloom_filter *filter) {
@@ -80,6 +81,7 @@ int cmd__bloom(int argc, const char **argv)
                }
 
                print_bloom_filter(&filter);
+               free(filter.data);
        }
 
        if (!strcmp(argv[1], "get_filter_for_commit")) {
index a6e936721fe660bb110e3d691d61dad80fddc307..4ba9eb65606d42f70f345a1b18bcd575db31e4cf 100644 (file)
@@ -37,7 +37,7 @@
  *
  */
 
-static int iterate_cb(const char *var, const char *value, void *data)
+static int iterate_cb(const char *var, const char *value, void *data UNUSED)
 {
        static int nr;
 
index e7c0137a4779ff005d3b440e1874d570a2d5d797..e6c1b1e22bb36da604af3238341f6b7b14753796 100644 (file)
@@ -2,33 +2,34 @@
 #include "cache.h"
 
 /*
- * Usage: test-tool cron <file> [-l]
+ * Usage: test-tool crontab <file> -l|<input>
  *
  * If -l is specified, then write the contents of <file> to stdout.
- * Otherwise, write from stdin into <file>.
+ * Otherwise, copy the contents of <input> into <file>.
  */
 int cmd__crontab(int argc, const char **argv)
 {
        int a;
        FILE *from, *to;
 
-       if (argc == 3 && !strcmp(argv[2], "-l")) {
+       if (argc != 3)
+               usage("test-tool crontab <file> -l|<input>");
+
+       if (!strcmp(argv[2], "-l")) {
                from = fopen(argv[1], "r");
                if (!from)
                        return 0;
                to = stdout;
-       } else if (argc == 2) {
-               from = stdin;
-               to = fopen(argv[1], "w");
-       } else
-               return error("unknown arguments");
+       } else {
+               from = xfopen(argv[2], "r");
+               to = xfopen(argv[1], "w");
+       }
 
        while ((a = fgetc(from)) != EOF)
                fputc(a, to);
 
-       if (argc == 3)
-               fclose(from);
-       else
+       fclose(from);
+       if (to != stdout)
                fclose(to);
 
        return 0;
index e749a49c88e66e4b3ce388b2c0762d36d4090f99..b15481ea596dcdd2337a4dd9d99761ecb5514ea4 100644 (file)
@@ -20,8 +20,9 @@ int cmd__delta(int argc, const char **argv)
 {
        int fd;
        struct stat st;
-       void *from_buf, *data_buf, *out_buf;
+       void *from_buf = NULL, *data_buf = NULL, *out_buf = NULL;
        unsigned long from_size, data_size, out_size;
+       int ret = 1;
 
        if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) {
                fprintf(stderr, "usage: %s\n", usage_str);
@@ -38,21 +39,21 @@ int cmd__delta(int argc, const char **argv)
        if (read_in_full(fd, from_buf, from_size) < 0) {
                perror(argv[2]);
                close(fd);
-               return 1;
+               goto cleanup;
        }
        close(fd);
 
        fd = open(argv[3], O_RDONLY);
        if (fd < 0 || fstat(fd, &st)) {
                perror(argv[3]);
-               return 1;
+               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);
-               return 1;
+               goto cleanup;
        }
        close(fd);
 
@@ -66,14 +67,20 @@ int cmd__delta(int argc, const char **argv)
                                      &out_size);
        if (!out_buf) {
                fprintf(stderr, "delta operation failed (returned NULL)\n");
-               return 1;
+               goto cleanup;
        }
 
        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]);
-               return 1;
+               goto cleanup;
        }
 
-       return 0;
+       ret = 0;
+cleanup:
+       free(from_buf);
+       free(data_buf);
+       free(out_buf);
+
+       return ret;
 }
index 6a3f88f5f5d4a8af09dca7c13da6132d66093ca2..0d6d7f1ecbf198af006b4d80b8027a196d5caab3 100644 (file)
@@ -59,11 +59,16 @@ int cmd__dump_cache_tree(int ac, const char **av)
 {
        struct index_state istate;
        struct cache_tree *another = cache_tree();
+       int ret;
+
        setup_git_directory();
        if (read_cache() < 0)
                die("unable to read index file");
        istate = the_index;
        istate.cache_tree = another;
        cache_tree_update(&istate, WRITE_TREE_DRY_RUN);
-       return dump_cache_tree(active_cache_tree, another, "");
+       ret = dump_cache_tree(active_cache_tree, another, "");
+       cache_tree_free(&another);
+
+       return ret;
 }
index 4e5553e20249debf36a76296f18599300ee91af5..45665ec19a5d6d4e2cf37c1a2a9f87d69ff3be02 100644 (file)
@@ -184,8 +184,6 @@ int cmd__fast_rebase(int argc, const char **argv)
                last_picked_commit = commit;
                last_commit = create_commit(result.tree, commit, last_commit);
        }
-       /* TODO: There should be some kind of rev_info_free(&revs) call... */
-       memset(&revs, 0, sizeof(revs));
 
        merge_switch_to_result(&merge_opt, head_tree, &result, 1, !result.clean);
 
index 261c545b9d199c6ba8c87eaaab7ce8da4f5cba69..5860dab0ffac976bc3e6d0ef2da2153566477018 100644 (file)
@@ -54,5 +54,6 @@ int cmd_hash_impl(int ac, const char **av, int algo)
                fwrite(hash, 1, algop->rawsz, stdout);
        else
                puts(hash_to_hex_algop(hash, algop));
+       free(buffer);
        return 0;
 }
index 37c452535f8bb2bcb3ee27461097ef0bf578ebac..8c3edacc0007df7ddb52f2f65d00e44b95edeb5a 100644 (file)
@@ -181,12 +181,18 @@ static struct json_writer nest1 = JSON_WRITER_INIT;
 
 static void make_nest1(int pretty)
 {
+       make_obj1(0);
+       make_arr1(0);
+
        jw_object_begin(&nest1, pretty);
        {
                jw_object_sub_jw(&nest1, "obj1", &obj1);
                jw_object_sub_jw(&nest1, "arr1", &arr1);
        }
        jw_end(&nest1);
+
+       jw_release(&obj1);
+       jw_release(&arr1);
 }
 
 static char *expect_inline1 =
@@ -313,6 +319,9 @@ static void make_mixed1(int pretty)
                jw_object_sub_jw(&mixed1, "arr1", &arr1);
        }
        jw_end(&mixed1);
+
+       jw_release(&obj1);
+       jw_release(&arr1);
 }
 
 static void cmp(const char *test, const struct json_writer *jw, const char *exp)
@@ -325,8 +334,8 @@ static void cmp(const char *test, const struct json_writer *jw, const char *exp)
        exit(1);
 }
 
-#define t(v) do { make_##v(0); cmp(#v, &v, expect_##v); } while (0)
-#define p(v) do { make_##v(1); cmp(#v, &v, pretty_##v); } while (0)
+#define t(v) do { make_##v(0); cmp(#v, &v, expect_##v); jw_release(&v); } while (0)
+#define p(v) do { make_##v(1); cmp(#v, &v, pretty_##v); jw_release(&v); } while (0)
 
 /*
  * Run some basic regression tests with some known patterns.
@@ -381,7 +390,6 @@ static int unit_tests(void)
 
        /* mixed forms */
        t(mixed1);
-       jw_init(&mixed1);
        p(mixed1);
 
        return 0;
@@ -544,7 +552,7 @@ static int scripted(void)
 
        printf("%s\n", jw.json.buf);
 
-       strbuf_release(&jw.json);
+       jw_release(&jw);
        return 0;
 }
 
index ebf68f7de82465d2761bceedd47715badbf76dbb..335e5bb3a9008c8ce1cb31198bd54808c70566dc 100644 (file)
@@ -13,41 +13,46 @@ struct line {
        struct line *next;
 };
 
-static void *get_next(const void *a)
-{
-       return ((const struct line *)a)->next;
-}
+DEFINE_LIST_SORT(static, sort_lines, struct line, next);
 
-static void set_next(void *a, void *b)
+static int compare_strings(const struct line *x, const struct line *y)
 {
-       ((struct line *)a)->next = b;
-}
-
-static int compare_strings(const void *a, const void *b)
-{
-       const struct line *x = a, *y = b;
        return strcmp(x->text, y->text);
 }
 
 static int sort_stdin(void)
 {
-       struct line *line, *p = NULL, *lines = NULL;
+       struct line *lines;
+       struct line **tail = &lines;
        struct strbuf sb = STRBUF_INIT;
-
-       while (!strbuf_getline(&sb, stdin)) {
-               line = xmalloc(sizeof(struct line));
-               line->text = strbuf_detach(&sb, NULL);
-               if (p) {
-                       line->next = p->next;
-                       p->next = line;
-               } else {
-                       line->next = NULL;
-                       lines = line;
-               }
-               p = line;
+       struct mem_pool lines_pool;
+       char *p;
+
+       strbuf_read(&sb, 0, 0);
+
+       /*
+        * Split by newline, but don't create an item
+        * for the empty string after the last separator.
+        */
+       if (sb.len && sb.buf[sb.len - 1] == '\n')
+               strbuf_setlen(&sb, sb.len - 1);
+
+       mem_pool_init(&lines_pool, 0);
+       p = sb.buf;
+       for (;;) {
+               char *eol = strchr(p, '\n');
+               struct line *line = mem_pool_alloc(&lines_pool, sizeof(*line));
+               line->text = p;
+               *tail = line;
+               tail = &line->next;
+               if (!eol)
+                       break;
+               *eol = '\0';
+               p = eol + 1;
        }
+       *tail = NULL;
 
-       lines = llist_mergesort(lines, get_next, set_next, compare_strings);
+       sort_lines(&lines, compare_strings);
 
        while (lines) {
                puts(lines->text);
@@ -273,21 +278,11 @@ struct number {
        struct number *next;
 };
 
-static void *get_next_number(const void *a)
-{
-       stats.get_next++;
-       return ((const struct number *)a)->next;
-}
-
-static void set_next_number(void *a, void *b)
-{
-       stats.set_next++;
-       ((struct number *)a)->next = b;
-}
+DEFINE_LIST_SORT_DEBUG(static, sort_numbers, struct number, next,
+                      stats.get_next++, stats.set_next++);
 
-static int compare_numbers(const void *av, const void *bv)
+static int compare_numbers(const struct number *an, const struct number *bn)
 {
-       const struct number *an = av, *bn = bv;
        int a = an->value, b = bn->value;
        stats.compare++;
        return (a > b) - (a < b);
@@ -325,8 +320,7 @@ static int test(const struct dist *dist, const struct mode *mode, int n, int m)
        *tail = NULL;
 
        stats.get_next = stats.set_next = stats.compare = 0;
-       list = llist_mergesort(list, get_next_number, set_next_number,
-                              compare_numbers);
+       sort_numbers(&list, compare_numbers);
 
        QSORT(arr, n, compare_ints);
        for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
index 48d3cf6692da0612eff2f8c61051780ef944def6..506835521a463aebd1a06259cf96e05d71e3833b 100644 (file)
@@ -192,3 +192,131 @@ int cmd__parse_options(int argc, const char **argv)
 
        return ret;
 }
+
+static void print_args(int argc, const char **argv)
+{
+       int i;
+       for (i = 0; i < argc; i++)
+               printf("arg %02d: %s\n", i, argv[i]);
+}
+
+static int parse_options_flags__cmd(int argc, const char **argv,
+                                   enum parse_opt_flags test_flags)
+{
+       const char *usage[] = {
+               "<...> cmd [options]",
+               NULL
+       };
+       int opt = 0;
+       const struct option options[] = {
+               OPT_INTEGER('o', "opt", &opt, "an integer option"),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, NULL, options, usage, test_flags);
+
+       printf("opt: %d\n", opt);
+       print_args(argc, argv);
+
+       return 0;
+}
+
+static enum parse_opt_flags test_flags = 0;
+static const struct option test_flag_options[] = {
+       OPT_GROUP("flag-options:"),
+       OPT_BIT(0, "keep-dashdash", &test_flags,
+               "pass PARSE_OPT_KEEP_DASHDASH to parse_options()",
+               PARSE_OPT_KEEP_DASHDASH),
+       OPT_BIT(0, "stop-at-non-option", &test_flags,
+               "pass PARSE_OPT_STOP_AT_NON_OPTION to parse_options()",
+               PARSE_OPT_STOP_AT_NON_OPTION),
+       OPT_BIT(0, "keep-argv0", &test_flags,
+               "pass PARSE_OPT_KEEP_ARGV0 to parse_options()",
+               PARSE_OPT_KEEP_ARGV0),
+       OPT_BIT(0, "keep-unknown-opt", &test_flags,
+               "pass PARSE_OPT_KEEP_UNKNOWN_OPT to parse_options()",
+               PARSE_OPT_KEEP_UNKNOWN_OPT),
+       OPT_BIT(0, "no-internal-help", &test_flags,
+               "pass PARSE_OPT_NO_INTERNAL_HELP to parse_options()",
+               PARSE_OPT_NO_INTERNAL_HELP),
+       OPT_BIT(0, "subcommand-optional", &test_flags,
+               "pass PARSE_OPT_SUBCOMMAND_OPTIONAL to parse_options()",
+               PARSE_OPT_SUBCOMMAND_OPTIONAL),
+       OPT_END()
+};
+
+int cmd__parse_options_flags(int argc, const char **argv)
+{
+       const char *usage[] = {
+               "test-tool parse-options-flags [flag-options] cmd [options]",
+               NULL
+       };
+
+       argc = parse_options(argc, argv, NULL, test_flag_options, usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (!argc || strcmp(argv[0], "cmd")) {
+               error("'cmd' is mandatory");
+               usage_with_options(usage, test_flag_options);
+       }
+
+       return parse_options_flags__cmd(argc, argv, test_flags);
+}
+
+static int subcmd_one(int argc, const char **argv, const char *prefix)
+{
+       printf("fn: subcmd_one\n");
+       print_args(argc, argv);
+       return 0;
+}
+
+static int subcmd_two(int argc, const char **argv, const char *prefix)
+{
+       printf("fn: subcmd_two\n");
+       print_args(argc, argv);
+       return 0;
+}
+
+static int parse_subcommand__cmd(int argc, const char **argv,
+                                enum parse_opt_flags test_flags)
+{
+       const char *usage[] = {
+               "<...> cmd subcmd-one",
+               "<...> cmd subcmd-two",
+               NULL
+       };
+       parse_opt_subcommand_fn *fn = NULL;
+       int opt = 0;
+       struct option options[] = {
+               OPT_SUBCOMMAND("subcmd-one", &fn, subcmd_one),
+               OPT_SUBCOMMAND("subcmd-two", &fn, subcmd_two),
+               OPT_INTEGER('o', "opt", &opt, "an integer option"),
+               OPT_END()
+       };
+
+       if (test_flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
+               fn = subcmd_one;
+       argc = parse_options(argc, argv, NULL, options, usage, test_flags);
+
+       printf("opt: %d\n", opt);
+
+       return fn(argc, argv, NULL);
+}
+
+int cmd__parse_subcommand(int argc, const char **argv)
+{
+       const char *usage[] = {
+               "test-tool parse-subcommand [flag-options] cmd <subcommand>",
+               NULL
+       };
+
+       argc = parse_options(argc, argv, NULL, test_flag_options, usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (!argc || strcmp(argv[0], "cmd")) {
+               error("'cmd' is mandatory");
+               usage_with_options(usage, test_flag_options);
+       }
+
+       return parse_subcommand__cmd(argc, argv, test_flags);
+}
index 229ed416b0e67867331bfd75fe376834766f7da5..d20e1b7a18d613a97b00e29fa491dc7e1654b21a 100644 (file)
@@ -296,9 +296,8 @@ int cmd__path_utils(int argc, const char **argv)
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
                char *buf = xmallocz(strlen(argv[2]));
                int rv = normalize_path_copy(buf, argv[2]);
-               if (rv)
-                       buf = "++failed++";
-               puts(buf);
+               puts(rv ? "++failed++" : buf);
+               free(buf);
                return 0;
        }
 
@@ -356,7 +355,10 @@ int cmd__path_utils(int argc, const char **argv)
                int nongit_ok;
                setup_git_directory_gently(&nongit_ok);
                while (argc > 3) {
-                       puts(prefix_path(prefix, prefix_len, argv[3]));
+                       char *pfx = prefix_path(prefix, prefix_len, argv[3]);
+
+                       puts(pfx);
+                       free(pfx);
                        argc--;
                        argv++;
                }
@@ -366,6 +368,7 @@ int cmd__path_utils(int argc, const char **argv)
        if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) {
                char *prefix = strip_path_suffix(argv[2], argv[3]);
                printf("%s\n", prefix ? prefix : "(null)");
+               free(prefix);
                return 0;
        }
 
index 9646d85fc84a9e52ff4c05e7614a9582c0fc3b7e..ae8a5648daf5c1385afe43f327bf9a5a3d98e1f1 100644 (file)
@@ -96,6 +96,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)
                        die("no such worktree: %s", gitdir);
 
                *refs = get_worktree_ref_store(*p);
+               free_worktrees(worktrees);
        } else
                die("unknown backend %s", argv[0]);
 
@@ -160,7 +161,7 @@ static int cmd_rename_ref(struct ref_store *refs, const char **argv)
 }
 
 static int each_ref(const char *refname, const struct object_id *oid,
-                   int flags, void *cb_data)
+                   int flags, void *cb_data UNUSED)
 {
        printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags);
        return 0;
@@ -206,7 +207,7 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)
 
 static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,
                       const char *committer, timestamp_t timestamp,
-                      int tz, const char *msg, void *cb_data)
+                      int tz, const char *msg, void *cb_data UNUSED)
 {
        printf("%s %s %s %" PRItime " %+05d%s%s", oid_to_hex(old_oid),
               oid_to_hex(new_oid), committer, timestamp, tz,
index d6f28ca8d148d9c05fa2941b59054840da0b156f..bd871a735b4fbb19ed99e9bfab56f13d138a0567 100644 (file)
@@ -34,6 +34,7 @@ static int test_regex_bug(void)
        if (m[0].rm_so == 3) /* matches '\n' when it should not */
                die("regex bug confirmed: re-build git with NO_REGEX=1");
 
+       regfree(&r);
        return 0;
 }
 
@@ -94,18 +95,20 @@ int cmd__regex(int argc, const char **argv)
                die("failed regcomp() for pattern '%s' (%s)", pat, errbuf);
        }
        if (!str)
-               return 0;
+               goto cleanup;
 
        ret = regexec(&r, str, 1, m, 0);
        if (ret) {
                if (silent || ret == REG_NOMATCH)
-                       return ret;
+                       goto cleanup;
 
                regerror(ret, &r, errbuf, sizeof(errbuf));
                die("failed regexec() for subject '%s' (%s)", str, errbuf);
        }
 
-       return 0;
+cleanup:
+       regfree(&r);
+       return ret;
 usage:
        usage("\ttest-tool regex --bug\n"
              "\ttest-tool regex [--silent] <pattern>\n"
diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c
new file mode 100644 (file)
index 0000000..f8d564c
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Example implementation for the Git filter protocol version 2
+ * See Documentation/gitattributes.txt, section "Filter Protocol"
+ *
+ * Usage: test-tool rot13-filter [--always-delay] --log=<path> <capabilities>
+ *
+ * Log path defines a debug log file that the script writes to. The
+ * subsequent arguments define a list of supported protocol capabilities
+ * ("clean", "smudge", etc).
+ *
+ * When --always-delay is given all pathnames with the "can-delay" flag
+ * that don't appear on the list bellow are delayed with a count of 1
+ * (see more below).
+ *
+ * This implementation supports special test cases:
+ * (1) If data with the pathname "clean-write-fail.r" is processed with
+ *     a "clean" operation then the write operation will die.
+ * (2) If data with the pathname "smudge-write-fail.r" is processed with
+ *     a "smudge" operation then the write operation will die.
+ * (3) If data with the pathname "error.r" is processed with any
+ *     operation then the filter signals that it cannot or does not want
+ *     to process the file.
+ * (4) If data with the pathname "abort.r" is processed with any
+ *     operation then the filter signals that it cannot or does not want
+ *     to process the file and any file after that is processed with the
+ *     same command.
+ * (5) If data with a pathname that is a key in the delay hash is
+ *     requested (e.g. "test-delay10.a") then the filter responds with
+ *     a "delay" status and sets the "requested" field in the delay hash.
+ *     The filter will signal the availability of this object after
+ *     "count" (field in delay hash) "list_available_blobs" commands.
+ * (6) If data with the pathname "missing-delay.a" is processed that the
+ *     filter will drop the path from the "list_available_blobs" response.
+ * (7) If data with the pathname "invalid-delay.a" is processed that the
+ *     filter will add the path "unfiltered" which was not delayed before
+ *     to the "list_available_blobs" response.
+ */
+
+#include "test-tool.h"
+#include "pkt-line.h"
+#include "string-list.h"
+#include "strmap.h"
+#include "parse-options.h"
+
+static FILE *logfile;
+static int always_delay, has_clean_cap, has_smudge_cap;
+static struct strmap delay = STRMAP_INIT;
+
+static inline const char *str_or_null(const char *str)
+{
+       return str ? str : "(null)";
+}
+
+static char *rot13(char *str)
+{
+       char *c;
+       for (c = str; *c; c++)
+               if (isalpha(*c))
+                       *c += tolower(*c) < 'n' ? 13 : -13;
+       return str;
+}
+
+static char *get_value(char *buf, const char *key)
+{
+       const char *orig_buf = buf;
+       if (!buf ||
+           !skip_prefix((const char *)buf, key, (const char **)&buf) ||
+           !skip_prefix((const char *)buf, "=", (const char **)&buf) ||
+           !*buf)
+               die("expected key '%s', got '%s'", key, str_or_null(orig_buf));
+       return buf;
+}
+
+/*
+ * Read a text packet, expecting that it is in the form "key=value" for
+ * the given key. An EOF does not trigger any error and is reported
+ * back to the caller with NULL. Die if the "key" part of "key=value" does
+ * not match the given key, or the value part is empty.
+ */
+static char *packet_key_val_read(const char *key)
+{
+       char *buf;
+       if (packet_read_line_gently(0, NULL, &buf) < 0)
+               return NULL;
+       return xstrdup(get_value(buf, key));
+}
+
+static inline void assert_remote_capability(struct strset *caps, const char *cap)
+{
+       if (!strset_contains(caps, cap))
+               die("required '%s' capability not available from remote", cap);
+}
+
+static void read_capabilities(struct strset *remote_caps)
+{
+       for (;;) {
+               char *buf = packet_read_line(0, NULL);
+               if (!buf)
+                       break;
+               strset_add(remote_caps, get_value(buf, "capability"));
+       }
+
+       assert_remote_capability(remote_caps, "clean");
+       assert_remote_capability(remote_caps, "smudge");
+       assert_remote_capability(remote_caps, "delay");
+}
+
+static void check_and_write_capabilities(struct strset *remote_caps,
+                                        const char **caps, int nr_caps)
+{
+       int i;
+       for (i = 0; i < nr_caps; i++) {
+               if (!strset_contains(remote_caps, caps[i]))
+                       die("our capability '%s' is not available from remote",
+                           caps[i]);
+               packet_write_fmt(1, "capability=%s\n", caps[i]);
+       }
+       packet_flush(1);
+}
+
+struct delay_entry {
+       int requested, count;
+       char *output;
+};
+
+static void free_delay_entries(void)
+{
+       struct hashmap_iter iter;
+       struct strmap_entry *ent;
+
+       strmap_for_each_entry(&delay, &iter, ent) {
+               struct delay_entry *delay_entry = ent->value;
+               free(delay_entry->output);
+               free(delay_entry);
+       }
+       strmap_clear(&delay, 0);
+}
+
+static void add_delay_entry(char *pathname, int count, int requested)
+{
+       struct delay_entry *entry = xcalloc(1, sizeof(*entry));
+       entry->count = count;
+       entry->requested = requested;
+       if (strmap_put(&delay, pathname, entry))
+               BUG("adding the same path twice to delay hash?");
+}
+
+static void reply_list_available_blobs_cmd(void)
+{
+       struct hashmap_iter iter;
+       struct strmap_entry *ent;
+       struct string_list_item *str_item;
+       struct string_list paths = STRING_LIST_INIT_NODUP;
+
+       /* flush */
+       if (packet_read_line(0, NULL))
+               die("bad list_available_blobs end");
+
+       strmap_for_each_entry(&delay, &iter, ent) {
+               struct delay_entry *delay_entry = ent->value;
+               if (!delay_entry->requested)
+                       continue;
+               delay_entry->count--;
+               if (!strcmp(ent->key, "invalid-delay.a")) {
+                       /* Send Git a pathname that was not delayed earlier */
+                       packet_write_fmt(1, "pathname=unfiltered");
+               }
+               if (!strcmp(ent->key, "missing-delay.a")) {
+                       /* Do not signal Git that this file is available */
+               } else if (!delay_entry->count) {
+                       string_list_append(&paths, ent->key);
+                       packet_write_fmt(1, "pathname=%s", ent->key);
+               }
+       }
+
+       /* Print paths in sorted order. */
+       string_list_sort(&paths);
+       for_each_string_list_item(str_item, &paths)
+               fprintf(logfile, " %s", str_item->string);
+       string_list_clear(&paths, 0);
+
+       packet_flush(1);
+
+       fprintf(logfile, " [OK]\n");
+       packet_write_fmt(1, "status=success");
+       packet_flush(1);
+}
+
+static void command_loop(void)
+{
+       for (;;) {
+               char *buf, *output;
+               char *pathname;
+               struct delay_entry *entry;
+               struct strbuf input = STRBUF_INIT;
+               char *command = packet_key_val_read("command");
+
+               if (!command) {
+                       fprintf(logfile, "STOP\n");
+                       break;
+               }
+               fprintf(logfile, "IN: %s", command);
+
+               if (!strcmp(command, "list_available_blobs")) {
+                       reply_list_available_blobs_cmd();
+                       free(command);
+                       continue;
+               }
+
+               pathname = packet_key_val_read("pathname");
+               if (!pathname)
+                       die("unexpected EOF while expecting pathname");
+               fprintf(logfile, " %s", pathname);
+
+               /* Read until flush */
+               while ((buf = packet_read_line(0, NULL))) {
+                       if (!strcmp(buf, "can-delay=1")) {
+                               entry = strmap_get(&delay, pathname);
+                               if (entry && !entry->requested)
+                                       entry->requested = 1;
+                               else if (!entry && always_delay)
+                                       add_delay_entry(pathname, 1, 1);
+                       } else if (starts_with(buf, "ref=") ||
+                                  starts_with(buf, "treeish=") ||
+                                  starts_with(buf, "blob=")) {
+                               fprintf(logfile, " %s", buf);
+                       } else {
+                               /*
+                                * In general, filters need to be graceful about
+                                * new metadata, since it's documented that we
+                                * can pass any key-value pairs, but for tests,
+                                * let's be a little stricter.
+                                */
+                               die("Unknown message '%s'", buf);
+                       }
+               }
+
+               read_packetized_to_strbuf(0, &input, 0);
+               fprintf(logfile, " %"PRIuMAX" [OK] -- ", (uintmax_t)input.len);
+
+               entry = strmap_get(&delay, pathname);
+               if (entry && entry->output) {
+                       output = entry->output;
+               } else if (!strcmp(pathname, "error.r") || !strcmp(pathname, "abort.r")) {
+                       output = "";
+               } else if (!strcmp(command, "clean") && has_clean_cap) {
+                       output = rot13(input.buf);
+               } else if (!strcmp(command, "smudge") && has_smudge_cap) {
+                       output = rot13(input.buf);
+               } else {
+                       die("bad command '%s'", command);
+               }
+
+               if (!strcmp(pathname, "error.r")) {
+                       fprintf(logfile, "[ERROR]\n");
+                       packet_write_fmt(1, "status=error");
+                       packet_flush(1);
+               } else if (!strcmp(pathname, "abort.r")) {
+                       fprintf(logfile, "[ABORT]\n");
+                       packet_write_fmt(1, "status=abort");
+                       packet_flush(1);
+               } else if (!strcmp(command, "smudge") &&
+                          (entry = strmap_get(&delay, pathname)) &&
+                          entry->requested == 1) {
+                       fprintf(logfile, "[DELAYED]\n");
+                       packet_write_fmt(1, "status=delayed");
+                       packet_flush(1);
+                       entry->requested = 2;
+                       if (entry->output != output) {
+                               free(entry->output);
+                               entry->output = xstrdup(output);
+                       }
+               } else {
+                       int i, nr_packets = 0;
+                       size_t output_len;
+                       const char *p;
+                       packet_write_fmt(1, "status=success");
+                       packet_flush(1);
+
+                       if (skip_prefix(pathname, command, &p) &&
+                           !strcmp(p, "-write-fail.r")) {
+                               fprintf(logfile, "[WRITE FAIL]\n");
+                               die("%s write error", command);
+                       }
+
+                       output_len = strlen(output);
+                       fprintf(logfile, "OUT: %"PRIuMAX" ", (uintmax_t)output_len);
+
+                       if (write_packetized_from_buf_no_flush_count(output,
+                               output_len, 1, &nr_packets))
+                               die("failed to write buffer to stdout");
+                       packet_flush(1);
+
+                       for (i = 0; i < nr_packets; i++)
+                               fprintf(logfile, ".");
+                       fprintf(logfile, " [OK]\n");
+
+                       packet_flush(1);
+               }
+               free(pathname);
+               strbuf_release(&input);
+               free(command);
+       }
+}
+
+static void packet_initialize(void)
+{
+       char *pkt_buf = packet_read_line(0, NULL);
+
+       if (!pkt_buf || strcmp(pkt_buf, "git-filter-client"))
+               die("bad initialize: '%s'", str_or_null(pkt_buf));
+
+       pkt_buf = packet_read_line(0, NULL);
+       if (!pkt_buf || strcmp(pkt_buf, "version=2"))
+               die("bad version: '%s'", str_or_null(pkt_buf));
+
+       pkt_buf = packet_read_line(0, NULL);
+       if (pkt_buf)
+               die("bad version end: '%s'", pkt_buf);
+
+       packet_write_fmt(1, "git-filter-server");
+       packet_write_fmt(1, "version=2");
+       packet_flush(1);
+}
+
+static const char *rot13_usage[] = {
+       "test-tool rot13-filter [--always-delay] --log=<path> <capabilities>",
+       NULL
+};
+
+int cmd__rot13_filter(int argc, const char **argv)
+{
+       int i, nr_caps;
+       struct strset remote_caps = STRSET_INIT;
+       const char *log_path = NULL;
+
+       struct option options[] = {
+               OPT_BOOL(0, "always-delay", &always_delay,
+                        "delay all paths with the can-delay flag"),
+               OPT_STRING(0, "log", &log_path, "path",
+                          "path to the debug log file"),
+               OPT_END()
+       };
+       nr_caps = parse_options(argc, argv, NULL, options, rot13_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (!log_path || !nr_caps)
+               usage_with_options(rot13_usage, options);
+
+       logfile = fopen(log_path, "a");
+       if (!logfile)
+               die_errno("failed to open log file");
+
+       for (i = 0; i < nr_caps; i++) {
+               if (!strcmp(argv[i], "smudge"))
+                       has_smudge_cap = 1;
+               if (!strcmp(argv[i], "clean"))
+                       has_clean_cap = 1;
+       }
+
+       add_delay_entry("test-delay10.a", 1, 0);
+       add_delay_entry("test-delay11.a", 1, 0);
+       add_delay_entry("test-delay20.a", 2, 0);
+       add_delay_entry("test-delay10.b", 1, 0);
+       add_delay_entry("missing-delay.a", 1, 0);
+       add_delay_entry("invalid-delay.a", 1, 0);
+
+       fprintf(logfile, "START\n");
+       packet_initialize();
+
+       read_capabilities(&remote_caps);
+       check_and_write_capabilities(&remote_caps, argv, nr_caps);
+       fprintf(logfile, "init handshake complete\n");
+       strset_clear(&remote_caps);
+
+       command_loop();
+
+       if (fclose(logfile))
+               die_errno("error closing logfile");
+       free_delay_entries();
+       return 0;
+}
index 393f1604ff954703a2a5e075fbda1e14d0827dc0..026c802479d012b30bc625c820f5d0fcc25e997c 100644 (file)
@@ -12,6 +12,7 @@ int cmd__scrap_cache_tree(int ac, const char **av)
        hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
        if (read_cache() < 0)
                die("unable to read index file");
+       cache_tree_free(&active_cache_tree);
        active_cache_tree = NULL;
        if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
                die("unable to write index file");
index 28e905afc36afdc3202ec68ac915b1ddc6a08781..824e5c0a95819f8d11393a74da4b231728bb0615 100644 (file)
@@ -24,7 +24,7 @@ int cmd__serve_v2(int argc, const char **argv)
        /* ignore all unknown cmdline switches for now */
        argc = parse_options(argc, argv, prefix, options, serve_usage,
                             PARSE_OPT_KEEP_DASHDASH |
-                            PARSE_OPT_KEEP_UNKNOWN);
+                            PARSE_OPT_KEEP_UNKNOWN_OPT);
 
        if (advertise_capabilities)
                protocol_v2_advertise_capabilities();
index e2692746dfdb0e6a5c3b1c748124059bcbdd5fae..22a41c409263c077843598e4cc51881a52b0ce30 100644 (file)
@@ -15,14 +15,11 @@ int cmd__submodule_config(int argc, const char **argv)
 {
        const char **arg = argv;
        int my_argc = argc;
-       int output_url = 0;
        int lookup_name = 0;
 
        arg++;
        my_argc--;
        while (arg[0] && starts_with(arg[0], "--")) {
-               if (!strcmp(arg[0], "--url"))
-                       output_url = 1;
                if (!strcmp(arg[0], "--name"))
                        lookup_name = 1;
                arg++;
@@ -57,12 +54,8 @@ int cmd__submodule_config(int argc, const char **argv)
                if (!submodule)
                        die_usage(argc, argv, "Submodule not found.");
 
-               if (output_url)
-                       printf("Submodule url: '%s' for path '%s'\n",
-                                       submodule->url, submodule->path);
-               else
-                       printf("Submodule name: '%s' for path '%s'\n",
-                                       submodule->name, submodule->path);
+               printf("Submodule name: '%s' for path '%s'\n", submodule->name,
+                      submodule->path);
 
                arg += 2;
        }
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
new file mode 100644 (file)
index 0000000..e0e0c53
--- /dev/null
@@ -0,0 +1,146 @@
+#include "test-tool.h"
+#include "test-tool-utils.h"
+#include "cache.h"
+#include "parse-options.h"
+#include "remote.h"
+#include "submodule-config.h"
+#include "submodule.h"
+
+#define TEST_TOOL_CHECK_NAME_USAGE \
+       "test-tool submodule check-name <name>"
+static const char *submodule_check_name_usage[] = {
+       TEST_TOOL_CHECK_NAME_USAGE,
+       NULL
+};
+
+#define TEST_TOOL_IS_ACTIVE_USAGE \
+       "test-tool submodule is-active <name>"
+static const char *submodule_is_active_usage[] = {
+       TEST_TOOL_IS_ACTIVE_USAGE,
+       NULL
+};
+
+#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \
+       "test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>"
+static const char *submodule_resolve_relative_url_usage[] = {
+       TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,
+       NULL,
+};
+
+static const char *submodule_usage[] = {
+       TEST_TOOL_CHECK_NAME_USAGE,
+       TEST_TOOL_IS_ACTIVE_USAGE,
+       TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,
+       NULL
+};
+
+/*
+ * Exit non-zero if any of the submodule names given on the command line is
+ * invalid. If no names are given, filter stdin to print only valid names
+ * (which is primarily intended for testing).
+ */
+static int check_name(int argc, const char **argv)
+{
+       if (argc > 1) {
+               while (*++argv) {
+                       if (check_submodule_name(*argv) < 0)
+                               return 1;
+               }
+       } else {
+               struct strbuf buf = STRBUF_INIT;
+               while (strbuf_getline(&buf, stdin) != EOF) {
+                       if (!check_submodule_name(buf.buf))
+                               printf("%s\n", buf.buf);
+               }
+               strbuf_release(&buf);
+       }
+       return 0;
+}
+
+static int cmd__submodule_check_name(int argc, const char **argv)
+{
+       struct option options[] = {
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, "test-tools", options,
+                            submodule_check_name_usage, 0);
+       if (argc)
+               usage_with_options(submodule_check_name_usage, options);
+
+       return check_name(argc, argv);
+}
+
+static int cmd__submodule_is_active(int argc, const char **argv)
+{
+       struct option options[] = {
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, "test-tools", options,
+                            submodule_is_active_usage, 0);
+       if (argc != 1)
+               usage_with_options(submodule_is_active_usage, options);
+
+       setup_git_directory();
+
+       return !is_submodule_active(the_repository, argv[0]);
+}
+
+static int resolve_relative_url(int argc, const char **argv)
+{
+       char *remoteurl, *res;
+       const char *up_path, *url;
+
+       up_path = argv[0];
+       remoteurl = xstrdup(argv[1]);
+       url = argv[2];
+
+       if (!strcmp(up_path, "(null)"))
+               up_path = NULL;
+
+       res = relative_url(remoteurl, url, up_path);
+       puts(res);
+       free(res);
+       free(remoteurl);
+       return 0;
+}
+
+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)
+{
+       struct option options[] = {
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, "test-tools", options,
+                            submodule_resolve_relative_url_usage, 0);
+       if (argc != 3)
+               usage_with_options(submodule_resolve_relative_url_usage, options);
+
+       return resolve_relative_url(argc, argv);
+}
+
+static struct test_cmd cmds[] = {
+       { "check-name", cmd__submodule_check_name },
+       { "is-active", cmd__submodule_is_active },
+       { "resolve-relative-url", cmd__submodule_resolve_relative_url},
+};
+
+int cmd__submodule(int argc, const char **argv)
+{
+       struct option options[] = {
+               OPT_END()
+       };
+       size_t i;
+
+       argc = parse_options(argc, argv, "test-tools", options, submodule_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+       if (argc < 1)
+               usage_with_options(submodule_usage, options);
+
+       for (i = 0; i < ARRAY_SIZE(cmds); i++)
+               if (!strcmp(cmds[i].name, argv[0]))
+                       return cmds[i].fn(argc, argv);
+
+       usage_msg_optf("unknown subcommand '%s'", submodule_usage, options,
+                      argv[0]);
+
+       return 0;
+}
diff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h
new file mode 100644 (file)
index 0000000..6a0e5e0
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef TEST_TOOL_UTILS_H
+#define TEST_TOOL_UTILS_H
+
+struct test_cmd {
+       const char *name;
+       int (*fn)(int argc, const char **argv);
+};
+
+#endif
index 318fdbab0c315cd0823b76de2864d9689dc5c377..d1d013bcd920b197163b7c780f0131b0a1356541 100644 (file)
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "test-tool.h"
+#include "test-tool-utils.h"
 #include "trace2.h"
 #include "parse-options.h"
 
@@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {
        NULL
 };
 
-struct test_cmd {
-       const char *name;
-       int (*fn)(int argc, const char **argv);
-};
-
 static struct test_cmd cmds[] = {
        { "advise", cmd__advise_if_enabled },
        { "bitmap", cmd__bitmap },
@@ -51,7 +47,9 @@ static struct test_cmd cmds[] = {
        { "online-cpus", cmd__online_cpus },
        { "pack-mtimes", cmd__pack_mtimes },
        { "parse-options", cmd__parse_options },
+       { "parse-options-flags", cmd__parse_options_flags },
        { "parse-pathspec-file", cmd__parse_pathspec_file },
+       { "parse-subcommand", cmd__parse_subcommand },
        { "partial-clone", cmd__partial_clone },
        { "path-utils", cmd__path_utils },
        { "pcre2-config", cmd__pcre2_config },
@@ -65,6 +63,7 @@ static struct test_cmd cmds[] = {
        { "read-midx", cmd__read_midx },
        { "ref-store", cmd__ref_store },
        { "reftable", cmd__reftable },
+       { "rot13-filter", cmd__rot13_filter },
        { "dump-reftable", cmd__dump_reftable },
        { "regex", cmd__regex },
        { "repository", cmd__repository },
@@ -78,6 +77,7 @@ static struct test_cmd cmds[] = {
        { "simple-ipc", cmd__simple_ipc },
        { "strcmp-offset", cmd__strcmp_offset },
        { "string-list", cmd__string_list },
+       { "submodule", cmd__submodule },
        { "submodule-config", cmd__submodule_config },
        { "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
        { "subprocess", cmd__subprocess },
index bb79927163196cd4815d32fb45ee82a6e1f0bdfc..6b46b6444b657c3debdc286c50e81db5ba495f8b 100644 (file)
@@ -41,7 +41,9 @@ int cmd__oidtree(int argc, const char **argv);
 int cmd__online_cpus(int argc, const char **argv);
 int cmd__pack_mtimes(int argc, const char **argv);
 int cmd__parse_options(int argc, const char **argv);
+int cmd__parse_options_flags(int argc, const char **argv);
 int cmd__parse_pathspec_file(int argc, const char** argv);
+int cmd__parse_subcommand(int argc, const char **argv);
 int cmd__partial_clone(int argc, const char **argv);
 int cmd__path_utils(int argc, const char **argv);
 int cmd__pcre2_config(int argc, const char **argv);
@@ -54,6 +56,7 @@ int cmd__read_cache(int argc, const char **argv);
 int cmd__read_graph(int argc, const char **argv);
 int cmd__read_midx(int argc, const char **argv);
 int cmd__ref_store(int argc, const char **argv);
+int cmd__rot13_filter(int argc, const char **argv);
 int cmd__reftable(int argc, const char **argv);
 int cmd__regex(int argc, const char **argv);
 int cmd__repository(int argc, const char **argv);
@@ -68,6 +71,7 @@ int cmd__sigchain(int argc, const char **argv);
 int cmd__simple_ipc(int argc, const char **argv);
 int cmd__strcmp_offset(int argc, const char **argv);
 int cmd__string_list(int argc, const char **argv);
+int cmd__submodule(int argc, const char **argv);
 int cmd__submodule_config(int argc, const char **argv);
 int cmd__submodule_nested_repo_config(int argc, const char **argv);
 int cmd__subprocess(int argc, const char **argv);
index 8f4d67e646953c5b094b55ec8112f6ba3b9b9024..86edd454f5c9e86f516f564868d94b1859b524f7 100644 (file)
@@ -5,8 +5,9 @@
 int cmd__urlmatch_normalization(int argc, const char **argv)
 {
        const char usage[] = "test-tool urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
-       char *url1, *url2;
+       char *url1 = NULL, *url2 = NULL;
        int opt_p = 0, opt_l = 0;
+       int ret = 0;
 
        /*
         * For one url, succeed if url_normalize succeeds on it, fail otherwise.
@@ -39,7 +40,7 @@ int cmd__urlmatch_normalization(int argc, const char **argv)
                        printf("%s\n", url1);
                if (opt_l)
                        printf("%u\n", (unsigned)info.url_len);
-               return 0;
+               goto cleanup;
        }
 
        if (opt_p || opt_l)
@@ -47,5 +48,9 @@ int cmd__urlmatch_normalization(int argc, const char **argv)
 
        url1 = url_normalize(argv[1], NULL);
        url2 = url_normalize(argv[2], NULL);
-       return (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
+       ret = (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
+cleanup:
+       free(url1);
+       free(url2);
+       return ret;
 }
index f013f8a31e5294d879f1e872c7f37626fa583ed6..a2b56b9cae5e3736220afcc30919d1c8bca0b69a 100644 (file)
@@ -12,7 +12,7 @@ static int driver_cb(struct userdiff_driver *driver,
        return 0;
 }
 
-static int cmd__userdiff_config(const char *var, const char *value, void *cb)
+static int cmd__userdiff_config(const char *var, const char *value, void *cb UNUSED)
 {
        if (userdiff_config(var, value) < 0)
                return -1;
index a95537e759b0365db3f80ccf9135838da0cbde5e..f5959370941e33ee4ca9cfe3daa09df8a17858a8 100644 (file)
@@ -440,7 +440,7 @@ midx_bitmap_partial_tests () {
                test_commit packed &&
                git repack &&
                test_commit loose &&
-               git multi-pack-index write --bitmap 2>err &&
+               git multi-pack-index write --bitmap &&
                test_path_is_file $midx &&
                test_path_is_file $midx-$(midx_checksum $objdir).bitmap
        '
diff --git a/t/lib-perl.sh b/t/lib-perl.sh
new file mode 100644 (file)
index 0000000..d0bf509
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2022 Ævar Arnfjörð Bjarmason
+
+test_lazy_prereq PERL_TEST_MORE '
+       perl -MTest::More -e 0
+'
+
+skip_all_if_no_Test_More () {
+       if ! test_have_prereq PERL
+       then
+               skip_all='skipping perl interface tests, perl not available'
+               test_done
+       fi
+
+       if ! test_have_prereq PERL_TEST_MORE
+       then
+               skip_all="Perl Test::More unavailable, skipping test"
+               test_done
+       fi
+}
index ec6b9b107da4eaab70e221b07c25c9f949f09b14..b57541356bd03d139334a144339b01a92be2c70a 100644 (file)
@@ -207,3 +207,18 @@ check_reworded_commits () {
                >reword-log &&
        test_cmp reword-expected reword-log
 }
+
+# usage: set_replace_editor <file>
+#
+# Replace the todo file with the exact contents of the given file.
+set_replace_editor () {
+       cat >script <<-\EOF &&
+       cat FILENAME >"$1"
+
+       echo 'rebase -i script after editing:'
+       cat "$1"
+       EOF
+
+       sed -e "s/FILENAME/$1/g" <script | write_script fake-editor.sh &&
+       test_set_editor "$(pwd)/fake-editor.sh"
+}
index f7c7df0ca427b396ed757dd7e323d9eb03a366ff..03e0abbdb83f260f3c688734d5e0d3914c460581 100644 (file)
@@ -207,7 +207,7 @@ prolog () {
 # should be updated to an existing commit.
 reset_work_tree_to () {
        rm -rf submodule_update &&
-       git clone submodule_update_repo submodule_update &&
+       git clone --template= submodule_update_repo submodule_update &&
        (
                cd submodule_update &&
                rm -rf sub1 &&
@@ -902,13 +902,14 @@ test_submodule_switch_recursing_with_args () {
        '
        # ... but an ignored file is fine.
        test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" '
-               test_when_finished "rm submodule_update/.git/info/exclude" &&
+               test_when_finished "rm -rf submodule_update/.git/info" &&
                prolog &&
                reset_work_tree_to_interested no_submodule &&
                (
                        cd submodule_update &&
                        git branch -t add_sub1 origin/add_sub1 &&
                        : >sub1 &&
+                       mkdir .git/info &&
                        echo sub1 >.git/info/exclude &&
                        $command add_sub1 &&
                        test_superproject_content origin/add_sub1 &&
@@ -951,7 +952,9 @@ test_submodule_switch_recursing_with_args () {
                reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
+                       rm -rf .git/modules/sub1/info &&
                        git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+                       mkdir .git/modules/sub1/info &&
                        echo ignored >.git/modules/sub1/info/exclude &&
                        : >sub1/ignored &&
                        $command replace_sub1_with_file &&
index fb9127a66f7561e528584c326a7d2539d2647dcb..8f217d7be7d557b642714cd8fa47bdb9d8f8981a 100644 (file)
@@ -95,6 +95,10 @@ You can set the following variables (also in your config.mak):
        Git (e.g., performance of index-pack as the number of threads
        changes). These can be enabled with GIT_PERF_EXTRA.
 
+    GIT_PERF_USE_SCALAR
+       Boolean indicating whether to register test repo(s) with Scalar
+       before executing tests.
+
 You can also pass the options taken by ordinary git tests; the most
 useful one is:
 
index 63d3bc7cece59937424b3aed6288eca553234665..55a8feb1dc4f964f1630a0af09e575fa76b870fe 100644 (file)
@@ -67,3 +67,34 @@ test_partial_bitmap () {
                        --filter=tree:0 >/dev/null
        '
 }
+
+test_pack_bitmap () {
+       test_perf "repack to disk" '
+               git repack -ad
+       '
+
+       test_full_bitmap
+
+       test_expect_success "create partial bitmap state" '
+               # pick a commit to represent the repo tip in the past
+               cutoff=$(git rev-list HEAD~100 -1) &&
+               orig_tip=$(git rev-parse HEAD) &&
+
+               # now kill off all of the refs and pretend we had
+               # just the one tip
+               rm -rf .git/logs .git/refs/* .git/packed-refs &&
+               git update-ref HEAD $cutoff &&
+
+               # and then repack, which will leave us with a nice
+               # big bitmap pack of the "old" history, and all of
+               # the new history will be loose, as if it had been pushed
+               # up incrementally and exploded via unpack-objects
+               git repack -Ad &&
+
+               # and now restore our original tip, as if the pushes
+               # had happened
+               git update-ref HEAD $orig_tip
+       '
+
+       test_partial_bitmap
+}
index 1afc08fe7f1990cdf7143f0dfd3cfaa66628ca73..85be14e4ddb2a00516e84a8ff4c62796f3e354b4 100755 (executable)
@@ -49,7 +49,7 @@ test_perf "single-threaded, $desc" "
        test-tool lazy-init-name-hash --single --count=$count
 "
 
-test_perf REPO_BIG_ENOUGH_FOR_MULTI "multi-threaded, $desc" "
+test_perf "multi-threaded, $desc" --prereq REPO_BIG_ENOUGH_FOR_MULTI "
        test-tool lazy-init-name-hash --multi --count=$count
 "
 
index 900b385c4bbc2d0bf9a803f06b48fe1c25909e86..c481c012d2fc17a7944f308c2d6ef68acb284dee 100755 (executable)
@@ -46,7 +46,7 @@ test_expect_success "setup repo" '
 '
 
 test_perf "read-tree br_base br_ballast ($nr_files)" '
-       git read-tree -m br_base br_ballast -n
+       git read-tree -n -m br_base br_ballast
 '
 
 test_perf "switch between br_base br_ballast ($nr_files)" '
index ed366e2e1295254d176941a60e1fa5128d24f02e..ae4ddac8640c1aa8dd8e2ddd9babe01cb8cdbcf7 100755 (executable)
@@ -40,11 +40,11 @@ done
 
 for file in unsorted sorted reversed
 do
-       test_perf "llist_mergesort() $file" "
+       test_perf "DEFINE_LIST_SORT $file" "
                test-tool mergesort sort <$file >actual
        "
 
-       test_expect_success "llist_mergesort() $file sorts like sort(1)" "
+       test_expect_success "DEFINE_LIST_SORT $file sorts like sort(1)" "
                test_cmp_bin sorted actual
        "
 done
index c181110a43931fb2a8131270a4d8bdcb0a2e7a4b..fce8151d41cbbd9eadd098b26c864d61b5b74bcc 100755 (executable)
@@ -123,5 +123,6 @@ test_perf_on_all git blame $SPARSE_CONE/f3/a
 test_perf_on_all git read-tree -mu HEAD
 test_perf_on_all git checkout-index -f --all
 test_perf_on_all git update-index --add --remove $SPARSE_CONE/a
+test_perf_on_all "git rm -f $SPARSE_CONE/a && git checkout HEAD -- $SPARSE_CONE/a"
 
 test_done
index 7ad4f237bc37ff0547bcd036cbbfc160cf723a4f..b1399f1007e6dd8044bf0fc8945e7c5cfaa91673 100755 (executable)
@@ -4,51 +4,37 @@ test_description='Tests pack performance using bitmaps'
 . ./perf-lib.sh
 . "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
 
-test_perf_large_repo
-
-# note that we do everything through config,
-# since we want to be able to compare bitmap-aware
-# git versus non-bitmap git
-#
-# We intentionally use the deprecated pack.writebitmaps
-# config so that we can test against older versions of git.
-test_expect_success 'setup bitmap config' '
-       git config pack.writebitmaps true
-'
-
-# we need to create the tag up front such that it is covered by the repack and
-# thus by generated bitmaps.
-test_expect_success 'create tags' '
-       git tag --message="tag pointing to HEAD" perf-tag HEAD
-'
-
-test_perf 'repack to disk' '
-       git repack -ad
-'
-
-test_full_bitmap
-
-test_expect_success 'create partial bitmap state' '
-       # pick a commit to represent the repo tip in the past
-       cutoff=$(git rev-list HEAD~100 -1) &&
-       orig_tip=$(git rev-parse HEAD) &&
-
-       # now kill off all of the refs and pretend we had
-       # just the one tip
-       rm -rf .git/logs .git/refs/* .git/packed-refs &&
-       git update-ref HEAD $cutoff &&
-
-       # and then repack, which will leave us with a nice
-       # big bitmap pack of the "old" history, and all of
-       # the new history will be loose, as if it had been pushed
-       # up incrementally and exploded via unpack-objects
-       git repack -Ad &&
-
-       # and now restore our original tip, as if the pushes
-       # had happened
-       git update-ref HEAD $orig_tip
-'
-
-test_partial_bitmap
+test_lookup_pack_bitmap () {
+       test_expect_success 'start the test from scratch' '
+               rm -rf * .git
+       '
+
+       test_perf_large_repo
+
+       # note that we do everything through config,
+       # since we want to be able to compare bitmap-aware
+       # git versus non-bitmap git
+       #
+       # We intentionally use the deprecated pack.writebitmaps
+       # config so that we can test against older versions of git.
+       test_expect_success 'setup bitmap config' '
+               git config pack.writebitmaps true
+       '
+
+       # we need to create the tag up front such that it is covered by the repack and
+       # thus by generated bitmaps.
+       test_expect_success 'create tags' '
+               git tag --message="tag pointing to HEAD" perf-tag HEAD
+       '
+
+       test_perf "enable lookup table: $1" '
+               git config pack.writeBitmapLookupTable '"$1"'
+       '
+
+       test_pack_bitmap
+}
+
+test_lookup_pack_bitmap false
+test_lookup_pack_bitmap true
 
 test_done
index 47c3fd7581cc99d562bb5796f3374e207573a304..426fab87e3293e0d1817159eacd1f63e6cd27fd7 100755 (executable)
@@ -3,42 +3,52 @@
 test_description='performance of fetches from bitmapped packs'
 . ./perf-lib.sh
 
-test_perf_default_repo
-
-test_expect_success 'create bitmapped server repo' '
-       git config pack.writebitmaps true &&
-       git repack -ad
-'
-
-# simulate a fetch from a repository that last fetched N days ago, for
-# various values of N. We do so by following the first-parent chain,
-# and assume the first entry in the chain that is N days older than the current
-# HEAD is where the HEAD would have been then.
-for days in 1 2 4 8 16 32 64 128; do
-       title=$(printf '%10s' "($days days)")
-       test_expect_success "setup revs from $days days ago" '
-               now=$(git log -1 --format=%ct HEAD) &&
-               then=$(($now - ($days * 86400))) &&
-               tip=$(git rev-list -1 --first-parent --until=$then HEAD) &&
-               {
-                       echo HEAD &&
-                       echo ^$tip
-               } >revs
+test_fetch_bitmaps () {
+       test_expect_success 'setup test directory' '
+               rm -fr * .git
        '
 
-       test_perf "server $title" '
-               git pack-objects --stdout --revs \
-                                --thin --delta-base-offset \
-                                <revs >tmp.pack
-       '
+       test_perf_default_repo
 
-       test_size "size   $title" '
-               wc -c <tmp.pack
+       test_expect_success 'create bitmapped server repo' '
+               git config pack.writebitmaps true &&
+               git config pack.writeBitmapLookupTable '"$1"' &&
+               git repack -ad
        '
 
-       test_perf "client $title" '
-               git index-pack --stdin --fix-thin <tmp.pack
-       '
-done
+       # simulate a fetch from a repository that last fetched N days ago, for
+       # various values of N. We do so by following the first-parent chain,
+       # and assume the first entry in the chain that is N days older than the current
+       # HEAD is where the HEAD would have been then.
+       for days in 1 2 4 8 16 32 64 128; do
+               title=$(printf '%10s' "($days days)")
+               test_expect_success "setup revs from $days days ago" '
+                       now=$(git log -1 --format=%ct HEAD) &&
+                       then=$(($now - ($days * 86400))) &&
+                       tip=$(git rev-list -1 --first-parent --until=$then HEAD) &&
+                       {
+                               echo HEAD &&
+                               echo ^$tip
+                       } >revs
+               '
+
+               test_perf "server $title (lookup=$1)" '
+                       git pack-objects --stdout --revs \
+                                       --thin --delta-base-offset \
+                                       <revs >tmp.pack
+               '
+
+               test_size "size   $title" '
+                       wc -c <tmp.pack
+               '
+
+               test_perf "client $title (lookup=$1)" '
+                       git index-pack --stdin --fix-thin <tmp.pack
+               '
+       done
+}
+
+test_fetch_bitmaps true
+test_fetch_bitmaps false
 
 test_done
diff --git a/t/perf/p5312-pack-bitmaps-revs.sh b/t/perf/p5312-pack-bitmaps-revs.sh
new file mode 100755 (executable)
index 0000000..0684b69
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+test_description='Tests pack performance using bitmaps (rev index enabled)'
+. ./perf-lib.sh
+. "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
+
+test_lookup_pack_bitmap () {
+       test_expect_success 'start the test from scratch' '
+               rm -rf * .git
+       '
+
+       test_perf_large_repo
+
+       test_expect_success 'setup bitmap config' '
+               git config pack.writebitmaps true &&
+               git config pack.writeReverseIndex true
+       '
+
+       # we need to create the tag up front such that it is covered by the repack and
+       # thus by generated bitmaps.
+       test_expect_success 'create tags' '
+               git tag --message="tag pointing to HEAD" perf-tag HEAD
+       '
+
+       test_perf "enable lookup table: $1" '
+               git config pack.writeBitmapLookupTable '"$1"'
+       '
+
+       test_pack_bitmap
+}
+
+test_lookup_pack_bitmap false
+test_lookup_pack_bitmap true
+
+test_done
index f2fa228f16a1ce5056da5add225cc3130fadeae3..d082e6cacbeb344e405f9da7ca86065c8cf2d0c4 100755 (executable)
@@ -4,49 +4,64 @@ test_description='Tests performance using midx bitmaps'
 . ./perf-lib.sh
 . "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
 
-test_perf_large_repo
-
-# we need to create the tag up front such that it is covered by the repack and
-# thus by generated bitmaps.
-test_expect_success 'create tags' '
-       git tag --message="tag pointing to HEAD" perf-tag HEAD
-'
-
-test_expect_success 'start with bitmapped pack' '
-       git repack -adb
-'
-
-test_perf 'setup multi-pack index' '
-       git multi-pack-index write --bitmap
-'
-
-test_expect_success 'drop pack bitmap' '
-       rm -f .git/objects/pack/pack-*.bitmap
-'
-
-test_full_bitmap
-
-test_expect_success 'create partial bitmap state' '
-       # pick a commit to represent the repo tip in the past
-       cutoff=$(git rev-list HEAD~100 -1) &&
-       orig_tip=$(git rev-parse HEAD) &&
-
-       # now pretend we have just one tip
-       rm -rf .git/logs .git/refs/* .git/packed-refs &&
-       git update-ref HEAD $cutoff &&
-
-       # and then repack, which will leave us with a nice
-       # big bitmap pack of the "old" history, and all of
-       # the new history will be loose, as if it had been pushed
-       # up incrementally and exploded via unpack-objects
-       git repack -Ad &&
-       git multi-pack-index write --bitmap &&
-
-       # and now restore our original tip, as if the pushes
-       # had happened
-       git update-ref HEAD $orig_tip
-'
-
-test_partial_bitmap
+test_bitmap () {
+       local enabled="$1"
+
+       test_expect_success "remove existing repo (lookup=$enabled)" '
+               rm -fr * .git
+       '
+
+       test_perf_large_repo
+
+       # we need to create the tag up front such that it is covered by the repack and
+       # thus by generated bitmaps.
+       test_expect_success 'create tags' '
+               git tag --message="tag pointing to HEAD" perf-tag HEAD
+       '
+
+       test_expect_success "use lookup table: $enabled" '
+               git config pack.writeBitmapLookupTable '"$enabled"'
+       '
+
+       test_expect_success "start with bitmapped pack (lookup=$enabled)" '
+               git repack -adb
+       '
+
+       test_perf "setup multi-pack index (lookup=$enabled)" '
+               git multi-pack-index write --bitmap
+       '
+
+       test_expect_success "drop pack bitmap (lookup=$enabled)" '
+               rm -f .git/objects/pack/pack-*.bitmap
+       '
+
+       test_full_bitmap
+
+       test_expect_success "create partial bitmap state (lookup=$enabled)" '
+               # pick a commit to represent the repo tip in the past
+               cutoff=$(git rev-list HEAD~100 -1) &&
+               orig_tip=$(git rev-parse HEAD) &&
+
+               # now pretend we have just one tip
+               rm -rf .git/logs .git/refs/* .git/packed-refs &&
+               git update-ref HEAD $cutoff &&
+
+               # and then repack, which will leave us with a nice
+               # big bitmap pack of the "old" history, and all of
+               # the new history will be loose, as if it had been pushed
+               # up incrementally and exploded via unpack-objects
+               git repack -Ad &&
+               git multi-pack-index write --bitmap &&
+
+               # and now restore our original tip, as if the pushes
+               # had happened
+               git update-ref HEAD $orig_tip
+       '
+
+       test_partial_bitmap
+}
+
+test_bitmap false
+test_bitmap true
 
 test_done
index 9338b9ea008d59f5e81b9e7a01375e68676e3d8d..c3f9a4caa4caadca271982c2e9f872d977c3610b 100755 (executable)
@@ -249,7 +249,7 @@ test_expect_success "Cleanup temp and matrix branches" "
        do
                for fsm_val in $fsm_values
                do
-                       cleanup $uc_val $fsm_val
+                       cleanup $uc_val $fsm_val || return 1
                done
        done
 "
diff --git a/t/perf/p9210-scalar.sh b/t/perf/p9210-scalar.sh
new file mode 100755 (executable)
index 0000000..265f7cd
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+test_description='test scalar performance'
+. ./perf-lib.sh
+
+test_perf_large_repo "$TRASH_DIRECTORY/to-clone"
+
+test_expect_success 'enable server-side partial clone' '
+       git -C to-clone config uploadpack.allowFilter true &&
+       git -C to-clone config uploadpack.allowAnySHA1InWant true
+'
+
+test_perf 'scalar clone' '
+       rm -rf scalar-clone &&
+       scalar clone "file://$(pwd)/to-clone" scalar-clone
+'
+
+test_perf 'git clone' '
+       rm -rf git-clone &&
+       git clone "file://$(pwd)/to-clone" git-clone
+'
+
+test_compare_perf () {
+       command=$1
+       shift
+       args=$*
+       test_perf "$command $args (scalar)" "
+               $command -C scalar-clone/src $args
+       "
+
+       test_perf "$command $args (non-scalar)" "
+               $command -C git-clone $args
+       "
+}
+
+test_compare_perf git status
+test_compare_perf test_commit --append --no-tag A
+
+test_done
index 27c28017921a0bc804bb2488a3163bf632c09340..e7786775a9016151e063335047256bfea93d2f63 100644 (file)
@@ -49,6 +49,9 @@ export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP
 MODERN_GIT=$GIT_BUILD_DIR/bin-wrappers/git
 export MODERN_GIT
 
+MODERN_SCALAR=$GIT_BUILD_DIR/bin-wrappers/scalar
+export MODERN_SCALAR
+
 perf_results_dir=$TEST_RESULTS_DIR
 test -n "$GIT_PERF_SUBSECTION" && perf_results_dir="$perf_results_dir/$GIT_PERF_SUBSECTION"
 mkdir -p "$perf_results_dir"
@@ -120,6 +123,10 @@ test_perf_create_repo_from () {
                        # status" due to a locked index. Since we have
                        # a copy it's fine to remove the lock.
                        rm .git/index.lock
+               fi &&
+               if test_bool_env GIT_PERF_USE_SCALAR false
+               then
+                       "$MODERN_SCALAR" register
                fi
        ) || error "failed to copy repository '$source' to '$repo'"
 }
@@ -130,7 +137,11 @@ test_perf_fresh_repo () {
        "$MODERN_GIT" init -q "$repo" &&
        (
                cd "$repo" &&
-               test_perf_do_repo_symlink_config_
+               test_perf_do_repo_symlink_config_ &&
+               if test_bool_env GIT_PERF_USE_SCALAR false
+               then
+                       "$MODERN_SCALAR" register
+               fi
        )
 }
 
index 55219aa405638304411bc319cc29bb5eb2a39d0b..34115edec356831d4863a3ca891be0d885bf46fc 100755 (executable)
@@ -171,6 +171,9 @@ run_subsection () {
        get_var_from_env_or_config "GIT_PERF_MAKE_COMMAND" "perf" "makeCommand"
        get_var_from_env_or_config "GIT_PERF_MAKE_OPTS" "perf" "makeOpts"
 
+       get_var_from_env_or_config "GIT_PERF_USE_SCALAR" "perf" "useScalar" "--bool"
+       export GIT_PERF_USE_SCALAR
+
        get_var_from_env_or_config "GIT_PERF_REPO_NAME" "perf" "repoName"
        export GIT_PERF_REPO_NAME
 
@@ -229,10 +232,10 @@ then
        )
 elif test -n "$GIT_PERF_SUBSECTION"
 then
-       egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null ||
+       grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null ||
                die "subsection '$GIT_PERF_SUBSECTION' not found in '$GIT_PERF_CONFIG_FILE'"
 
-       egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec
+       grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec
        do
                (
                        GIT_PERF_SUBSECTION="$subsec"
index 17a268ccd1b014201e25c810ebade41f6f31aecf..502b4bcf9ea0ad06cddaad50b999dd8024af28eb 100755 (executable)
@@ -578,6 +578,78 @@ test_expect_success 'subtest: --run invalid range end' '
        EOF_ERR
 '
 
+test_expect_success 'subtest: --invert-exit-code without --immediate' '
+       run_sub_test_lib_test_err full-pass \
+               --invert-exit-code &&
+       check_sub_test_lib_test_err full-pass \
+               <<-\EOF_OUT 3<<-EOF_ERR
+       ok 1 - passing test #1
+       ok 2 - passing test #2
+       ok 3 - passing test #3
+       # passed all 3 test(s)
+       1..3
+       # faking up non-zero exit with --invert-exit-code
+       EOF_OUT
+       EOF_ERR
+'
+
+test_expect_success 'subtest: --invert-exit-code with --immediate: all passed' '
+       run_sub_test_lib_test_err full-pass \
+               --invert-exit-code --immediate &&
+       check_sub_test_lib_test_err full-pass \
+               <<-\EOF_OUT 3<<-EOF_ERR
+       ok 1 - passing test #1
+       ok 2 - passing test #2
+       ok 3 - passing test #3
+       # passed all 3 test(s)
+       1..3
+       # faking up non-zero exit with --invert-exit-code
+       EOF_OUT
+       EOF_ERR
+'
+
+test_expect_success 'subtest: --invert-exit-code without --immediate: partial pass' '
+       run_sub_test_lib_test partial-pass \
+               --invert-exit-code &&
+       check_sub_test_lib_test partial-pass <<-\EOF
+       ok 1 - passing test #1
+       not ok 2 - # TODO induced breakage (--invert-exit-code): failing test #2
+       #       false
+       ok 3 - passing test #3
+       # failed 1 among 3 test(s)
+       1..3
+       # faked up failures as TODO & now exiting with 0 due to --invert-exit-code
+       EOF
+'
+
+test_expect_success 'subtest: --invert-exit-code with --immediate: partial pass' '
+       run_sub_test_lib_test partial-pass \
+               --invert-exit-code --immediate &&
+       check_sub_test_lib_test partial-pass \
+               <<-\EOF_OUT 3<<-EOF_ERR
+       ok 1 - passing test #1
+       not ok 2 - # TODO induced breakage (--invert-exit-code): failing test #2
+       #       false
+       1..2
+       # faked up failures as TODO & now exiting with 0 due to --invert-exit-code
+       EOF_OUT
+       EOF_ERR
+'
+
+test_expect_success 'subtest: --invert-exit-code --immediate: got a failure' '
+       run_sub_test_lib_test partial-pass \
+               --invert-exit-code --immediate &&
+       check_sub_test_lib_test_err partial-pass \
+               <<-\EOF_OUT 3<<-EOF_ERR
+       ok 1 - passing test #1
+       not ok 2 - # TODO induced breakage (--invert-exit-code): failing test #2
+       #       false
+       1..2
+       # faked up failures as TODO & now exiting with 0 due to --invert-exit-code
+       EOF_OUT
+       EOF_ERR
+'
+
 test_expect_success 'subtest: tests respect prerequisites' '
        write_and_run_sub_test_lib_test prereqs <<-\EOF &&
 
index f6356db183b98c5c29acdb4b03dcb453533a5728..26eaca095a26a6a654364bdd8acf208af30b2d00 100755 (executable)
@@ -65,7 +65,7 @@ test_expect_success 'check commit-tree' '
        test_path_is_file "$REAL/objects/$(objpath $SHA)"
 '
 
-test_expect_success !SANITIZE_LEAK 'check rev-list' '
+test_expect_success 'check rev-list' '
        git update-ref "HEAD" "$SHA" &&
        git rev-list HEAD >actual &&
        echo $SHA >expected &&
index 143f1005179c8afb11aba90e4d279b6d288c8a48..f7ee2f2ff0e6ee3be99ecd4d545c376963653482 100755 (executable)
@@ -3,6 +3,7 @@
 test_description=gitattributes
 
 TEST_PASSES_SANITIZE_LEAK=true
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 attr_check_basic () {
@@ -284,7 +285,7 @@ test_expect_success 'using --git-dir and --work-tree' '
 '
 
 test_expect_success 'setup bare' '
-       git clone --bare . bare.git
+       git clone --template= --bare . bare.git
 '
 
 test_expect_success 'bare repository: check that .gitattribute is ignored' '
@@ -315,6 +316,7 @@ test_expect_success 'bare repository: check that --cached honors index' '
 test_expect_success 'bare repository: test info/attributes' '
        (
                cd bare.git &&
+               mkdir info &&
                (
                        echo "f test=f" &&
                        echo "a/i test=a/i"
@@ -360,6 +362,7 @@ test_expect_success SYMLINKS 'symlinks respected in core.attributesFile' '
 
 test_expect_success SYMLINKS 'symlinks respected in info/attributes' '
        test_when_finished "rm .git/info/attributes" &&
+       mkdir .git/info &&
        ln -s ../../attr .git/info/attributes &&
        attr_check file set
 '
index 2e9d652d826af230fc90166c9ef53da3f6e7aa7e..8114fac73b320b85949d8d7ce1422c35e1eb8158 100755 (executable)
@@ -31,7 +31,7 @@ test_expect_success WRITE_TREE_OUT 'write-tree output on unwritable repository'
        test_cmp expect out.write-tree
 '
 
-test_expect_success POSIXPERM,SANITY,!SANITIZE_LEAK 'commit should notice unwritable repository' '
+test_expect_success POSIXPERM,SANITY 'commit should notice unwritable repository' '
        test_when_finished "chmod 775 .git/objects .git/objects/??" &&
        chmod a-w .git/objects .git/objects/?? &&
        test_must_fail git commit -m second 2>out.commit
index 5575dade8eee8184b24d6685213b9a30dcee4364..c70d11bc914d09df5baa8cf74e9a2c292fc861b8 100755 (executable)
@@ -3,6 +3,7 @@
 test_description=check-ignore
 
 TEST_PASSES_SANITIZE_LEAK=true
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 init_vars () {
@@ -225,7 +226,8 @@ test_expect_success 'setup' '
                !globaltwo
                globalthree
        EOF
-       cat <<-\EOF >>.git/info/exclude
+       mkdir .git/info &&
+       cat <<-\EOF >.git/info/exclude
                per-repo
        EOF
 '
@@ -543,9 +545,9 @@ test_expect_success_multi 'submodule from subdirectory' '' '
 
 test_expect_success 'global ignore not yet enabled' '
        expect_from_stdin <<-\EOF &&
-               .git/info/exclude:7:per-repo    per-repo
+               .git/info/exclude:1:per-repo    per-repo
                a/.gitignore:2:*three   a/globalthree
-               .git/info/exclude:7:per-repo    a/per-repo
+               .git/info/exclude:1:per-repo    a/per-repo
        EOF
        test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
 '
@@ -566,10 +568,10 @@ test_expect_success 'global ignore with -v' '
        enable_global_excludes &&
        expect_from_stdin <<-EOF &&
                $global_excludes:1:globalone    globalone
-               .git/info/exclude:7:per-repo    per-repo
+               .git/info/exclude:1:per-repo    per-repo
                $global_excludes:3:globalthree  globalthree
                a/.gitignore:2:*three   a/globalthree
-               .git/info/exclude:7:per-repo    a/per-repo
+               .git/info/exclude:1:per-repo    a/per-repo
                $global_excludes:2:!globaltwo   globaltwo
        EOF
        test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
index 6c33a4369015c813a73384ff68149463c5189105..dbfc5c826764bca4ec5561b603d8016f7d50f20d 100755 (executable)
@@ -44,6 +44,8 @@ test_expect_success 'invalid usage' '
        test_expect_code 129 git help -g add &&
        test_expect_code 129 git help -a -g &&
 
+       test_expect_code 129 git help --user-interfaces add &&
+
        test_expect_code 129 git help -g -c &&
        test_expect_code 129 git help --config-for-completion add &&
        test_expect_code 129 git help --config-sections-for-completion add
@@ -104,9 +106,9 @@ test_expect_success 'git help' '
        test_i18ngrep "^   commit " help.output &&
        test_i18ngrep "^   fetch  " help.output
 '
+
 test_expect_success 'git help -g' '
        git help -g >help.output &&
-       test_i18ngrep "^   attributes " help.output &&
        test_i18ngrep "^   everyday   " help.output &&
        test_i18ngrep "^   tutorial   " help.output
 '
@@ -127,6 +129,12 @@ test_expect_success 'git help succeeds without git.html' '
        test_cmp expect test-browser.log
 '
 
+test_expect_success 'git help --user-interfaces' '
+       git help --user-interfaces >help.output &&
+       grep "^   attributes   " help.output &&
+       grep "^   mailmap   " help.output
+'
+
 test_expect_success 'git help -c' '
        git help -c >help.output &&
        cat >expect <<-\EOF &&
@@ -220,6 +228,10 @@ test_expect_success "'git help -a' section spacing" '
        Low-level Commands / Syncing Repositories
 
        Low-level Commands / Internal Helpers
+
+       User-facing repository, command and file interfaces
+
+       Developer-facing file formats, protocols and other interfaces
        EOF
        test_cmp expect actual
 '
index 086822fc45b66c8caf6aff43af86da2a466618ac..0a087a1983da43fdfce0506218fa021e5f1840be 100755 (executable)
@@ -1,8 +1,9 @@
 #!/bin/sh
 
 test_description='test basic hash implementation'
-. ./test-lib.sh
 
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
 
 test_expect_success 'test basic SHA-1 hash values' '
        test-tool sha1 </dev/null >actual &&
index 3b0c336b38e4c7f81268227984472cb35572cdc2..19a730c29ed8f791d7885c31ff2a908cb1b5dfb3 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test json-writer JSON generation'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'unit test of json-writer routines' '
index 1c840348bd1eec848850c9679fb5e0368c5348da..abecd75e4e430b6a1182690ae54a0e5d4e76bc32 100755 (executable)
@@ -17,9 +17,6 @@ tr \
   'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
 EOF
 
-write_script rot13-filter.pl "$PERL_PATH" \
-       <"$TEST_DIRECTORY"/t0021/rot13-filter.pl
-
 generate_random_characters () {
        LEN=$1
        NAME=$2
@@ -365,8 +362,8 @@ test_expect_success 'diff does not reuse worktree files that need cleaning' '
        test_line_count = 0 count
 '
 
-test_expect_success PERL 'required process filter should filter data' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'required process filter should filter data' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
        rm -rf repo &&
        mkdir repo &&
@@ -450,8 +447,8 @@ test_expect_success PERL 'required process filter should filter data' '
        )
 '
 
-test_expect_success PERL 'required process filter should filter data for various subcommands' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'required process filter should filter data for various subcommands' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
        (
                cd repo &&
@@ -561,9 +558,9 @@ test_expect_success PERL 'required process filter should filter data for various
        )
 '
 
-test_expect_success PERL 'required process filter takes precedence' '
+test_expect_success 'required process filter takes precedence' '
        test_config_global filter.protocol.clean false &&
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean" &&
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean" &&
        test_config_global filter.protocol.required true &&
        rm -rf repo &&
        mkdir repo &&
@@ -587,8 +584,8 @@ test_expect_success PERL 'required process filter takes precedence' '
        )
 '
 
-test_expect_success PERL 'required process filter should be used only for "clean" operation only' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean" &&
+test_expect_success 'required process filter should be used only for "clean" operation only' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -622,8 +619,8 @@ test_expect_success PERL 'required process filter should be used only for "clean
        )
 '
 
-test_expect_success PERL 'required process filter should process multiple packets' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'required process filter should process multiple packets' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
 
        rm -rf repo &&
@@ -687,8 +684,8 @@ test_expect_success PERL 'required process filter should process multiple packet
        )
 '
 
-test_expect_success PERL 'required process filter with clean error should fail' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'required process filter with clean error should fail' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
        rm -rf repo &&
        mkdir repo &&
@@ -706,8 +703,8 @@ test_expect_success PERL 'required process filter with clean error should fail'
        )
 '
 
-test_expect_success PERL 'process filter should restart after unexpected write failure' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'process filter should restart after unexpected write failure' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -735,7 +732,7 @@ test_expect_success PERL 'process filter should restart after unexpected write f
                rm -f debug.log &&
                git checkout --quiet --no-progress . 2>git-stderr.log &&
 
-               grep "smudge write error at" git-stderr.log &&
+               grep "smudge write error" git-stderr.log &&
                test_i18ngrep "error: external filter" git-stderr.log &&
 
                cat >expected.log <<-EOF &&
@@ -761,8 +758,8 @@ test_expect_success PERL 'process filter should restart after unexpected write f
        )
 '
 
-test_expect_success PERL 'process filter should not be restarted if it signals an error' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'process filter should not be restarted if it signals an error' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -804,8 +801,8 @@ test_expect_success PERL 'process filter should not be restarted if it signals a
        )
 '
 
-test_expect_success PERL 'process filter abort stops processing of all further files' '
-       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
+test_expect_success 'process filter abort stops processing of all further files' '
+       test_config_global filter.protocol.process "test-tool rot13-filter --log=debug.log clean smudge" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -861,10 +858,10 @@ test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
        )
 '
 
-test_expect_success PERL 'delayed checkout in process filter' '
-       test_config_global filter.a.process "rot13-filter.pl a.log clean smudge delay" &&
+test_expect_success 'delayed checkout in process filter' '
+       test_config_global filter.a.process "test-tool rot13-filter --log=a.log clean smudge delay" &&
        test_config_global filter.a.required true &&
-       test_config_global filter.b.process "rot13-filter.pl b.log clean smudge delay" &&
+       test_config_global filter.b.process "test-tool rot13-filter --log=b.log clean smudge delay" &&
        test_config_global filter.b.required true &&
 
        rm -rf repo &&
@@ -940,8 +937,8 @@ test_expect_success PERL 'delayed checkout in process filter' '
        )
 '
 
-test_expect_success PERL 'missing file in delayed checkout' '
-       test_config_global filter.bug.process "rot13-filter.pl bug.log clean smudge delay" &&
+test_expect_success 'missing file in delayed checkout' '
+       test_config_global filter.bug.process "test-tool rot13-filter --log=bug.log clean smudge delay" &&
        test_config_global filter.bug.required true &&
 
        rm -rf repo &&
@@ -960,8 +957,8 @@ test_expect_success PERL 'missing file in delayed checkout' '
        grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log
 '
 
-test_expect_success PERL 'invalid file in delayed checkout' '
-       test_config_global filter.bug.process "rot13-filter.pl bug.log clean smudge delay" &&
+test_expect_success 'invalid file in delayed checkout' '
+       test_config_global filter.bug.process "test-tool rot13-filter --log=bug.log clean smudge delay" &&
        test_config_global filter.bug.required true &&
 
        rm -rf repo &&
@@ -990,10 +987,10 @@ do
                mode_prereq='UTF8_NFD_TO_NFC' ;;
        esac
 
-       test_expect_success PERL,SYMLINKS,$mode_prereq \
+       test_expect_success SYMLINKS,$mode_prereq \
        "delayed checkout with $mode-collision don't write to the wrong place" '
                test_config_global filter.delay.process \
-                       "\"$TEST_ROOT/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
+                       "test-tool rot13-filter --always-delay --log=delayed.log clean smudge delay" &&
                test_config_global filter.delay.required true &&
 
                git init $mode-collision &&
@@ -1026,12 +1023,12 @@ do
        '
 done
 
-test_expect_success PERL,SYMLINKS,CASE_INSENSITIVE_FS \
+test_expect_success SYMLINKS,CASE_INSENSITIVE_FS \
 "delayed checkout with submodule collision don't write to the wrong place" '
        git init collision-with-submodule &&
        (
                cd collision-with-submodule &&
-               git config filter.delay.process "\"$TEST_ROOT/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
+               git config filter.delay.process "test-tool rot13-filter --always-delay --log=delayed.log clean smudge delay" &&
                git config filter.delay.required true &&
 
                # We need Git to treat the submodule "a" and the
@@ -1062,11 +1059,11 @@ test_expect_success PERL,SYMLINKS,CASE_INSENSITIVE_FS \
        )
 '
 
-test_expect_success PERL 'setup for progress tests' '
+test_expect_success 'setup for progress tests' '
        git init progress &&
        (
                cd progress &&
-               git config filter.delay.process "rot13-filter.pl delay-progress.log clean smudge delay" &&
+               git config filter.delay.process "test-tool rot13-filter --log=delay-progress.log clean smudge delay" &&
                git config filter.delay.required true &&
 
                echo "*.a filter=delay" >.gitattributes &&
@@ -1132,12 +1129,12 @@ do
        '
 done
 
-test_expect_success PERL 'delayed checkout correctly reports the number of updated entries' '
+test_expect_success 'delayed checkout correctly reports the number of updated entries' '
        rm -rf repo &&
        git init repo &&
        (
                cd repo &&
-               git config filter.delay.process "../rot13-filter.pl delayed.log clean smudge delay" &&
+               git config filter.delay.process "test-tool rot13-filter --log=delayed.log clean smudge delay" &&
                git config filter.delay.required true &&
 
                echo "*.a filter=delay" >.gitattributes &&
diff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl
deleted file mode 100644 (file)
index 7bb9376..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-#
-# Example implementation for the Git filter protocol version 2
-# See Documentation/gitattributes.txt, section "Filter Protocol"
-#
-# Usage: rot13-filter.pl [--always-delay] <log path> <capabilities>
-#
-# Log path defines a debug log file that the script writes to. The
-# subsequent arguments define a list of supported protocol capabilities
-# ("clean", "smudge", etc).
-#
-# When --always-delay is given all pathnames with the "can-delay" flag
-# that don't appear on the list bellow are delayed with a count of 1
-# (see more below).
-#
-# This implementation supports special test cases:
-# (1) If data with the pathname "clean-write-fail.r" is processed with
-#     a "clean" operation then the write operation will die.
-# (2) If data with the pathname "smudge-write-fail.r" is processed with
-#     a "smudge" operation then the write operation will die.
-# (3) If data with the pathname "error.r" is processed with any
-#     operation then the filter signals that it cannot or does not want
-#     to process the file.
-# (4) If data with the pathname "abort.r" is processed with any
-#     operation then the filter signals that it cannot or does not want
-#     to process the file and any file after that is processed with the
-#     same command.
-# (5) If data with a pathname that is a key in the DELAY hash is
-#     requested (e.g. "test-delay10.a") then the filter responds with
-#     a "delay" status and sets the "requested" field in the DELAY hash.
-#     The filter will signal the availability of this object after
-#     "count" (field in DELAY hash) "list_available_blobs" commands.
-# (6) If data with the pathname "missing-delay.a" is processed that the
-#     filter will drop the path from the "list_available_blobs" response.
-# (7) If data with the pathname "invalid-delay.a" is processed that the
-#     filter will add the path "unfiltered" which was not delayed before
-#     to the "list_available_blobs" response.
-#
-
-use 5.008;
-sub gitperllib {
-       # Git assumes that all path lists are Unix-y colon-separated ones. But
-       # when the Git for Windows executes the test suite, its MSYS2 Bash
-       # calls git.exe, and colon-separated path lists are converted into
-       # Windows-y semicolon-separated lists of *Windows* paths (which
-       # naturally contain a colon after the drive letter, so splitting by
-       # colons simply does not cut it).
-       #
-       # Detect semicolon-separated path list and handle them appropriately.
-
-       if ($ENV{GITPERLLIB} =~ /;/) {
-               return split(/;/, $ENV{GITPERLLIB});
-       }
-       return split(/:/, $ENV{GITPERLLIB});
-}
-use lib (gitperllib());
-use strict;
-use warnings;
-use IO::File;
-use Git::Packet;
-
-my $MAX_PACKET_CONTENT_SIZE = 65516;
-
-my $always_delay = 0;
-if ( $ARGV[0] eq '--always-delay' ) {
-       $always_delay = 1;
-       shift @ARGV;
-}
-
-my $log_file                = shift @ARGV;
-my @capabilities            = @ARGV;
-
-open my $debug, ">>", $log_file or die "cannot open log file: $!";
-
-my %DELAY = (
-       'test-delay10.a' => { "requested" => 0, "count" => 1 },
-       'test-delay11.a' => { "requested" => 0, "count" => 1 },
-       'test-delay20.a' => { "requested" => 0, "count" => 2 },
-       'test-delay10.b' => { "requested" => 0, "count" => 1 },
-       'missing-delay.a' => { "requested" => 0, "count" => 1 },
-       'invalid-delay.a' => { "requested" => 0, "count" => 1 },
-);
-
-sub rot13 {
-       my $str = shift;
-       $str =~ y/A-Za-z/N-ZA-Mn-za-m/;
-       return $str;
-}
-
-print $debug "START\n";
-$debug->flush();
-
-packet_initialize("git-filter", 2);
-
-my %remote_caps = packet_read_and_check_capabilities("clean", "smudge", "delay");
-packet_check_and_write_capabilities(\%remote_caps, @capabilities);
-
-print $debug "init handshake complete\n";
-$debug->flush();
-
-while (1) {
-       my ( $res, $command ) = packet_key_val_read("command");
-       if ( $res == -1 ) {
-               print $debug "STOP\n";
-               exit();
-       }
-       print $debug "IN: $command";
-       $debug->flush();
-
-       if ( $command eq "list_available_blobs" ) {
-               # Flush
-               packet_compare_lists([1, ""], packet_bin_read()) ||
-                       die "bad list_available_blobs end";
-
-               foreach my $pathname ( sort keys %DELAY ) {
-                       if ( $DELAY{$pathname}{"requested"} >= 1 ) {
-                               $DELAY{$pathname}{"count"} = $DELAY{$pathname}{"count"} - 1;
-                               if ( $pathname eq "invalid-delay.a" ) {
-                                       # Send Git a pathname that was not delayed earlier
-                                       packet_txt_write("pathname=unfiltered");
-                               }
-                               if ( $pathname eq "missing-delay.a" ) {
-                                       # Do not signal Git that this file is available
-                               } elsif ( $DELAY{$pathname}{"count"} == 0 ) {
-                                       print $debug " $pathname";
-                                       packet_txt_write("pathname=$pathname");
-                               }
-                       }
-               }
-
-               packet_flush();
-
-               print $debug " [OK]\n";
-               $debug->flush();
-               packet_txt_write("status=success");
-               packet_flush();
-       } else {
-               my ( $res, $pathname ) = packet_key_val_read("pathname");
-               if ( $res == -1 ) {
-                       die "unexpected EOF while expecting pathname";
-               }
-               print $debug " $pathname";
-               $debug->flush();
-
-               # Read until flush
-               my ( $done, $buffer ) = packet_txt_read();
-               while ( $buffer ne '' ) {
-                       if ( $buffer eq "can-delay=1" ) {
-                               if ( exists $DELAY{$pathname} and $DELAY{$pathname}{"requested"} == 0 ) {
-                                       $DELAY{$pathname}{"requested"} = 1;
-                               } elsif ( !exists $DELAY{$pathname} and $always_delay ) {
-                                       $DELAY{$pathname} = { "requested" => 1, "count" => 1 };
-                               }
-                       } elsif ($buffer =~ /^(ref|treeish|blob)=/) {
-                               print $debug " $buffer";
-                       } else {
-                               # In general, filters need to be graceful about
-                               # new metadata, since it's documented that we
-                               # can pass any key-value pairs, but for tests,
-                               # let's be a little stricter.
-                               die "Unknown message '$buffer'";
-                       }
-
-                       ( $done, $buffer ) = packet_txt_read();
-               }
-               if ( $done == -1 ) {
-                       die "unexpected EOF after pathname '$pathname'";
-               }
-
-               my $input = "";
-               {
-                       binmode(STDIN);
-                       my $buffer;
-                       my $done = 0;
-                       while ( !$done ) {
-                               ( $done, $buffer ) = packet_bin_read();
-                               $input .= $buffer;
-                       }
-                       if ( $done == -1 ) {
-                               die "unexpected EOF while reading input for '$pathname'";
-                       }                       
-                       print $debug " " . length($input) . " [OK] -- ";
-                       $debug->flush();
-               }
-
-               my $output;
-               if ( exists $DELAY{$pathname} and exists $DELAY{$pathname}{"output"} ) {
-                       $output = $DELAY{$pathname}{"output"}
-               } elsif ( $pathname eq "error.r" or $pathname eq "abort.r" ) {
-                       $output = "";
-               } elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) {
-                       $output = rot13($input);
-               } elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) {
-                       $output = rot13($input);
-               } else {
-                       die "bad command '$command'";
-               }
-
-               if ( $pathname eq "error.r" ) {
-                       print $debug "[ERROR]\n";
-                       $debug->flush();
-                       packet_txt_write("status=error");
-                       packet_flush();
-               } elsif ( $pathname eq "abort.r" ) {
-                       print $debug "[ABORT]\n";
-                       $debug->flush();
-                       packet_txt_write("status=abort");
-                       packet_flush();
-               } elsif ( $command eq "smudge" and
-                       exists $DELAY{$pathname} and
-                       $DELAY{$pathname}{"requested"} == 1 ) {
-                       print $debug "[DELAYED]\n";
-                       $debug->flush();
-                       packet_txt_write("status=delayed");
-                       packet_flush();
-                       $DELAY{$pathname}{"requested"} = 2;
-                       $DELAY{$pathname}{"output"} = $output;
-               } else {
-                       packet_txt_write("status=success");
-                       packet_flush();
-
-                       if ( $pathname eq "${command}-write-fail.r" ) {
-                               print $debug "[WRITE FAIL]\n";
-                               $debug->flush();
-                               die "${command} write error";
-                       }
-
-                       print $debug "OUT: " . length($output) . " ";
-                       $debug->flush();
-
-                       while ( length($output) > 0 ) {
-                               my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE );
-                               packet_bin_write($packet);
-                               # dots represent the number of packets
-                               print $debug ".";
-                               if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
-                                       $output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
-                               } else {
-                                       $output = "";
-                               }
-                       }
-                       packet_flush();
-                       print $debug " [OK]\n";
-                       $debug->flush();
-                       packet_flush();
-               }
-       }
-}
index 7f80f463930407410c6d3f671fb1f7833ec3b01e..a94ac1eae377c023ae3e02eaae393db6e8d232d3 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='CRLF conversion all combinations'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 compare_files () {
@@ -386,9 +387,7 @@ test_expect_success 'setup main' '
        test_tick
 '
 
-# Disable extra chain-linting for the next set of tests. There are many
-# auto-generated ones that are not worth checking over and over.
-GIT_TEST_CHAIN_LINT_HARDER_DEFAULT=0
+
 
 warn_LF_CRLF="LF will be replaced by CRLF"
 warn_CRLF_LF="CRLF will be replaced by LF"
@@ -605,9 +604,6 @@ do
        checkout_files     ""    "$id" "crlf" true    ""       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
 done
 
-# The rest of the tests are unique; do the usual linting.
-unset GIT_TEST_CHAIN_LINT_HARDER_DEFAULT
-
 # Should be the last test case: remove some files from the worktree
 test_expect_success 'ls-files --eol -d -z' '
        rm crlf_false_attr__CRLF.txt crlf_false_attr__CRLF_mix_LF.txt crlf_false_attr__LF.txt .gitattributes &&
index 82905a2156f7daad6cbdbd1ae5e54d9235f0cdbc..c196fdb0ee21a27b6093902dcafe133abfc98ce0 100755 (executable)
@@ -5,6 +5,8 @@ test_description='working-tree-encoding conversion via gitattributes'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-encoding.sh"
 
@@ -69,6 +71,7 @@ test_expect_success 'check $GIT_DIR/info/attributes support' '
        test_when_finished "rm -f test.utf32.git" &&
        test_when_finished "git reset --hard HEAD" &&
 
+       mkdir .git/info &&
        echo "*.utf32 text working-tree-encoding=utf-32" >.git/info/attributes &&
        git add test.utf32 &&
 
index 0ed14971a5801b68045f27232d9912cc09154a57..471cb37ac28affec3771d0b46e8dae02d4f09716 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='reftable unittests'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'unittests' '
index 3908597d42d705161b5b8808e55c8125f8edffe1..aecb308cf668057995a167090a421b906983f32b 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='verify safe.directory checks'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 GIT_TEST_ASSUME_DIFFERENT_OWNER=1
@@ -16,24 +17,20 @@ test_expect_success 'safe.directory is not set' '
        expect_rejected_dir
 '
 
-test_expect_success 'ignoring safe.directory on the command line' '
-       test_must_fail git -c safe.directory="$(pwd)" status 2>err &&
-       grep "dubious ownership" err
+test_expect_success 'safe.directory on the command line' '
+       git -c safe.directory="$(pwd)" status
 '
 
-test_expect_success 'ignoring safe.directory in the environment' '
-       test_must_fail env GIT_CONFIG_COUNT=1 \
-               GIT_CONFIG_KEY_0="safe.directory" \
-               GIT_CONFIG_VALUE_0="$(pwd)" \
-               git status 2>err &&
-       grep "dubious ownership" err
+test_expect_success 'safe.directory in the environment' '
+       env GIT_CONFIG_COUNT=1 \
+           GIT_CONFIG_KEY_0="safe.directory" \
+           GIT_CONFIG_VALUE_0="$(pwd)" \
+           git status
 '
 
-test_expect_success 'ignoring safe.directory in GIT_CONFIG_PARAMETERS' '
-       test_must_fail env \
-               GIT_CONFIG_PARAMETERS="${SQ}safe.directory${SQ}=${SQ}$(pwd)${SQ}" \
-               git status 2>err &&
-       grep "dubious ownership" err
+test_expect_success 'safe.directory in GIT_CONFIG_PARAMETERS' '
+       env GIT_CONFIG_PARAMETERS="${SQ}safe.directory${SQ}=${SQ}$(pwd)${SQ}" \
+           git status
 '
 
 test_expect_success 'ignoring safe.directory in repo config' '
diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh
new file mode 100755 (executable)
index 0000000..ecbdc82
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+test_description='verify safe.bareRepository checks'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+pwd="$(pwd)"
+
+expect_accepted () {
+       git "$@" rev-parse --git-dir
+}
+
+expect_rejected () {
+       test_must_fail git "$@" rev-parse --git-dir 2>err &&
+       grep -F "cannot use bare repository" err
+}
+
+test_expect_success 'setup bare repo in worktree' '
+       git init outer-repo &&
+       git init --bare outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository unset' '
+       expect_accepted -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository=all' '
+       test_config_global safe.bareRepository all &&
+       expect_accepted -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository=explicit' '
+       test_config_global safe.bareRepository explicit &&
+       expect_rejected -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository in the repository' '
+       # safe.bareRepository must not be "explicit", otherwise
+       # git config fails with "fatal: not in a git directory" (like
+       # safe.directory)
+       test_config -C outer-repo/bare-repo safe.bareRepository \
+               all &&
+       test_config_global safe.bareRepository explicit &&
+       expect_rejected -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository on the command line' '
+       test_config_global safe.bareRepository explicit &&
+       expect_accepted -C outer-repo/bare-repo \
+               -c safe.bareRepository=all
+'
+
+test_done
index ed2fb620a9d62d80b6fadb7fdbce76aff40cccc4..5cc62306e39c4f7ab2f6fec35d3cafc7bd65be86 100755 (executable)
@@ -456,4 +456,257 @@ test_expect_success '--end-of-options treats remainder as args' '
            --end-of-options --verbose
 '
 
+test_expect_success 'KEEP_DASHDASH works' '
+       test-tool parse-options-flags --keep-dashdash cmd --opt=1 -- --opt=2 --unknown >actual &&
+       cat >expect <<-\EOF &&
+       opt: 1
+       arg 00: --
+       arg 01: --opt=2
+       arg 02: --unknown
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'KEEP_ARGV0 works' '
+       test-tool parse-options-flags --keep-argv0 cmd arg0 --opt=3 >actual &&
+       cat >expect <<-\EOF &&
+       opt: 3
+       arg 00: cmd
+       arg 01: arg0
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'STOP_AT_NON_OPTION works' '
+       test-tool parse-options-flags --stop-at-non-option cmd --opt=4 arg0 --opt=5 --unknown >actual &&
+       cat >expect <<-\EOF &&
+       opt: 4
+       arg 00: arg0
+       arg 01: --opt=5
+       arg 02: --unknown
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'KEEP_UNKNOWN_OPT works' '
+       test-tool parse-options-flags --keep-unknown-opt cmd --unknown=1 --opt=6 -u2 >actual &&
+       cat >expect <<-\EOF &&
+       opt: 6
+       arg 00: --unknown=1
+       arg 01: -u2
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'NO_INTERNAL_HELP works for -h' '
+       test_expect_code 129 test-tool parse-options-flags --no-internal-help cmd -h 2>err &&
+       grep "^error: unknown switch \`h$SQ" err &&
+       grep "^usage: " err
+'
+
+for help_opt in help help-all
+do
+       test_expect_success "NO_INTERNAL_HELP works for --$help_opt" "
+               test_expect_code 129 test-tool parse-options-flags --no-internal-help cmd --$help_opt 2>err &&
+               grep '^error: unknown option \`'$help_opt\' err &&
+               grep '^usage: ' err
+       "
+done
+
+test_expect_success 'KEEP_UNKNOWN_OPT | NO_INTERNAL_HELP works' '
+       test-tool parse-options-flags --keep-unknown-opt --no-internal-help cmd -h --help --help-all >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       arg 00: -h
+       arg 01: --help
+       arg 02: --help-all
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - no subcommand shows error and usage' '
+       test_expect_code 129 test-tool parse-subcommand cmd 2>err &&
+       grep "^error: need a subcommand" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - subcommand after -- shows error and usage' '
+       test_expect_code 129 test-tool parse-subcommand cmd -- subcmd-one 2>err &&
+       grep "^error: need a subcommand" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - subcommand after --end-of-options shows error and usage' '
+       test_expect_code 129 test-tool parse-subcommand cmd --end-of-options subcmd-one 2>err &&
+       grep "^error: need a subcommand" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - unknown subcommand shows error and usage' '
+       test_expect_code 129 test-tool parse-subcommand cmd nope 2>err &&
+       grep "^error: unknown subcommand: \`nope$SQ" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - subcommands cannot be abbreviated' '
+       test_expect_code 129 test-tool parse-subcommand cmd subcmd-o 2>err &&
+       grep "^error: unknown subcommand: \`subcmd-o$SQ$" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - no negated subcommands' '
+       test_expect_code 129 test-tool parse-subcommand cmd no-subcmd-one 2>err &&
+       grep "^error: unknown subcommand: \`no-subcmd-one$SQ" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - simple' '
+       test-tool parse-subcommand cmd subcmd-two >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_two
+       arg 00: subcmd-two
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - stop parsing at the first subcommand' '
+       test-tool parse-subcommand cmd --opt=1 subcmd-two subcmd-one --opt=2 >actual &&
+       cat >expect <<-\EOF &&
+       opt: 1
+       fn: subcmd_two
+       arg 00: subcmd-two
+       arg 01: subcmd-one
+       arg 02: --opt=2
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - KEEP_ARGV0' '
+       test-tool parse-subcommand --keep-argv0 cmd subcmd-two >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_two
+       arg 00: cmd
+       arg 01: subcmd-two
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + subcommand not given' '
+       test-tool parse-subcommand --subcommand-optional cmd >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + given subcommand' '
+       test-tool parse-subcommand --subcommand-optional cmd subcmd-two branch file >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_two
+       arg 00: subcmd-two
+       arg 01: branch
+       arg 02: file
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + subcommand not given + unknown dashless args' '
+       test-tool parse-subcommand --subcommand-optional cmd branch file >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       arg 00: branch
+       arg 01: file
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + subcommand not given + unknown option' '
+       test_expect_code 129 test-tool parse-subcommand --subcommand-optional cmd --subcommand-opt 2>err &&
+       grep "^error: unknown option" err &&
+       grep ^usage: err
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT + subcommand not given + unknown option' '
+       test-tool parse-subcommand --subcommand-optional --keep-unknown-opt cmd --subcommand-opt >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       arg 00: --subcommand-opt
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT + subcommand ignored after unknown option' '
+       test-tool parse-subcommand --subcommand-optional --keep-unknown-opt cmd --subcommand-opt subcmd-two >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       arg 00: --subcommand-opt
+       arg 01: subcmd-two
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT + command and subcommand options cannot be mixed' '
+       test-tool parse-subcommand --subcommand-optional --keep-unknown-opt cmd --subcommand-opt branch --opt=1 >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       arg 00: --subcommand-opt
+       arg 01: branch
+       arg 02: --opt=1
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT | KEEP_ARGV0' '
+       test-tool parse-subcommand --subcommand-optional --keep-unknown-opt --keep-argv0 cmd --subcommand-opt branch >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       arg 00: cmd
+       arg 01: --subcommand-opt
+       arg 02: branch
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT | KEEP_DASHDASH' '
+       test-tool parse-subcommand --subcommand-optional --keep-unknown-opt --keep-dashdash cmd -- --subcommand-opt file >actual &&
+       cat >expect <<-\EOF &&
+       opt: 0
+       fn: subcmd_one
+       arg 00: --
+       arg 01: --subcommand-opt
+       arg 02: file
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommand - completion helper' '
+       test-tool parse-subcommand cmd --git-completion-helper >actual &&
+       echo "subcmd-one subcmd-two --opt= --no-opt" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'subcommands are incompatible with STOP_AT_NON_OPTION' '
+       test_must_fail test-tool parse-subcommand --stop-at-non-option cmd subcmd-one 2>err &&
+       grep ^BUG err
+'
+
+test_expect_success 'subcommands are incompatible with KEEP_UNKNOWN_OPT unless in combination with SUBCOMMAND_OPTIONAL' '
+       test_must_fail test-tool parse-subcommand --keep-unknown-opt cmd subcmd-two 2>err &&
+       grep ^BUG err
+'
+
+test_expect_success 'subcommands are incompatible with KEEP_DASHDASH unless in combination with SUBCOMMAND_OPTIONAL' '
+       test_must_fail test-tool parse-subcommand --keep-dashdash cmd subcmd-two 2>err &&
+       grep ^BUG err
+'
+
 test_done
index 5c9dc90d0b096d9f104caedeb035b50b919b6811..325eb1c3cd0add75bcaf3b629c2692420c279f8a 100755 (executable)
@@ -5,6 +5,7 @@ test_description='Various filesystem issues'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 auml=$(printf '\303\244')
index aa35350b6f396f562463a16ffcba364ab94ed5d5..68e29c904a62c9ef51d6a1bfc3449795d50ac10f 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='Test various path utilities'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 norm_path() {
@@ -21,7 +22,7 @@ relative_path() {
 
 test_submodule_relative_url() {
        test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
-               actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+               actual=\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') &&
                test \"\$actual\" = '$4'
        "
 }
index 6f9a501c72b3a2520fd4d4734b45fe56a2a6d35e..ba8ad1d1ca0adeee8f001450951ec782e1fc3d74 100755 (executable)
@@ -5,7 +5,7 @@ test_description='verify sort functions'
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
-test_expect_success 'llist_mergesort()' '
+test_expect_success 'DEFINE_LIST_SORT_DEBUG' '
        test-tool mergesort test
 '
 
index 906757264844b67b0c72914b3aa2a6d02e17101c..d8e2fc42e15c73dfffebba57071b8d3e4bfd1ed1 100755 (executable)
@@ -5,6 +5,8 @@ test_description="Test whether cache-tree is properly updated
 Tests whether various commands properly update and/or rewrite the
 cache-tree extension.
 "
+
+TEST_PASSES_SANITIZE_LEAK=true
  . ./test-lib.sh
 
 cmp_cache_tree () {
index 08f5fe9caef0c8901e49401abf2762753d8a0b7c..b6d2f591acdd999483b2d28af8bbbe3d30008ea7 100755 (executable)
@@ -78,4 +78,52 @@ test_expect_success 'indicates populated hooks' '
        test_cmp expect actual
 '
 
+test_expect_success UNZIP '--diagnose creates diagnostics zip archive' '
+       test_when_finished rm -rf report &&
+
+       git bugreport --diagnose -o report -s test >out &&
+
+       zip_path=report/git-diagnostics-test.zip &&
+       grep "Available space" out &&
+       test_path_is_file "$zip_path" &&
+
+       # Check zipped archive content
+       "$GIT_UNZIP" -p "$zip_path" diagnostics.log >out &&
+       test_file_not_empty out &&
+
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
+       grep ".git/objects" out &&
+
+       "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
+       grep "^Total: [0-9][0-9]*" out &&
+
+       # Should not include .git directory contents by default
+       ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
+'
+
+test_expect_success UNZIP '--diagnose=stats excludes .git dir contents' '
+       test_when_finished rm -rf report &&
+
+       git bugreport --diagnose=stats -o report -s test >out &&
+
+       # Includes pack quantity/size info
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
+       grep ".git/objects" out &&
+
+       # Does not include .git directory contents
+       ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
+'
+
+test_expect_success UNZIP '--diagnose=all includes .git dir contents' '
+       test_when_finished rm -rf report &&
+
+       git bugreport --diagnose=all -o report -s test >out &&
+
+       # Includes .git directory contents
+       "$GIT_UNZIP" -l "$zip_path" | grep ".git/" &&
+
+       "$GIT_UNZIP" -p "$zip_path" .git/HEAD >out &&
+       test_file_not_empty out
+'
+
 test_done
diff --git a/t/t0092-diagnose.sh b/t/t0092-diagnose.sh
new file mode 100755 (executable)
index 0000000..133e574
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='git diagnose'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success UNZIP 'creates diagnostics zip archive' '
+       test_when_finished rm -rf report &&
+
+       git diagnose -o report -s test >out &&
+       grep "Available space" out &&
+
+       zip_path=report/git-diagnostics-test.zip &&
+       test_path_is_file "$zip_path" &&
+
+       # Check zipped archive content
+       "$GIT_UNZIP" -p "$zip_path" diagnostics.log >out &&
+       test_file_not_empty out &&
+
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
+       grep ".git/objects" out &&
+
+       "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
+       grep "^Total: [0-9][0-9]*" out &&
+
+       # Should not include .git directory contents by default
+       ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
+'
+
+test_expect_success UNZIP 'counts loose objects' '
+       test_commit A &&
+
+       # After committing, should have non-zero loose objects
+       git diagnose -o test-count -s 1 >out &&
+       zip_path=test-count/git-diagnostics-1.zip &&
+       "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
+       grep "^Total: [1-9][0-9]* loose objects" out
+'
+
+test_expect_success UNZIP '--mode=stats excludes .git dir contents' '
+       test_when_finished rm -rf report &&
+
+       git diagnose -o report -s test --mode=stats >out &&
+
+       # Includes pack quantity/size info
+       zip_path=report/git-diagnostics-test.zip &&
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
+       grep ".git/objects" out &&
+
+       # Does not include .git directory contents
+       ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
+'
+
+test_expect_success UNZIP '--mode=all includes .git dir contents' '
+       test_when_finished rm -rf report &&
+
+       git diagnose -o report -s test --mode=all >out &&
+
+       # Includes pack quantity/size info
+       zip_path=report/git-diagnostics-test.zip &&
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
+       grep ".git/objects" out &&
+
+       # Includes .git directory contents
+       "$GIT_UNZIP" -l "$zip_path" | grep ".git/" &&
+
+       "$GIT_UNZIP" -p "$zip_path" .git/HEAD >out &&
+       test_file_not_empty out
+'
+
+test_done
index 5945973552a6af6ac1971920b573086b081f6160..b567383eb836bff0c743522692cecdb354cbd0e6 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='Testing the various Bloom filter computations in bloom.c'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'compute unseeded murmur3 hash for empty string' '
@@ -67,7 +69,7 @@ test_expect_success 'compute bloom key for test string 2' '
        test_cmp expect actual
 '
 
-test_expect_success 'get bloom filters for commit with no changes' '
+test_expect_success !SANITIZE_LEAK 'get bloom filters for commit with no changes' '
        git init &&
        git commit --allow-empty -m "c0" &&
        cat >expect <<-\EOF &&
index 4dc9fecf7241ef416c7dfa0616d6d9df491fe673..12d817fbd34002cf5e8cd6561551b23303c27f6f 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='urlmatch URL normalization'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # The base name of the test url files
index df2ea34932bcfe99cd5719cc2e2f587e6b09c49e..5a6f28051bd275577110ddbba5618f756ca0937e 100755 (executable)
@@ -7,22 +7,12 @@ test_description='Perl gettext interface (Git::I18N)'
 
 TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-gettext.sh
+. "$TEST_DIRECTORY"/lib-perl.sh
+skip_all_if_no_Test_More
 
-if ! test_have_prereq PERL; then
-       skip_all='skipping perl interface tests, perl not available'
-       test_done
-fi
-
-perl -MTest::More -e 0 2>/dev/null || {
-       skip_all="Perl Test::More unavailable, skipping test"
-       test_done
-}
-
-# The external test will outputs its own plan
-test_external_has_tap=1
-
-test_external_without_stderr \
-    'Perl Git::I18N API' \
-    perl "$TEST_DIRECTORY"/t0202/test.pl
+test_expect_success 'run t0202/test.pl to test Git::I18N.pm' '
+       "$PERL_PATH" "$TEST_DIRECTORY"/t0202/test.pl 2>stderr &&
+       test_must_be_empty stderr
+'
 
 test_done
index 0ce1f22eff66285ee0da9b1830de961555fbad2b..86cff324ff181110cf1ef8a44af6c4295b7f5d40 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description="The Git C functions aren't broken by setlocale(3)"
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-gettext.sh
 
 test_expect_success 'git show a ISO-8859-1 commit under C locale' '
index b6408560c0ca934601cda3fed8091510a3918745..30a9f51e9f1ecc7820c244fe1bb604e0acea8e94 100644 (file)
@@ -216,12 +216,19 @@ while (<>) {
 
     elsif ($event eq 'data') {
        my $cat = $line->{'category'};
-       if ($cat eq 'test_category') {
-           
-           my $key = $line->{'key'};
-           my $value = $line->{'value'};
-           $processes->{$sid}->{'data'}->{$cat}->{$key} = $value;
-       }
+       my $key = $line->{'key'};
+       my $value = $line->{'value'};
+       $processes->{$sid}->{'data'}->{$cat}->{$key} = $value;
+    }
+
+    elsif ($event eq 'data_json') {
+       # NEEDSWORK: Ignore due to
+       # compat/win32/trace2_win32_process_info.c, which should log a
+       # "cmd_ancestry" event instead.
+    }
+
+    else {
+       push @{$processes->{$sid}->{$event}} => $line->{value};
     }
 
     # This trace2 target does not emit 'printf' events.
index dadf3b14583bec460a51cbf69362a875dd3cc867..23b8942edba45c32822886ee93acef9b5474ea02 100755 (executable)
@@ -88,7 +88,8 @@ done
 
 for opt in --buffer \
        --follow-symlinks \
-       --batch-all-objects
+       --batch-all-objects \
+       -z
 do
        test_expect_success "usage: bad option combination: $opt without batch mode" '
                test_incompatible_usage git cat-file $opt &&
@@ -100,6 +101,10 @@ echo_without_newline () {
     printf '%s' "$*"
 }
 
+echo_without_newline_nul () {
+       echo_without_newline "$@" | tr '\n' '\0'
+}
+
 strlen () {
     echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
 }
@@ -398,6 +403,12 @@ test_expect_success '--batch with multiple sha1s gives correct format' '
        test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)"
 '
 
+test_expect_success '--batch, -z with multiple sha1s gives correct format' '
+       echo_without_newline_nul "$batch_input" >in &&
+       test "$(maybe_remove_timestamp "$batch_output" 1)" = \
+       "$(maybe_remove_timestamp "$(git cat-file --batch -z <in)" 1)"
+'
+
 batch_check_input="$hello_sha1
 $tree_sha1
 $commit_sha1
@@ -418,6 +429,30 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" '
     "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
 '
 
+test_expect_success "--batch-check, -z with multiple sha1s gives correct format" '
+    echo_without_newline_nul "$batch_check_input" >in &&
+    test "$batch_check_output" = "$(git cat-file --batch-check -z <in)"
+'
+
+test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
+       touch -- "newline${LF}embedded" &&
+       git add -- "newline${LF}embedded" &&
+       git commit -m "file with newline embedded" &&
+       test_tick &&
+
+       printf "HEAD:newline${LF}embedded" >in &&
+       git cat-file --batch-check -z <in >actual &&
+
+       echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
+       test_cmp expect actual
+'
+
+batch_command_multiple_info="info $hello_sha1
+info $tree_sha1
+info $commit_sha1
+info $tag_sha1
+info deadbeef"
+
 test_expect_success '--batch-command with multiple info calls gives correct format' '
        cat >expect <<-EOF &&
        $hello_sha1 blob $hello_size
@@ -427,17 +462,23 @@ test_expect_success '--batch-command with multiple info calls gives correct form
        deadbeef missing
        EOF
 
-       git cat-file --batch-command --buffer >actual <<-EOF &&
-       info $hello_sha1
-       info $tree_sha1
-       info $commit_sha1
-       info $tag_sha1
-       info deadbeef
-       EOF
+       echo "$batch_command_multiple_info" >in &&
+       git cat-file --batch-command --buffer <in >actual &&
+
+       test_cmp expect actual &&
+
+       echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
+       git cat-file --batch-command --buffer -z <in >actual &&
 
        test_cmp expect actual
 '
 
+batch_command_multiple_contents="contents $hello_sha1
+contents $commit_sha1
+contents $tag_sha1
+contents deadbeef
+flush"
+
 test_expect_success '--batch-command with multiple command calls gives correct format' '
        remove_timestamp >expect <<-EOF &&
        $hello_sha1 blob $hello_size
@@ -449,13 +490,14 @@ test_expect_success '--batch-command with multiple command calls gives correct f
        deadbeef missing
        EOF
 
-       git cat-file --batch-command --buffer >actual_raw <<-EOF &&
-       contents $hello_sha1
-       contents $commit_sha1
-       contents $tag_sha1
-       contents deadbeef
-       flush
-       EOF
+       echo "$batch_command_multiple_contents" >in &&
+       git cat-file --batch-command --buffer <in >actual_raw &&
+
+       remove_timestamp <actual_raw >actual &&
+       test_cmp expect actual &&
+
+       echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
+       git cat-file --batch-command --buffer -z <in >actual_raw &&
 
        remove_timestamp <actual_raw >actual &&
        test_cmp expect actual
index 63a553d7b32224550a48008772e396e88455af11..742f0fa909fd6e8a7fe2b376b3e5083a30d71c73 100755 (executable)
@@ -11,6 +11,7 @@ test_description='sparse checkout tests
   A    init.t
 '
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-read-tree.sh
 
@@ -53,6 +54,7 @@ test_expect_success 'read-tree without .git/info/sparse-checkout' '
 '
 
 test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' '
+       mkdir .git/info &&
        echo >.git/info/sparse-checkout &&
        read_tree_u_must_succeed -m -u HEAD &&
        git ls-files -t >result &&
index 9fdbb2af80e0a82429289d06b24d4dcfac3f263d..45eef9457fe13d9eef6e463405190ca84c67bda5 100755 (executable)
@@ -6,6 +6,7 @@
 test_description='Try various core-level commands in subdirectory.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-read-tree.sh
 
index 042b0e442929b427d48049610e89810a495903bb..f6709c9f569ec7170d24694b369abf0d6f8518ec 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test conversion filters on large files'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 set_attr() {
index 5b8e47e346c710ac4ddb4592d707c9b9fdf358a7..35261afc9d6d02fe1d9d1572591406b293522fa8 100755 (executable)
@@ -139,4 +139,11 @@ test_expect_success 'internal tree objects are not "missing"' '
        )
 '
 
+test_expect_success 'partial clone of corrupted repository' '
+       test_config -C misnamed uploadpack.allowFilter true &&
+       git clone --no-local --no-checkout --filter=blob:none \
+               misnamed corrupt-partial && \
+       test_must_fail git -C corrupt-partial checkout --force
+'
+
 test_done
index d1833c0f31b467e1dc5173a7332bfbb16c5de05c..3a14218b245d4cf67f9bdde4c18a7eee8ac6524a 100755 (executable)
@@ -5,6 +5,7 @@ test_description='sparse checkout scope tests'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -25,6 +26,7 @@ test_expect_success 'create feature branch' '
 
 test_expect_success 'perform sparse checkout of main' '
        git config --local --bool core.sparsecheckout true &&
+       mkdir .git/info &&
        echo "!/*" >.git/info/sparse-checkout &&
        echo "/a" >>.git/info/sparse-checkout &&
        echo "/c" >>.git/info/sparse-checkout &&
@@ -73,7 +75,7 @@ test_expect_success 'skip-worktree on files outside sparse patterns' '
 
 test_expect_success 'in partial clone, sparse checkout only fetches needed blobs' '
        test_create_repo server &&
-       git clone "file://$(pwd)/server" client &&
+       git clone --template= "file://$(pwd)/server" client &&
 
        test_config -C server uploadpack.allowfilter 1 &&
        test_config -C server uploadpack.allowanysha1inwant 1 &&
@@ -85,6 +87,7 @@ test_expect_success 'in partial clone, sparse checkout only fetches needed blobs
        git -C server commit -m message &&
 
        test_config -C client core.sparsecheckout 1 &&
+       mkdir client/.git/info &&
        echo "!/*" >client/.git/info/sparse-checkout &&
        echo "/a" >>client/.git/info/sparse-checkout &&
        git -C client fetch --filter=blob:none origin &&
index 5dced39889fff99335148bd00f900fab4038622d..b9350c075c2a02db00c154bb3522a087208cdc84 100755 (executable)
@@ -380,6 +380,15 @@ test_expect_success 'checkout with modified sparse directory' '
        test_all_match git checkout base
 '
 
+test_expect_success 'checkout orphan then non-orphan' '
+       init_repos &&
+
+       test_all_match git checkout --orphan test-orphan &&
+       test_all_match git status --porcelain=v2 &&
+       test_all_match git checkout base &&
+       test_all_match git status --porcelain=v2
+'
+
 test_expect_success 'add outside sparse cone' '
        init_repos &&
 
@@ -556,7 +565,7 @@ test_expect_success 'blame with pathspec inside sparse definition' '
                        deep/deeper1/a \
                        deep/deeper1/deepest/a
        do
-               test_all_match git blame $file
+               test_all_match git blame $file || return 1
        done
 '
 
@@ -567,7 +576,7 @@ test_expect_success 'blame with pathspec outside sparse definition' '
        init_repos &&
        test_sparse_match git sparse-checkout set &&
 
-       for file in \
+       for file in \
                        deep/a \
                        deep/deeper1/a \
                        deep/deeper1/deepest/a
@@ -579,7 +588,7 @@ test_expect_success 'blame with pathspec outside sparse definition' '
                # We compare sparse-checkout-err and sparse-index-err in
                # `test_sparse_match`. Given we know they are the same, we
                # only check the content of sparse-index-err here.
-               test_cmp expect sparse-index-err
+               test_cmp expect sparse-index-err || return 1
        done
 '
 
@@ -937,7 +946,7 @@ test_expect_success 'read-tree --prefix' '
        test_all_match git read-tree --prefix=deep/deeper1/deepest -u deepest &&
        test_all_match git status --porcelain=v2 &&
 
-       test_all_match git rm -rf --sparse folder1/ &&
+       run_on_all git rm -rf --sparse folder1/ &&
        test_all_match git read-tree --prefix=folder1/ -u update-folder1 &&
        test_all_match git status --porcelain=v2 &&
 
@@ -1365,10 +1374,14 @@ ensure_not_expanded () {
                shift &&
                test_must_fail env \
                        GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
-                       git -C sparse-index "$@" || return 1
+                       git -C sparse-index "$@" \
+                       >sparse-index-out \
+                       2>sparse-index-error || return 1
        else
                GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
-                       git -C sparse-index "$@" || return 1
+                       git -C sparse-index "$@" \
+                       >sparse-index-out \
+                       2>sparse-index-error || return 1
        fi &&
        test_region ! index ensure_full_index trace2.txt
 }
@@ -1567,7 +1580,7 @@ test_expect_success 'sparse index is not expanded: blame' '
                        deep/deeper1/a \
                        deep/deeper1/deepest/a
        do
-               ensure_not_expanded blame $file
+               ensure_not_expanded blame $file || return 1
        done
 '
 
@@ -1853,4 +1866,119 @@ test_expect_success 'checkout behaves oddly with df-conflict-2' '
        test_cmp full-checkout-err sparse-index-err
 '
 
+test_expect_success 'mv directory from out-of-cone to in-cone' '
+       init_repos &&
+
+       # <source> as a sparse directory (or SKIP_WORKTREE_DIR without enabling
+       # sparse index).
+       test_all_match git mv --sparse folder1 deep &&
+       test_all_match git status --porcelain=v2 &&
+       test_sparse_match git ls-files -t &&
+       git -C sparse-checkout ls-files -t >actual &&
+       grep -e "H deep/folder1/0/0/0" actual &&
+       grep -e "H deep/folder1/0/1" actual &&
+       grep -e "H deep/folder1/a" actual &&
+
+       test_all_match git reset --hard &&
+
+       # <source> as a directory deeper than sparse index boundary (where
+       # sparse index will expand).
+       test_sparse_match git mv --sparse folder1/0 deep &&
+       test_sparse_match git status --porcelain=v2 &&
+       test_sparse_match git ls-files -t &&
+       git -C sparse-checkout ls-files -t >actual &&
+       grep -e "H deep/0/0/0" actual &&
+       grep -e "H deep/0/1" actual
+'
+
+test_expect_success 'rm pathspec inside sparse definition' '
+       init_repos &&
+
+       test_all_match git rm deep/a &&
+       test_all_match git status --porcelain=v2 &&
+
+       # test wildcard
+       run_on_all git reset --hard &&
+       test_all_match git rm deep/* &&
+       test_all_match git status --porcelain=v2 &&
+
+       # test recursive rm
+       run_on_all git reset --hard &&
+       test_all_match git rm -r deep &&
+       test_all_match git status --porcelain=v2
+'
+
+test_expect_success 'rm pathspec outside sparse definition' '
+       init_repos &&
+
+       for file in folder1/a folder1/0/1
+       do
+               test_sparse_match test_must_fail git rm $file &&
+               test_sparse_match test_must_fail git rm --cached $file &&
+               test_sparse_match git rm --sparse $file &&
+               test_sparse_match git status --porcelain=v2 || return 1
+       done &&
+
+       cat >folder1-full <<-EOF &&
+       rm ${SQ}folder1/0/0/0${SQ}
+       rm ${SQ}folder1/0/1${SQ}
+       rm ${SQ}folder1/a${SQ}
+       EOF
+
+       cat >folder1-sparse <<-EOF &&
+       rm ${SQ}folder1/${SQ}
+       EOF
+
+       # test wildcard
+       run_on_sparse git reset --hard &&
+       run_on_sparse git sparse-checkout reapply &&
+       test_sparse_match test_must_fail git rm folder1/* &&
+       run_on_sparse git rm --sparse folder1/* &&
+       test_cmp folder1-full sparse-checkout-out &&
+       test_cmp folder1-sparse sparse-index-out &&
+       test_sparse_match git status --porcelain=v2 &&
+
+       # test recursive rm
+       run_on_sparse git reset --hard &&
+       run_on_sparse git sparse-checkout reapply &&
+       test_sparse_match test_must_fail git rm --sparse folder1 &&
+       run_on_sparse git rm --sparse -r folder1 &&
+       test_cmp folder1-full sparse-checkout-out &&
+       test_cmp folder1-sparse sparse-index-out &&
+       test_sparse_match git status --porcelain=v2
+'
+
+test_expect_success 'rm pathspec expands index when necessary' '
+       init_repos &&
+
+       # in-cone pathspec (do not expand)
+       ensure_not_expanded rm "deep/deep*" &&
+       test_must_be_empty sparse-index-err &&
+
+       # out-of-cone pathspec (expand)
+       ! ensure_not_expanded rm --sparse "folder1/a*" &&
+       test_must_be_empty sparse-index-err &&
+
+       # pathspec that should expand index
+       ! ensure_not_expanded rm "*/a" &&
+       test_must_be_empty sparse-index-err &&
+
+       ! ensure_not_expanded rm "**a" &&
+       test_must_be_empty sparse-index-err
+'
+
+test_expect_success 'sparse index is not expanded: rm' '
+       init_repos &&
+
+       ensure_not_expanded rm deep/a &&
+
+       # test in-cone wildcard
+       git -C sparse-index reset --hard &&
+       ensure_not_expanded rm deep/* &&
+
+       # test recursive rm
+       git -C sparse-index reset --hard &&
+       ensure_not_expanded rm -r deep
+'
+
 test_done
index 84bf1970d8bfe7b13327fb0d66f691dcfa58cbb0..93a2f91f8a5181c5307c6de14ab6f2823d2b959a 100755 (executable)
@@ -48,7 +48,7 @@ done
 test_expect_success 'shared=all' '
        mkdir sub &&
        cd sub &&
-       git init --shared=all &&
+       git init --template= --shared=all &&
        test 2 = $(git config core.sharedrepository)
 '
 
@@ -57,6 +57,7 @@ test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository'
        git add a1 &&
        test_tick &&
        git commit -m a1 &&
+       mkdir .git/info &&
        umask 0277 &&
        git update-server-info &&
        actual="$(ls -l .git/info/refs)" &&
index 335d3f3211aa874fd3a8e0d0006dd9fc53a4e589..c69ae41306c90d33b2ac253a25961ae76fec81e7 100755 (executable)
@@ -18,7 +18,7 @@ test_expect_success 'checking for a working acl setup' '
        if setfacl -m d:m:rwx -m u:root:rwx . &&
           getfacl . | grep user:root:rwx &&
           touch should-have-readable-acl &&
-          getfacl should-have-readable-acl | egrep "mask::?rw-"
+          getfacl should-have-readable-acl | grep -E "mask::?rw-"
        then
                test_set_prereq SETFACL
        fi
@@ -34,7 +34,7 @@ check_perms_and_acl () {
        getfacl "$1" > actual &&
        grep -q "user:root:rwx" actual &&
        grep -q "user:${LOGNAME}:rwx" actual &&
-       egrep "mask::?r--" actual > /dev/null 2>&1 &&
+       grep -E "mask::?r--" actual > /dev/null 2>&1 &&
        grep -q "group::---" actual || false
 }
 
index 9fb0b90f252aa17a04a52678eb48a3a9bf9883ee..0c204089b83595bc516e9c26416cd67191d3c083 100755 (executable)
@@ -165,4 +165,14 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '
        test_cmp expect actual
 '
 
+test_expect_success 'symbolic-ref refuses invalid target for non-HEAD' '
+       test_must_fail git symbolic-ref refs/heads/invalid foo..bar
+'
+
+test_expect_success 'symbolic-ref allows top-level target for non-HEAD' '
+       git symbolic-ref refs/heads/top-level FETCH_HEAD &&
+       git update-ref FETCH_HEAD HEAD &&
+       test_cmp_rev top-level HEAD
+'
+
 test_done
index cabc516ae9a4fa1c404c245f4b3b9efd7e93200e..5ed9d7318e0cc97435952039c7e8c1af842a24a9 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='Test git check-ref-format'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 valid_ref() {
index 51f829162819740fea8b080db3be6b422452b366..e4627cf1b61f0b3128a79e28f15a9d5e5693e30c 100755 (executable)
@@ -5,6 +5,7 @@ test_description='test main ref store api'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 RUN="test-tool ref-store main"
index ad8006c81397336fc5919858d0b13ec4d564b723..05b1881c5911780b53a3d882dbe1a4dfae0034d8 100755 (executable)
@@ -5,6 +5,7 @@ test_description='test worktree ref store api'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 RWT="test-tool ref-store worktree:wt"
index d51ecd5e9250f004e0b0c894b308172237e5666c..2268bca3c11ac8e2d73e3a399b8debc44fc712cb 100755 (executable)
@@ -4,6 +4,7 @@ test_description='Test reflog display routines'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index 53c2aa10b72745f96c6619fc5f8e5c9f50a48d54..ace4556788de761e225567787bc34ac4e6dc18bf 100755 (executable)
@@ -507,6 +507,54 @@ test_expect_success 'rev-list --verify-objects with bad sha1' '
        test_i18ngrep -q "error: hash mismatch $(dirname $new)$(test_oid ff_2)" out
 '
 
+# An actual bit corruption is more likely than swapped commits, but
+# this provides an easy way to have commits which don't match their purported
+# hashes, but which aren't so broken we can't read them at all.
+test_expect_success 'rev-list --verify-objects notices swapped commits' '
+       git init swapped-commits &&
+       (
+               cd swapped-commits &&
+               test_commit one &&
+               test_commit two &&
+               one_oid=$(git rev-parse HEAD) &&
+               two_oid=$(git rev-parse HEAD^) &&
+               one=.git/objects/$(test_oid_to_path $one_oid) &&
+               two=.git/objects/$(test_oid_to_path $two_oid) &&
+               mv $one tmp &&
+               mv $two $one &&
+               mv tmp $two &&
+               test_must_fail git rev-list --verify-objects HEAD
+       )
+'
+
+test_expect_success 'set up repository with commit-graph' '
+       git init corrupt-graph &&
+       (
+               cd corrupt-graph &&
+               test_commit one &&
+               test_commit two &&
+               git commit-graph write --reachable
+       )
+'
+
+corrupt_graph_obj () {
+       oid=$(git -C corrupt-graph rev-parse "$1") &&
+       obj=corrupt-graph/.git/objects/$(test_oid_to_path $oid) &&
+       test_when_finished 'mv backup $obj' &&
+       mv $obj backup &&
+       echo garbage >$obj
+}
+
+test_expect_success 'rev-list --verify-objects with commit graph (tip)' '
+       corrupt_graph_obj HEAD &&
+       test_must_fail git -C corrupt-graph rev-list --verify-objects HEAD
+'
+
+test_expect_success 'rev-list --verify-objects with commit graph (parent)' '
+       corrupt_graph_obj HEAD^ &&
+       test_must_fail git -C corrupt-graph rev-list --verify-objects HEAD
+'
+
 test_expect_success 'force fsck to ignore double author' '
        git cat-file commit HEAD >basis &&
        sed "s/^author .*/&,&/" <basis | tr , \\n >multiple-authors &&
index 1c2df08333bc600e4fc22f1f55c1d6950b876d67..0e13bcb4ebbf703337bda31e5714620dcc2cf636 100755 (executable)
@@ -4,6 +4,7 @@ test_description='test git rev-parse'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_one () {
index 284fe18e7262ae9198d61a34142aa2e82696ce2a..de1d48f3ba29116d073b0a5573a2031fae7fcc1d 100755 (executable)
@@ -306,6 +306,13 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
        test_cmp expect actual
 '
 
+test_expect_success 'test --parseopt invalid opt-spec' '
+       test_write_lines x -- "=, x" >spec &&
+       echo "fatal: missing opt-spec before option flags" >expect &&
+       test_must_fail git rev-parse --parseopt -- >out <spec 2>err &&
+       test_cmp expect err
+'
+
 test_expect_success 'test --parseopt help output: multi-line blurb after empty line' '
        sed -e "s/^|//" >spec <<-\EOF &&
        |cmd [--some-option]
index ba43168d1237ad5216e3ba5ed22069323fbf93b0..bc136833c1098d1c4e43d4b05cfadc7bef50b24c 100755 (executable)
@@ -132,7 +132,7 @@ test_expect_success 'use --default' '
        test_must_fail git rev-parse --verify --default bar
 '
 
-test_expect_success !SANITIZE_LEAK 'main@{n} for various n' '
+test_expect_success 'main@{n} for various n' '
        git reflog >out &&
        N=$(wc -l <out) &&
        Nm1=$(($N-1)) &&
index 5dc221ef382df13089b84dcb03002c2a8f19a9ba..d8fa489998acc5984da7e21a8a2adf43cfe88cee 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='racy split index'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index 64096adac7e108cb605cce1d7f3a40a28b87c676..43fcb7c0bfc85e3d29455ec37cfbf437e00238a9 100755 (executable)
@@ -157,9 +157,9 @@ test_expect_success 'git hook run a hook with a bad shebang' '
        write_script bad-hooks/test-hook "/bad/path/no/spaces" </dev/null &&
 
        # TODO: We should emit the same (or at least a more similar)
-       # error on Windows and !Windows. See the OS-specific code in
-       # start_command()
-       if test_have_prereq !WINDOWS
+       # error on MINGW (essentially Git for Windows) and all other
+       # platforms.. See the OS-specific code in start_command()
+       if test_have_prereq !MINGW
        then
                cat >expect <<-\EOF
                fatal: cannot run bad-hooks/test-hook: ...
index 7705e3a31708355c05271aa9d5eafa5af359043f..5d119871d416cd4e79b3bff7c56aeac729b276e6 100755 (executable)
@@ -3,6 +3,7 @@
 test_description='basic checkout-index tests
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'checkout-index --gobbledegook' '
index 52e51b0726f39c3e7ffbedad5a77484b8bec6070..771c3c3c50e60583e3ba8dffbb62f47a7619f35b 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='checkout'
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 # Arguments: [!] <branch> <oid> [<checkout options>]
@@ -257,11 +258,12 @@ test_expect_success 'checkout -b to a new branch preserves mergeable changes des
                git checkout branch1-scratch &&
                test_might_fail git branch -D branch3 &&
                git config core.sparseCheckout false &&
-               rm .git/info/sparse-checkout" &&
+               rm -rf .git/info" &&
 
        test_commit file2 &&
 
        echo stuff >>file1 &&
+       mkdir .git/info &&
        echo file2 >.git/info/sparse-checkout &&
        git config core.sparseCheckout true &&
 
index bc46713a43e24193bae9a4be204455eb5c066501..2eab6474f8d0f4b3116455c95cb71cd69f78a311 100755 (executable)
@@ -4,6 +4,7 @@ test_description='checkout into detached HEAD state'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_detached () {
index 7b327b754494a8ebb27bb11c7f70649063ccd8d2..81e772fb4ebbf1d6c4d156560aa10dfdb02a0852 100755 (executable)
@@ -7,6 +7,7 @@ Ensures that checkout -m on a resolved file restores the conflicted file'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index c683e60007219807b18bfb42bac83c297cdc8234..00ce3033d3489285b8580d6e23f3eeb24074862f 100755 (executable)
@@ -230,12 +230,9 @@ test_expect_success SYMLINKS 'parallel checkout checks for symlinks in leading d
 # check the final report including sequential, parallel, and delayed entries
 # all at the same time. So we must have finer control of the parallel checkout
 # variables.
-test_expect_success PERL '"git checkout ." report should not include failed entries' '
-       write_script rot13-filter.pl "$PERL_PATH" \
-               <"$TEST_DIRECTORY"/t0021/rot13-filter.pl &&
-
+test_expect_success '"git checkout ." report should not include failed entries' '
        test_config_global filter.delay.process \
-               "\"$(pwd)/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
+               "test-tool rot13-filter --always-delay --log=delayed.log clean smudge delay" &&
        test_config_global filter.delay.required true &&
        test_config_global filter.cat.clean cat  &&
        test_config_global filter.cat.smudge cat  &&
index 252545796182e3e4c469284f1a99a8691a0812a8..f3511cd43a9ddc929c886ef7c44f4e4704b6c367 100755 (executable)
@@ -138,12 +138,9 @@ test_expect_success 'parallel-checkout and external filter' '
 # The delayed queue is independent from the parallel queue, and they should be
 # able to work together in the same checkout process.
 #
-test_expect_success PERL 'parallel-checkout and delayed checkout' '
-       write_script rot13-filter.pl "$PERL_PATH" \
-               <"$TEST_DIRECTORY"/t0021/rot13-filter.pl &&
-
+test_expect_success 'parallel-checkout and delayed checkout' '
        test_config_global filter.delay.process \
-               "\"$(pwd)/rot13-filter.pl\" --always-delay \"$(pwd)/delayed.log\" clean smudge delay" &&
+               "test-tool rot13-filter --always-delay --log=\"$(pwd)/delayed.log\" clean smudge delay" &&
        test_config_global filter.delay.required true &&
 
        echo "abcd" >original &&
index 43d950de6400fca709286c5316e71e037791f04f..98265ba1b495eb91df0fa60467ebf0ac932cf1b5 100755 (executable)
@@ -17,6 +17,7 @@ outside the repository.  Two instances for which this can occur are tested:
           repository can be added to the index.
        '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success '1a: setup--config worktree' '
index 2f564d533d05965fff88f51bc0f1280abae43518..f3242fef6b65772ea973a1906210950cc0411f73 100755 (executable)
@@ -5,6 +5,7 @@ test_description='test git worktree add'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
@@ -229,6 +230,7 @@ test_expect_success 'checkout with grafts' '
        SHA1=$(git rev-parse HEAD) &&
        test_commit def &&
        test_commit xyz &&
+       mkdir .git/info &&
        echo "$(git rev-parse HEAD) $SHA1" >.git/info/grafts &&
        cat >expected <<-\EOF &&
        xyz
@@ -559,6 +561,8 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
 '
 
 post_checkout_hook () {
+       test_when_finished "rm -rf .git/hooks" &&
+       mkdir .git/hooks &&
        test_hook -C "$1" post-checkout <<-\EOF
        {
                echo $*
index a4e1a178e0a00335affa95d566728e3085804b47..1168e9f998232ccfa3d4c7c2e875b95299f23ead 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='test git worktree move, remove, lock and unlock'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t2407-worktree-heads.sh b/t/t2407-worktree-heads.sh
new file mode 100755 (executable)
index 0000000..019a40d
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+test_description='test operations trying to overwrite refs at worktree HEAD'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit init &&
+
+       for i in 1 2 3 4
+       do
+               git checkout -b conflict-$i &&
+               echo "not I" >$i.t &&
+               git add $i.t &&
+               git commit -m "will conflict" &&
+
+               git checkout - &&
+               test_commit $i &&
+               git branch wt-$i &&
+               git branch fake-$i &&
+               git worktree add wt-$i wt-$i || return 1
+       done &&
+
+       # Create a server that updates each branch by one commit
+       git init server &&
+       test_commit -C server initial &&
+       git remote add server ./server &&
+       for i in 1 2 3 4
+       do
+               git -C server checkout -b wt-$i &&
+               test_commit -C server A-$i || return 1
+       done &&
+       for i in 1 2
+       do
+               git -C server checkout -b fake-$i &&
+               test_commit -C server f-$i || return 1
+       done
+'
+
+test_expect_success 'refuse to overwrite: checked out in worktree' '
+       for i in 1 2 3 4
+       do
+               test_must_fail git branch -f wt-$i HEAD 2>err &&
+               grep "cannot force update the branch" err &&
+
+               test_must_fail git branch -D wt-$i 2>err &&
+               grep "Cannot delete branch" err || return 1
+       done
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in bisect' '
+       test_when_finished git -C wt-4 bisect reset &&
+
+       # Set up a bisect so HEAD no longer points to wt-4.
+       git -C wt-4 bisect start &&
+       git -C wt-4 bisect bad wt-4 &&
+       git -C wt-4 bisect good wt-1 &&
+
+       test_must_fail git branch -f wt-4 HEAD 2>err &&
+       grep "cannot force update the branch '\''wt-4'\'' checked out at.*wt-4" err
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (apply)' '
+       test_when_finished git -C wt-2 rebase --abort &&
+
+       # This will fail part-way through due to a conflict.
+       test_must_fail git -C wt-2 rebase --apply conflict-2 &&
+
+       test_must_fail git branch -f wt-2 HEAD 2>err &&
+       grep "cannot force update the branch '\''wt-2'\'' checked out at.*wt-2" err
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (merge)' '
+       test_when_finished git -C wt-2 rebase --abort &&
+
+       # This will fail part-way through due to a conflict.
+       test_must_fail git -C wt-2 rebase conflict-2 &&
+
+       test_must_fail git branch -f wt-2 HEAD 2>err &&
+       grep "cannot force update the branch '\''wt-2'\'' checked out at.*wt-2" err
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase with --update-refs' '
+       test_when_finished git -C wt-3 rebase --abort &&
+
+       git branch -f can-be-updated wt-3 &&
+       test_must_fail git -C wt-3 rebase --update-refs conflict-3 &&
+
+       for i in 3 4
+       do
+               test_must_fail git branch -f can-be-updated HEAD 2>err &&
+               grep "cannot force update the branch '\''can-be-updated'\'' checked out at.*wt-3" err ||
+                       return 1
+       done
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: checked out' '
+       test_must_fail git fetch server +refs/heads/wt-3:refs/heads/wt-3 2>err &&
+       grep "refusing to fetch into branch '\''refs/heads/wt-3'\''" err &&
+
+       # General fetch into refs/heads/ will fail on first ref,
+       # so use a generic error message check.
+       test_must_fail git fetch server +refs/heads/*:refs/heads/* 2>err &&
+       grep "refusing to fetch into branch" err
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: worktree in bisect' '
+       test_when_finished git -C wt-4 bisect reset &&
+
+       # Set up a bisect so HEAD no longer points to wt-4.
+       git -C wt-4 bisect start &&
+       git -C wt-4 bisect bad wt-4 &&
+       git -C wt-4 bisect good wt-1 &&
+
+       test_must_fail git fetch server +refs/heads/wt-4:refs/heads/wt-4 2>err &&
+       grep "refusing to fetch into branch" err
+'
+
+test_expect_success !SANITIZE_LEAK 'refuse to fetch over ref: worktree in rebase' '
+       test_when_finished git -C wt-3 rebase --abort &&
+
+       # This will fail part-way through due to a conflict.
+       test_must_fail git -C wt-3 rebase conflict-3 &&
+
+       test_must_fail git fetch server +refs/heads/wt-3:refs/heads/wt-3 2>err &&
+       grep "refusing to fetch into branch" err
+'
+
+test_expect_success 'refuse to overwrite when in error states' '
+       test_when_finished rm -rf .git/worktrees/wt-*/rebase-merge &&
+       test_when_finished rm -rf .git/worktrees/wt-*/BISECT_* &&
+
+       # Both branches are currently under rebase.
+       mkdir -p .git/worktrees/wt-3/rebase-merge &&
+       touch .git/worktrees/wt-3/rebase-merge/interactive &&
+       echo refs/heads/fake-1 >.git/worktrees/wt-3/rebase-merge/head-name &&
+       echo refs/heads/fake-2 >.git/worktrees/wt-3/rebase-merge/onto &&
+       mkdir -p .git/worktrees/wt-4/rebase-merge &&
+       touch .git/worktrees/wt-4/rebase-merge/interactive &&
+       echo refs/heads/fake-2 >.git/worktrees/wt-4/rebase-merge/head-name &&
+       echo refs/heads/fake-1 >.git/worktrees/wt-4/rebase-merge/onto &&
+
+       # Both branches are currently under bisect.
+       touch .git/worktrees/wt-4/BISECT_LOG &&
+       echo refs/heads/fake-2 >.git/worktrees/wt-4/BISECT_START &&
+       touch .git/worktrees/wt-1/BISECT_LOG &&
+       echo refs/heads/fake-1 >.git/worktrees/wt-1/BISECT_START &&
+
+       for i in 1 2
+       do
+               test_must_fail git branch -f fake-$i HEAD 2>err &&
+               grep "cannot force update the branch '\''fake-$i'\'' checked out at" err ||
+                       return 1
+       done
+'
+
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+test_expect_success !SANITIZE_LEAK 'refuse to overwrite during rebase with --update-refs' '
+       git commit --fixup HEAD~2 --allow-empty &&
+       (
+               set_cat_todo_editor &&
+               test_must_fail git rebase -i --update-refs HEAD~3 >todo &&
+               ! grep "update-refs" todo
+       ) &&
+       git branch -f allow-update HEAD~2 &&
+       (
+               set_cat_todo_editor &&
+               test_must_fail git rebase -i --update-refs HEAD~3 >todo &&
+               grep "update-ref refs/heads/allow-update" todo
+       )
+'
+
+# This must be the last test in this file
+test_expect_success '$EDITOR and friends are unchanged' '
+       test_editor_unchanged
+'
+
+test_done
index e07ac6c6dce93f50ff1900fc42e151f5370935a4..1ed0aa967ece5a38cf49bc43178e4fba187d4cd4 100755 (executable)
@@ -103,7 +103,7 @@ test_expect_success 'git ls-files --others with various exclude options.' '
        test_cmp expect output
 '
 
-test_expect_success !SANITIZE_LEAK 'restore gitignore' '
+test_expect_success 'restore gitignore' '
        git checkout --ignore-skip-worktree-bits $allignores &&
        rm .git/index
 '
@@ -126,7 +126,7 @@ cat > expect << EOF
 #      three/
 EOF
 
-test_expect_success !SANITIZE_LEAK 'git status honors core.excludesfile' \
+test_expect_success 'git status honors core.excludesfile' \
        'test_cmp expect output'
 
 test_expect_success 'trailing slash in exclude allows directory match(1)' '
index 2682b1f43a666564a6f74bd20deca547f721ac34..190e2f6eed758229579a85118106e80d05c8d7d8 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git ls-files --deduplicate test'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
diff --git a/t/t3013-ls-files-format.sh b/t/t3013-ls-files-format.sh
new file mode 100755 (executable)
index 0000000..efb7450
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='git ls-files --format test'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+for flag in -s -o -k -t --resolve-undo --deduplicate --eol
+do
+       test_expect_success "usage: --format is incompatible with $flag" '
+               test_expect_code 129 git ls-files --format="%(objectname)" $flag
+       '
+done
+
+test_expect_success 'setup' '
+       printf "LINEONE\nLINETWO\nLINETHREE\n" >o1.txt &&
+       printf "LINEONE\r\nLINETWO\r\nLINETHREE\r\n" >o2.txt &&
+       printf "LINEONE\r\nLINETWO\nLINETHREE\n" >o3.txt &&
+       git add o?.txt &&
+       oid=$(git hash-object o1.txt) &&
+       git update-index --add --cacheinfo 120000 $oid o4.txt &&
+       git update-index --add --cacheinfo 160000 $oid o5.txt &&
+       git update-index --add --cacheinfo 100755 $oid o6.txt &&
+       git commit -m base
+'
+
+test_expect_success 'git ls-files --format objectmode v.s. -s' '
+       git ls-files -s >files &&
+       cut -d" " -f1 files >expect &&
+       git ls-files --format="%(objectmode)" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format objectname v.s. -s' '
+       git ls-files -s >files &&
+       cut -d" " -f2 files >expect &&
+       git ls-files --format="%(objectname)" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format v.s. --eol' '
+       git ls-files --eol >tmp &&
+       sed -e "s/      / /g" -e "s/  */ /g" tmp >expect 2>err &&
+       test_must_be_empty err &&
+       git ls-files --format="i/%(eolinfo:index) w/%(eolinfo:worktree) attr/%(eolattr) %(path)" >actual 2>err &&
+       test_must_be_empty err &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format path v.s. -s' '
+       git ls-files -s >files &&
+       cut -f2 files >expect &&
+       git ls-files --format="%(path)" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format with -m' '
+       echo change >o1.txt &&
+       cat >expect <<-\EOF &&
+       o1.txt
+       o4.txt
+       o5.txt
+       o6.txt
+       EOF
+       git ls-files --format="%(path)" -m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format with -d' '
+       echo o7 >o7.txt &&
+       git add o7.txt &&
+       rm o7.txt &&
+       cat >expect <<-\EOF &&
+       o4.txt
+       o5.txt
+       o6.txt
+       o7.txt
+       EOF
+       git ls-files --format="%(path)" -d >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format v.s -s' '
+       git ls-files --stage >expect &&
+       git ls-files --format="%(objectmode) %(objectname) %(stage)%x09%(path)" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format with --debug' '
+       git ls-files --debug >expect &&
+       git ls-files --format="%(path)" --debug >actual &&
+       test_cmp expect actual
+'
+
+test_done
index f9539968e4c16a53e2d0add8b448c7338925828f..5d871fde960a032bbf5523dc2fee578745d1479d 100755 (executable)
@@ -5,11 +5,6 @@ test_description='wildmatch tests'
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
-# Disable expensive chain-lint tests; all of the tests in this script
-# are variants of a few trivial test-tool invocations, and there are a lot of
-# them.
-GIT_TEST_CHAIN_LINT_HARDER_DEFAULT=0
-
 should_create_test_file() {
        file=$1
 
index 9723c2827ccddc84824035e600d90d28aed0e1eb..b82cffc0b35848389174d49f3a256cbeade668a0 100755 (executable)
@@ -201,8 +201,8 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
 
 test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' '
        msg="Branch: renamed refs/heads/baz to refs/heads/bam" &&
-       grep " 0\{40\}.*$msg$" .git/logs/HEAD &&
-       grep "^0\{40\}.*$msg$" .git/logs/HEAD
+       grep " $ZERO_OID.*$msg$" .git/logs/HEAD &&
+       grep "^$ZERO_OID.*$msg$" .git/logs/HEAD
 '
 
 test_expect_success 'git branch -M should leave orphaned HEAD alone' '
index d12e4e4cc6c64073fcef4e71ba6a9c52ce8af1dc..459beaf7d9cec09cfbc617d6461eacd1d5917dff 100755 (executable)
@@ -162,7 +162,7 @@ test_expect_success 'A^! and A^-<n> (unmodified)' '
 '
 
 test_expect_success 'A^{/..} is not mistaken for a range' '
-       test_must_fail git range-diff topic^.. topic^{/..} 2>error &&
+       test_must_fail git range-diff topic^.. topic^{/..} -- 2>error &&
        test_i18ngrep "not a commit range" error
 '
 
@@ -772,6 +772,17 @@ test_expect_success '--left-only/--right-only' '
        test_cmp expect actual
 '
 
+test_expect_success 'ranges with pathspecs' '
+       git range-diff topic...mode-only-change -- other-file >actual &&
+       test_line_count = 2 actual &&
+       topic_oid=$(git rev-parse --short topic) &&
+       mode_change_oid=$(git rev-parse --short mode-only-change^) &&
+       file_change_oid=$(git rev-parse --short mode-only-change) &&
+       grep "$mode_change_oid" actual &&
+       ! grep "$file_change_oid" actual &&
+       ! grep "$topic_oid" actual
+'
+
 test_expect_success 'submodule changes are shown irrespective of diff.submodule' '
        git init sub-repo &&
        test_commit -C sub-repo sub-first &&
index d742be8840276a52ef5887659d5405e1f9b08404..3288aaec7dc9362dc923b963e31ccd05005ba351 100755 (executable)
@@ -505,6 +505,11 @@ test_expect_success 'list notes with "git notes"' '
        test_cmp expect actual
 '
 
+test_expect_success '"git notes" without subcommand does not take arguments' '
+       test_expect_code 129 git notes HEAD^^ 2>err &&
+       grep "^error: unknown subcommand" err
+'
+
 test_expect_success 'list specific note with "git notes list <object>"' '
        git rev-parse refs/notes/commits:$commit_3 >expect &&
        git notes list HEAD^^ >actual &&
index 03dfcd3954cee5402dde186c6edd17b47db211dd..2c3a2452668c514ce40c107537cc4e0c1abe5312 100755 (executable)
@@ -5,6 +5,7 @@ test_description='Test notes trees that also contain non-notes'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 number_of_commits=100
index 64a9915761a82a6ea8d640dabfe3811db6450a5a..1ec1fb6715efda8a0ec546956a0deece76efefff 100755 (executable)
@@ -9,7 +9,7 @@ path_has_fanout() {
        path=$1 &&
        fanout=$2 &&
        after_last_slash=$(($(test_oid hexsz) - $fanout * 2)) &&
-       echo $path | grep -q "^\([0-9a-f]\{2\}/\)\{$fanout\}[0-9a-f]\{$after_last_slash\}$"
+       echo $path | grep -q -E "^([0-9a-f]{2}/){$fanout}[0-9a-f]{$after_last_slash}$"
 }
 
 touched_one_note_with_fanout() {
@@ -51,7 +51,7 @@ test_expect_success 'creating many notes with git-notes' '
        done
 '
 
-test_expect_success !SANITIZE_LEAK 'many notes created correctly with git-notes' '
+test_expect_success 'many notes created correctly with git-notes' '
        git log >output.raw &&
        grep "^    " output.raw >output &&
        i=$num_notes &&
index 1aa366a410e9a3e2ad4c2fa84431198fbb553a5f..ae316502c4531b7cdadfddff12e2f95ea7c9797c 100755 (executable)
@@ -4,6 +4,7 @@ test_description='Examples from the git-notes man page
 
 Make sure the manual is not full of lies.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index f31afd4a54754a982e26b78271317ea61a3b9cda..4f5abb5ad25e9d39fc85d4d20a4ab1d4905b61e2 100755 (executable)
@@ -1244,9 +1244,9 @@ test_expect_success 'short commit ID collide' '
                test $colliding_id = "$(git rev-parse HEAD | cut -c 1-4)" &&
                grep "^pick $colliding_id " \
                        .git/rebase-merge/git-rebase-todo.tmp &&
-               grep "^pick [0-9a-f]\{$hexsz\}" \
+               grep -E "^pick [0-9a-f]{$hexsz}" \
                        .git/rebase-merge/git-rebase-todo &&
-               grep "^pick [0-9a-f]\{$hexsz\}" \
+               grep -E "^pick [0-9a-f]{$hexsz}" \
                        .git/rebase-merge/git-rebase-todo.backup &&
                git rebase --continue
        ) &&
@@ -1261,7 +1261,7 @@ test_expect_success 'respect core.abbrev' '
                set_cat_todo_editor &&
                test_must_fail git rebase -i HEAD~4 >todo-list
        ) &&
-       test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list)
+       test 4 = $(grep -c -E "pick [0-9a-f]{12,}" todo-list)
 '
 
 test_expect_success 'todo count' '
@@ -1743,6 +1743,279 @@ test_expect_success 'ORIG_HEAD is updated correctly' '
        test_cmp_rev ORIG_HEAD test-orig-head@{1}
 '
 
+test_expect_success '--update-refs adds label and update-ref commands' '
+       git checkout -b update-refs no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       git commit --allow-empty --fixup=third &&
+       git branch -f is-not-reordered &&
+       git commit --allow-empty --fixup=HEAD~4 &&
+       git branch -f shared-tip &&
+       (
+               set_cat_todo_editor &&
+
+               cat >expect <<-EOF &&
+               pick $(git log -1 --format=%h J) J
+               fixup $(git log -1 --format=%h update-refs) fixup! J # empty
+               update-ref refs/heads/second
+               update-ref refs/heads/first
+               pick $(git log -1 --format=%h K) K
+               pick $(git log -1 --format=%h L) L
+               fixup $(git log -1 --format=%h is-not-reordered) fixup! L # empty
+               update-ref refs/heads/third
+               pick $(git log -1 --format=%h M) M
+               update-ref refs/heads/no-conflict-branch
+               update-ref refs/heads/is-not-reordered
+               update-ref refs/heads/shared-tip
+               EOF
+
+               test_must_fail git rebase -i --autosquash --update-refs primary >todo &&
+               test_cmp expect todo &&
+
+               test_must_fail git -c rebase.autosquash=true \
+                                  -c rebase.updaterefs=true \
+                                  rebase -i primary >todo &&
+
+               test_cmp expect todo
+       )
+'
+
+test_expect_success '--update-refs adds commands with --rebase-merges' '
+       git checkout -b update-refs-with-merge no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       git merge -m merge branch2 &&
+       git branch -f merge-branch &&
+       git commit --fixup=third --allow-empty &&
+       (
+               set_cat_todo_editor &&
+
+               cat >expect <<-EOF &&
+               label onto
+               reset onto
+               pick $(git log -1 --format=%h branch2~1) F
+               pick $(git log -1 --format=%h branch2) I
+               update-ref refs/heads/branch2
+               label merge
+               reset onto
+               pick $(git log -1 --format=%h refs/heads/second) J
+               update-ref refs/heads/second
+               update-ref refs/heads/first
+               pick $(git log -1 --format=%h refs/heads/third~1) K
+               pick $(git log -1 --format=%h refs/heads/third) L
+               fixup $(git log -1 --format=%h update-refs-with-merge) fixup! L # empty
+               update-ref refs/heads/third
+               pick $(git log -1 --format=%h HEAD~2) M
+               update-ref refs/heads/no-conflict-branch
+               merge -C $(git log -1 --format=%h HEAD~1) merge # merge
+               update-ref refs/heads/merge-branch
+               EOF
+
+               test_must_fail git rebase -i --autosquash \
+                                  --rebase-merges=rebase-cousins \
+                                  --update-refs primary >todo &&
+
+               test_cmp expect todo &&
+
+               test_must_fail git -c rebase.autosquash=true \
+                                  -c rebase.updaterefs=true \
+                                  rebase -i \
+                                  --rebase-merges=rebase-cousins \
+                                  primary >todo &&
+
+               test_cmp expect todo
+       )
+'
+
+test_expect_success '--update-refs updates refs correctly' '
+       git checkout -B update-refs no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       test_commit extra2 fileX &&
+       git commit --amend --fixup=L &&
+
+       git rebase -i --autosquash --update-refs primary 2>err &&
+
+       test_cmp_rev HEAD~3 refs/heads/first &&
+       test_cmp_rev HEAD~3 refs/heads/second &&
+       test_cmp_rev HEAD~1 refs/heads/third &&
+       test_cmp_rev HEAD refs/heads/no-conflict-branch &&
+
+       cat >expect <<-\EOF &&
+       Successfully rebased and updated refs/heads/update-refs.
+       Updated the following refs with --update-refs:
+               refs/heads/first
+               refs/heads/no-conflict-branch
+               refs/heads/second
+               refs/heads/third
+       EOF
+
+       # Clear "Rebasing (X/Y)" progress lines and drop leading tabs.
+       sed -e "s/Rebasing.*Successfully/Successfully/g" -e "s/^\t//g" \
+               <err >err.trimmed &&
+       test_cmp expect err.trimmed
+'
+
+test_expect_success 'respect user edits to update-ref steps' '
+       git checkout -B update-refs-break no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       git branch -f unseen base &&
+
+       # First, we will add breaks to the expected todo file
+       cat >fake-todo-1 <<-EOF &&
+       pick $(git rev-parse HEAD~3)
+       break
+       update-ref refs/heads/second
+       update-ref refs/heads/first
+
+       pick $(git rev-parse HEAD~2)
+       pick $(git rev-parse HEAD~1)
+       update-ref refs/heads/third
+
+       pick $(git rev-parse HEAD)
+       update-ref refs/heads/no-conflict-branch
+       EOF
+
+       # Second, we will drop some update-refs commands (and move one)
+       cat >fake-todo-2 <<-EOF &&
+       update-ref refs/heads/second
+
+       pick $(git rev-parse HEAD~2)
+       update-ref refs/heads/third
+       pick $(git rev-parse HEAD~1)
+       break
+
+       pick $(git rev-parse HEAD)
+       EOF
+
+       # Third, we will:
+       # * insert a new one (new-branch),
+       # * re-add an old one (first), and
+       # * add a second instance of a previously-stored one (second)
+       cat >fake-todo-3 <<-EOF &&
+       update-ref refs/heads/unseen
+       update-ref refs/heads/new-branch
+       pick $(git rev-parse HEAD)
+       update-ref refs/heads/first
+       update-ref refs/heads/second
+       EOF
+
+       (
+               set_replace_editor fake-todo-1 &&
+               git rebase -i --update-refs primary &&
+
+               # These branches are currently locked.
+               for b in first second third no-conflict-branch
+               do
+                       test_must_fail git branch -f $b base || return 1
+               done &&
+
+               set_replace_editor fake-todo-2 &&
+               git rebase --edit-todo &&
+
+               # These branches are currently locked.
+               for b in second third
+               do
+                       test_must_fail git branch -f $b base || return 1
+               done &&
+
+               # These branches are currently unlocked for checkout.
+               for b in first no-conflict-branch
+               do
+                       git worktree add wt-$b $b &&
+                       git worktree remove wt-$b || return 1
+               done &&
+
+               git rebase --continue &&
+
+               set_replace_editor fake-todo-3 &&
+               git rebase --edit-todo &&
+
+               # These branches are currently locked.
+               for b in second third first unseen
+               do
+                       test_must_fail git branch -f $b base || return 1
+               done &&
+
+               # These branches are currently unlocked for checkout.
+               for b in no-conflict-branch
+               do
+                       git worktree add wt-$b $b &&
+                       git worktree remove wt-$b || return 1
+               done &&
+
+               git rebase --continue
+       ) &&
+
+       test_cmp_rev HEAD~2 refs/heads/third &&
+       test_cmp_rev HEAD~1 refs/heads/unseen &&
+       test_cmp_rev HEAD~1 refs/heads/new-branch &&
+       test_cmp_rev HEAD refs/heads/first &&
+       test_cmp_rev HEAD refs/heads/second &&
+       test_cmp_rev HEAD refs/heads/no-conflict-branch
+'
+
+test_expect_success '--update-refs: check failed ref update' '
+       git checkout -B update-refs-error no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~2 &&
+       git branch -f third HEAD~1 &&
+
+       cat >fake-todo <<-EOF &&
+       pick $(git rev-parse HEAD~3)
+       break
+       update-ref refs/heads/first
+
+       pick $(git rev-parse HEAD~2)
+       update-ref refs/heads/second
+
+       pick $(git rev-parse HEAD~1)
+       update-ref refs/heads/third
+
+       pick $(git rev-parse HEAD)
+       update-ref refs/heads/no-conflict-branch
+       EOF
+
+       (
+               set_replace_editor fake-todo &&
+               git rebase -i --update-refs base
+       ) &&
+
+       # At this point, the values of first, second, and third are
+       # recorded in the update-refs file. We will force-update the
+       # "second" ref, but "git branch -f" will not work because of
+       # the lock in the update-refs file.
+       git rev-parse third >.git/refs/heads/second &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "update_ref failed for ref '\''refs/heads/second'\''" err &&
+
+       cat >expect <<-\EOF &&
+       Updated the following refs with --update-refs:
+               refs/heads/first
+               refs/heads/no-conflict-branch
+               refs/heads/third
+       Failed to update the following refs with --update-refs:
+               refs/heads/second
+       EOF
+
+       # Clear "Rebasing (X/Y)" progress lines and drop leading tabs.
+       tail -n 6 err >err.last &&
+       sed -e "s/Rebasing.*Successfully/Successfully/g" -e "s/^\t//g" \
+               <err.last >err.trimmed &&
+       test_cmp expect err.trimmed
+'
+
 # This must be the last test in this file
 test_expect_success '$EDITOR and friends are unchanged' '
        test_editor_unchanged
index 0ad3a07bf470939a8fa53f38e83fa609f2d7371f..7a9f1127a4b974aea5c7390447b44f1798ba20ab 100755 (executable)
@@ -35,6 +35,7 @@ git_rebase_interactive () {
        ls -1pR * >>actual &&
        test_cmp expect actual &&
        set_fake_editor &&
+       mkdir .git/info &&
        echo "fake-editor.sh" >.git/info/exclude &&
        may_only_be_test_must_fail "$2" &&
        $2 git rebase -i "$1"
index 979e843c65a97cf914e9f8f966893d2c965a9052..f32799e04633fd831293d5b64106f9c856d3d407 100755 (executable)
@@ -12,6 +12,7 @@ test_description='test cherry-pick and revert with conflicts
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 pristine_detach () {
@@ -558,6 +559,7 @@ test_expect_success 'cherry-pick preserves sparse-checkout' '
                echo \"/*\" >.git/info/sparse-checkout
                git read-tree --reset -u HEAD
                rm .git/info/sparse-checkout" &&
+       mkdir .git/info &&
        echo /unrelated >.git/info/sparse-checkout &&
        git read-tree --reset -u HEAD &&
        test_must_fail git cherry-pick -Xours picked>actual &&
index 8689b48589c0d515b9d15b86e4e00807fd26f566..51afbd7b24a10c247520ba2f9be702da57f83afd 100755 (executable)
@@ -291,7 +291,7 @@ test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" '
        git reset --hard &&
        touch fo\[ou\]bar foobar &&
        git add '\''fo\[ou\]bar'\'' &&
-       git ls-files fo\[ou\]bar | fgrep fo\[ou\]bar &&
+       git ls-files fo\[ou\]bar | grep -F fo\[ou\]bar &&
        ! ( git ls-files foobar | grep foobar )
 '
 
index 3b7df9bed5ad3e740090e2dc9b3fecb40479a65f..5841f280fb2d4c3185e0a42b9d9a894d72cc4e79 100755 (executable)
@@ -7,9 +7,9 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-if ! test_have_prereq PERL
+if test_have_prereq !ADD_I_USE_BUILTIN,!PERL
 then
-       skip_all='skipping add -i tests, perl not available'
+       skip_all='skipping add -i (scripted) tests, perl not available'
        test_done
 fi
 
@@ -761,9 +761,20 @@ test_expect_success 'detect bogus diffFilter output' '
        git reset --hard &&
 
        echo content >test &&
-       test_config interactive.diffFilter "sed 1d" &&
+       test_config interactive.diffFilter "sed 6d" &&
        printf y >y &&
-       force_color test_must_fail git add -p <y
+       force_color test_must_fail git add -p <y >output 2>&1 &&
+       grep "mismatched output" output
+'
+
+test_expect_success 'handle iffy colored hunk headers' '
+       git reset --hard &&
+
+       echo content >test &&
+       printf n >n &&
+       force_color git -c interactive.diffFilter="sed s/.*@@.*/XX/" \
+               add -p >output 2>&1 <n &&
+       grep "^XX$" output
 '
 
 test_expect_success 'handle very large filtered diff' '
@@ -944,6 +955,18 @@ test_expect_success 'status ignores dirty submodules (except HEAD)' '
        ! 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 &&
+
+       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_expect_success 'set up pathological context' '
        git reset --hard &&
        test_write_lines a a a a a a a a a a a >a &&
index a1801a8cbd4185f80253b019eb40a2c6a378d7ab..82bfb2fd2aca9eae78af33fa67620e76458b3ac6 100755 (executable)
@@ -100,7 +100,7 @@ EOF
 
 echo "#!$SHELL_PATH" >fake-editor.sh
 cat >> fake-editor.sh <<\EOF
-egrep -v '^index' "$1" >orig-patch &&
+grep -E -v '^index' "$1" >orig-patch &&
 mv -f patch "$1"
 EOF
 
index 2a4c3fd61c000d2278d362a34ae069760709172d..376cc8f4ab8429b0488ad23b0f9731c9af237124 100755 (executable)
@@ -25,7 +25,7 @@ test_expect_success 'usage on main command -h emits a summary of subcommands' '
        grep -F "or: git stash show" usage
 '
 
-test_expect_failure 'usage for subcommands should emit subcommand usage' '
+test_expect_success 'usage for subcommands should emit subcommand usage' '
        test_expect_code 129 git stash push -h >usage &&
        grep -F "usage: git stash [push" usage
 '
index 0276edbe3d389b70cace45906626276cce3db44b..4c661d4d54a779f8bc056c62e5d9e864401420c7 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='Test ref-filter and pretty APIs for commit and tag messages using CRLF'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 LIB_CRLF_BRANCHES=""
index 056e922164d04976570b4e5fc25975f1cbfc8b7a..dfcf3a0aaae3e2a72f6f41023b01c639a99c2f44 100755 (executable)
@@ -352,6 +352,8 @@ log -GF -p --pickaxe-all master
 log -IA -IB -I1 -I2 -p master
 log --decorate --all
 log --decorate=full --all
+log --decorate --clear-decorations --all
+log --decorate=full --clear-decorations --all
 
 rev-list --parents HEAD
 rev-list --children HEAD
index 3f9b872eceb734cb1e7adbd53a4de0580b1cd524..6b0b334a5d6ca160fc60ecf3f8e607a13633f562 100644 (file)
@@ -20,7 +20,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0 (refs/notes/commits)
+commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:06:00 2006 +0000
 
diff --git a/t/t4013/diff.log_--decorate=full_--clear-decorations_--all b/t/t4013/diff.log_--decorate=full_--clear-decorations_--all
new file mode 100644 (file)
index 0000000..1c030a6
--- /dev/null
@@ -0,0 +1,61 @@
+$ git log --decorate=full --clear-decorations --all
+commit b7e0bc69303b488b47deca799a7d723971dfa6cd (refs/heads/mode)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode
+
+commit a6f364368ca320bc5a92e18912e16fa6b3dff598 (refs/heads/note)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode (file2)
+
+Notes:
+    note
+
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (refs/heads/rearrange)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Rearranged lines in dir/sub
+
+commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0 (refs/notes/commits)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Notes added by 'git notes add'
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_--decorate=full_--decorate-all_--all b/t/t4013/diff.log_--decorate=full_--decorate-all_--all
new file mode 100644 (file)
index 0000000..d6e7928
--- /dev/null
@@ -0,0 +1,61 @@
+$ git log --decorate=full --decorate-all --all
+commit b7e0bc69303b488b47deca799a7d723971dfa6cd (refs/heads/mode)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode
+
+commit a6f364368ca320bc5a92e18912e16fa6b3dff598 (refs/heads/note)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode (file2)
+
+Notes:
+    note
+
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (refs/heads/rearrange)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Rearranged lines in dir/sub
+
+commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0 (refs/notes/commits)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Notes added by 'git notes add'
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
index f5e20e1e14aaef179ac9570b0e16bc47077ff79d..c7df1f581410d1155d87122ce91f6890390cf90a 100644 (file)
@@ -20,7 +20,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0 (refs/notes/commits)
+commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:06:00 2006 +0000
 
diff --git a/t/t4013/diff.log_--decorate_--clear-decorations_--all b/t/t4013/diff.log_--decorate_--clear-decorations_--all
new file mode 100644 (file)
index 0000000..88be82c
--- /dev/null
@@ -0,0 +1,61 @@
+$ git log --decorate --clear-decorations --all
+commit b7e0bc69303b488b47deca799a7d723971dfa6cd (mode)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode
+
+commit a6f364368ca320bc5a92e18912e16fa6b3dff598 (note)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode (file2)
+
+Notes:
+    note
+
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (rearrange)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Rearranged lines in dir/sub
+
+commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0 (refs/notes/commits)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Notes added by 'git notes add'
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (initial)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_--decorate_--decorate-all_--all b/t/t4013/diff.log_--decorate_--decorate-all_--all
new file mode 100644 (file)
index 0000000..5d22618
--- /dev/null
@@ -0,0 +1,61 @@
+$ git log --decorate --decorate-all --all
+commit b7e0bc69303b488b47deca799a7d723971dfa6cd (mode)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode
+
+commit a6f364368ca320bc5a92e18912e16fa6b3dff598 (note)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    update mode (file2)
+
+Notes:
+    note
+
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (rearrange)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Rearranged lines in dir/sub
+
+commit cbacedd14cb8b89255a2c02b59e77a2e9a8021a0 (refs/notes/commits)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Notes added by 'git notes add'
+
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (initial)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
index fbec8ad2ef7bb263765357c2f783448184c6b808..de1da4673da9626f0c155fd4c67597a403870ece 100755 (executable)
@@ -1400,6 +1400,43 @@ test_expect_success '--from omits redundant in-body header' '
        test_cmp expect patch.head
 '
 
+test_expect_success 'with --force-in-body-from, redundant in-body from is kept' '
+       git format-patch --force-in-body-from \
+               -1 --stdout --from="A U Thor <author@example.com>" >patch &&
+       cat >expect <<-\EOF &&
+       From: A U Thor <author@example.com>
+
+       From: A U Thor <author@example.com>
+
+       EOF
+       sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
+       test_cmp expect patch.head
+'
+
+test_expect_success 'format.forceInBodyFrom, equivalent to --force-in-body-from' '
+       git -c format.forceInBodyFrom=yes format-patch \
+               -1 --stdout --from="A U Thor <author@example.com>" >patch &&
+       cat >expect <<-\EOF &&
+       From: A U Thor <author@example.com>
+
+       From: A U Thor <author@example.com>
+
+       EOF
+       sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
+       test_cmp expect patch.head
+'
+
+test_expect_success 'format.forceInBodyFrom, equivalent to --force-in-body-from' '
+       git -c format.forceInBodyFrom=yes format-patch --no-force-in-body-from \
+               -1 --stdout --from="A U Thor <author@example.com>" >patch &&
+       cat >expect <<-\EOF &&
+       From: A U Thor <author@example.com>
+
+       EOF
+       sed -ne "/^From:/p; /^$/p; /^---$/q" patch >patch.head &&
+       test_cmp expect patch.head
+'
+
 test_expect_success 'in-body headers trigger content encoding' '
        test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
        test_when_finished "git reset --hard HEAD^" &&
@@ -1420,7 +1457,7 @@ append_signoff()
        C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
        git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
        sed -n -e "1,/^---$/p" append_signoff.patch |
-               egrep -n "^Subject|Sign|^$"
+               grep -E -n "^Subject|Sign|^$"
 }
 
 test_expect_success 'signoff: commit with no body' '
@@ -2237,10 +2274,10 @@ test_expect_success 'format-patch --base with --attach' '
 test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
        test_when_finished "rm -fr patches" &&
        git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
-       ! egrep "^--+mimemime" patches/0000*.patch &&
-       egrep "^--+mimemime$" patches/0001*.patch >output &&
+       ! grep -E "^--+mimemime" patches/0000*.patch &&
+       grep -E "^--+mimemime$" patches/0001*.patch >output &&
        test_line_count = 2 output &&
-       egrep "^--+mimemime--$" patches/0001*.patch >output &&
+       grep -E "^--+mimemime--$" patches/0001*.patch >output &&
        test_line_count = 1 output
 '
 
index ed461f481e2af5e3d73ac628eeee1fb52218d90b..5bc28ad9f042a0476d94d9e90e5b58073cc17f99 100755 (executable)
@@ -5,6 +5,7 @@ test_description='Return value of diffs'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index 858a5522f96b63b971daf85f20e5d66aaebc48e6..c1ac09ecc7140a3dcfcdf906bb4533ba131881de 100755 (executable)
@@ -33,7 +33,7 @@ test_expect_success 'GIT_EXTERNAL_DIFF environment' '
 
 '
 
-test_expect_success !SANITIZE_LEAK 'GIT_EXTERNAL_DIFF environment should apply only to diff' '
+test_expect_success 'GIT_EXTERNAL_DIFF environment should apply only to diff' '
        GIT_EXTERNAL_DIFF=echo git log -p -1 HEAD >out &&
        grep "^diff --git a/file b/file" out
 
@@ -74,7 +74,7 @@ test_expect_success 'diff.external' '
        test_cmp expect actual
 '
 
-test_expect_success !SANITIZE_LEAK 'diff.external should apply only to diff' '
+test_expect_success 'diff.external should apply only to diff' '
        test_config diff.external echo &&
        git log -p -1 HEAD >out &&
        grep "^diff --git a/file b/file" out
index 4701796d10e1028debe4581f2fa10038b38be003..29e49d22902dd7e7566f2662174475bf35c6ebed 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test unique sha1 abbreviation on "index from..to" line'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index 4838a1df8b4369dc5024cdd7929d851b76482805..725278ad19c720468113659dbcc63aa013ac7de0 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='diff function context'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 dir="$TEST_DIRECTORY/t4051"
index 04b8a1542a8ec3ad2ffc28964f21940d034c2ed6..9a7505cbb8bf900510e8be4fc1a636124deec366 100755 (executable)
@@ -5,6 +5,7 @@ test_description='combined diff show only paths that are different to all parent
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # verify that diffc.expect matches output of
index 35f94957fceb2b02df9846a256f925833c6b4ba0..07323ebafe0d0cb49f08c4396116fa1f45687cd8 100755 (executable)
@@ -56,6 +56,11 @@ test_expect_success 'remerge-diff on a clean merge' '
        test_cmp expect actual
 '
 
+test_expect_success 'remerge-diff on a clean merge with a filter' '
+       git show --oneline --remerge-diff --diff-filter=U bc_resolution >actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'remerge-diff with both a resolved conflict and an unrelated change' '
        git log -1 --oneline ab_resolution >tmp &&
        cat <<-EOF >>tmp &&
@@ -89,6 +94,22 @@ test_expect_success 'remerge-diff with both a resolved conflict and an unrelated
        test_cmp expect actual
 '
 
+test_expect_success 'pickaxe still includes additional headers for relevant changes' '
+       # reuses "expect" from the previous testcase
+
+       git log --oneline --remerge-diff -Sacht ab_resolution >tmp &&
+       sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'can filter out additional headers with pickaxe' '
+       git show --remerge-diff --submodule=log --find-object=HEAD ab_resolution >actual &&
+       test_must_be_empty actual &&
+
+       git show --remerge-diff -S"not present" --all >actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'setup non-content conflicts' '
        git switch --orphan base &&
 
@@ -184,6 +205,14 @@ test_expect_success 'remerge-diff w/ diff-filter=U: all conflict headers, no dif
        test_cmp expect actual
 '
 
+test_expect_success 'submodule formatting ignores additional headers' '
+       # Reuses "expect" from last testcase
+
+       git show --oneline --remerge-diff --diff-filter=U --submodule=log >tmp &&
+       sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'remerge-diff w/ diff-filter=R: relevant file + conflict header' '
        git log -1 --oneline resolution >tmp &&
        cat <<-EOF >>tmp &&
index da3e64f8110d54d7243c017a9a614baa7098142f..8ff364076673747adaaa74aec3f0a966caf033e5 100755 (executable)
@@ -7,6 +7,7 @@ test_description='git apply should not get confused with type changes.
 
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup repository and commits' '
index c614eaf04cca93a22157d08e9fc464639468eb3a..b375aca0d74ea3a23e6eae69077e9b286b5c144f 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git apply of i-t-a file'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 6e66352558212e9a40404ef892a0944ab3d09db3..cc15cb4ff62ab4c939b369826e5795e46f218d84 100755 (executable)
@@ -704,9 +704,12 @@ test_expect_success 'set up more tangled history' '
        git checkout -b tangle HEAD~6 &&
        test_commit tangle-a tangle-a a &&
        git merge main~3 &&
+       git update-ref refs/prefetch/merge HEAD &&
        git merge side~1 &&
+       git update-ref refs/rewritten/merge HEAD &&
        git checkout main &&
        git merge tangle &&
+       git update-ref refs/hidden/tangle HEAD &&
        git checkout -b reach &&
        test_commit reach &&
        git checkout main &&
@@ -974,9 +977,9 @@ test_expect_success 'decorate-refs-exclude and simplify-by-decoration' '
        Merge-tag-reach (HEAD -> main)
        reach (tag: reach, reach)
        seventh (tag: seventh)
-       Merge-branch-tangle
-       Merge-branch-side-early-part-into-tangle (tangle)
-       tangle-a (tag: tangle-a)
+       Merge-branch-tangle (refs/hidden/tangle)
+       Merge-branch-side-early-part-into-tangle (refs/rewritten/merge, tangle)
+       Merge-branch-main-early-part-into-tangle (refs/prefetch/merge)
        EOF
        git log -n6 --decorate=short --pretty="tformat:%f%d" \
                --decorate-refs-exclude="*octopus*" \
@@ -1025,6 +1028,115 @@ test_expect_success 'decorate-refs and simplify-by-decoration without output' '
        test_cmp expect actual
 '
 
+test_expect_success 'decorate-refs-exclude HEAD' '
+       git log --decorate=full --oneline \
+               --decorate-refs-exclude="HEAD" >actual &&
+       ! grep HEAD actual
+'
+
+test_expect_success 'decorate-refs focus from default' '
+       git log --decorate=full --oneline \
+               --decorate-refs="refs/heads" >actual &&
+       ! grep HEAD actual
+'
+
+test_expect_success '--clear-decorations overrides defaults' '
+       cat >expect.default <<-\EOF &&
+       Merge-tag-reach (HEAD -> refs/heads/main)
+       Merge-tags-octopus-a-and-octopus-b
+       seventh (tag: refs/tags/seventh)
+       octopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)
+       octopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)
+       reach (tag: refs/tags/reach, refs/heads/reach)
+       Merge-branch-tangle
+       Merge-branch-side-early-part-into-tangle (refs/heads/tangle)
+       Merge-branch-main-early-part-into-tangle
+       tangle-a (tag: refs/tags/tangle-a)
+       Merge-branch-side
+       side-2 (tag: refs/tags/side-2, refs/heads/side)
+       side-1 (tag: refs/tags/side-1)
+       Second
+       sixth
+       fifth
+       fourth
+       third
+       second
+       initial
+       EOF
+       git log --decorate=full --pretty="tformat:%f%d" >actual &&
+       test_cmp expect.default actual &&
+
+       cat >expect.all <<-\EOF &&
+       Merge-tag-reach (HEAD -> refs/heads/main)
+       Merge-tags-octopus-a-and-octopus-b
+       seventh (tag: refs/tags/seventh)
+       octopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)
+       octopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)
+       reach (tag: refs/tags/reach, refs/heads/reach)
+       Merge-branch-tangle (refs/hidden/tangle)
+       Merge-branch-side-early-part-into-tangle (refs/rewritten/merge, refs/heads/tangle)
+       Merge-branch-main-early-part-into-tangle (refs/prefetch/merge)
+       tangle-a (tag: refs/tags/tangle-a)
+       Merge-branch-side
+       side-2 (tag: refs/tags/side-2, refs/heads/side)
+       side-1 (tag: refs/tags/side-1)
+       Second
+       sixth
+       fifth
+       fourth
+       third
+       second
+       initial
+       EOF
+       git log --decorate=full --pretty="tformat:%f%d" \
+               --clear-decorations >actual &&
+       test_cmp expect.all actual &&
+       git -c log.initialDecorationSet=all log \
+               --decorate=full --pretty="tformat:%f%d" >actual &&
+       test_cmp expect.all actual
+'
+
+test_expect_success '--clear-decorations clears previous exclusions' '
+       cat >expect.all <<-\EOF &&
+       Merge-tag-reach (HEAD -> refs/heads/main)
+       reach (tag: refs/tags/reach, refs/heads/reach)
+       Merge-tags-octopus-a-and-octopus-b
+       octopus-b (tag: refs/tags/octopus-b, refs/heads/octopus-b)
+       octopus-a (tag: refs/tags/octopus-a, refs/heads/octopus-a)
+       seventh (tag: refs/tags/seventh)
+       Merge-branch-tangle (refs/hidden/tangle)
+       Merge-branch-side-early-part-into-tangle (refs/rewritten/merge, refs/heads/tangle)
+       Merge-branch-main-early-part-into-tangle (refs/prefetch/merge)
+       tangle-a (tag: refs/tags/tangle-a)
+       side-2 (tag: refs/tags/side-2, refs/heads/side)
+       side-1 (tag: refs/tags/side-1)
+       initial
+       EOF
+
+       git log --decorate=full --pretty="tformat:%f%d" \
+               --simplify-by-decoration \
+               --decorate-refs-exclude="heads/octopus*" \
+               --decorate-refs="heads" \
+               --clear-decorations >actual &&
+       test_cmp expect.all actual &&
+
+       cat >expect.filtered <<-\EOF &&
+       Merge-tags-octopus-a-and-octopus-b
+       octopus-b (refs/heads/octopus-b)
+       octopus-a (refs/heads/octopus-a)
+       initial
+       EOF
+
+       git log --decorate=full --pretty="tformat:%f%d" \
+               --simplify-by-decoration \
+               --decorate-refs-exclude="heads/octopus" \
+               --decorate-refs="heads" \
+               --clear-decorations \
+               --decorate-refs-exclude="tags/" \
+               --decorate-refs="heads/octopus*" >actual &&
+       test_cmp expect.filtered actual
+'
+
 test_expect_success 'log.decorate config parsing' '
        git log --oneline --decorate=full >expect.full &&
        git log --oneline --decorate=short >expect.short &&
@@ -2112,9 +2224,9 @@ test_expect_success REFFILES 'log diagnoses bogus HEAD hash' '
        test_i18ngrep broken stderr
 '
 
-test_expect_success 'log diagnoses bogus HEAD symref' '
+test_expect_success REFFILES 'log diagnoses bogus HEAD symref' '
        git init empty &&
-       git --git-dir empty/.git symbolic-ref HEAD refs/heads/invalid.lock &&
+       echo "ref: refs/heads/invalid.lock" > empty/.git/HEAD &&
        test_must_fail git -C empty log 2>stderr &&
        test_i18ngrep broken stderr &&
        test_must_fail git -C empty log --default totally-bogus 2>stderr &&
@@ -2192,6 +2304,20 @@ test_expect_success 'log --decorate includes all levels of tag annotated tags' '
        test_cmp expect actual
 '
 
+test_expect_success 'log --decorate does not include things outside filter' '
+       reflist="refs/prefetch refs/rebase-merge refs/bundle" &&
+
+       for ref in $reflist
+       do
+               git update-ref $ref/fake HEAD || return 1
+       done &&
+
+       git log --decorate=full --oneline >actual &&
+
+       # None of the refs are visible:
+       ! grep /fake actual
+'
+
 test_expect_success 'log --end-of-options' '
        git update-ref refs/heads/--source HEAD &&
        git log --end-of-options --source >actual &&
index 0b2d21ec5510158cc9bb5b861a94bdfc6eccea12..cd1cab3e54b9170d5751279bd68e02dbc3cbcad2 100755 (executable)
@@ -963,4 +963,63 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
        test_cmp expect actual
 '
 
+test_expect_success 'prepare for cat-file --mailmap' '
+       rm -f .mailmap &&
+       git commit --allow-empty -m foo --author="Orig <orig@example.com>"
+'
+
+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       A U Thor <author@example.com> Orig <orig@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       author Orig <orig@example.com>
+       EOF
+       git cat-file --no-use-mailmap commit HEAD >log &&
+       sed -n "/^author /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--use-mailmap enables mailmap in cat-file' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       A U Thor <author@example.com> Orig <orig@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       author A U Thor <author@example.com>
+       EOF
+       git cat-file --use-mailmap commit HEAD >log &&
+       sed -n "/^author /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       Orig <orig@example.com> C O Mitter <committer@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       tagger C O Mitter <committer@example.com>
+       EOF
+       git tag -a -m "annotated tag" v1 &&
+       git cat-file --no-mailmap -p v1 >log &&
+       sed -n "/^tagger /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       Orig <orig@example.com> C O Mitter <committer@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       tagger Orig <orig@example.com>
+       EOF
+       git tag -a -m "annotated tag" v2 &&
+       git cat-file --mailmap -p v2 >log &&
+       sed -n "/^tagger /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 36ac6aff1e40dd8ebc1bc894bf63d2228bcd32a3..ded33a82e2c94cd4f44c1df4c9fe93ce9bf5f148 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2010 Nazri Ramliy
 #
 
-test_description='Test for "git log --decorate" colors'
+test_description='test "git log --decorate" colors'
 
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -17,6 +17,7 @@ test_expect_success setup '
        git config color.decorate.remoteBranch red &&
        git config color.decorate.tag "reverse bold yellow" &&
        git config color.decorate.stash magenta &&
+       git config color.decorate.grafted black &&
        git config color.decorate.HEAD cyan &&
 
        c_reset="<RESET>" &&
@@ -27,6 +28,7 @@ test_expect_success setup '
        c_tag="<BOLD;REVERSE;YELLOW>" &&
        c_stash="<MAGENTA>" &&
        c_HEAD="<CYAN>" &&
+       c_grafted="<BLACK>" &&
 
        test_commit A &&
        git clone . other &&
@@ -42,25 +44,79 @@ test_expect_success setup '
        git stash save Changes to A.t
 '
 
-cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD ->\
- ${c_reset}${c_branch}main${c_reset}${c_commit},\
- ${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit},\
- ${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit},\
- ${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
- On main: Changes to A.t
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
-EOF
+cmp_filtered_decorations () {
+       sed "s/$OID_REGEX/COMMIT_ID/" actual | test_decode_color >filtered &&
+       test_cmp expect filtered
+}
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
 # to this test since it does not contain any decoration, hence --first-parent
-test_expect_success 'Commit Decorations Colored Correctly' '
-       git log --first-parent --abbrev=10 --all --decorate --oneline --color=always |
-       sed "s/[0-9a-f]\{10,10\}/COMMIT_ID/" |
-       test_decode_color >out &&
-       test_cmp expected out
+test_expect_success 'commit decorations colored correctly' '
+       cat >expect <<-EOF &&
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
+${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit}, \
+${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset} \
+On main: Changes to A.t
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+       EOF
+
+       git log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&
+       cmp_filtered_decorations
+'
+
+test_expect_success 'test coloring with replace-objects' '
+       test_when_finished rm -rf .git/refs/replace* &&
+       test_commit C &&
+       test_commit D &&
+
+       git replace HEAD~1 HEAD~2 &&
+
+       cat >expect <<-EOF &&
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
+${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: D${c_reset}${c_commit})${c_reset} D
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: C${c_reset}${c_commit}, \
+${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+EOF
+
+       git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
+       cmp_filtered_decorations &&
+       git replace -d HEAD~1 &&
+
+       GIT_REPLACE_REF_BASE=refs/replace2/ git replace HEAD~1 HEAD~2 &&
+       GIT_REPLACE_REF_BASE=refs/replace2/ git log --first-parent \
+               --no-abbrev --decorate --oneline --color=always HEAD >actual &&
+       cmp_filtered_decorations
+'
+
+test_expect_success 'test coloring with grafted commit' '
+       test_when_finished rm -rf .git/refs/replace* &&
+
+       git replace --graft HEAD HEAD~2 &&
+
+       cat >expect <<-EOF &&
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
+${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: D${c_reset}${c_commit}, \
+${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+       EOF
+
+       git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
+       cmp_filtered_decorations &&
+       git replace -d HEAD &&
+
+       GIT_REPLACE_REF_BASE=refs/replace2/ git replace --graft HEAD HEAD~2 &&
+       GIT_REPLACE_REF_BASE=refs/replace2/ git log --first-parent \
+               --no-abbrev --decorate --oneline --color=always HEAD >actual &&
+       cmp_filtered_decorations
 '
 
 test_done
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
new file mode 100755 (executable)
index 0000000..28ca5c3
--- /dev/null
@@ -0,0 +1,813 @@
+#!/bin/sh
+
+test_description='git merge-tree --write-tree'
+
+. ./test-lib.sh
+
+# This test is ort-specific
+if test "$GIT_TEST_MERGE_ALGORITHM" != "ort"
+then
+       skip_all="GIT_TEST_MERGE_ALGORITHM != ort"
+       test_done
+fi
+
+test_expect_success setup '
+       test_write_lines 1 2 3 4 5 >numbers &&
+       echo hello >greeting &&
+       echo foo >whatever &&
+       git add numbers greeting whatever &&
+       test_tick &&
+       git commit -m initial &&
+
+       git branch side1 &&
+       git branch side2 &&
+       git branch side3 &&
+
+       git checkout side1 &&
+       test_write_lines 1 2 3 4 5 6 >numbers &&
+       echo hi >greeting &&
+       echo bar >whatever &&
+       git add numbers greeting whatever &&
+       test_tick &&
+       git commit -m modify-stuff &&
+
+       git checkout side2 &&
+       test_write_lines 0 1 2 3 4 5 >numbers &&
+       echo yo >greeting &&
+       git rm whatever &&
+       mkdir whatever &&
+       >whatever/empty &&
+       git add numbers greeting whatever/empty &&
+       test_tick &&
+       git commit -m other-modifications &&
+
+       git checkout side3 &&
+       git mv numbers sequence &&
+       test_tick &&
+       git commit -m rename-numbers &&
+
+       git switch --orphan unrelated &&
+       >something-else &&
+       git add something-else &&
+       test_tick &&
+       git commit -m first-commit
+'
+
+test_expect_success 'Clean merge' '
+       TREE_OID=$(git merge-tree --write-tree side1 side3) &&
+       q_to_tab <<-EOF >expect &&
+       100644 blob $(git rev-parse side1:greeting)Qgreeting
+       100644 blob $(git rev-parse side1:numbers)Qsequence
+       100644 blob $(git rev-parse side1:whatever)Qwhatever
+       EOF
+
+       git ls-tree $TREE_OID >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Content merge and a few conflicts' '
+       git checkout side1^0 &&
+       test_must_fail git merge side2 &&
+       expected_tree=$(git rev-parse AUTO_MERGE) &&
+
+       # We will redo the merge, while we are still in a conflicted state!
+       git ls-files -u >conflicted-file-info &&
+       test_when_finished "git reset --hard" &&
+
+       test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT &&
+       actual_tree=$(head -n 1 RESULT) &&
+
+       # Due to differences of e.g. "HEAD" vs "side1", the results will not
+       # exactly match.  Dig into individual files.
+
+       # Numbers should have three-way merged cleanly
+       test_write_lines 0 1 2 3 4 5 6 >expect &&
+       git show ${actual_tree}:numbers >actual &&
+       test_cmp expect actual &&
+
+       # whatever and whatever~<branch> should have same HASHES
+       git rev-parse ${expected_tree}:whatever ${expected_tree}:whatever~HEAD >expect &&
+       git rev-parse ${actual_tree}:whatever ${actual_tree}:whatever~side1 >actual &&
+       test_cmp expect actual &&
+
+       # greeting should have a merge conflict
+       git show ${expected_tree}:greeting >tmp &&
+       sed -e s/HEAD/side1/ tmp >expect &&
+       git show ${actual_tree}:greeting >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' '
+       # Mis-spell with single "s" instead of double "s"
+       test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect &&
+
+       grep "error: unknown option.*mesages" expect
+'
+
+test_expect_success 'Barf on too many arguments' '
+       test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect &&
+
+       grep "^usage: git merge-tree" expect
+'
+
+anonymize_hash() {
+       sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@"
+}
+
+test_expect_success 'test conflict notices and such' '
+       test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out &&
+       anonymize_hash out >actual &&
+
+       # Expected results:
+       #   "greeting" should merge with conflicts
+       #   "numbers" should merge cleanly
+       #   "whatever" has *both* a modify/delete and a file/directory conflict
+       cat <<-EOF >expect &&
+       HASH
+       greeting
+       whatever~side1
+
+       Auto-merging greeting
+       CONFLICT (content): Merge conflict in greeting
+       Auto-merging numbers
+       CONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
+       CONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1.  Version side1 of whatever~side1 left in tree.
+       EOF
+
+       test_cmp expect actual
+'
+
+# directory rename + content conflict
+#   Commit O: foo, olddir/{a,b,c}
+#   Commit A: modify foo, newdir/{a,b,c}
+#   Commit B: modify foo differently & rename foo -> olddir/bar
+#   Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo)
+
+test_expect_success 'directory rename + content conflict' '
+       # Setup
+       git init dir-rename-and-content &&
+       (
+               cd dir-rename-and-content &&
+               test_write_lines 1 2 3 4 5 >foo &&
+               mkdir olddir &&
+               for i in a b c; do echo $i >olddir/$i || exit 1; done &&
+               git add foo olddir &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               test_write_lines 1 2 3 4 5 6 >foo &&
+               git add foo &&
+               git mv olddir newdir &&
+               git commit -m "Modify foo, rename olddir to newdir" &&
+
+               git checkout B &&
+               test_write_lines 1 2 3 4 5 six >foo &&
+               git add foo &&
+               git mv foo olddir/bar &&
+               git commit -m "Modify foo & rename foo -> olddir/bar"
+       ) &&
+       # Testing
+       (
+               cd dir-rename-and-content &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+               anonymize_hash out >actual &&
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 1Qnewdir/bar
+               100644 HASH 2Qnewdir/bar
+               100644 HASH 3Qnewdir/bar
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               Q2Qnewdir/barQolddir/barQCONFLICT (directory rename suggested)QCONFLICT (file location): foo renamed to olddir/bar in B^0, inside a directory that was renamed in A^0, suggesting it should perhaps be moved to newdir/bar.
+               Q1Qnewdir/barQAuto-mergingQAuto-merging newdir/bar
+               Q1Qnewdir/barQCONFLICT (contents)QCONFLICT (content): Merge conflict in newdir/bar
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# rename/delete + modify/delete handling
+#   Commit O: foo
+#   Commit A: modify foo + rename to bar
+#   Commit B: delete foo
+#   Expected: CONFLICT(rename/delete) + CONFLICT(modify/delete)
+
+test_expect_success 'rename/delete handling' '
+       # Setup
+       git init rename-delete &&
+       (
+               cd rename-delete &&
+               test_write_lines 1 2 3 4 5 >foo &&
+               git add foo &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               test_write_lines 1 2 3 4 5 6 >foo &&
+               git add foo &&
+               git mv foo bar &&
+               git commit -m "Modify foo, rename to bar" &&
+
+               git checkout B &&
+               git rm foo &&
+               git commit -m "remove foo"
+       ) &&
+       # Testing
+       (
+               cd rename-delete &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+               anonymize_hash out >actual &&
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 1Qbar
+               100644 HASH 2Qbar
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               Q2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in A^0, but deleted in B^0.
+               Q1QbarQCONFLICT (modify/delete)QCONFLICT (modify/delete): bar deleted in B^0 and modified in A^0.  Version A^0 of bar left in tree.
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# rename/add handling
+#   Commit O: foo
+#   Commit A: modify foo, add different bar
+#   Commit B: modify & rename foo->bar
+#   Expected: CONFLICT(add/add) [via rename collide] for bar
+
+test_expect_success 'rename/add handling' '
+       # Setup
+       git init rename-add &&
+       (
+               cd rename-add &&
+               test_write_lines original 1 2 3 4 5 >foo &&
+               git add foo &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               test_write_lines 1 2 3 4 5 >foo &&
+               echo "different file" >bar &&
+               git add foo bar &&
+               git commit -m "Modify foo, add bar" &&
+
+               git checkout B &&
+               test_write_lines original 1 2 3 4 5 6 >foo &&
+               git add foo &&
+               git mv foo bar &&
+               git commit -m "rename foo to bar"
+       ) &&
+       # Testing
+       (
+               cd rename-add &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+
+               #
+               # First, check that the bar that appears at stage 3 does not
+               # correspond to an individual blob anywhere in history
+               #
+               hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
+               git rev-list --objects --all >all_blobs &&
+               ! grep $hash all_blobs &&
+
+               #
+               # Second, check anonymized hash output against expectation
+               #
+               anonymize_hash out >actual &&
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 2Qbar
+               100644 HASH 3Qbar
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               Q1QbarQAuto-mergingQAuto-merging bar
+               Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
+               Q1QfooQAuto-mergingQAuto-merging foo
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# rename/add, where add is a mode conflict
+#   Commit O: foo
+#   Commit A: modify foo, add symlink bar
+#   Commit B: modify & rename foo->bar
+#   Expected: CONFLICT(distinct modes) for bar
+
+test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' '
+       # Setup
+       git init rename-add-symlink &&
+       (
+               cd rename-add-symlink &&
+               test_write_lines original 1 2 3 4 5 >foo &&
+               git add foo &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               test_write_lines 1 2 3 4 5 >foo &&
+               ln -s foo bar &&
+               git add foo bar &&
+               git commit -m "Modify foo, add symlink bar" &&
+
+               git checkout B &&
+               test_write_lines original 1 2 3 4 5 6 >foo &&
+               git add foo &&
+               git mv foo bar &&
+               git commit -m "rename foo to bar"
+       ) &&
+       # Testing
+       (
+               cd rename-add-symlink &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+
+               #
+               # First, check that the bar that appears at stage 3 does not
+               # correspond to an individual blob anywhere in history
+               #
+               hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
+               git rev-list --objects --all >all_blobs &&
+               ! grep $hash all_blobs &&
+
+               #
+               # Second, check anonymized hash output against expectation
+               #
+               anonymize_hash out >actual &&
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               120000 HASH 2Qbar
+               100644 HASH 3Qbar~B^0
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               Q2QbarQbar~B^0QCONFLICT (distinct modes)QCONFLICT (distinct types): bar had different types on each side; renamed one of them so each can be recorded somewhere.
+               Q1QfooQAuto-mergingQAuto-merging foo
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# rename/rename(1to2) + content conflict handling
+#   Commit O: foo
+#   Commit A: modify foo & rename to bar
+#   Commit B: modify foo & rename to baz
+#   Expected: CONFLICT(rename/rename)
+
+test_expect_success 'rename/rename + content conflict' '
+       # Setup
+       git init rr-plus-content &&
+       (
+               cd rr-plus-content &&
+               test_write_lines 1 2 3 4 5 >foo &&
+               git add foo &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               test_write_lines 1 2 3 4 5 six >foo &&
+               git add foo &&
+               git mv foo bar &&
+               git commit -m "Modify foo + rename to bar" &&
+
+               git checkout B &&
+               test_write_lines 1 2 3 4 5 6 >foo &&
+               git add foo &&
+               git mv foo baz &&
+               git commit -m "Modify foo + rename to baz"
+       ) &&
+       # Testing
+       (
+               cd rr-plus-content &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+               anonymize_hash out >actual &&
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 2Qbar
+               100644 HASH 3Qbaz
+               100644 HASH 1Qfoo
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               Q1QfooQAuto-mergingQAuto-merging foo
+               Q3QfooQbarQbazQCONFLICT (rename/rename)QCONFLICT (rename/rename): foo renamed to bar in A^0 and to baz in B^0.
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# rename/add/delete
+#   Commit O: foo
+#   Commit A: rm foo, add different bar
+#   Commit B: rename foo->bar
+#   Expected: CONFLICT (rename/delete), CONFLICT(add/add) [via rename collide]
+#             for bar
+
+test_expect_success 'rename/add/delete conflict' '
+       # Setup
+       git init rad &&
+       (
+               cd rad &&
+               echo "original file" >foo &&
+               git add foo &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               git rm foo &&
+               echo "different file" >bar &&
+               git add bar &&
+               git commit -m "Remove foo, add bar" &&
+
+               git checkout B &&
+               git mv foo bar &&
+               git commit -m "rename foo to bar"
+       ) &&
+       # Testing
+       (
+               cd rad &&
+
+               test_expect_code 1 \
+                       git merge-tree -z B^0 A^0 >out &&
+               echo >>out &&
+               anonymize_hash out >actual &&
+
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 2Qbar
+               100644 HASH 3Qbar
+
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in B^0, but deleted in A^0.
+               Q1QbarQAuto-mergingQAuto-merging bar
+               Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# rename/rename(2to1)/delete/delete
+#   Commit O: foo, bar
+#   Commit A: rename foo->baz, rm bar
+#   Commit B: rename bar->baz, rm foo
+#   Expected: 2x CONFLICT (rename/delete), CONFLICT (add/add) via colliding
+#             renames for baz
+
+test_expect_success 'rename/rename(2to1)/delete/delete conflict' '
+       # Setup
+       git init rrdd &&
+       (
+               cd rrdd &&
+               echo foo >foo &&
+               echo bar >bar &&
+               git add foo bar &&
+               git commit -m O &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               git mv foo baz &&
+               git rm bar &&
+               git commit -m "Rename foo, remove bar" &&
+
+               git checkout B &&
+               git mv bar baz &&
+               git rm foo &&
+               git commit -m "Rename bar, remove foo"
+       ) &&
+       # Testing
+       (
+               cd rrdd &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+               anonymize_hash out >actual &&
+
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 2Qbaz
+               100644 HASH 3Qbaz
+
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               2QbazQbarQCONFLICT (rename/delete)QCONFLICT (rename/delete): bar renamed to baz in B^0, but deleted in A^0.
+               Q2QbazQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to baz in A^0, but deleted in B^0.
+               Q1QbazQAuto-mergingQAuto-merging baz
+               Q1QbazQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in baz
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# mod6: chains of rename/rename(1to2) + add/add via colliding renames
+#   Commit O: one,      three,       five
+#   Commit A: one->two, three->four, five->six
+#   Commit B: one->six, three->two,  five->four
+#   Expected: three CONFLICT(rename/rename) messages + three CONFLICT(add/add)
+#             messages; each path in two of the multi-way merged contents
+#             found in two, four, six
+
+test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via colliding renames' '
+       # Setup
+       git init mod6 &&
+       (
+               cd mod6 &&
+               test_seq 11 19 >one &&
+               test_seq 31 39 >three &&
+               test_seq 51 59 >five &&
+               git add . &&
+               test_tick &&
+               git commit -m "O" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               test_seq 10 19 >one &&
+               echo 40        >>three &&
+               git add one three &&
+               git mv  one   two  &&
+               git mv  three four &&
+               git mv  five  six  &&
+               test_tick &&
+               git commit -m "A" &&
+
+               git checkout B &&
+               echo 20    >>one       &&
+               echo forty >>three     &&
+               echo 60    >>five      &&
+               git add one three five &&
+               git mv  one   six  &&
+               git mv  three two  &&
+               git mv  five  four &&
+               test_tick &&
+               git commit -m "B"
+       ) &&
+       # Testing
+       (
+               cd mod6 &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+
+               #
+               # First, check that some of the hashes that appear as stage
+               # conflict entries do not appear as individual blobs anywhere
+               # in history.
+               #
+               hash1=$(cat out | tr "\0" "\n" | head | grep 2.four | cut -f 2 -d " ") &&
+               hash2=$(cat out | tr "\0" "\n" | head | grep 3.two | cut -f 2 -d " ") &&
+               git rev-list --objects --all >all_blobs &&
+               ! grep $hash1 all_blobs &&
+               ! grep $hash2 all_blobs &&
+
+               #
+               # Now compare anonymized hash output with expectation
+               #
+               anonymize_hash out >actual &&
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 1Qfive
+               100644 HASH 2Qfour
+               100644 HASH 3Qfour
+               100644 HASH 1Qone
+               100644 HASH 2Qsix
+               100644 HASH 3Qsix
+               100644 HASH 1Qthree
+               100644 HASH 2Qtwo
+               100644 HASH 3Qtwo
+
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               3QfiveQsixQfourQCONFLICT (rename/rename)QCONFLICT (rename/rename): five renamed to six in A^0 and to four in B^0.
+               Q1QfourQAuto-mergingQAuto-merging four
+               Q1QfourQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in four
+               Q1QoneQAuto-mergingQAuto-merging one
+               Q3QoneQtwoQsixQCONFLICT (rename/rename)QCONFLICT (rename/rename): one renamed to two in A^0 and to six in B^0.
+               Q1QsixQAuto-mergingQAuto-merging six
+               Q1QsixQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in six
+               Q1QthreeQAuto-mergingQAuto-merging three
+               Q3QthreeQfourQtwoQCONFLICT (rename/rename)QCONFLICT (rename/rename): three renamed to four in A^0 and to two in B^0.
+               Q1QtwoQAuto-mergingQAuto-merging two
+               Q1QtwoQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in two
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+# directory rename + rename/delete + modify/delete + directory/file conflict
+#   Commit O: foo, olddir/{a,b,c}
+#   Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file
+#   Commit B: modify foo & rename foo -> olddir/bar
+#   Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo)
+
+test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
+       # Setup
+       git init 4-stacked-conflict &&
+       (
+               cd 4-stacked-conflict &&
+               test_write_lines 1 2 3 4 5 >foo &&
+               mkdir olddir &&
+               for i in a b c; do echo $i >olddir/$i || exit 1; done &&
+               git add foo olddir &&
+               git commit -m "original" &&
+
+               git branch O &&
+               git branch A &&
+               git branch B &&
+
+               git checkout A &&
+               git rm foo &&
+               git mv olddir newdir &&
+               mkdir newdir/bar &&
+               >newdir/bar/file &&
+               git add newdir/bar/file &&
+               git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file" &&
+
+               git checkout B &&
+               test_write_lines 1 2 3 4 5 6 >foo &&
+               git add foo &&
+               git mv foo olddir/bar &&
+               git commit -m "Modify foo & rename foo -> olddir/bar"
+       ) &&
+       # Testing
+       (
+               cd 4-stacked-conflict &&
+
+               test_expect_code 1 \
+                       git merge-tree -z A^0 B^0 >out &&
+               echo >>out &&
+               anonymize_hash out >actual &&
+
+               q_to_tab <<-\EOF | lf_to_nul >expect &&
+               HASH
+               100644 HASH 1Qnewdir/bar~B^0
+               100644 HASH 3Qnewdir/bar~B^0
+               EOF
+
+               q_to_nul <<-EOF >>expect &&
+               Q2Qnewdir/barQolddir/barQCONFLICT (directory rename suggested)QCONFLICT (file location): foo renamed to olddir/bar in B^0, inside a directory that was renamed in A^0, suggesting it should perhaps be moved to newdir/bar.
+               Q2Qnewdir/barQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to newdir/bar in B^0, but deleted in A^0.
+               Q2Qnewdir/bar~B^0Qnewdir/barQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of newdir/bar from B^0; moving it to newdir/bar~B^0 instead.
+               Q1Qnewdir/bar~B^0QCONFLICT (modify/delete)QCONFLICT (modify/delete): newdir/bar~B^0 deleted in A^0 and modified in B^0.  Version B^0 of newdir/bar~B^0 left in tree.
+               Q
+               EOF
+               test_cmp expect actual
+       )
+'
+
+for opt in $(git merge-tree --git-completion-helper-all)
+do
+       if test $opt = "--trivial-merge" || test $opt = "--write-tree"
+       then
+               continue
+       fi
+
+       test_expect_success "usage: --trivial-merge is incompatible with $opt" '
+               test_expect_code 128 git merge-tree --trivial-merge $opt side1 side2 side3
+       '
+done
+
+test_expect_success 'Just the conflicted files without the messages' '
+       test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out &&
+       anonymize_hash out >actual &&
+
+       test_write_lines HASH greeting whatever~side1 >expect &&
+
+       test_cmp expect actual
+'
+
+test_expect_success 'Check conflicted oids and modes without messages' '
+       test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out &&
+       anonymize_hash out >actual &&
+
+       # Compare the basic output format
+       q_to_tab >expect <<-\EOF &&
+       HASH
+       100644 HASH 1Qgreeting
+       100644 HASH 2Qgreeting
+       100644 HASH 3Qgreeting
+       100644 HASH 1Qwhatever~side1
+       100644 HASH 2Qwhatever~side1
+       EOF
+
+       test_cmp expect actual &&
+
+       # Check the actual hashes against the `ls-files -u` output too
+       tail -n +2 out | sed -e s/side1/HEAD/ >actual &&
+       test_cmp conflicted-file-info actual
+'
+
+test_expect_success 'NUL terminated conflicted file "lines"' '
+       git checkout -b tweak1 side1 &&
+       test_write_lines zero 1 2 3 4 5 6 >numbers &&
+       git add numbers &&
+       git mv numbers "Αυτά μου φαίνονται κινέζικα" &&
+       git commit -m "Renamed numbers" &&
+
+       test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out &&
+       echo >>out &&
+       anonymize_hash out >actual &&
+
+       # Expected results:
+       #   "greeting" should merge with conflicts
+       #   "whatever" has *both* a modify/delete and a file/directory conflict
+       #   "Αυτά μου φαίνονται κινέζικα" should have a conflict
+       echo HASH | lf_to_nul >expect &&
+
+       q_to_tab <<-EOF | lf_to_nul >>expect &&
+       100644 HASH 1Qgreeting
+       100644 HASH 2Qgreeting
+       100644 HASH 3Qgreeting
+       100644 HASH 1Qwhatever~tweak1
+       100644 HASH 2Qwhatever~tweak1
+       100644 HASH 1QΑυτά μου φαίνονται κινέζικα
+       100644 HASH 2QΑυτά μου φαίνονται κινέζικα
+       100644 HASH 3QΑυτά μου φαίνονται κινέζικα
+
+       EOF
+
+       q_to_nul <<-EOF >>expect &&
+       1QgreetingQAuto-mergingQAuto-merging greeting
+       Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
+       Q2Qwhatever~tweak1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from tweak1; moving it to whatever~tweak1 instead.
+       Q1Qwhatever~tweak1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~tweak1 deleted in side2 and modified in tweak1.  Version tweak1 of whatever~tweak1 left in tree.
+       Q1QΑυτά μου φαίνονται κινέζικαQAuto-mergingQAuto-merging Αυτά μου φαίνονται κινέζικα
+       Q1QΑυτά μου φαίνονται κινέζικαQCONFLICT (contents)QCONFLICT (content): Merge conflict in Αυτά μου φαίνονται κινέζικα
+       Q
+       EOF
+
+       test_cmp expect actual
+'
+
+test_expect_success 'error out by default for unrelated histories' '
+       test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error &&
+
+       grep "refusing to merge unrelated histories" error
+'
+
+test_expect_success 'can override merge of unrelated histories' '
+       git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree &&
+       TREE=$(cat tree) &&
+
+       git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect &&
+       git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual &&
+
+       test_cmp expect actual
+'
+
+test_done
index 7f8d2ab0a72dac716198a424556d1e9323f2f8c3..eaa0b22ece4ff3ce7d79faed2edf8ab829c97051 100755 (executable)
@@ -24,6 +24,7 @@ commit id embedding:
 
 '
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 SUBSTFORMAT=%H%n
@@ -143,6 +144,7 @@ test_expect_success 'populate workdir' '
 test_expect_success \
     'add ignored file' \
     'echo ignore me >a/ignored &&
+     mkdir .git/info &&
      echo ignored export-ignore >.git/info/attributes'
 
 test_expect_success 'add files to repository' '
@@ -157,7 +159,8 @@ test_expect_success 'setup export-subst' '
 '
 
 test_expect_success 'create bare clone' '
-       git clone --bare . bare.git &&
+       git clone --template= --bare . bare.git &&
+       mkdir bare.git/info &&
        cp .git/info/attributes bare.git/info/attributes
 '
 
@@ -339,21 +342,21 @@ test_expect_success 'only enabled filters are available remotely' '
        test_cmp_bin remote.bar config.bar
 '
 
-test_expect_success GZIP 'git archive --format=tgz' '
+test_expect_success 'git archive --format=tgz' '
        git archive --format=tgz HEAD >j.tgz
 '
 
-test_expect_success GZIP 'git archive --format=tar.gz' '
+test_expect_success 'git archive --format=tar.gz' '
        git archive --format=tar.gz HEAD >j1.tar.gz &&
        test_cmp_bin j.tgz j1.tar.gz
 '
 
-test_expect_success GZIP 'infer tgz from .tgz filename' '
+test_expect_success 'infer tgz from .tgz filename' '
        git archive --output=j2.tgz HEAD &&
        test_cmp_bin j.tgz j2.tgz
 '
 
-test_expect_success GZIP 'infer tgz from .tar.gz filename' '
+test_expect_success 'infer tgz from .tar.gz filename' '
        git archive --output=j3.tar.gz HEAD &&
        test_cmp_bin j.tgz j3.tar.gz
 '
@@ -363,17 +366,33 @@ test_expect_success GZIP 'extract tgz file' '
        test_cmp_bin b.tar j.tar
 '
 
-test_expect_success GZIP 'remote tar.gz is allowed by default' '
+test_expect_success 'remote tar.gz is allowed by default' '
        git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
        test_cmp_bin j.tgz remote.tar.gz
 '
 
-test_expect_success GZIP 'remote tar.gz can be disabled' '
+test_expect_success 'remote tar.gz can be disabled' '
        git config tar.tar.gz.remote false &&
        test_must_fail git archive --remote=. --format=tar.gz HEAD \
                >remote.tar.gz
 '
 
+test_expect_success GZIP 'git archive --format=tgz (external gzip)' '
+       test_config tar.tgz.command "gzip -cn" &&
+       git archive --format=tgz HEAD >external_gzip.tgz
+'
+
+test_expect_success GZIP 'git archive --format=tar.gz (external gzip)' '
+       test_config tar.tar.gz.command "gzip -cn" &&
+       git archive --format=tar.gz HEAD >external_gzip.tar.gz &&
+       test_cmp_bin external_gzip.tgz external_gzip.tar.gz
+'
+
+test_expect_success GZIP 'extract tgz file (external gzip)' '
+       gzip -d -c <external_gzip.tgz >external_gzip.tar &&
+       test_cmp_bin b.tar external_gzip.tar
+'
+
 test_expect_success 'archive and :(glob)' '
        git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual &&
        cat >expect <<EOF &&
index 712ae52299431c3d31038123a02f895708086bdd..2f6eef5e3720452df49c4810bd9f4f63dc1167fb 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git archive attribute tests'
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 SUBSTFORMAT='%H (%h)%n'
@@ -20,6 +21,7 @@ extract_tar_to_dir () {
 
 test_expect_success 'setup' '
        echo ignored >ignored &&
+       mkdir .git/info &&
        echo ignored export-ignore >>.git/info/attributes &&
        git add ignored &&
 
@@ -46,7 +48,8 @@ test_expect_success 'setup' '
 
        git commit -m. &&
 
-       git clone --bare . bare &&
+       git clone --template= --bare . bare &&
+       mkdir bare/info &&
        cp .git/info/attributes bare/info/attributes
 '
 
index a66b5ba27e869e377a317258c03cde8953323d8f..78ab75f1bc2442144670a2df06de790ee43d82b7 100755 (executable)
@@ -3,6 +3,7 @@
 test_description='git archive attribute pattern tests'
 
 TEST_PASSES_SANITIZE_LEAK=true
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 test_expect_exists() {
@@ -15,6 +16,7 @@ test_expect_missing() {
 
 test_expect_success 'setup' '
        echo ignored >ignored &&
+       mkdir .git/info &&
        echo ignored export-ignore >>.git/info/attributes &&
        git add ignored &&
 
@@ -54,7 +56,8 @@ test_expect_success 'setup' '
 
        git commit -m. &&
 
-       git clone --bare . bare &&
+       git clone --template= --bare . bare &&
+       mkdir bare/info &&
        cp .git/info/attributes bare/info/attributes
 '
 
index 3992d08158a29ee8a9a1b73a7f7b6446308b2e6a..fc499cdff01d01a6079221e78b50a7924e5ecb71 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git archive --format=zip test'
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 SUBSTFORMAT=%H%n
@@ -121,6 +122,7 @@ test_expect_success 'prepare file list' '
 test_expect_success \
     'add ignored file' \
     'echo ignore me >a/ignored &&
+     mkdir .git/info &&
      echo ignored export-ignore >.git/info/attributes'
 
 test_expect_success 'add files to repository' '
@@ -139,7 +141,8 @@ test_expect_success 'setup export-subst and diff attributes' '
 '
 
 test_expect_success 'create bare clone' '
-       git clone --bare . bare.git &&
+       git clone --template= --bare . bare.git &&
+       mkdir bare.git/info &&
        cp .git/info/attributes bare.git/info/attributes &&
        # Recreate our changes to .git/config rather than just copying it, as
        # we do not want to clobber core.bare or other settings.
index 41e6dc4dcfc5163c8db4d7875567162ea7cc1828..2926e8dfc41223cc0030685beec8f6612db25a4d 100755 (executable)
@@ -4,6 +4,8 @@
 #
 
 test_description='resilience to pack corruptions with redundant objects'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # Note: the test objects are created with knowledge of their pack encoding
index 693b2411c89929b7cf3b765419c1f8db96554636..655cafa054121130945056643f2fb05a165f3ef1 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='handling of duplicate objects in incoming packfiles'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-pack.sh
 
index 55b787630fcb6e0631bc6b8a1cd6626c30063417..4e910c5b9d2a9ddba8c2d808248189fe993873c3 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test index-pack handling of delta cycles in packfiles'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-pack.sh
 
index f775fc1ce691d5337b31d067cd93944b7bae3bc5..6d693eef82f74a72ad4f29c399e297427c892d12 100755 (executable)
@@ -26,22 +26,415 @@ has_any () {
        grep -Ff "$1" "$2"
 }
 
-setup_bitmap_history
-
-test_expect_success 'setup writing bitmaps during repack' '
-       git config repack.writeBitmaps true
-'
-
-test_expect_success 'full repack creates bitmaps' '
-       GIT_TRACE2_EVENT="$(pwd)/trace" \
+test_bitmap_cases () {
+       writeLookupTable=false
+       for i in "$@"
+       do
+               case "$i" in
+               "pack.writeBitmapLookupTable") writeLookupTable=true;;
+               esac
+       done
+
+       test_expect_success 'setup test repository' '
+               rm -fr * .git &&
+               git init &&
+               git config pack.writeBitmapLookupTable '"$writeLookupTable"'
+       '
+       setup_bitmap_history
+
+       test_expect_success 'setup writing bitmaps during repack' '
+               git config repack.writeBitmaps true
+       '
+
+       test_expect_success 'full repack creates bitmaps' '
+               GIT_TRACE2_EVENT="$(pwd)/trace" \
+                       git repack -ad &&
+               ls .git/objects/pack/ | grep bitmap >output &&
+               test_line_count = 1 output &&
+               grep "\"key\":\"num_selected_commits\",\"value\":\"106\"" trace &&
+               grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace
+       '
+
+       basic_bitmap_tests
+
+       test_expect_success 'pack-objects respects --local (non-local loose)' '
+               git init --bare alt.git &&
+               echo $(pwd)/alt.git/objects >.git/objects/info/alternates &&
+               echo content1 >file1 &&
+               # non-local loose object which is not present in bitmapped pack
+               altblob=$(GIT_DIR=alt.git git hash-object -w file1) &&
+               # non-local loose object which is also present in bitmapped pack
+               git cat-file blob $blob | GIT_DIR=alt.git git hash-object -w --stdin &&
+               git add file1 &&
+               test_tick &&
+               git commit -m commit_file1 &&
+               echo HEAD | git pack-objects --local --stdout --revs >1.pack &&
+               git index-pack 1.pack &&
+               list_packed_objects 1.idx >1.objects &&
+               printf "%s\n" "$altblob" "$blob" >nonlocal-loose &&
+               ! has_any nonlocal-loose 1.objects
+       '
+
+       test_expect_success 'pack-objects respects --honor-pack-keep (local non-bitmapped pack)' '
+               echo content2 >file2 &&
+               blob2=$(git hash-object -w file2) &&
+               git add file2 &&
+               test_tick &&
+               git commit -m commit_file2 &&
+               printf "%s\n" "$blob2" "$bitmaptip" >keepobjects &&
+               pack2=$(git pack-objects pack2 <keepobjects) &&
+               mv pack2-$pack2.* .git/objects/pack/ &&
+               >.git/objects/pack/pack2-$pack2.keep &&
+               rm $(objpath $blob2) &&
+               echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >2a.pack &&
+               git index-pack 2a.pack &&
+               list_packed_objects 2a.idx >2a.objects &&
+               ! has_any keepobjects 2a.objects
+       '
+
+       test_expect_success 'pack-objects respects --local (non-local pack)' '
+               mv .git/objects/pack/pack2-$pack2.* alt.git/objects/pack/ &&
+               echo HEAD | git pack-objects --local --stdout --revs >2b.pack &&
+               git index-pack 2b.pack &&
+               list_packed_objects 2b.idx >2b.objects &&
+               ! has_any keepobjects 2b.objects
+       '
+
+       test_expect_success 'pack-objects respects --honor-pack-keep (local bitmapped pack)' '
+               ls .git/objects/pack/ | grep bitmap >output &&
+               test_line_count = 1 output &&
+               packbitmap=$(basename $(cat output) .bitmap) &&
+               list_packed_objects .git/objects/pack/$packbitmap.idx >packbitmap.objects &&
+               test_when_finished "rm -f .git/objects/pack/$packbitmap.keep" &&
+               >.git/objects/pack/$packbitmap.keep &&
+               echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >3a.pack &&
+               git index-pack 3a.pack &&
+               list_packed_objects 3a.idx >3a.objects &&
+               ! has_any packbitmap.objects 3a.objects
+       '
+
+       test_expect_success 'pack-objects respects --local (non-local bitmapped pack)' '
+               mv .git/objects/pack/$packbitmap.* alt.git/objects/pack/ &&
+               rm -f .git/objects/pack/multi-pack-index &&
+               test_when_finished "mv alt.git/objects/pack/$packbitmap.* .git/objects/pack/" &&
+               echo HEAD | git pack-objects --local --stdout --revs >3b.pack &&
+               git index-pack 3b.pack &&
+               list_packed_objects 3b.idx >3b.objects &&
+               ! has_any packbitmap.objects 3b.objects
+       '
+
+       test_expect_success 'pack-objects to file can use bitmap' '
+               # make sure we still have 1 bitmap index from previous tests
+               ls .git/objects/pack/ | grep bitmap >output &&
+               test_line_count = 1 output &&
+               # verify equivalent packs are generated with/without using bitmap index
+               packasha1=$(git pack-objects --no-use-bitmap-index --all packa </dev/null) &&
+               packbsha1=$(git pack-objects --use-bitmap-index --all packb </dev/null) &&
+               list_packed_objects packa-$packasha1.idx >packa.objects &&
+               list_packed_objects packb-$packbsha1.idx >packb.objects &&
+               test_cmp packa.objects packb.objects
+       '
+
+       test_expect_success 'full repack, reusing previous bitmaps' '
                git repack -ad &&
-       ls .git/objects/pack/ | grep bitmap >output &&
-       test_line_count = 1 output &&
-       grep "\"key\":\"num_selected_commits\",\"value\":\"106\"" trace &&
-       grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace
-'
+               ls .git/objects/pack/ | grep bitmap >output &&
+               test_line_count = 1 output
+       '
+
+       test_expect_success 'fetch (full bitmap)' '
+               git --git-dir=clone.git fetch origin second:second &&
+               git rev-parse HEAD >expect &&
+               git --git-dir=clone.git rev-parse HEAD >actual &&
+               test_cmp expect actual
+       '
+
+       test_expect_success 'create objects for missing-HAVE tests' '
+               blob=$(echo "missing have" | git hash-object -w --stdin) &&
+               tree=$(printf "100644 blob $blob\tfile\n" | git mktree) &&
+               parent=$(echo parent | git commit-tree $tree) &&
+               commit=$(echo commit | git commit-tree $tree -p $parent) &&
+               cat >revs <<-EOF
+               HEAD
+               ^HEAD^
+               ^$commit
+               EOF
+       '
+
+       test_expect_success 'pack-objects respects --incremental' '
+               cat >revs2 <<-EOF &&
+               HEAD
+               $commit
+               EOF
+               git pack-objects --incremental --stdout --revs <revs2 >4.pack &&
+               git index-pack 4.pack &&
+               list_packed_objects 4.idx >4.objects &&
+               test_line_count = 4 4.objects &&
+               git rev-list --objects $commit >revlist &&
+               cut -d" " -f1 revlist |sort >objects &&
+               test_cmp 4.objects objects
+       '
+
+       test_expect_success 'pack with missing blob' '
+               rm $(objpath $blob) &&
+               git pack-objects --stdout --revs <revs >/dev/null
+       '
+
+       test_expect_success 'pack with missing tree' '
+               rm $(objpath $tree) &&
+               git pack-objects --stdout --revs <revs >/dev/null
+       '
+
+       test_expect_success 'pack with missing parent' '
+               rm $(objpath $parent) &&
+               git pack-objects --stdout --revs <revs >/dev/null
+       '
+
+       test_expect_success JGIT,SHA1 'we can read jgit bitmaps' '
+               git clone --bare . compat-jgit.git &&
+               (
+                       cd compat-jgit.git &&
+                       rm -f objects/pack/*.bitmap &&
+                       jgit gc &&
+                       git rev-list --test-bitmap HEAD
+               )
+       '
+
+       test_expect_success JGIT,SHA1 'jgit can read our bitmaps' '
+               git clone --bare . compat-us.git &&
+               (
+                       cd compat-us.git &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+                       git repack -adb &&
+                       # jgit gc will barf if it does not like our bitmaps
+                       jgit gc
+               )
+       '
+
+       test_expect_success 'splitting packs does not generate bogus bitmaps' '
+               test-tool genrandom foo $((1024 * 1024)) >rand &&
+               git add rand &&
+               git commit -m "commit with big file" &&
+               git -c pack.packSizeLimit=500k repack -adb &&
+               git init --bare no-bitmaps.git &&
+               git -C no-bitmaps.git fetch .. HEAD
+       '
+
+       test_expect_success 'set up reusable pack' '
+               rm -f .git/objects/pack/*.keep &&
+               git repack -adb &&
+               reusable_pack () {
+                       git for-each-ref --format="%(objectname)" |
+                       git pack-objects --delta-base-offset --revs --stdout "$@"
+               }
+       '
+
+       test_expect_success 'pack reuse respects --honor-pack-keep' '
+               test_when_finished "rm -f .git/objects/pack/*.keep" &&
+               for i in .git/objects/pack/*.pack
+               do
+                       >${i%.pack}.keep || return 1
+               done &&
+               reusable_pack --honor-pack-keep >empty.pack &&
+               git index-pack empty.pack &&
+               git show-index <empty.idx >actual &&
+               test_must_be_empty actual
+       '
+
+       test_expect_success 'pack reuse respects --local' '
+               mv .git/objects/pack/* alt.git/objects/pack/ &&
+               test_when_finished "mv alt.git/objects/pack/* .git/objects/pack/" &&
+               reusable_pack --local >empty.pack &&
+               git index-pack empty.pack &&
+               git show-index <empty.idx >actual &&
+               test_must_be_empty actual
+       '
+
+       test_expect_success 'pack reuse respects --incremental' '
+               reusable_pack --incremental >empty.pack &&
+               git index-pack empty.pack &&
+               git show-index <empty.idx >actual &&
+               test_must_be_empty actual
+       '
+
+       test_expect_success 'truncated bitmap fails gracefully (ewah)' '
+               test_config pack.writebitmaphashcache false &&
+               test_config pack.writebitmaplookuptable false &&
+               git repack -ad &&
+               git rev-list --use-bitmap-index --count --all >expect &&
+               bitmap=$(ls .git/objects/pack/*.bitmap) &&
+               test_when_finished "rm -f $bitmap" &&
+               test_copy_bytes 256 <$bitmap >$bitmap.tmp &&
+               mv -f $bitmap.tmp $bitmap &&
+               git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
+               test_cmp expect actual &&
+               test_i18ngrep corrupt.ewah.bitmap stderr
+       '
+
+       test_expect_success 'truncated bitmap fails gracefully (cache)' '
+               git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+               git repack -ad &&
+               git rev-list --use-bitmap-index --count --all >expect &&
+               bitmap=$(ls .git/objects/pack/*.bitmap) &&
+               test_when_finished "rm -f $bitmap" &&
+               test_copy_bytes 512 <$bitmap >$bitmap.tmp &&
+               mv -f $bitmap.tmp $bitmap &&
+               git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
+               test_cmp expect actual &&
+               test_i18ngrep corrupted.bitmap.index stderr
+       '
+
+       # Create a state of history with these properties:
+       #
+       #  - refs that allow a client to fetch some new history, while sharing some old
+       #    history with the server; we use branches delta-reuse-old and
+       #    delta-reuse-new here
+       #
+       #  - the new history contains an object that is stored on the server as a delta
+       #    against a base that is in the old history
+       #
+       #  - the base object is not immediately reachable from the tip of the old
+       #    history; finding it would involve digging down through history we know the
+       #    other side has
+       #
+       # This should result in a state where fetching from old->new would not
+       # traditionally reuse the on-disk delta (because we'd have to dig to realize
+       # that the client has it), but we will do so if bitmaps can tell us cheaply
+       # that the other side has it.
+       test_expect_success 'set up thin delta-reuse parent' '
+               # This first commit contains the buried base object.
+               test-tool genrandom delta 16384 >file &&
+               git add file &&
+               git commit -m "delta base" &&
+               base=$(git rev-parse --verify HEAD:file) &&
+
+               # These intermediate commits bury the base back in history.
+               # This becomes the "old" state.
+               for i in 1 2 3 4 5
+               do
+                       echo $i >file &&
+                       git commit -am "intermediate $i" || return 1
+               done &&
+               git branch delta-reuse-old &&
+
+               # And now our new history has a delta against the buried base. Note
+               # that this must be smaller than the original file, since pack-objects
+               # prefers to create deltas from smaller objects to larger.
+               test-tool genrandom delta 16300 >file &&
+               git commit -am "delta result" &&
+               delta=$(git rev-parse --verify HEAD:file) &&
+               git branch delta-reuse-new &&
+
+               # Repack with bitmaps and double check that we have the expected delta
+               # relationship.
+               git repack -adb &&
+               have_delta $delta $base
+       '
+
+       # Now we can sanity-check the non-bitmap behavior (that the server is not able
+       # to reuse the delta). This isn't strictly something we care about, so this
+       # test could be scrapped in the future. But it makes sure that the next test is
+       # actually triggering the feature we want.
+       #
+       # Note that our tools for working with on-the-wire "thin" packs are limited. So
+       # we actually perform the fetch, retain the resulting pack, and inspect the
+       # result.
+       test_expect_success 'fetch without bitmaps ignores delta against old base' '
+               test_config pack.usebitmaps false &&
+               test_when_finished "rm -rf client.git" &&
+               git init --bare client.git &&
+               (
+                       cd client.git &&
+                       git config transfer.unpackLimit 1 &&
+                       git fetch .. delta-reuse-old:delta-reuse-old &&
+                       git fetch .. delta-reuse-new:delta-reuse-new &&
+                       have_delta $delta $ZERO_OID
+               )
+       '
+
+       # And do the same for the bitmap case, where we do expect to find the delta.
+       test_expect_success 'fetch with bitmaps can reuse old base' '
+               test_config pack.usebitmaps true &&
+               test_when_finished "rm -rf client.git" &&
+               git init --bare client.git &&
+               (
+                       cd client.git &&
+                       git config transfer.unpackLimit 1 &&
+                       git fetch .. delta-reuse-old:delta-reuse-old &&
+                       git fetch .. delta-reuse-new:delta-reuse-new &&
+                       have_delta $delta $base
+               )
+       '
+
+       test_expect_success 'pack.preferBitmapTips' '
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+
+                       # create enough commits that not all are receive bitmap
+                       # coverage even if they are all at the tip of some reference.
+                       test_commit_bulk --message="%s" 103 &&
+
+                       git rev-list HEAD >commits.raw &&
+                       sort <commits.raw >commits &&
+
+                       git log --format="create refs/tags/%s %H" HEAD >refs &&
+                       git update-ref --stdin <refs &&
+
+                       git repack -adb &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+
+                       # remember which commits did not receive bitmaps
+                       comm -13 bitmaps commits >before &&
+                       test_file_not_empty before &&
+
+                       # mark the commits which did not receive bitmaps as preferred,
+                       # and generate the bitmap again
+                       perl -pe "s{^}{create refs/tags/include/$. }" <before |
+                               git update-ref --stdin &&
+                       git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
+
+                       # finally, check that the commit(s) without bitmap coverage
+                       # are not the same ones as before
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       comm -13 bitmaps commits >after &&
+
+                       ! test_cmp before after
+               )
+       '
+
+       test_expect_success 'complains about multiple pack bitmaps' '
+               rm -fr repo &&
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+
+                       test_commit base &&
+
+                       git repack -adb &&
+                       bitmap="$(ls .git/objects/pack/pack-*.bitmap)" &&
+                       mv "$bitmap" "$bitmap.bak" &&
+
+                       test_commit other &&
+                       git repack -ab &&
+
+                       mv "$bitmap.bak" "$bitmap" &&
+
+                       find .git/objects/pack -type f -name "*.pack" >packs &&
+                       find .git/objects/pack -type f -name "*.bitmap" >bitmaps &&
+                       test_line_count = 2 packs &&
+                       test_line_count = 2 bitmaps &&
+
+                       git rev-list --use-bitmap-index HEAD 2>err &&
+                       grep "ignoring extra bitmap file" err
+               )
+       '
+}
 
-basic_bitmap_tests
+test_bitmap_cases
 
 test_expect_success 'incremental repack fails when bitmaps are requested' '
        test_commit more-1 &&
@@ -54,219 +447,17 @@ test_expect_success 'incremental repack can disable bitmaps' '
        git repack -d --no-write-bitmap-index
 '
 
-test_expect_success 'pack-objects respects --local (non-local loose)' '
-       git init --bare alt.git &&
-       echo $(pwd)/alt.git/objects >.git/objects/info/alternates &&
-       echo content1 >file1 &&
-       # non-local loose object which is not present in bitmapped pack
-       altblob=$(GIT_DIR=alt.git git hash-object -w file1) &&
-       # non-local loose object which is also present in bitmapped pack
-       git cat-file blob $blob | GIT_DIR=alt.git git hash-object -w --stdin &&
-       git add file1 &&
-       test_tick &&
-       git commit -m commit_file1 &&
-       echo HEAD | git pack-objects --local --stdout --revs >1.pack &&
-       git index-pack 1.pack &&
-       list_packed_objects 1.idx >1.objects &&
-       printf "%s\n" "$altblob" "$blob" >nonlocal-loose &&
-       ! has_any nonlocal-loose 1.objects
-'
-
-test_expect_success 'pack-objects respects --honor-pack-keep (local non-bitmapped pack)' '
-       echo content2 >file2 &&
-       blob2=$(git hash-object -w file2) &&
-       git add file2 &&
-       test_tick &&
-       git commit -m commit_file2 &&
-       printf "%s\n" "$blob2" "$bitmaptip" >keepobjects &&
-       pack2=$(git pack-objects pack2 <keepobjects) &&
-       mv pack2-$pack2.* .git/objects/pack/ &&
-       >.git/objects/pack/pack2-$pack2.keep &&
-       rm $(objpath $blob2) &&
-       echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >2a.pack &&
-       git index-pack 2a.pack &&
-       list_packed_objects 2a.idx >2a.objects &&
-       ! has_any keepobjects 2a.objects
-'
-
-test_expect_success 'pack-objects respects --local (non-local pack)' '
-       mv .git/objects/pack/pack2-$pack2.* alt.git/objects/pack/ &&
-       echo HEAD | git pack-objects --local --stdout --revs >2b.pack &&
-       git index-pack 2b.pack &&
-       list_packed_objects 2b.idx >2b.objects &&
-       ! has_any keepobjects 2b.objects
-'
-
-test_expect_success 'pack-objects respects --honor-pack-keep (local bitmapped pack)' '
-       ls .git/objects/pack/ | grep bitmap >output &&
-       test_line_count = 1 output &&
-       packbitmap=$(basename $(cat output) .bitmap) &&
-       list_packed_objects .git/objects/pack/$packbitmap.idx >packbitmap.objects &&
-       test_when_finished "rm -f .git/objects/pack/$packbitmap.keep" &&
-       >.git/objects/pack/$packbitmap.keep &&
-       echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >3a.pack &&
-       git index-pack 3a.pack &&
-       list_packed_objects 3a.idx >3a.objects &&
-       ! has_any packbitmap.objects 3a.objects
-'
-
-test_expect_success 'pack-objects respects --local (non-local bitmapped pack)' '
-       mv .git/objects/pack/$packbitmap.* alt.git/objects/pack/ &&
-       rm -f .git/objects/pack/multi-pack-index &&
-       test_when_finished "mv alt.git/objects/pack/$packbitmap.* .git/objects/pack/" &&
-       echo HEAD | git pack-objects --local --stdout --revs >3b.pack &&
-       git index-pack 3b.pack &&
-       list_packed_objects 3b.idx >3b.objects &&
-       ! has_any packbitmap.objects 3b.objects
-'
-
-test_expect_success 'pack-objects to file can use bitmap' '
-       # make sure we still have 1 bitmap index from previous tests
-       ls .git/objects/pack/ | grep bitmap >output &&
-       test_line_count = 1 output &&
-       # verify equivalent packs are generated with/without using bitmap index
-       packasha1=$(git pack-objects --no-use-bitmap-index --all packa </dev/null) &&
-       packbsha1=$(git pack-objects --use-bitmap-index --all packb </dev/null) &&
-       list_packed_objects packa-$packasha1.idx >packa.objects &&
-       list_packed_objects packb-$packbsha1.idx >packb.objects &&
-       test_cmp packa.objects packb.objects
-'
-
-test_expect_success 'full repack, reusing previous bitmaps' '
-       git repack -ad &&
-       ls .git/objects/pack/ | grep bitmap >output &&
-       test_line_count = 1 output
-'
-
-test_expect_success 'fetch (full bitmap)' '
-       git --git-dir=clone.git fetch origin second:second &&
-       git rev-parse HEAD >expect &&
-       git --git-dir=clone.git rev-parse HEAD >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'create objects for missing-HAVE tests' '
-       blob=$(echo "missing have" | git hash-object -w --stdin) &&
-       tree=$(printf "100644 blob $blob\tfile\n" | git mktree) &&
-       parent=$(echo parent | git commit-tree $tree) &&
-       commit=$(echo commit | git commit-tree $tree -p $parent) &&
-       cat >revs <<-EOF
-       HEAD
-       ^HEAD^
-       ^$commit
-       EOF
-'
-
-test_expect_success 'pack-objects respects --incremental' '
-       cat >revs2 <<-EOF &&
-       HEAD
-       $commit
-       EOF
-       git pack-objects --incremental --stdout --revs <revs2 >4.pack &&
-       git index-pack 4.pack &&
-       list_packed_objects 4.idx >4.objects &&
-       test_line_count = 4 4.objects &&
-       git rev-list --objects $commit >revlist &&
-       cut -d" " -f1 revlist |sort >objects &&
-       test_cmp 4.objects objects
-'
-
-test_expect_success 'pack with missing blob' '
-       rm $(objpath $blob) &&
-       git pack-objects --stdout --revs <revs >/dev/null
-'
-
-test_expect_success 'pack with missing tree' '
-       rm $(objpath $tree) &&
-       git pack-objects --stdout --revs <revs >/dev/null
-'
-
-test_expect_success 'pack with missing parent' '
-       rm $(objpath $parent) &&
-       git pack-objects --stdout --revs <revs >/dev/null
-'
-
-test_expect_success JGIT,SHA1 'we can read jgit bitmaps' '
-       git clone --bare . compat-jgit.git &&
-       (
-               cd compat-jgit.git &&
-               rm -f objects/pack/*.bitmap &&
-               jgit gc &&
-               git rev-list --test-bitmap HEAD
-       )
-'
-
-test_expect_success JGIT,SHA1 'jgit can read our bitmaps' '
-       git clone --bare . compat-us.git &&
-       (
-               cd compat-us.git &&
-               git repack -adb &&
-               # jgit gc will barf if it does not like our bitmaps
-               jgit gc
-       )
-'
-
-test_expect_success 'splitting packs does not generate bogus bitmaps' '
-       test-tool genrandom foo $((1024 * 1024)) >rand &&
-       git add rand &&
-       git commit -m "commit with big file" &&
-       git -c pack.packSizeLimit=500k repack -adb &&
-       git init --bare no-bitmaps.git &&
-       git -C no-bitmaps.git fetch .. HEAD
-'
-
-test_expect_success 'set up reusable pack' '
-       rm -f .git/objects/pack/*.keep &&
-       git repack -adb &&
-       reusable_pack () {
-               git for-each-ref --format="%(objectname)" |
-               git pack-objects --delta-base-offset --revs --stdout "$@"
-       }
-'
-
-test_expect_success 'pack reuse respects --honor-pack-keep' '
-       test_when_finished "rm -f .git/objects/pack/*.keep" &&
-       for i in .git/objects/pack/*.pack
-       do
-               >${i%.pack}.keep || return 1
-       done &&
-       reusable_pack --honor-pack-keep >empty.pack &&
-       git index-pack empty.pack &&
-       git show-index <empty.idx >actual &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'pack reuse respects --local' '
-       mv .git/objects/pack/* alt.git/objects/pack/ &&
-       test_when_finished "mv alt.git/objects/pack/* .git/objects/pack/" &&
-       reusable_pack --local >empty.pack &&
-       git index-pack empty.pack &&
-       git show-index <empty.idx >actual &&
-       test_must_be_empty actual
-'
+test_bitmap_cases "pack.writeBitmapLookupTable"
 
-test_expect_success 'pack reuse respects --incremental' '
-       reusable_pack --incremental >empty.pack &&
-       git index-pack empty.pack &&
-       git show-index <empty.idx >actual &&
-       test_must_be_empty actual
+test_expect_success 'verify writing bitmap lookup table when enabled' '
+       GIT_TRACE2_EVENT="$(pwd)/trace2" \
+               git repack -ad &&
+       grep "\"label\":\"writing_lookup_table\"" trace2
 '
 
-test_expect_success 'truncated bitmap fails gracefully (ewah)' '
+test_expect_success 'truncated bitmap fails gracefully (lookup table)' '
        test_config pack.writebitmaphashcache false &&
-       git repack -ad &&
-       git rev-list --use-bitmap-index --count --all >expect &&
-       bitmap=$(ls .git/objects/pack/*.bitmap) &&
-       test_when_finished "rm -f $bitmap" &&
-       test_copy_bytes 256 <$bitmap >$bitmap.tmp &&
-       mv -f $bitmap.tmp $bitmap &&
-       git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
-       test_cmp expect actual &&
-       test_i18ngrep corrupt.ewah.bitmap stderr
-'
-
-test_expect_success 'truncated bitmap fails gracefully (cache)' '
-       git repack -ad &&
+       git repack -adb &&
        git rev-list --use-bitmap-index --count --all >expect &&
        bitmap=$(ls .git/objects/pack/*.bitmap) &&
        test_when_finished "rm -f $bitmap" &&
@@ -277,152 +468,4 @@ test_expect_success 'truncated bitmap fails gracefully (cache)' '
        test_i18ngrep corrupted.bitmap.index stderr
 '
 
-# Create a state of history with these properties:
-#
-#  - refs that allow a client to fetch some new history, while sharing some old
-#    history with the server; we use branches delta-reuse-old and
-#    delta-reuse-new here
-#
-#  - the new history contains an object that is stored on the server as a delta
-#    against a base that is in the old history
-#
-#  - the base object is not immediately reachable from the tip of the old
-#    history; finding it would involve digging down through history we know the
-#    other side has
-#
-# This should result in a state where fetching from old->new would not
-# traditionally reuse the on-disk delta (because we'd have to dig to realize
-# that the client has it), but we will do so if bitmaps can tell us cheaply
-# that the other side has it.
-test_expect_success 'set up thin delta-reuse parent' '
-       # This first commit contains the buried base object.
-       test-tool genrandom delta 16384 >file &&
-       git add file &&
-       git commit -m "delta base" &&
-       base=$(git rev-parse --verify HEAD:file) &&
-
-       # These intermediate commits bury the base back in history.
-       # This becomes the "old" state.
-       for i in 1 2 3 4 5
-       do
-               echo $i >file &&
-               git commit -am "intermediate $i" || return 1
-       done &&
-       git branch delta-reuse-old &&
-
-       # And now our new history has a delta against the buried base. Note
-       # that this must be smaller than the original file, since pack-objects
-       # prefers to create deltas from smaller objects to larger.
-       test-tool genrandom delta 16300 >file &&
-       git commit -am "delta result" &&
-       delta=$(git rev-parse --verify HEAD:file) &&
-       git branch delta-reuse-new &&
-
-       # Repack with bitmaps and double check that we have the expected delta
-       # relationship.
-       git repack -adb &&
-       have_delta $delta $base
-'
-
-# Now we can sanity-check the non-bitmap behavior (that the server is not able
-# to reuse the delta). This isn't strictly something we care about, so this
-# test could be scrapped in the future. But it makes sure that the next test is
-# actually triggering the feature we want.
-#
-# Note that our tools for working with on-the-wire "thin" packs are limited. So
-# we actually perform the fetch, retain the resulting pack, and inspect the
-# result.
-test_expect_success 'fetch without bitmaps ignores delta against old base' '
-       test_config pack.usebitmaps false &&
-       test_when_finished "rm -rf client.git" &&
-       git init --bare client.git &&
-       (
-               cd client.git &&
-               git config transfer.unpackLimit 1 &&
-               git fetch .. delta-reuse-old:delta-reuse-old &&
-               git fetch .. delta-reuse-new:delta-reuse-new &&
-               have_delta $delta $ZERO_OID
-       )
-'
-
-# And do the same for the bitmap case, where we do expect to find the delta.
-test_expect_success 'fetch with bitmaps can reuse old base' '
-       test_config pack.usebitmaps true &&
-       test_when_finished "rm -rf client.git" &&
-       git init --bare client.git &&
-       (
-               cd client.git &&
-               git config transfer.unpackLimit 1 &&
-               git fetch .. delta-reuse-old:delta-reuse-old &&
-               git fetch .. delta-reuse-new:delta-reuse-new &&
-               have_delta $delta $base
-       )
-'
-
-test_expect_success 'pack.preferBitmapTips' '
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
-
-               # create enough commits that not all are receive bitmap
-               # coverage even if they are all at the tip of some reference.
-               test_commit_bulk --message="%s" 103 &&
-
-               git rev-list HEAD >commits.raw &&
-               sort <commits.raw >commits &&
-
-               git log --format="create refs/tags/%s %H" HEAD >refs &&
-               git update-ref --stdin <refs &&
-
-               git repack -adb &&
-               test-tool bitmap list-commits | sort >bitmaps &&
-
-               # remember which commits did not receive bitmaps
-               comm -13 bitmaps commits >before &&
-               test_file_not_empty before &&
-
-               # mark the commits which did not receive bitmaps as preferred,
-               # and generate the bitmap again
-               perl -pe "s{^}{create refs/tags/include/$. }" <before |
-                       git update-ref --stdin &&
-               git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
-
-               # finally, check that the commit(s) without bitmap coverage
-               # are not the same ones as before
-               test-tool bitmap list-commits | sort >bitmaps &&
-               comm -13 bitmaps commits >after &&
-
-               ! test_cmp before after
-       )
-'
-
-test_expect_success 'complains about multiple pack bitmaps' '
-       rm -fr repo &&
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
-
-               test_commit base &&
-
-               git repack -adb &&
-               bitmap="$(ls .git/objects/pack/pack-*.bitmap)" &&
-               mv "$bitmap" "$bitmap.bak" &&
-
-               test_commit other &&
-               git repack -ab &&
-
-               mv "$bitmap.bak" "$bitmap" &&
-
-               find .git/objects/pack -type f -name "*.pack" >packs &&
-               find .git/objects/pack -type f -name "*.bitmap" >bitmaps &&
-               test_line_count = 2 packs &&
-               test_line_count = 2 bitmaps &&
-
-               git rev-list --use-bitmap-index HEAD 2>err &&
-               grep "ignoring extra bitmap file" err
-       )
-'
-
 test_done
index 872a95df3383742e392ef3750be3dfcbecb01ec8..9dae60f73e3253bbb4b44355535c8cf1ebc58be8 100755 (executable)
@@ -17,23 +17,40 @@ test_description='check bitmap operation with shallow repositories'
 # the tree for A. But in a shallow one, we've grafted away
 # A, and fetching A to B requires that the other side send
 # us the tree for file=1.
-test_expect_success 'setup shallow repo' '
-       echo 1 >file &&
-       git add file &&
-       git commit -m orig &&
-       echo 2 >file &&
-       git commit -a -m update &&
-       git clone --no-local --bare --depth=1 . shallow.git &&
-       echo 1 >file &&
-       git commit -a -m repeat
-'
-
-test_expect_success 'turn on bitmaps in the parent' '
-       git repack -adb
-'
-
-test_expect_success 'shallow fetch from bitmapped repo' '
-       (cd shallow.git && git fetch)
-'
+test_shallow_bitmaps () {
+       writeLookupTable=false
+
+       for i in "$@"
+       do
+               case $i in
+               "pack.writeBitmapLookupTable") writeLookupTable=true;;
+               esac
+       done
+
+       test_expect_success 'setup shallow repo' '
+               rm -rf * .git &&
+               git init &&
+               git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+               echo 1 >file &&
+               git add file &&
+               git commit -m orig &&
+               echo 2 >file &&
+               git commit -a -m update &&
+               git clone --no-local --bare --depth=1 . shallow.git &&
+               echo 1 >file &&
+               git commit -a -m repeat
+       '
+
+       test_expect_success 'turn on bitmaps in the parent' '
+               git repack -adb
+       '
+
+       test_expect_success 'shallow fetch from bitmapped repo' '
+               (cd shallow.git && git fetch)
+       '
+}
+
+test_shallow_bitmaps
+test_shallow_bitmaps "pack.writeBitmapLookupTable"
 
 test_done
index 0aec8619e22dc97c9ec7d78c7e136fb388034fc7..73a241743aa50101c032b53566de7ba2e7a3b410 100755 (executable)
@@ -49,9 +49,9 @@ Then no matter which order we start looking at the packs in, we know that we
 will always find a delta for "file", because its lookup will always come
 immediately after the lookup for "dummy".
 '
-. ./test-lib.sh
-
 
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
 
 # Create a pack containing the tree $1 and blob $1:file, with
 # the latter stored as a delta against $2:file.
index 8bacd96275b0ac881b9202ecaff83394ca562dd2..c80ea9e8b71ee8707c8c1cc4020fb83a1b90029f 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='pack-object compression configuration'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index db89542dfb3fe93dad02b90cf5ced1b46ee96a15..049c5fc8ead328860ef7ed38dea410f4524107c9 100755 (executable)
@@ -12,12 +12,12 @@ test_expect_success 'usage' '
 
 test_expect_success 'usage shown without sub-command' '
        test_expect_code 129 git commit-graph 2>err &&
-       ! grep error: err
+       grep usage: err
 '
 
 test_expect_success 'usage shown with an error on unknown sub-command' '
        cat >expect <<-\EOF &&
-       error: unrecognized subcommand: unknown
+       error: unknown subcommand: `unknown'\''
        EOF
        test_expect_code 129 git commit-graph unknown 2>stderr &&
        grep error stderr >actual &&
@@ -361,13 +361,14 @@ test_expect_success 'replace-objects invalidates commit-graph' '
 test_expect_success 'commit grafts invalidate commit-graph' '
        cd "$TRASH_DIRECTORY" &&
        test_when_finished rm -rf graft &&
-       git clone full graft &&
+       git clone --template= full graft &&
        (
                cd graft &&
                git commit-graph write --reachable &&
                test_path_is_file .git/objects/info/commit-graph &&
                H1=$(git rev-parse --verify HEAD~1) &&
                H3=$(git rev-parse --verify HEAD~3) &&
+               mkdir .git/info &&
                echo "$H1 $H3" >.git/info/grafts &&
                git -c core.commitGraph=false log >expect &&
                git -c core.commitGraph=true log >actual &&
index 124d47603df4ae71a9a1eeee9059752855f6860b..406363381f10bcc6ee4f8040afadcc362d85fc29 100755 (executable)
@@ -134,7 +134,7 @@ test_expect_success 'island core places core objects first' '
            repack -adfi &&
        git verify-pack -v .git/objects/pack/*.pack |
        cut -d" " -f1 |
-       egrep "$root|$two" >actual &&
+       grep -E "$root|$two" >actual &&
        test_cmp expect actual
 '
 
index 8a56d98a0e88cef9add7d5603730daf3c6e91897..70770fe274d84fca1d988c1d4dfd7457943363ee 100755 (executable)
@@ -6,6 +6,8 @@
 test_description='git pack-object with "large" deltas
 
 '
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-pack.sh
 
index 4fe57414c13caca90d862b417ad5471cab28ee12..ad6eea5fa0f20a4e9a72612eee4b3c22729a0da8 100755 (executable)
@@ -15,17 +15,24 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 sane_unset GIT_TEST_MIDX_WRITE_REV
 sane_unset GIT_TEST_MIDX_READ_RIDX
 
-midx_bitmap_core
-
 bitmap_reuse_tests() {
        from=$1
        to=$2
+       writeLookupTable=false
+
+       for i in $3-${$#}
+       do
+               case $i in
+               "pack.writeBitmapLookupTable") writeLookupTable=true;;
+               esac
+       done
 
        test_expect_success "setup pack reuse tests ($from -> $to)" '
                rm -fr repo &&
                git init repo &&
                (
                        cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
                        test_commit_bulk 16 &&
                        git tag old-tip &&
 
@@ -43,6 +50,7 @@ bitmap_reuse_tests() {
        test_expect_success "build bitmap from existing ($from -> $to)" '
                (
                        cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
                        test_commit_bulk --id=further 16 &&
                        git tag new-tip &&
 
@@ -59,6 +67,7 @@ bitmap_reuse_tests() {
        test_expect_success "verify resulting bitmaps ($from -> $to)" '
                (
                        cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
                        git for-each-ref &&
                        git rev-list --test-bitmap refs/tags/old-tip &&
                        git rev-list --test-bitmap refs/tags/new-tip
@@ -66,244 +75,338 @@ bitmap_reuse_tests() {
        '
 }
 
-bitmap_reuse_tests 'pack' 'MIDX'
-bitmap_reuse_tests 'MIDX' 'pack'
-bitmap_reuse_tests 'MIDX' 'MIDX'
+test_midx_bitmap_cases () {
+       writeLookupTable=false
+       writeBitmapLookupTable=
+
+       for i in "$@"
+       do
+               case $i in
+               "pack.writeBitmapLookupTable")
+                       writeLookupTable=true
+                       writeBitmapLookupTable="$i"
+                       ;;
+               esac
+       done
+
+       test_expect_success 'setup test_repository' '
+               rm -rf * .git &&
+               git init &&
+               git config pack.writeBitmapLookupTable '"$writeLookupTable"'
+       '
 
-test_expect_success 'missing object closure fails gracefully' '
-       rm -fr repo &&
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
+       midx_bitmap_core
 
-               test_commit loose &&
-               test_commit packed &&
+       bitmap_reuse_tests 'pack' 'MIDX' "$writeBitmapLookupTable"
+       bitmap_reuse_tests 'MIDX' 'pack' "$writeBitmapLookupTable"
+       bitmap_reuse_tests 'MIDX' 'MIDX' "$writeBitmapLookupTable"
 
-               # Do not pass "--revs"; we want a pack without the "loose"
-               # commit.
-               git pack-objects $objdir/pack/pack <<-EOF &&
-               $(git rev-parse packed)
-               EOF
+       test_expect_success 'missing object closure fails gracefully' '
+               rm -fr repo &&
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-               test_must_fail git multi-pack-index write --bitmap 2>err &&
-               grep "doesn.t have full closure" err &&
-               test_path_is_missing $midx
-       )
-'
+                       test_commit loose &&
+                       test_commit packed &&
 
-midx_bitmap_partial_tests
+                       # Do not pass "--revs"; we want a pack without the "loose"
+                       # commit.
+                       git pack-objects $objdir/pack/pack <<-EOF &&
+                       $(git rev-parse packed)
+                       EOF
 
-test_expect_success 'removing a MIDX clears stale bitmaps' '
-       rm -fr repo &&
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
-               test_commit base &&
-               git repack &&
-               git multi-pack-index write --bitmap &&
+                       test_must_fail git multi-pack-index write --bitmap 2>err &&
+                       grep "doesn.t have full closure" err &&
+                       test_path_is_missing $midx
+               )
+       '
 
-               # Write a MIDX and bitmap; remove the MIDX but leave the bitmap.
-               stale_bitmap=$midx-$(midx_checksum $objdir).bitmap &&
-               rm $midx &&
+       midx_bitmap_partial_tests
 
-               # Then write a new MIDX.
-               test_commit new &&
-               git repack &&
-               git multi-pack-index write --bitmap &&
+       test_expect_success 'removing a MIDX clears stale bitmaps' '
+               rm -fr repo &&
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
+                       test_commit base &&
+                       git repack &&
+                       git multi-pack-index write --bitmap &&
+
+                       # Write a MIDX and bitmap; remove the MIDX but leave the bitmap.
+                       stale_bitmap=$midx-$(midx_checksum $objdir).bitmap &&
+                       rm $midx &&
+
+                       # Then write a new MIDX.
+                       test_commit new &&
+                       git repack &&
+                       git multi-pack-index write --bitmap &&
+
+                       test_path_is_file $midx &&
+                       test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+                       test_path_is_missing $stale_bitmap
+               )
+       '
 
-               test_path_is_file $midx &&
-               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
-               test_path_is_missing $stale_bitmap
-       )
-'
+       test_expect_success 'pack.preferBitmapTips' '
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-test_expect_success 'pack.preferBitmapTips' '
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
+                       test_commit_bulk --message="%s" 103 &&
 
-               test_commit_bulk --message="%s" 103 &&
+                       git log --format="%H" >commits.raw &&
+                       sort <commits.raw >commits &&
 
-               git log --format="%H" >commits.raw &&
-               sort <commits.raw >commits &&
+                       git log --format="create refs/tags/%s %H" HEAD >refs &&
+                       git update-ref --stdin <refs &&
 
-               git log --format="create refs/tags/%s %H" HEAD >refs &&
-               git update-ref --stdin <refs &&
+                       git multi-pack-index write --bitmap &&
+                       test_path_is_file $midx &&
+                       test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
 
-               git multi-pack-index write --bitmap &&
-               test_path_is_file $midx &&
-               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       comm -13 bitmaps commits >before &&
+                       test_line_count = 1 before &&
 
-               test-tool bitmap list-commits | sort >bitmaps &&
-               comm -13 bitmaps commits >before &&
-               test_line_count = 1 before &&
+                       perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
+                               <before | git update-ref --stdin &&
 
-               perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \
-                       <before | git update-ref --stdin &&
+                       rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+                       rm -fr $midx &&
 
-               rm -fr $midx-$(midx_checksum $objdir).bitmap &&
-               rm -fr $midx &&
+                       git -c pack.preferBitmapTips=refs/tags/include \
+                               multi-pack-index write --bitmap &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       comm -13 bitmaps commits >after &&
 
-               git -c pack.preferBitmapTips=refs/tags/include \
-                       multi-pack-index write --bitmap &&
-               test-tool bitmap list-commits | sort >bitmaps &&
-               comm -13 bitmaps commits >after &&
+                       ! test_cmp before after
+               )
+       '
 
-               ! test_cmp before after
-       )
-'
+       test_expect_success 'writing a bitmap with --refs-snapshot' '
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-test_expect_success 'writing a bitmap with --refs-snapshot' '
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
+                       test_commit one &&
+                       test_commit two &&
 
-               test_commit one &&
-               test_commit two &&
+                       git rev-parse one >snapshot &&
 
-               git rev-parse one >snapshot &&
+                       git repack -ad &&
 
-               git repack -ad &&
+                       # First, write a MIDX which see both refs/tags/one and
+                       # refs/tags/two (causing both of those commits to receive
+                       # bitmaps).
+                       git multi-pack-index write --bitmap &&
 
-               # First, write a MIDX which see both refs/tags/one and
-               # refs/tags/two (causing both of those commits to receive
-               # bitmaps).
-               git multi-pack-index write --bitmap &&
+                       test_path_is_file $midx &&
+                       test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
 
-               test_path_is_file $midx &&
-               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       grep "$(git rev-parse one)" bitmaps &&
+                       grep "$(git rev-parse two)" bitmaps &&
 
-               test-tool bitmap list-commits | sort >bitmaps &&
-               grep "$(git rev-parse one)" bitmaps &&
-               grep "$(git rev-parse two)" bitmaps &&
+                       rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+                       rm -fr $midx &&
 
-               rm -fr $midx-$(midx_checksum $objdir).bitmap &&
-               rm -fr $midx &&
+                       # Then again, but with a refs snapshot which only sees
+                       # refs/tags/one.
+                       git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
 
-               # Then again, but with a refs snapshot which only sees
-               # refs/tags/one.
-               git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+                       test_path_is_file $midx &&
+                       test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
 
-               test_path_is_file $midx &&
-               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       grep "$(git rev-parse one)" bitmaps &&
+                       ! grep "$(git rev-parse two)" bitmaps
+               )
+       '
 
-               test-tool bitmap list-commits | sort >bitmaps &&
-               grep "$(git rev-parse one)" bitmaps &&
-               ! grep "$(git rev-parse two)" bitmaps
-       )
-'
+       test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' '
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' '
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
+                       test_commit_bulk --message="%s" 103 &&
 
-               test_commit_bulk --message="%s" 103 &&
+                       git log --format="%H" >commits.raw &&
+                       sort <commits.raw >commits &&
 
-               git log --format="%H" >commits.raw &&
-               sort <commits.raw >commits &&
+                       git log --format="create refs/tags/%s %H" HEAD >refs &&
+                       git update-ref --stdin <refs &&
 
-               git log --format="create refs/tags/%s %H" HEAD >refs &&
-               git update-ref --stdin <refs &&
+                       git multi-pack-index write --bitmap &&
+                       test_path_is_file $midx &&
+                       test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
 
-               git multi-pack-index write --bitmap &&
-               test_path_is_file $midx &&
-               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       comm -13 bitmaps commits >before &&
+                       test_line_count = 1 before &&
+
+                       (
+                               grep -vf before commits.raw &&
+                               # mark missing commits as preferred
+                               sed "s/^/+/" before
+                       ) >snapshot &&
+
+                       rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+                       rm -fr $midx &&
 
-               test-tool bitmap list-commits | sort >bitmaps &&
-               comm -13 bitmaps commits >before &&
-               test_line_count = 1 before &&
+                       git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+                       test-tool bitmap list-commits | sort >bitmaps &&
+                       comm -13 bitmaps commits >after &&
 
+                       ! test_cmp before after
+               )
+       '
+
+       test_expect_success 'hash-cache values are propagated from pack bitmaps' '
+               rm -fr repo &&
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
                (
-                       grep -vf before commits.raw &&
-                       # mark missing commits as preferred
-                       sed "s/^/+/" before
-               ) >snapshot &&
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-               rm -fr $midx-$(midx_checksum $objdir).bitmap &&
-               rm -fr $midx &&
+                       test_commit base &&
+                       test_commit base2 &&
+                       git repack -adb &&
 
-               git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
-               test-tool bitmap list-commits | sort >bitmaps &&
-               comm -13 bitmaps commits >after &&
+                       test-tool bitmap dump-hashes >pack.raw &&
+                       test_file_not_empty pack.raw &&
+                       sort pack.raw >pack.hashes &&
 
-               ! test_cmp before after
-       )
-'
+                       test_commit new &&
+                       git repack &&
+                       git multi-pack-index write --bitmap &&
 
-test_expect_success 'hash-cache values are propagated from pack bitmaps' '
-       rm -fr repo &&
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
+                       test-tool bitmap dump-hashes >midx.raw &&
+                       sort midx.raw >midx.hashes &&
 
-               test_commit base &&
-               test_commit base2 &&
-               git repack -adb &&
+                       # ensure that every namehash in the pack bitmap can be found in
+                       # the midx bitmap (i.e., that there are no oid-namehash pairs
+                       # unique to the pack bitmap).
+                       comm -23 pack.hashes midx.hashes >dropped.hashes &&
+                       test_must_be_empty dropped.hashes
+               )
+       '
 
-               test-tool bitmap dump-hashes >pack.raw &&
-               test_file_not_empty pack.raw &&
-               sort pack.raw >pack.hashes &&
+       test_expect_success 'no .bitmap is written without any objects' '
+               rm -fr repo &&
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-               test_commit new &&
-               git repack &&
-               git multi-pack-index write --bitmap &&
+                       empty="$(git pack-objects $objdir/pack/pack </dev/null)" &&
+                       cat >packs <<-EOF &&
+                       pack-$empty.idx
+                       EOF
 
-               test-tool bitmap dump-hashes >midx.raw &&
-               sort midx.raw >midx.hashes &&
+                       git multi-pack-index write --bitmap --stdin-packs \
+                               <packs 2>err &&
 
-               # ensure that every namehash in the pack bitmap can be found in
-               # the midx bitmap (i.e., that there are no oid-namehash pairs
-               # unique to the pack bitmap).
-               comm -23 pack.hashes midx.hashes >dropped.hashes &&
-               test_must_be_empty dropped.hashes
-       )
-'
+                       grep "bitmap without any objects" err &&
 
-test_expect_success 'no .bitmap is written without any objects' '
-       rm -fr repo &&
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
-               cd repo &&
+                       test_path_is_file $midx &&
+                       test_path_is_missing $midx-$(midx_checksum $objdir).bitmap
+               )
+       '
+
+       test_expect_success 'graceful fallback when missing reverse index' '
+               rm -fr repo &&
+               git init repo &&
+               test_when_finished "rm -fr repo" &&
+               (
+                       cd repo &&
+                       git config pack.writeBitmapLookupTable '"$writeLookupTable"' &&
 
-               empty="$(git pack-objects $objdir/pack/pack </dev/null)" &&
-               cat >packs <<-EOF &&
-               pack-$empty.idx
-               EOF
+                       test_commit base &&
 
-               git multi-pack-index write --bitmap --stdin-packs \
-                       <packs 2>err &&
+                       # write a pack and MIDX bitmap containing base
+                       git repack -adb &&
+                       git multi-pack-index write --bitmap &&
 
-               grep "bitmap without any objects" err &&
+                       GIT_TEST_MIDX_READ_RIDX=0 \
+                               git rev-list --use-bitmap-index HEAD 2>err &&
+                       ! grep "ignoring extra bitmap file" err
+               )
+       '
+}
 
-               test_path_is_file $midx &&
-               test_path_is_missing $midx-$(midx_checksum $objdir).bitmap
-       )
-'
+test_midx_bitmap_cases
 
-test_expect_success 'graceful fallback when missing reverse index' '
+test_midx_bitmap_cases "pack.writeBitmapLookupTable"
+
+test_expect_success 'multi-pack-index write writes lookup table if enabled' '
        rm -fr repo &&
        git init repo &&
        test_when_finished "rm -fr repo" &&
        (
                cd repo &&
+               test_commit base &&
+               git config pack.writeBitmapLookupTable true &&
+               git repack -ad &&
+               GIT_TRACE2_EVENT="$(pwd)/trace" \
+                       git multi-pack-index write --bitmap &&
+               grep "\"label\":\"writing_lookup_table\"" trace
+       )
+'
+
+test_expect_success 'preferred pack change with existing MIDX bitmap' '
+       git init preferred-pack-with-existing &&
+       (
+               cd preferred-pack-with-existing &&
 
                test_commit base &&
+               test_commit other &&
+
+               git rev-list --objects --no-object-names base >p1.objects &&
+               git rev-list --objects --no-object-names other >p2.objects &&
 
-               # write a pack and MIDX bitmap containing base
-               git repack -adb &&
-               git multi-pack-index write --bitmap &&
+               p1="$(git pack-objects "$objdir/pack/pack" \
+                       --delta-base-offset <p1.objects)" &&
+               p2="$(git pack-objects "$objdir/pack/pack" \
+                       --delta-base-offset <p2.objects)" &&
+
+               # Generate a MIDX containing the first two packs,
+               # marking p1 as preferred, and ensure that it can be
+               # successfully cloned.
+               git multi-pack-index write --bitmap \
+                       --preferred-pack="pack-$p1.pack" &&
+               test_path_is_file $midx &&
+               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+               git clone --no-local . clone1 &&
+
+               # Then generate a new pack which sorts ahead of any
+               # existing pack (by tweaking the pack prefix).
+               test_commit foo &&
+               git pack-objects --all --unpacked $objdir/pack/pack0 &&
+
+               # Generate a new MIDX which changes the preferred pack
+               # to a pack contained in the existing MIDX.
+               git multi-pack-index write --bitmap \
+                       --preferred-pack="pack-$p2.pack" &&
+               test_path_is_file $midx &&
+               test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
 
-               GIT_TEST_MIDX_READ_RIDX=0 \
-                       git rev-list --use-bitmap-index HEAD 2>err &&
-               ! grep "ignoring extra bitmap file" err
+               # When the above circumstances are met, the preferred
+               # pack should change appropriately and clones should
+               # (still) succeed.
+               git clone --no-local . clone2
        )
 '
 
index d30ba632c87c072b591cb085061a4d6f2dcb1c0b..e65e311cd73aec492ac0850cd6e79d126415ac36 100755 (executable)
@@ -17,7 +17,27 @@ GIT_TEST_MIDX_READ_RIDX=0
 export GIT_TEST_MIDX_WRITE_REV
 export GIT_TEST_MIDX_READ_RIDX
 
-midx_bitmap_core rev
-midx_bitmap_partial_tests rev
+test_midx_bitmap_rev () {
+       writeLookupTable=false
+
+       for i in "$@"
+       do
+               case $i in
+               "pack.writeBitmapLookupTable") writeLookupTable=true;;
+               esac
+       done
+
+       test_expect_success 'setup bitmap config' '
+               rm -rf * .git &&
+               git init &&
+               git config pack.writeBitmapLookupTable '"$writeLookupTable"'
+       '
+
+       midx_bitmap_core rev
+       midx_bitmap_partial_tests rev
+}
+
+test_midx_bitmap_rev
+test_midx_bitmap_rev "pack.writeBitmapLookupTable"
 
 test_done
index 8968f7a08d8700bb22aec956e3f8e50ab2f376bd..303f7a5d842d36edb191bb05ec61df9a6af8d7c9 100755 (executable)
@@ -29,7 +29,8 @@ basic_cruft_pack_tests () {
                                while read oid
                                do
                                        path="$objdir/$(test_oid_to_path "$oid")" &&
-                                       printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")"
+                                       printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" ||
+                                       echo "object list generation failed for $oid"
                                done |
                                sort -k1
                        ) >expect &&
@@ -232,7 +233,7 @@ test_expect_success 'cruft tags rescue tagged objects' '
                while read oid
                do
                        test-tool chmtime -1000 \
-                               "$objdir/$(test_oid_to_path $oid)"
+                               "$objdir/$(test_oid_to_path $oid)" || exit 1
                done <objects &&
 
                test-tool chmtime -500 \
@@ -272,7 +273,7 @@ test_expect_success 'cruft commits rescue parents, trees' '
                while read object
                do
                        test-tool chmtime -1000 \
-                               "$objdir/$(test_oid_to_path $object)"
+                               "$objdir/$(test_oid_to_path $object)" || exit 1
                done <objects &&
                test-tool chmtime +500 "$objdir/$(test_oid_to_path \
                        $(git rev-parse HEAD))" &&
@@ -345,7 +346,7 @@ test_expect_success 'expired objects are pruned' '
                while read object
                do
                        test-tool chmtime -1000 \
-                               "$objdir/$(test_oid_to_path $object)"
+                               "$objdir/$(test_oid_to_path $object)" || exit 1
                done <objects &&
 
                keep="$(basename "$(ls $packdir/pack-*.pack)")" &&
diff --git a/t/t5351-unpack-large-objects.sh b/t/t5351-unpack-large-objects.sh
new file mode 100755 (executable)
index 0000000..8c8af99
--- /dev/null
@@ -0,0 +1,103 @@
+#!/bin/sh
+#
+# Copyright (c) 2022 Han Xin
+#
+
+test_description='git unpack-objects with large objects'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+prepare_dest () {
+       test_when_finished "rm -rf dest.git" &&
+       git init --bare dest.git &&
+       git -C dest.git config core.bigFileThreshold "$1"
+}
+
+test_expect_success "create large objects (1.5 MB) and PACK" '
+       test-tool genrandom foo 1500000 >big-blob &&
+       test_commit --append foo big-blob &&
+       test-tool genrandom bar 1500000 >big-blob &&
+       test_commit --append bar big-blob &&
+       PACK=$(echo HEAD | git pack-objects --revs pack) &&
+       git verify-pack -v pack-$PACK.pack >out &&
+       sed -n -e "s/^\([0-9a-f][0-9a-f]*\).*\(commit\|tree\|blob\).*/\1/p" \
+               <out >obj-list
+'
+
+test_expect_success 'set memory limitation to 1MB' '
+       GIT_ALLOC_LIMIT=1m &&
+       export GIT_ALLOC_LIMIT
+'
+
+test_expect_success 'unpack-objects failed under memory limitation' '
+       prepare_dest 2m &&
+       test_must_fail git -C dest.git unpack-objects <pack-$PACK.pack 2>err &&
+       grep "fatal: attempting to allocate" err
+'
+
+test_expect_success 'unpack-objects works with memory limitation in dry-run mode' '
+       prepare_dest 2m &&
+       git -C dest.git unpack-objects -n <pack-$PACK.pack &&
+       test_stdout_line_count = 0 find dest.git/objects -type f &&
+       test_dir_is_empty dest.git/objects/pack
+'
+
+test_expect_success 'unpack big object in stream' '
+       prepare_dest 1m &&
+       git -C dest.git unpack-objects <pack-$PACK.pack &&
+       test_dir_is_empty dest.git/objects/pack
+'
+
+check_fsync_events () {
+       local trace="$1" &&
+       shift &&
+
+       cat >expect &&
+       sed -n \
+               -e '/^{"event":"data",.*"category":"fsync",/ {
+                       s/.*"category":"fsync",//;
+                       s/}$//;
+                       p;
+               }' \
+               <"$trace" >actual &&
+       test_cmp expect actual
+}
+
+BATCH_CONFIGURATION='-c core.fsync=loose-object -c core.fsyncmethod=batch'
+
+test_expect_success 'unpack big object in stream (core.fsyncmethod=batch)' '
+       prepare_dest 1m &&
+       GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+       GIT_TEST_FSYNC=true \
+               git -C dest.git $BATCH_CONFIGURATION unpack-objects <pack-$PACK.pack &&
+       if grep "core.fsyncMethod = batch is unsupported" trace2.txt
+       then
+               flush_count=7
+       else
+               flush_count=1
+       fi &&
+       check_fsync_events trace2.txt <<-EOF &&
+       "key":"fsync/writeout-only","value":"6"
+       "key":"fsync/hardware-flush","value":"$flush_count"
+       EOF
+
+       test_dir_is_empty dest.git/objects/pack &&
+       git -C dest.git cat-file --batch-check="%(objectname)" <obj-list >current &&
+       cmp obj-list current
+'
+
+test_expect_success 'do not unpack existing large objects' '
+       prepare_dest 1m &&
+       git -C dest.git index-pack --stdin <pack-$PACK.pack &&
+       git -C dest.git unpack-objects <pack-$PACK.pack &&
+
+       # The destination came up with the exact same pack...
+       DEST_PACK=$(echo dest.git/objects/pack/pack-*.pack) &&
+       cmp pack-$PACK.pack $DEST_PACK &&
+
+       # ...and wrote no loose objects
+       test_stdout_line_count = 0 find dest.git/objects -type f ! -name "pack-*"
+'
+
+test_done
index 915af2de95e162a9581ca23a6efb229737e665a6..46ebdfbeebaf522281e8e4aa4c68e9fb33ca8513 100755 (executable)
@@ -7,6 +7,7 @@ test_description='Test the post-merge hook.'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index ee6d2dde9f35677fb9c83a228839bb7ad405a4fa..d18f2823d86e8b94c5331b1087f962469fc91f2c 100755 (executable)
@@ -407,6 +407,7 @@ test_expect_success 'in_vain not triggered before first ACK' '
 '
 
 test_expect_success 'in_vain resetted upon ACK' '
+       test_when_finished rm -f log trace2 &&
        rm -rf myserver myclient &&
        git init myserver &&
 
@@ -432,7 +433,8 @@ test_expect_success 'in_vain resetted upon ACK' '
        # first. The 256th commit is common between the client and the server,
        # and should reset in_vain. This allows negotiation to continue until
        # the client reports that first_anotherbranch_commit is common.
-       git -C myclient fetch --progress origin main 2>log &&
+       GIT_TRACE2_EVENT="$(pwd)/trace2" git -C myclient fetch --progress origin main 2>log &&
+       grep \"key\":\"total_rounds\",\"value\":\"6\" trace2 &&
        test_i18ngrep "Total 3 " log
 '
 
index 195fc64dd44ae74c1546698e111f1a19c07dbb04..5ebbaa489689dce28d1b47e16b73e19e25183c5f 100755 (executable)
@@ -5,6 +5,7 @@ test_description='test automatic tag following'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # End state of the repository:
index fff14e13ed43b385f1ce7c0d01c0bea815c954d5..9006196ac601e8f93f046b54eafe11aa9df58563 100755 (executable)
@@ -241,6 +241,26 @@ test_expect_success 'add invalid foreign_vcs remote' '
        test_cmp expect actual
 '
 
+test_expect_success 'without subcommand' '
+       echo origin >expect &&
+       git -C test remote >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'without subcommand accepts -v' '
+       cat >expect <<-EOF &&
+       origin  $(pwd)/one (fetch)
+       origin  $(pwd)/one (push)
+       EOF
+       git -C test remote -v >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'without subcommand does not take arguments' '
+       test_expect_code 129 git -C test remote origin 2>err &&
+       grep "^error: unknown subcommand:" err
+'
+
 cat >test/expect <<EOF
 * remote origin
   Fetch URL: $(pwd)/one
@@ -302,6 +322,52 @@ test_expect_success 'show' '
        )
 '
 
+cat >expect <<EOF
+* remote origin
+  Fetch URL: $(pwd)/one
+  Push  URL: $(pwd)/one
+  HEAD branch: main
+  Remote branches:
+    main skipped
+    side tracked
+  Local branches configured for 'git pull':
+    ahead merges with remote main
+    main  merges with remote main
+  Local refs configured for 'git push':
+    main pushes to main     (local out of date)
+    main pushes to upstream (create)
+EOF
+
+test_expect_success 'show with negative refspecs' '
+       test_when_finished "git -C test config --unset-all --fixed-value remote.origin.fetch ^refs/heads/main" &&
+       git -C test config --add remote.origin.fetch ^refs/heads/main &&
+       git -C test remote show origin >output &&
+       test_cmp expect output
+'
+
+cat >expect <<EOF
+* remote origin
+  Fetch URL: $(pwd)/one
+  Push  URL: $(pwd)/one
+  HEAD branch: main
+  Remote branches:
+    main new (next fetch will store in remotes/origin)
+    side stale (use 'git remote prune' to remove)
+  Local branches configured for 'git pull':
+    ahead merges with remote main
+    main  merges with remote main
+  Local refs configured for 'git push':
+    main pushes to main     (local out of date)
+    main pushes to upstream (create)
+EOF
+
+test_expect_failure 'show stale with negative refspecs' '
+       test_when_finished "git -C test config --unset-all --fixed-value remote.origin.fetch ^refs/heads/side" &&
+       git -C test config --add remote.origin.fetch ^refs/heads/side &&
+       git -C test remote show origin >output &&
+       test_cmp expect output
+'
+
 cat >test/expect <<EOF
 * remote origin
   Fetch URL: $(pwd)/one
@@ -957,11 +1023,12 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
 '
 
 test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
-       git clone one six &&
+       git clone --template= one six &&
        origin_url=$(pwd)/one &&
        (
                cd six &&
                git remote rm origin &&
+               mkdir .git/branches &&
                echo "$origin_url#main" >.git/branches/origin &&
                git remote rename origin origin &&
                test_path_is_missing .git/branches/origin &&
@@ -972,10 +1039,11 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
 '
 
 test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' '
-       git clone one seven &&
+       git clone --template= one seven &&
        (
                cd seven &&
                git remote rm origin &&
+               mkdir .git/branches &&
                echo "quux#foom" > .git/branches/origin &&
                git remote rename origin origin &&
                test_path_is_missing .git/branches/origin &&
index 541adbb31034f11820c77972719258ef49131353..3211002d466867fb2abb99eeff897029a7fdfa71 100755 (executable)
@@ -18,6 +18,7 @@ This test checks the following functionality:
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 D=$(pwd)
@@ -26,7 +27,8 @@ mk_empty () {
        repo_name="$1"
        test_when_finished "rm -rf \"$repo_name\"" &&
        test_path_is_missing "$repo_name" &&
-       git init "$repo_name" &&
+       git init --template= "$repo_name" &&
+       mkdir "$repo_name"/.git/hooks &&
        git -C "$repo_name" config receive.denyCurrentBranch warn
 }
 
@@ -78,7 +80,7 @@ mk_test_with_hooks() {
 
 mk_child() {
        test_when_finished "rm -rf \"$2\"" &&
-       git clone "$1" "$2"
+       git clone --template= "$1" "$2"
 }
 
 check_push_result () {
@@ -198,7 +200,10 @@ test_expect_success 'push with negotiation' '
        test_commit -C testrepo unrelated_commit &&
        git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
        test_when_finished "rm event" &&
-       GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main &&
+       GIT_TRACE2_EVENT="$(pwd)/event" \
+               git -c protocol.version=2 -c push.negotiate=1 \
+               push testrepo refs/heads/main:refs/remotes/origin/main &&
+       grep \"key\":\"total_rounds\",\"value\":\"1\" event &&
        grep_wrote 2 event # 1 commit, 1 tree
 '
 
@@ -222,7 +227,10 @@ test_expect_success 'push with negotiation does not attempt to fetch submodules'
        git push testrepo $the_first_commit:refs/remotes/origin/first_commit &&
        test_commit -C testrepo unrelated_commit &&
        git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&
-       git -c submodule.recurse=true -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
+       GIT_TRACE2_EVENT="$(pwd)/event"  git -c submodule.recurse=true \
+               -c protocol.version=2 -c push.negotiate=1 \
+               push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&
+       grep \"key\":\"total_rounds\",\"value\":\"1\" event &&
        ! grep "Fetching submodule" err
 '
 
@@ -937,6 +945,7 @@ test_expect_success 'fetch with branches' '
        mk_empty testrepo &&
        git branch second $the_first_commit &&
        git checkout second &&
+       mkdir testrepo/.git/branches &&
        echo ".." > testrepo/.git/branches/branch1 &&
        (
                cd testrepo &&
@@ -950,6 +959,7 @@ test_expect_success 'fetch with branches' '
 
 test_expect_success 'fetch with branches containing #' '
        mk_empty testrepo &&
+       mkdir testrepo/.git/branches &&
        echo "..#second" > testrepo/.git/branches/branch2 &&
        (
                cd testrepo &&
@@ -964,7 +974,11 @@ test_expect_success 'fetch with branches containing #' '
 test_expect_success 'push with branches' '
        mk_empty testrepo &&
        git checkout second &&
+
+       test_when_finished "rm -rf .git/branches" &&
+       mkdir .git/branches &&
        echo "testrepo" > .git/branches/branch1 &&
+
        git push branch1 &&
        (
                cd testrepo &&
@@ -976,7 +990,11 @@ test_expect_success 'push with branches' '
 
 test_expect_success 'push with branches containing #' '
        mk_empty testrepo &&
+
+       test_when_finished "rm -rf .git/branches" &&
+       mkdir .git/branches &&
        echo "testrepo#branch3" > .git/branches/branch2 &&
+
        git push branch2 &&
        (
                cd testrepo &&
@@ -1865,4 +1883,26 @@ test_expect_success LIBCURL 'push warns or fails when using username:password' '
        test_line_count = 1 warnings
 '
 
+test_expect_success 'push with config push.useBitmaps' '
+       mk_test testrepo heads/main &&
+       git checkout main &&
+       test_unconfig push.useBitmaps &&
+       GIT_TRACE2_EVENT="$PWD/default" \
+       git push testrepo main:test &&
+       test_subcommand git pack-objects --all-progress-implied --revs --stdout \
+               --thin --delta-base-offset -q <default &&
+
+       test_config push.useBitmaps true &&
+       GIT_TRACE2_EVENT="$PWD/true" \
+       git push testrepo main:test2 &&
+       test_subcommand git pack-objects --all-progress-implied --revs --stdout \
+               --thin --delta-base-offset -q <true &&
+
+       test_config push.useBitmaps false &&
+       GIT_TRACE2_EVENT="$PWD/false" \
+       git push testrepo main:test3 &&
+       test_subcommand git pack-objects --all-progress-implied --revs --stdout \
+               --thin --delta-base-offset -q --no-use-bitmap-index <false
+'
+
 test_done
index 081808009b2e74aa4cb81a768a15701dd4eca9d5..0b72112fb10759bb1d5e9de912ae1b2038df1d00 100755 (executable)
@@ -218,6 +218,23 @@ test_expect_success 'fail if upstream branch does not exist' '
        test_cmp expect file
 '
 
+test_expect_success 'fetch upstream branch even if refspec excludes it' '
+       # the branch names are not important here except that
+       # the first one must not be a prefix of the second,
+       # since otherwise the ref-prefix protocol extension
+       # would match both
+       git branch in-refspec HEAD^ &&
+       git branch not-in-refspec HEAD &&
+       git init -b in-refspec downstream &&
+       git -C downstream remote add -t in-refspec origin "file://$(pwd)/.git" &&
+       git -C downstream config branch.in-refspec.remote origin &&
+       git -C downstream config branch.in-refspec.merge refs/heads/not-in-refspec &&
+       git -C downstream pull &&
+       git rev-parse --verify not-in-refspec >expect &&
+       git -C downstream rev-parse --verify HEAD >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'fail if the index has unresolved entries' '
        git checkout -b third second^ &&
        test_when_finished "git checkout -f copy && git branch -D third" &&
index b2be3605f5a3f0649879a31803b5fc7cfe40d8a1..56716e29ddf1c3ded4cfae0443ee60ffe4eb0945 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git pull message generation'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 dollar='$Dollar'
index 2f09ff4fac60e832ea86c4158740ce36e58d3132..fbad2d5ff5e9e3a7d23a9117b48edf0c9a2b59d8 100755 (executable)
@@ -80,6 +80,25 @@ test_expect_success 'push to remote repository (standard)' '
         test $HEAD = $(git rev-parse --verify HEAD))
 '
 
+test_expect_success 'push to remote repository (standard) with sending Accept-Language' '
+       cat >exp <<-\EOF &&
+       => Send header: Accept-Language: ko-KR, *;q=0.9
+       => Send header: Accept-Language: ko-KR, *;q=0.9
+       EOF
+
+       cd "$ROOT_PATH"/test_repo_clone &&
+       : >path_lang &&
+       git add path_lang &&
+       test_tick &&
+       git commit -m path_lang &&
+       HEAD=$(git rev-parse --verify HEAD) &&
+       GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" git push -v -v 2>err &&
+       ! grep "Expect: 100-continue" err &&
+
+       grep "=> Send header: Accept-Language:" err >err.language &&
+       test_cmp exp err.language
+'
+
 test_expect_success 'push already up-to-date' '
        git push
 '
index dd5f44d986f2f774313ca11e7a1bfecf87060e7e..54f54f8d2ebde39c846e1c193e93e13e8b509618 100755 (executable)
@@ -56,7 +56,12 @@ test_expect_success 'hook does not run from repo config' '
        ! grep "hook running" stderr &&
        test_path_is_missing .git/hook.args &&
        test_path_is_missing .git/hook.stdin &&
-       test_path_is_missing .git/hook.stdout
+       test_path_is_missing .git/hook.stdout &&
+
+       # check that global config is used instead
+       test_config_global uploadpack.packObjectsHook ./hook &&
+       git clone --no-local . dst2.git 2>stderr &&
+       grep "hook running" stderr
 '
 
 test_expect_success 'hook works with partial clone' '
index f0d9cd584d3b1865490994f6ce85a7917e3bf129..8f182a3cbfe73cbcf1d61cbf96c14b78cf25a168 100755 (executable)
@@ -234,7 +234,7 @@ test_expect_success 'http-fetch --packfile' '
                --index-pack-arg=--keep \
                "$HTTPD_URL"/dumb/repo_pack.git/$p >out &&
 
-       grep "^keep.[0-9a-f]\{16,\}$" out &&
+       grep -E "^keep.[0-9a-f]{16,}$" out &&
        cut -c6- out >packhash &&
 
        # Ensure that the expected files are generated
@@ -369,7 +369,7 @@ ja;q=0.95, zh;q=0.94, sv;q=0.93, pt;q=0.92, nb;q=0.91, *;q=0.90" \
                ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt:nb
 '
 
-test_expect_success 'git client does not send an empty Accept-Language' '
+test_expect_success 'git client send an empty Accept-Language' '
        GIT_TRACE_CURL=true LANGUAGE= git ls-remote "$HTTPD_URL/dumb/repo.git" 2>stderr &&
        ! grep "^=> Send header: Accept-Language:" stderr
 '
@@ -422,7 +422,8 @@ test_expect_success 'set up evil alternates scheme' '
        sha1=$(git -C "$victim" rev-parse HEAD) &&
 
        evil=$HTTPD_DOCUMENT_ROOT_PATH/evil.git &&
-       git init --bare "$evil" &&
+       git init --template= --bare "$evil" &&
+       mkdir "$evil/info" &&
        # do this by hand to avoid object existence check
        printf "%s\\t%s\\n" $sha1 refs/heads/main >"$evil/info/refs"
 '
index b9351a732f6ef0267b2f4698f458471e54a40a93..6a38294a47671dccdc81849e1385a8c6e0310488 100755 (executable)
@@ -31,6 +31,7 @@ test_expect_success 'clone http repository' '
        > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
        > Accept: */*
        > Accept-Encoding: ENCODINGS
+       > Accept-Language: ko-KR, *;q=0.9
        > Pragma: no-cache
        < HTTP/1.1 200 OK
        < Pragma: no-cache
@@ -40,13 +41,15 @@ test_expect_success 'clone http repository' '
        > Accept-Encoding: ENCODINGS
        > Content-Type: application/x-git-upload-pack-request
        > Accept: application/x-git-upload-pack-result
+       > Accept-Language: ko-KR, *;q=0.9
        > Content-Length: xxx
        < HTTP/1.1 200 OK
        < Pragma: no-cache
        < Cache-Control: no-cache, max-age=0, must-revalidate
        < Content-Type: application/x-git-upload-pack-result
        EOF
-       GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION=0 \
+
+       GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION=0 LANGUAGE="ko_KR.UTF-8" \
                git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err &&
        test_cmp file clone/file &&
        tr '\''\015'\'' Q <err |
@@ -94,7 +97,10 @@ test_expect_success 'clone http repository' '
                test_cmp exp actual.smudged &&
 
                grep "Accept-Encoding:.*gzip" actual >actual.gzip &&
-               test_line_count = 2 actual.gzip
+               test_line_count = 2 actual.gzip &&
+
+               grep "Accept-Language: ko-KR, *" actual >actual.language &&
+               test_line_count = 2 actual.language
        fi
 '
 
@@ -175,8 +181,8 @@ test_expect_success 'no-op half-auth fetch does not require a password' '
        # This is not possible with protocol v2, since both objects and refs
        # are obtained from the "git-upload-pack" path. A solution to this is
        # to teach the server and client to be able to inline ls-refs requests
-       # as an Extra Parameter (see pack-protocol.txt), so that "info/refs"
-       # can serve refs, just like it does in protocol v0.
+       # as an Extra Parameter (see "git help gitformat-pack-protocol"), so that
+       # "info/refs" can serve refs, just like it does in protocol v0.
        GIT_TEST_PROTOCOL_VERSION=0 git --git-dir=half-auth fetch &&
        expect_askpass none
 '
diff --git a/t/t5557-http-get.sh b/t/t5557-http-get.sh
new file mode 100755 (executable)
index 0000000..76a4bbd
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+test_description='test downloading a file by URL'
+
+TEST_PASSES_SANITIZE_LEAK=true
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'get by URL: 404' '
+       test_when_finished "rm -f file.temp" &&
+       url="$HTTPD_URL/none.txt" &&
+       cat >input <<-EOF &&
+       capabilities
+       get $url file1
+       EOF
+
+       test_must_fail git remote-http $url <input 2>err &&
+       test_path_is_missing file1 &&
+       grep "failed to download file at URL" err
+'
+
+test_expect_success 'get by URL: 200' '
+       echo data >"$HTTPD_DOCUMENT_ROOT_PATH/exists.txt" &&
+
+       url="$HTTPD_URL/exists.txt" &&
+       cat >input <<-EOF &&
+       capabilities
+       get $url file2
+
+       EOF
+
+       git remote-http $url <input &&
+       test_cmp "$HTTPD_DOCUMENT_ROOT_PATH/exists.txt" file2
+'
+
+test_done
diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh
new file mode 100755 (executable)
index 0000000..ad666a2
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+test_description='test fetching bundles with --bundle-uri'
+
+. ./test-lib.sh
+
+test_expect_success 'fail to clone from non-existent file' '
+       test_when_finished rm -rf test &&
+       git clone --bundle-uri="$(pwd)/does-not-exist" . test 2>err &&
+       grep "failed to download bundle from URI" err
+'
+
+test_expect_success 'fail to clone from non-bundle file' '
+       test_when_finished rm -rf test &&
+       echo bogus >bogus &&
+       git clone --bundle-uri="$(pwd)/bogus" . test 2>err &&
+       grep "is not a bundle" err
+'
+
+test_expect_success 'create bundle' '
+       git init clone-from &&
+       git -C clone-from checkout -b topic &&
+       test_commit -C clone-from A &&
+       test_commit -C clone-from B &&
+       git -C clone-from bundle create B.bundle topic
+'
+
+test_expect_success 'clone with path bundle' '
+       git clone --bundle-uri="clone-from/B.bundle" \
+               clone-from clone-path &&
+       git -C clone-path rev-parse refs/bundles/topic >actual &&
+       git -C clone-from rev-parse topic >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'clone with file:// bundle' '
+       git clone --bundle-uri="file://$(pwd)/clone-from/B.bundle" \
+               clone-from clone-file &&
+       git -C clone-file rev-parse refs/bundles/topic >actual &&
+       git -C clone-from rev-parse topic >expect &&
+       test_cmp expect actual
+'
+
+#########################################################################
+# HTTP tests begin here
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'fail to fetch from non-existent HTTP URL' '
+       test_when_finished rm -rf test &&
+       git clone --bundle-uri="$HTTPD_URL/does-not-exist" . test 2>err &&
+       grep "failed to download bundle from URI" err
+'
+
+test_expect_success 'fail to fetch from non-bundle HTTP URL' '
+       test_when_finished rm -rf test &&
+       echo bogus >"$HTTPD_DOCUMENT_ROOT_PATH/bogus" &&
+       git clone --bundle-uri="$HTTPD_URL/bogus" . test 2>err &&
+       grep "is not a bundle" err
+'
+
+test_expect_success 'clone HTTP bundle' '
+       cp clone-from/B.bundle "$HTTPD_DOCUMENT_ROOT_PATH/B.bundle" &&
+
+       git clone --no-local --mirror clone-from \
+               "$HTTPD_DOCUMENT_ROOT_PATH/fetch.git" &&
+
+       git clone --bundle-uri="$HTTPD_URL/B.bundle" \
+               "$HTTPD_URL/smart/fetch.git" clone-http &&
+       git -C clone-http rev-parse refs/bundles/topic >actual &&
+       git -C clone-from rev-parse topic >expect &&
+       test_cmp expect actual &&
+
+       test_config -C clone-http log.excludedecoration refs/bundle/
+'
+
+# Do not add tests here unless they use the HTTP server, as they will
+# not run unless the HTTP dependencies exist.
+
+test_done
index cf3be0584f40d13ba187cd8c04efc358910714a7..2e57de9c12a39a63b870079c17b014ad24fb93c3 100755 (executable)
@@ -743,7 +743,11 @@ test_expect_success 'batch missing blob request during checkout' '
 
        # Ensure that there is only one negotiation by checking that there is
        # only "done" line sent. ("done" marks the end of negotiation.)
-       GIT_TRACE_PACKET="$(pwd)/trace" git -C client checkout HEAD^ &&
+       GIT_TRACE_PACKET="$(pwd)/trace" \
+               GIT_TRACE2_EVENT="$(pwd)/trace2_event" \
+               git -C client -c trace2.eventNesting=5 checkout HEAD^ &&
+       grep \"key\":\"total_rounds\",\"value\":\"1\" trace2_event >trace_lines &&
+       test_line_count = 1 trace_lines &&
        grep "fetch> done" trace >done_lines &&
        test_line_count = 1 done_lines
 '
index 0000c9f17fb905934ba6f5863e6aaba43461fef2..cf221e92c4d97e852f1bdefbf61f6caded87aff2 100755 (executable)
@@ -59,6 +59,14 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
 
 '
 
+test_expect_success 'disallows --bundle-uri with shallow options' '
+       for option in --depth=1 --shallow-since=01-01-2000 --shallow-exclude=HEAD
+       do
+               test_must_fail git clone --bundle-uri=bundle $option from to 2>err &&
+               grep "bundle-uri is incompatible" err || return 1
+       done
+'
+
 test_expect_success 'reject cloning shallow repository' '
        test_when_finished "rm -rf repo" &&
        test_must_fail git clone --reject-shallow shallow-repo out 2>err &&
index 5d42a355a8b81b0f2087eeb8302eb7859c04553c..b33cd4afca3d021f1f8f38393521589243ae95fb 100755 (executable)
@@ -1001,7 +1001,7 @@ test_expect_success 'part of packfile response provided as URI' '
        do
                git verify-pack --object-format=$(test_oid algo) --verbose $idx >out &&
                {
-                       grep "^[0-9a-f]\{16,\} " out || :
+                       grep -E "^[0-9a-f]{16,} " out || :
                } >out.objectlist &&
                if test_line_count = 1 out.objectlist
                then
index 9d6cd7d98649c0fe0f40c474d5ed88528ac9ba8c..df74f80061c564b7f69961f0f3d665b1afca460f 100755 (executable)
@@ -229,14 +229,16 @@ test_expect_success 'setup repos for fetching with ref-in-want tests' '
 '
 
 test_expect_success 'fetching with exact OID' '
-       test_when_finished "rm -f log" &&
+       test_when_finished "rm -f log trace2" &&
 
        rm -rf local &&
        cp -r "$LOCAL_PRISTINE" local &&
        oid=$(git -C "$REPO" rev-parse d) &&
-       GIT_TRACE_PACKET="$(pwd)/log" git -C local fetch origin \
+       GIT_TRACE_PACKET="$(pwd)/log" GIT_TRACE2_EVENT="$(pwd)/trace2" \
+               git -C local fetch origin \
                "$oid":refs/heads/actual &&
 
+       grep \"key\":\"total_rounds\",\"value\":\"2\" trace2 &&
        git -C "$REPO" rev-parse "d" >expected &&
        git -C local rev-parse refs/heads/actual >actual &&
        test_cmp expected actual &&
index 7294147334a92e6be082ad57177adb6e0857facc..16635ecc33e5e67ab56985a5e4a071492ed22cc9 100755 (executable)
@@ -99,6 +99,7 @@ do
        "
 
        test_expect_success 'with grafts' "
+               mkdir -p .git/info &&
                echo '$B0 $A2' >.git/info/grafts &&
                check $type $B2 -- $B2 $B1 $B0 $A2 $A1 $A0
        "
index 3153a0d891046421f53ea6543182c47ca750e07a..12e67e187ef21456f79a2ebdcc19c641d8ec81a6 100755 (executable)
@@ -8,6 +8,7 @@ test_description='git rev-list involving submodules that this repo has'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index af57a04b7ffa01644768ee507714ad5f5d5b79c6..738da23628b12b4660105195e2bbcedf68416f33 100755 (executable)
@@ -8,8 +8,13 @@ test_description='--ancestry-path'
 #   /                     \
 #  A-------K---------------L--M
 #
-#  D..M                 == E F G H I J K L M
-#  --ancestry-path D..M == E F H I J L M
+#  D..M                                     == E F G H I J K L M
+#  --ancestry-path                     D..M == E F   H I J   L M
+#  --ancestry-path=F                   D..M == E F       J   L M
+#  --ancestry-path=G                   D..M ==     G H I J   L M
+#  --ancestry-path=H                   D..M == E   G H I J   L M
+#  --ancestry-path=K                   D..M ==             K L M
+#  --ancestry-path=K --ancestry-path=F D..M == E F       J K L M
 #
 #  D..M -- M.t                 == M
 #  --ancestry-path D..M -- M.t == M
@@ -50,73 +55,41 @@ test_expect_success setup '
        test_commit M
 '
 
-test_expect_success 'rev-list D..M' '
-       test_write_lines E F G H I J K L M >expect &&
-       git rev-list --format=%s D..M |
-       sed -e "/^commit /d" |
-       sort >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'rev-list --ancestry-path D..M' '
-       test_write_lines E F H I J L M >expect &&
-       git rev-list --ancestry-path --format=%s D..M |
-       sed -e "/^commit /d" |
-       sort >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'rev-list D..M -- M.t' '
-       echo M >expect &&
-       git rev-list --format=%s D..M -- M.t |
-       sed -e "/^commit /d" >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'rev-list --ancestry-path D..M -- M.t' '
-       echo M >expect &&
-       git rev-list --ancestry-path --format=%s D..M -- M.t |
-       sed -e "/^commit /d" >actual &&
-       test_cmp expect actual
-'
+test_ancestry () {
+       args=$1
+       expected=$2
+       test_expect_success "log $args" "
+               test_write_lines $expected >expect &&
+               git log --format=%s $args >raw &&
+
+               if test -n \"$expected\"
+               then
+                       sort raw >actual &&
+                       test_cmp expect actual
+               else
+                       test_must_be_empty raw
+               fi
+       "
+}
 
-test_expect_success 'rev-list F...I' '
-       test_write_lines F G H I >expect &&
-       git rev-list --format=%s F...I |
-       sed -e "/^commit /d" |
-       sort >actual &&
-       test_cmp expect actual
-'
+test_ancestry "D..M" "E F G H I J K L M"
 
-test_expect_success 'rev-list --ancestry-path F...I' '
-       test_write_lines F H I >expect &&
-       git rev-list --ancestry-path --format=%s F...I |
-       sed -e "/^commit /d" |
-       sort >actual &&
-       test_cmp expect actual
-'
+test_ancestry "--ancestry-path D..M" "E F H I J L M"
+test_ancestry "--ancestry-path=F D..M" "E F J L M"
+test_ancestry "--ancestry-path=G D..M" "G H I J L M"
+test_ancestry "--ancestry-path=H D..M" "E G H I J L M"
+test_ancestry "--ancestry-path=K D..M" "K L M"
+test_ancestry "--ancestry-path=F --ancestry-path=K D..M" "E F J K L M"
 
-# G.t is dropped in an "-s ours" merge
-test_expect_success 'rev-list G..M -- G.t' '
-       git rev-list --format=%s G..M -- G.t |
-       sed -e "/^commit /d" >actual &&
-       test_must_be_empty actual
-'
+test_ancestry "D..M -- M.t" "M"
+test_ancestry "--ancestry-path D..M -- M.t" "M"
 
-test_expect_success 'rev-list --ancestry-path G..M -- G.t' '
-       echo L >expect &&
-       git rev-list --ancestry-path --format=%s G..M -- G.t |
-       sed -e "/^commit /d" >actual &&
-       test_cmp expect actual
-'
+test_ancestry "F...I" "F G H I"
+test_ancestry "--ancestry-path F...I" "F H I"
 
-test_expect_success 'rev-list --ancestry-path --simplify-merges G^..M -- G.t' '
-       test_write_lines G L >expect &&
-       git rev-list --ancestry-path --simplify-merges --format=%s G^..M -- G.t |
-       sed -e "/^commit /d" |
-       sort >actual &&
-       test_cmp expect actual
-'
+test_ancestry "G..M -- G.t" ""
+test_ancestry "--ancestry-path G..M -- G.t" "L"
+test_ancestry "--ancestry-path --simplify-merges G^..M -- G.t" "G L"
 
 #   b---bc
 #  / \ /
index a3a41c7a3e47899521d63c056532604a7d224c97..d20723d627629f5379f35c33c74ff22d1082152e 100755 (executable)
@@ -9,6 +9,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 TEST_PASSES_SANITIZE_LEAK=true
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 test_cmp_rev_output () {
@@ -26,6 +27,7 @@ test_expect_success 'setup' '
        git merge -m next --allow-unrelated-histories start2 &&
        test_commit final &&
 
+       mkdir .git/info &&
        test_seq 40 |
        while read i
        do
index cf0195e8263c6fdc25977f421252c41238f03419..4a9a4436e219c856095784324e4b097b3402ba29 100755 (executable)
@@ -17,7 +17,7 @@ test_expect_success 'setup unexpected non-blob entry' '
        broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
 '
 
-test_expect_success !SANITIZE_LEAK 'TODO (should fail!): traverse unexpected non-blob entry (lone)' '
+test_expect_success 'TODO (should fail!): traverse unexpected non-blob entry (lone)' '
        sed "s/Z$//" >expect <<-EOF &&
        $broken_tree Z
        $tree foo
@@ -121,7 +121,7 @@ test_expect_success 'setup unexpected non-blob tag' '
        tag=$(git hash-object -w --literally -t tag broken-tag)
 '
 
-test_expect_success !SANITIZE_LEAK 'TODO (should fail!): traverse unexpected non-blob tag (lone)' '
+test_expect_success 'TODO (should fail!): traverse unexpected non-blob tag (lone)' '
        git rev-list --objects $tag
 '
 
index b4aef32b713ca00f1d8ad4a098f02ca9dc9be126..d59111dedec8020a138296928649eaff4de45694 100755 (executable)
@@ -48,4 +48,26 @@ check_du HEAD
 check_du --objects HEAD
 check_du --objects HEAD^..HEAD
 
+# As mentioned above, don't use hardcode sizes as actual size, but use the
+# output from git cat-file.
+test_expect_success 'rev-list --disk-usage=human' '
+       git rev-list --objects HEAD --disk-usage=human >actual &&
+       disk_usage_slow --objects HEAD >actual_size &&
+       grep "$(cat actual_size) bytes" actual
+'
+
+test_expect_success 'rev-list --disk-usage=human with bitmaps' '
+       git rev-list --objects HEAD --use-bitmap-index --disk-usage=human >actual &&
+       disk_usage_slow --objects HEAD >actual_size &&
+       grep "$(cat actual_size) bytes" actual
+'
+
+test_expect_success 'rev-list use --disk-usage unproperly' '
+       test_must_fail git rev-list --objects HEAD --disk-usage=typo 2>err &&
+       cat >expect <<-\EOF &&
+       fatal: invalid value for '\''--disk-usage=<format>'\'': '\''typo'\'', the only allowed format is '\''human'\''
+       EOF
+       test_cmp err expect
+'
+
 test_done
index 9fdafeb1e907f4381f2b1e74c6c00771d188d136..cada952f9aee35fe795af5cd99af222f1a8b599f 100755 (executable)
@@ -293,7 +293,11 @@ test_expect_success 'add with all negative' '
        test_cmp expect actual
 '
 
-test_expect_success 'add -p with all negative' '
+test_lazy_prereq ADD_I_USE_BUILTIN_OR_PERL '
+       test_have_prereq ADD_I_USE_BUILTIN || test_have_prereq PERL
+'
+
+test_expect_success ADD_I_USE_BUILTIN_OR_PERL 'add -p with all negative' '
        H=$(git rev-parse HEAD) &&
        git reset --hard $H &&
        git clean -f &&
index 0f1cb49cedc645c5a9b0c56257d3aca4740d5cd3..3a241f259de157185ba2733504e5ed1de552c7c5 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='test case exclude pathspec'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup a submodule' '
index 57a67cf362730be7d2ec695310346cb15b276823..3de4ef6bd9e640d2f82deb111dd307e9a000db91 100755 (executable)
@@ -126,7 +126,7 @@ test_expect_success 'Simple merge in repo with interesting pathnames' '
        #     foo/bar-2/baz
        # The fact that foo/bar-2 appears between foo/bar and foo/bar/baz
        # can trip up some codepaths, and is the point of this test.
-       test_create_repo name-ordering &&
+       git init name-ordering &&
        (
                cd name-ordering &&
 
index 3a32b1a45cf8e4bf2a7b42eeec98923262b3e470..772238e582c6f11b81c12a519f81bbe48cecf635 100755 (executable)
@@ -210,7 +210,7 @@ test_expect_success 'updated working tree file should prevent the merge' '
        echo >>M one line addition &&
        cat M >M.saved &&
        git update-index M &&
-       test_expect_code 128 git pull --no-rebase . yellow &&
+       test_expect_code 2 git pull --no-rebase . yellow &&
        test_cmp M M.saved &&
        rm -f M.saved
 '
index 2f421d967abefbef96eb6f2c0d1201184b9b5d57..1a7082323dddfce66b2d419efe60c87314c5f8e1 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='RCS merge replacement: merge-file'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index b8735c6db4d7c9cc556231a5b0dab091f2f2eb61..36215518b6eb1a746ded0f9b475a7d3029b807a6 100755 (executable)
@@ -4,6 +4,7 @@ test_description='Test merge without common ancestors'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # This scenario is based on a real-world repository of Shawn Pearce.
index 7435fce71e004095c3a9fe181b038ae77a800192..29e2b25ce5de25f6f97aa6ac967332e7603eb91e 100755 (executable)
@@ -11,6 +11,7 @@ if core.symlinks is false.'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index 99abefd44b96e6528900bb672ba7de38c6bb9135..8650a88c40a2a58182ee39f36cdc59315ae1a35c 100755 (executable)
@@ -162,8 +162,8 @@ test_expect_success 'custom merge backend' '
 '
 
 test_expect_success 'up-to-date merge without common ancestor' '
-       test_create_repo repo1 &&
-       test_create_repo repo2 &&
+       git init repo1 &&
+       git init repo2 &&
        test_tick &&
        (
                cd repo1 &&
index 0753fc95f45efb642543f9f23191d3430d4d6cde..e8a28717cece3248c2d9996e797dcfdb9af128eb 100755 (executable)
@@ -5,7 +5,6 @@ test_description='ask merge-recursive to merge binary files'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
-TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 7763c1ba98080d5d1d68e1009fb70f6c80cf479a..8a1ba6d23a7dc4a7ca7a56988f3d945d9af38619 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='merge fast-forward and up to date'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 6ae2489286c278f978c3a87f1015f16fe2bb005f..b6182723aae158acb4e56ab9018c9b30f4f86cd6 100755 (executable)
@@ -4,6 +4,7 @@ test_description='merge: handle file mode'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'set up mode change in one branch' '
index affea255fe92ca134a553d2a69362a8f8f7a8ab1..b4f4a313f486a583ca62268f2106948cca8d7266 100755 (executable)
@@ -11,6 +11,7 @@ test_description='merge conflict in crlf repo
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 690c8482b13a3763b223be19799ce22197cd383c..17b54d625d0e468047377c378faae25c50633c9b 100755 (executable)
@@ -19,7 +19,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 #
 
 test_expect_success 'setup basic criss-cross + rename with no modifications' '
-       test_create_repo basic-rename &&
+       git init basic-rename &&
        (
                cd basic-rename &&
 
@@ -85,7 +85,7 @@ test_expect_success 'merge simple rename+criss-cross with no modifications' '
 #
 
 test_expect_success 'setup criss-cross + rename merges with basic modification' '
-       test_create_repo rename-modify &&
+       git init rename-modify &&
        (
                cd rename-modify &&
 
@@ -160,7 +160,7 @@ test_expect_success 'merge criss-cross + rename merges with basic modification'
 #
 
 test_expect_success 'setup differently handled merges of rename/add conflict' '
-       test_create_repo rename-add &&
+       git init rename-add &&
        (
                cd rename-add &&
 
@@ -324,7 +324,7 @@ test_expect_success 'git detects differently handled merges conflict, swapped' '
 # Merging commits D & E should result in modify/delete conflict.
 
 test_expect_success 'setup criss-cross + modify/delete resolved differently' '
-       test_create_repo modify-delete &&
+       git init modify-delete &&
        (
                cd modify-delete &&
 
@@ -499,7 +499,7 @@ test_expect_success 'git detects conflict merging criss-cross+modify/delete, rev
 #
 
 test_expect_success 'setup differently handled merges of directory/file conflict' '
-       test_create_repo directory-file &&
+       git init directory-file &&
        (
                cd directory-file &&
 
@@ -867,7 +867,7 @@ test_expect_failure 'merge of D2 & E4 merges a2s & reports conflict for a/file'
 # but that may cancel out at the final merge stage".
 
 test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
-       test_create_repo rename-squared-squared &&
+       git init rename-squared-squared &&
        (
                cd rename-squared-squared &&
 
@@ -944,7 +944,7 @@ test_expect_success 'handle rename/rename(1to2)/modify followed by what looks li
 # content merge handled.
 
 test_expect_success 'setup criss-cross + rename/rename/add-source + modify/modify' '
-       test_create_repo rename-rename-add-source &&
+       git init rename-rename-add-source &&
        (
                cd rename-rename-add-source &&
 
@@ -1032,7 +1032,7 @@ test_expect_failure 'detect rename/rename/add-source for virtual merge-base' '
 # base of B & C needs to not delete B:c for that to work, though...
 
 test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' '
-       test_create_repo rename-rename-add-dest &&
+       git init rename-rename-add-dest &&
        (
                cd rename-rename-add-dest &&
 
@@ -1111,7 +1111,7 @@ test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' '
 # git detect it?
 
 test_expect_success 'setup symlink modify/modify' '
-       test_create_repo symlink-modify-modify &&
+       git init symlink-modify-modify &&
        (
                cd symlink-modify-modify &&
 
@@ -1178,7 +1178,7 @@ test_expect_merge_algorithm failure success 'check symlink modify/modify' '
 # git detect it?
 
 test_expect_success 'setup symlink add/add' '
-       test_create_repo symlink-add-add &&
+       git init symlink-add-add &&
        (
                cd symlink-add-add &&
 
@@ -1244,11 +1244,11 @@ test_expect_merge_algorithm failure success 'check symlink add/add' '
 # git detect it?
 
 test_expect_success 'setup submodule modify/modify' '
-       test_create_repo submodule-modify-modify &&
+       git init submodule-modify-modify &&
        (
                cd submodule-modify-modify &&
 
-               test_create_repo submod &&
+               git init submod &&
                (
                        cd submod &&
                        touch file-A &&
@@ -1332,11 +1332,11 @@ test_expect_merge_algorithm failure success 'check submodule modify/modify' '
 # git detect it?
 
 test_expect_success 'setup submodule add/add' '
-       test_create_repo submodule-add-add &&
+       git init submodule-add-add &&
        (
                cd submodule-add-add &&
 
-               test_create_repo submod &&
+               git init submod &&
                (
                        cd submod &&
                        touch file-A &&
@@ -1419,11 +1419,11 @@ test_expect_merge_algorithm failure success 'check submodule add/add' '
 # This is an obvious add/add conflict for 'path'.  Can git detect it?
 
 test_expect_success 'setup conflicting entry types (submodule vs symlink)' '
-       test_create_repo submodule-symlink-add-add &&
+       git init submodule-symlink-add-add &&
        (
                cd submodule-symlink-add-add &&
 
-               test_create_repo path &&
+               git init path &&
                (
                        cd path &&
                        touch file-B &&
@@ -1494,7 +1494,7 @@ test_expect_merge_algorithm failure success 'check conflicting entry types (subm
 # This is an obvious add/add mode conflict.  Can git detect it?
 
 test_expect_success 'setup conflicting modes for regular file' '
-       test_create_repo regular-file-mode-conflict &&
+       git init regular-file-mode-conflict &&
        (
                cd regular-file-mode-conflict &&
 
@@ -1571,7 +1571,7 @@ test_expect_failure 'check conflicting modes for regular file' '
 #   to ensure that we handle it as well as practical.
 
 test_expect_success 'setup nested conflicts' '
-       test_create_repo nested_conflicts &&
+       git init nested_conflicts &&
        (
                cd nested_conflicts &&
 
@@ -1757,7 +1757,7 @@ test_expect_success 'check nested conflicts' '
 #   have three levels of conflict markers.  Can we distinguish all three?
 
 test_expect_success 'setup virtual merge base with nested conflicts' '
-       test_create_repo virtual_merge_base_has_nested_conflicts &&
+       git init virtual_merge_base_has_nested_conflicts &&
        (
                cd virtual_merge_base_has_nested_conflicts &&
 
index 62d1406119e8c2b08a1a93e3d8fb95167ad16e7d..482b73a998ff2aa6651fc3fc7bd845fffd2c80c3 100755 (executable)
@@ -4,6 +4,7 @@ test_description='Merge-recursive ours and theirs variants'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 36bcd7c3280152f16a4150d64afb7621e17e2ee5..5413e5dd9d68c36b95ecf9ccf5ca9e438ff0413b 100755 (executable)
@@ -31,7 +31,7 @@ test_description="limiting blob downloads when merging with partial clones"
 
 test_setup_repo () {
        test -d server && return
-       test_create_repo server &&
+       git init server &&
        (
                cd server &&
 
index bf4ce3c63d4c86f5f549ffa087fd81bb4fb7e327..346253c7c88ee58ebf6735b6c06ae69f18ce5861 100755 (executable)
@@ -6,11 +6,12 @@ test_description="recursive merge corner cases w/ renames but not criss-crosses"
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-merge.sh
 
 test_setup_rename_delete_untracked () {
-       test_create_repo rename-delete-untracked &&
+       git init rename-delete-untracked &&
        (
                cd rename-delete-untracked &&
 
@@ -55,7 +56,7 @@ test_expect_success "Does git preserve Gollum's precious artifact?" '
 # We should be able to merge B & C cleanly
 
 test_setup_rename_modify_add_source () {
-       test_create_repo rename-modify-add-source &&
+       git init rename-modify-add-source &&
        (
                cd rename-modify-add-source &&
 
@@ -95,7 +96,7 @@ test_expect_failure 'rename/modify/add-source conflict resolvable' '
 '
 
 test_setup_break_detection_1 () {
-       test_create_repo break-detection-1 &&
+       git init break-detection-1 &&
        (
                cd break-detection-1 &&
 
@@ -143,7 +144,7 @@ test_expect_failure 'conflict caused if rename not detected' '
 '
 
 test_setup_break_detection_2 () {
-       test_create_repo break-detection-2 &&
+       git init break-detection-2 &&
        (
                cd break-detection-2 &&
 
@@ -191,7 +192,7 @@ test_expect_failure 'missed conflict if rename not detected' '
 #   Commit C: rename a->b, add unrelated a
 
 test_setup_break_detection_3 () {
-       test_create_repo break-detection-3 &&
+       git init break-detection-3 &&
        (
                cd break-detection-3 &&
 
@@ -267,7 +268,7 @@ test_expect_failure 'detect rename/add-source and preserve all data, merge other
 '
 
 test_setup_rename_directory () {
-       test_create_repo rename-directory-$1 &&
+       git init rename-directory-$1 &&
        (
                cd rename-directory-$1 &&
 
@@ -385,7 +386,7 @@ test_expect_success 'rename/directory conflict + content merge conflict' '
 '
 
 test_setup_rename_directory_2 () {
-       test_create_repo rename-directory-2 &&
+       git init rename-directory-2 &&
        (
                cd rename-directory-2 &&
 
@@ -444,7 +445,7 @@ test_expect_success 'disappearing dir in rename/directory conflict handled' '
 #   Commit B: modify a, add different b
 
 test_setup_rename_with_content_merge_and_add () {
-       test_create_repo rename-with-content-merge-and-add-$1 &&
+       git init rename-with-content-merge-and-add-$1 &&
        (
                cd rename-with-content-merge-and-add-$1 &&
 
@@ -569,7 +570,7 @@ test_expect_success 'handle rename-with-content-merge vs. add, merge other way'
 #   * Nothing else should be present.  Is anything?
 
 test_setup_rename_rename_2to1 () {
-       test_create_repo rename-rename-2to1 &&
+       git init rename-rename-2to1 &&
        (
                cd rename-rename-2to1 &&
 
@@ -641,7 +642,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 #   Commit B: rename a->b
 #   Commit C: rename a->c
 test_setup_rename_rename_1to2 () {
-       test_create_repo rename-rename-1to2 &&
+       git init rename-rename-1to2 &&
        (
                cd rename-rename-1to2 &&
 
@@ -699,7 +700,7 @@ test_expect_success 'merge has correct working tree contents' '
 # Merging of B & C should NOT be clean; there's a rename/rename conflict
 
 test_setup_rename_rename_1to2_add_source_1 () {
-       test_create_repo rename-rename-1to2-add-source-1 &&
+       git init rename-rename-1to2-add-source-1 &&
        (
                cd rename-rename-1to2-add-source-1 &&
 
@@ -747,7 +748,7 @@ test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge'
 '
 
 test_setup_rename_rename_1to2_add_source_2 () {
-       test_create_repo rename-rename-1to2-add-source-2 &&
+       git init rename-rename-1to2-add-source-2 &&
        (
                cd rename-rename-1to2-add-source-2 &&
 
@@ -793,7 +794,7 @@ test_expect_failure 'rename/rename/add-source still tracks new a file' '
 '
 
 test_setup_rename_rename_1to2_add_dest () {
-       test_create_repo rename-rename-1to2-add-dest &&
+       git init rename-rename-1to2-add-dest &&
        (
                cd rename-rename-1to2-add-dest &&
 
@@ -873,7 +874,7 @@ test_expect_success 'rename/rename/add-dest merge still knows about conflicting
 #   Expected: CONFLICT (rename/add/delete), two-way merged bar
 
 test_setup_rad () {
-       test_create_repo rad &&
+       git init rad &&
        (
                cd rad &&
                echo "original file" >foo &&
@@ -945,7 +946,7 @@ test_expect_merge_algorithm failure success 'rad-check: rename/add/delete confli
 #   Expected: CONFLICT (rename/rename/delete/delete), two-way merged baz
 
 test_setup_rrdd () {
-       test_create_repo rrdd &&
+       git init rrdd &&
        (
                cd rrdd &&
                echo foo >foo &&
@@ -1021,7 +1022,7 @@ test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/del
 #             multi-way merged contents found in two, four, six
 
 test_setup_mod6 () {
-       test_create_repo mod6 &&
+       git init mod6 &&
        (
                cd mod6 &&
                test_seq 11 19 >one &&
@@ -1159,7 +1160,7 @@ test_conflicts_with_adds_and_renames() {
        #      tree
        test_setup_collision_conflict () {
        #test_expect_success "setup simple $sideL/$sideR conflict" '
-               test_create_repo simple_${sideL}_${sideR} &&
+               git init simple_${sideL}_${sideR} &&
                (
                        cd simple_${sideL}_${sideR} &&
 
@@ -1307,7 +1308,7 @@ test_conflicts_with_adds_and_renames add    add
 #   So, we have four different conflicting files that all end up at path
 #   'three'.
 test_setup_nested_conflicts_from_rename_rename () {
-       test_create_repo nested_conflicts_from_rename_rename &&
+       git init nested_conflicts_from_rename_rename &&
        (
                cd nested_conflicts_from_rename_rename &&
 
@@ -1416,7 +1417,7 @@ test_expect_success 'check nested conflicts from rename/rename(2to1)' '
 #   Expected: CONFLICT(rename/rename) message, three unstaged entries in the
 #             index, and contents of orig-[AB] at path orig-[AB]
 test_setup_rename_rename_1_to_2_binary () {
-       test_create_repo rename_rename_1_to_2_binary &&
+       git init rename_rename_1_to_2_binary &&
        (
                cd rename_rename_1_to_2_binary &&
 
index 99baf77cbfdce0ea13345a21ad11575d52e7de59..a4941878fe2a693910cca1f226277747706a5017 100755 (executable)
@@ -40,7 +40,7 @@ test_description="recursive merge with directory renames"
 #   Expected: y/{b,c,d,e/f}
 
 test_setup_1a () {
-       test_create_repo 1a &&
+       git init 1a &&
        (
                cd 1a &&
 
@@ -106,7 +106,7 @@ test_expect_success '1a: Simple directory rename detection' '
 #   Expected: y/{b,c,d,e}
 
 test_setup_1b () {
-       test_create_repo 1b &&
+       git init 1b &&
        (
                cd 1b &&
 
@@ -169,7 +169,7 @@ test_expect_success '1b: Merge a directory with another' '
 #   Expected: y/{b,c,d}  (because x/d -> z/d -> y/d)
 
 test_setup_1c () {
-       test_create_repo 1c &&
+       git init 1c &&
        (
                cd 1c &&
 
@@ -232,7 +232,7 @@ test_expect_success '1c: Transitive renaming' '
 #         y/wham_1 & z/wham_2 should too...giving us a conflict.
 
 test_setup_1d () {
-       test_create_repo 1d &&
+       git init 1d &&
        (
                cd 1d &&
 
@@ -328,7 +328,7 @@ test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict'
 #   Expected: y/{newb,newc,d}
 
 test_setup_1e () {
-       test_create_repo 1e &&
+       git init 1e &&
        (
                cd 1e &&
 
@@ -387,7 +387,7 @@ test_expect_success '1e: Renamed directory, with all files being renamed too' '
 #   Expected: y/{b,c}, x/{d,e,f,g}
 
 test_setup_1f () {
-       test_create_repo 1f &&
+       git init 1f &&
        (
                cd 1f &&
 
@@ -476,7 +476,7 @@ test_expect_success '1f: Split a directory into two other directories' '
 #   Commit B: z/{b,c,d}
 #   Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict
 test_setup_2a () {
-       test_create_repo 2a &&
+       git init 2a &&
        (
                cd 2a &&
 
@@ -538,7 +538,7 @@ test_expect_success '2a: Directory split into two on one side, with equal number
 #   Commit B: z/{b,c}, x/d
 #   Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict
 test_setup_2b () {
-       test_create_repo 2b &&
+       git init 2b &&
        (
                cd 2b &&
 
@@ -620,7 +620,7 @@ test_expect_success '2b: Directory split into two on one side, with equal number
 #   Commit B: y/{b,c}, x/d
 #   Expected: y/{b,c}, x/d
 test_setup_3a () {
-       test_create_repo 3a &&
+       git init 3a &&
        (
                cd 3a &&
 
@@ -684,7 +684,7 @@ test_expect_success '3a: Avoid implicit rename if involved as source on other si
 #         end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a
 #         rename/rename/rename(1to3) conflict, which is just weird.
 test_setup_3b () {
-       test_create_repo 3b &&
+       git init 3b &&
        (
                cd 3b &&
 
@@ -807,7 +807,7 @@ test_expect_success '3b: Avoid implicit rename if involved as source on current
 #   NOTE: Even though most files from z moved to y, we don't want f to follow.
 
 test_setup_4a () {
-       test_create_repo 4a &&
+       git init 4a &&
        (
                cd 4a &&
 
@@ -896,7 +896,7 @@ test_expect_success '4a: Directory split, with original directory still present'
 #         index.
 
 test_setup_5a () {
-       test_create_repo 5a &&
+       git init 5a &&
        (
                cd 5a &&
 
@@ -971,7 +971,7 @@ test_expect_success '5a: Merge directories, other side adds files to original an
 #         back to git behavior without the directory rename detection.
 
 test_setup_5b () {
-       test_create_repo 5b &&
+       git init 5b &&
        (
                cd 5b &&
 
@@ -1048,7 +1048,7 @@ test_expect_success '5b: Rename/delete in order to get add/add/add conflict' '
 #             though, because it doesn't have anything in the way.
 
 test_setup_5c () {
-       test_create_repo 5c &&
+       git init 5c &&
        (
                cd 5c &&
 
@@ -1138,7 +1138,7 @@ test_expect_success '5c: Transitive rename would cause rename/rename/rename/add/
 #         directory rename detection for z/f -> y/f.
 
 test_setup_5d () {
-       test_create_repo 5d &&
+       git init 5d &&
        (
                cd 5d &&
 
@@ -1239,7 +1239,7 @@ test_expect_success '5d: Directory/file/file conflict due to directory rename' '
 #         it is also involved in a rename/delete conflict.
 
 test_setup_6a () {
-       test_create_repo 6a &&
+       git init 6a &&
        (
                cd 6a &&
 
@@ -1337,7 +1337,7 @@ test_expect_success '6a: Tricky rename/delete' '
 #         the behavior on testcases 6b2 and 8e, and introduced this 6b1 testcase.
 
 test_setup_6b1 () {
-       test_create_repo 6b1 &&
+       git init 6b1 &&
        (
                cd 6b1 &&
 
@@ -1415,7 +1415,7 @@ test_expect_merge_algorithm failure success '6b1: Same renames done on both side
 #         the z/ -> y/ rename.
 
 test_setup_6b2 () {
-       test_create_repo 6b2 &&
+       git init 6b2 &&
        (
                cd 6b2 &&
 
@@ -1479,7 +1479,7 @@ test_expect_merge_algorithm failure success '6b2: Same rename done on both sides
 #         "accidentally detect a rename" and give us y/{b,c,d}.
 
 test_setup_6c () {
-       test_create_repo 6c &&
+       git init 6c &&
        (
                cd 6c &&
 
@@ -1542,7 +1542,7 @@ test_expect_success '6c: Rename only done on same side' '
 #         doesn't "accidentally detect a rename" and give us y/{b,c,d}.
 
 test_setup_6d () {
-       test_create_repo 6d &&
+       git init 6d &&
        (
                cd 6d &&
 
@@ -1605,7 +1605,7 @@ test_expect_success '6d: We do not always want transitive renaming' '
 #         add/add conflict on y/d_1 vs y/d_2.
 
 test_setup_6e () {
-       test_create_repo 6e &&
+       git init 6e &&
        (
                cd 6e &&
 
@@ -1700,7 +1700,7 @@ test_expect_success '6e: Add/add from one side' '
 #   NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
 
 test_setup_7a () {
-       test_create_repo 7a &&
+       git init 7a &&
        (
                cd 7a &&
 
@@ -1772,7 +1772,7 @@ test_expect_success '7a: rename-dir vs. rename-dir (NOT split evenly) PLUS add-o
 #   Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
 
 test_setup_7b () {
-       test_create_repo 7b &&
+       git init 7b &&
        (
                cd 7b &&
 
@@ -1861,7 +1861,7 @@ test_expect_success '7b: rename/rename(2to1), but only due to transitive rename'
 #         nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
 
 test_setup_7c () {
-       test_create_repo 7c &&
+       git init 7c &&
        (
                cd 7c &&
 
@@ -1926,7 +1926,7 @@ test_expect_success '7c: rename/rename(1to...2or3); transitive rename may add co
 #   NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
 
 test_setup_7d () {
-       test_create_repo 7d &&
+       git init 7d &&
        (
                cd 7d &&
 
@@ -2027,7 +2027,7 @@ test_expect_success '7d: transitive rename involved in rename/delete; how is it
 #         how it's resolved.
 
 test_setup_7e () {
-       test_create_repo 7e &&
+       git init 7e &&
        (
                cd 7e &&
 
@@ -2137,7 +2137,7 @@ test_expect_success '7e: transitive rename in rename/delete AND dirs in the way'
 # we potentially could.
 
 test_setup_8a () {
-       test_create_repo 8a &&
+       git init 8a &&
        (
                cd 8a &&
 
@@ -2216,7 +2216,7 @@ test_expect_success '8a: Dual-directory rename, one into the others way' '
 # e_1 and e_2.
 
 test_setup_8b () {
-       test_create_repo 8b &&
+       git init 8b &&
        (
                cd 8b &&
 
@@ -2290,7 +2290,7 @@ test_expect_success '8b: Dual-directory rename, one into the others way, with co
 #         notes in 8d.
 
 test_setup_8c () {
-       test_create_repo 8c &&
+       git init 8c &&
        (
                cd 8c &&
 
@@ -2370,7 +2370,7 @@ test_expect_success '8c: modify/delete or rename+modify/delete' '
 #   differently.
 
 test_setup_8d () {
-       test_create_repo 8d &&
+       git init 8d &&
        (
                cd 8d &&
 
@@ -2453,7 +2453,7 @@ test_expect_success '8d: rename/delete...or not?' '
 #        the behavior, and predict it without computing as many details.
 
 test_setup_8e () {
-       test_create_repo 8e &&
+       git init 8e &&
        (
                cd 8e &&
 
@@ -2537,7 +2537,7 @@ test_expect_success '8e: Both sides rename, one side adds to original directory'
 #         of that could take the new file in commit B at z/i to x/w/i or x/i.
 
 test_setup_9a () {
-       test_create_repo 9a &&
+       git init 9a &&
        (
                cd 9a &&
 
@@ -2609,7 +2609,7 @@ test_expect_success '9a: Inner renamed directory within outer renamed directory'
 #   Expected: y/{b,c,d_merged}
 
 test_setup_9b () {
-       test_create_repo 9b &&
+       git init 9b &&
        (
                cd 9b &&
 
@@ -2697,7 +2697,7 @@ test_expect_success '9b: Transitive rename with content merge' '
 #         history for any implicit directory renames.
 
 test_setup_9c () {
-       test_create_repo 9c &&
+       git init 9c &&
        (
                cd 9c &&
 
@@ -2786,7 +2786,7 @@ test_expect_success '9c: Doubly transitive rename?' '
 #   testcases and simplifies things for the user.
 
 test_setup_9d () {
-       test_create_repo 9d &&
+       git init 9d &&
        (
                cd 9d &&
 
@@ -2861,7 +2861,7 @@ test_expect_success '9d: N-way transitive rename?' '
 #             dir1/yo, dir2/yo, dir3/yo, dirN/yo
 
 test_setup_9e () {
-       test_create_repo 9e &&
+       git init 9e &&
        (
                cd 9e &&
 
@@ -2954,7 +2954,7 @@ test_expect_success '9e: N-to-1 whammo' '
 #   Expected: priority/{a,b}/$more_files, priority/c
 
 test_setup_9f () {
-       test_create_repo 9f &&
+       git init 9f &&
        (
                cd 9f &&
 
@@ -3027,7 +3027,7 @@ test_expect_success '9f: Renamed directory that only contained immediate subdirs
 # viewpoint...
 
 test_setup_9g () {
-       test_create_repo 9g &&
+       git init 9g &&
        (
                cd 9g &&
 
@@ -3096,7 +3096,7 @@ test_expect_failure '9g: Renamed directory that only contained immediate subdirs
 #   NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with
 #         a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)
 test_setup_9h () {
-       test_create_repo 9h &&
+       git init 9h &&
        (
                cd 9h &&
 
@@ -3177,7 +3177,7 @@ test_expect_success '9h: Avoid dir rename on merely modified path' '
 #       ERROR_MSG(untracked working tree files would be overwritten by merge)
 
 test_setup_10a () {
-       test_create_repo 10a &&
+       git init 10a &&
        (
                cd 10a &&
 
@@ -3243,7 +3243,7 @@ test_expect_success '10a: Overwrite untracked with normal rename/delete' '
 #       ERROR_MSG(refusing to lose untracked file at 'y/d')
 
 test_setup_10b () {
-       test_create_repo 10b &&
+       git init 10b &&
        (
                cd 10b &&
 
@@ -3334,7 +3334,7 @@ test_expect_success '10b: Overwrite untracked with dir rename + delete' '
 #             ERROR_MSG(Refusing to lose untracked file at y/c)
 
 test_setup_10c () {
-       test_create_repo 10c_$1 &&
+       git init 10c_$1 &&
        (
                cd 10c_$1 &&
 
@@ -3472,7 +3472,7 @@ test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), oth
 #             ERROR_MSG(Refusing to lose untracked file at y/wham)
 
 test_setup_10d () {
-       test_create_repo 10d &&
+       git init 10d &&
        (
                cd 10d &&
 
@@ -3568,7 +3568,7 @@ test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '
 #   Expected: y/{a,b,c} + untracked z/c
 
 test_setup_10e () {
-       test_create_repo 10e &&
+       git init 10e &&
        (
                cd 10e &&
 
@@ -3650,7 +3650,7 @@ test_expect_merge_algorithm failure success '10e: Does git complain about untrac
 #             z/c with uncommitted mods on top of A:z/c_v1
 
 test_setup_11a () {
-       test_create_repo 11a &&
+       git init 11a &&
        (
                cd 11a &&
 
@@ -3728,7 +3728,7 @@ test_expect_success '11a: Avoid losing dirty contents with simple rename' '
 
 
 test_setup_11b () {
-       test_create_repo 11b &&
+       git init 11b &&
        (
                cd 11b &&
 
@@ -3810,7 +3810,7 @@ test_expect_success '11b: Avoid losing dirty file involved in directory rename'
 #             y/c left untouched (still has uncommitted mods)
 
 test_setup_11c () {
-       test_create_repo 11c &&
+       git init 11c &&
        (
                cd 11c &&
 
@@ -3883,7 +3883,7 @@ test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict'
 #             y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods
 
 test_setup_11d () {
-       test_create_repo 11d &&
+       git init 11d &&
        (
                cd 11d &&
 
@@ -3968,7 +3968,7 @@ test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict'
 #             y/c has dirty file from before merge
 
 test_setup_11e () {
-       test_create_repo 11e &&
+       git init 11e &&
        (
                cd 11e &&
 
@@ -4060,7 +4060,7 @@ test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to
 #             ERROR_MSG(Refusing to lose dirty file at y/wham)
 
 test_setup_11f () {
-       test_create_repo 11f &&
+       git init 11f &&
        (
                cd 11f &&
 
@@ -4155,7 +4155,7 @@ test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to
 #   Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}
 
 test_setup_12a () {
-       test_create_repo 12a &&
+       git init 12a &&
        (
                cd 12a &&
 
@@ -4238,7 +4238,7 @@ test_expect_success '12a: Moving one directory hierarchy into another' '
 #             node2/node1/{leaf1, leaf2}
 
 test_setup_12b1 () {
-       test_create_repo 12b1 &&
+       git init 12b1 &&
        (
                cd 12b1 &&
 
@@ -4327,7 +4327,7 @@ test_expect_merge_algorithm failure success '12b1: Moving two directory hierarch
 #         even simple rules give weird results when given weird inputs.
 
 test_setup_12b2 () {
-       test_create_repo 12b2 &&
+       git init 12b2 &&
        (
                cd 12b2 &&
 
@@ -4402,7 +4402,7 @@ test_expect_success '12b2: Moving two directory hierarchies into each other' '
 #         each side of the merge.
 
 test_setup_12c1 () {
-       test_create_repo 12c1 &&
+       git init 12c1 &&
        (
                cd 12c1 &&
 
@@ -4492,7 +4492,7 @@ test_expect_merge_algorithm failure success '12c1: Moving one directory hierarch
 #         on each side of the merge.
 
 test_setup_12c2 () {
-       test_create_repo 12c2 &&
+       git init 12c2 &&
        (
                cd 12c2 &&
 
@@ -4584,7 +4584,7 @@ test_expect_success '12c2: Moving one directory hierarchy into another w/ conten
 #   Expected: subdir/foo, bar
 
 test_setup_12d () {
-       test_create_repo 12d &&
+       git init 12d &&
        (
                cd 12d &&
 
@@ -4642,7 +4642,7 @@ test_expect_success '12d: Rename/merge subdir into the root, variant 1' '
 #   Expected: foo, bar
 
 test_setup_12e () {
-       test_create_repo 12e &&
+       git init 12e &&
        (
                cd 12e &&
 
@@ -4743,7 +4743,7 @@ test_expect_success '12e: Rename/merge subdir into the root, variant 2' '
 #      pick and re-applying them in the subsequent one.
 
 test_setup_12f () {
-       test_create_repo 12f &&
+       git init 12f &&
        (
                cd 12f &&
 
@@ -4902,7 +4902,7 @@ test_expect_merge_algorithm failure success '12f: Trivial directory resolve, cac
 #   Expected: newfile_{merged}, newdir/{a_B,b_B,c_A}
 
 test_setup_12g () {
-       test_create_repo 12g &&
+       git init 12g &&
        (
                cd 12g &&
 
@@ -4973,7 +4973,7 @@ test_expect_success '12g: Testcase with two kinds of "relevant" renames' '
 #   Expected: newdir/{alpha_2, b}
 
 test_setup_12h () {
-       test_create_repo 12h &&
+       git init 12h &&
        (
                cd 12h &&
 
@@ -5032,7 +5032,7 @@ test_expect_failure '12h: renaming a file within a renamed directory' '
 #                source/bar vs. source/subdir/bar
 
 test_setup_12i () {
-       test_create_repo 12i &&
+       git init 12i &&
        (
                cd 12i &&
 
@@ -5090,7 +5090,7 @@ test_expect_success '12i: Directory rename causes rename-to-self' '
 #   Expected: {foo, bar, baz_2}, with conflicts on bar vs. subdir/bar
 
 test_setup_12j () {
-       test_create_repo 12j &&
+       git init 12j &&
        (
                cd 12j &&
 
@@ -5148,7 +5148,7 @@ test_expect_success '12j: Directory rename to root causes rename-to-self' '
 #   Expected: dirA/{foo, bar, baz_2}, with conflicts on dirA/bar vs. dirB/bar
 
 test_setup_12k () {
-       test_create_repo 12k &&
+       git init 12k &&
        (
                cd 12k &&
 
@@ -5218,7 +5218,7 @@ test_expect_success '12k: Directory rename with sibling causes rename-to-self' '
 #   is needed for there to be a sub1/ -> sub3/ rename.
 
 test_setup_12l () {
-       test_create_repo 12l_$1 &&
+       git init 12l_$1 &&
        (
                cd 12l_$1 &&
 
@@ -5322,7 +5322,7 @@ test_expect_merge_algorithm failure success '12l (A into B): Rename into each ot
 #   Expected: y/{b,c,d,e/f}, with notices/conflicts for both y/d and y/e/f
 
 test_setup_13a () {
-       test_create_repo 13a_$1 &&
+       git init 13a_$1 &&
        (
                cd 13a_$1 &&
 
@@ -5409,7 +5409,7 @@ test_expect_success '13a(info): messages for newly added files' '
 #             one about content, and one about file location
 
 test_setup_13b () {
-       test_create_repo 13b_$1 &&
+       git init 13b_$1 &&
        (
                cd 13b_$1 &&
 
@@ -5496,7 +5496,7 @@ test_expect_success '13b(info): messages for transitive rename with conflicted c
 #             shown in testcase 13d.
 
 test_setup_13c () {
-       test_create_repo 13c_$1 &&
+       git init 13c_$1 &&
        (
                cd 13c_$1 &&
 
@@ -5584,7 +5584,7 @@ test_expect_success '13c(info): messages for rename/rename(1to1) via transitive
 #               No conflict in where a/y ends up, so put it in d/y.
 
 test_setup_13d () {
-       test_create_repo 13d_$1 &&
+       git init 13d_$1 &&
        (
                cd 13d_$1 &&
 
@@ -5710,7 +5710,7 @@ test_expect_success '13d(info): messages for rename/rename(1to1) via dual transi
 #          least avoids hitting a BUG().
 #
 test_setup_13e () {
-       test_create_repo 13e &&
+       git init 13e &&
        (
                cd 13e &&
 
index b6e424a427b5566b2edf48b3d0a29ad6a927f67e..a61f20c22fe62031da12af45bd8ca427782043bf 100755 (executable)
@@ -114,6 +114,39 @@ test_expect_success 'resolve, non-trivial' '
        test_path_is_missing .git/MERGE_HEAD
 '
 
+test_expect_success 'resolve, trivial, related file removed' '
+       git reset --hard &&
+       git checkout B^0 &&
+
+       git rm a &&
+       test_path_is_missing a &&
+
+       test_must_fail git merge -s resolve C^0 &&
+
+       test_path_is_missing a &&
+       test_path_is_missing .git/MERGE_HEAD
+'
+
+test_expect_success 'resolve, non-trivial, related file removed' '
+       git reset --hard &&
+       git checkout B^0 &&
+
+       git rm a &&
+       test_path_is_missing a &&
+
+       # We also ask for recursive in order to turn off the "allow_trivial"
+       # setting in builtin/merge.c, and ensure that resolve really does
+       # correctly fail the merge (I guess this also tests that recursive
+       # correctly fails the merge, but the main thing we are attempting
+       # to test here is resolve and are just using the side effect of
+       # adding recursive to ensure that resolve is actually tested rather
+       # than the trivial merge codepath)
+       test_must_fail git merge -s resolve -s recursive D^0 &&
+
+       test_path_is_missing a &&
+       test_path_is_missing .git/MERGE_HEAD
+'
+
 test_expect_success 'recursive' '
        git reset --hard &&
        git checkout B^0 &&
@@ -242,4 +275,36 @@ test_expect_success 'subtree' '
        test_path_is_missing .git/MERGE_HEAD
 '
 
+test_expect_success 'avoid failure due to stat-dirty files' '
+       git reset --hard &&
+       git checkout B^0 &&
+
+       # Make "a" be stat-dirty
+       test-tool chmtime =+1 a &&
+
+       # stat-dirty file should not prevent stash creation in builtin/merge.c
+       git merge -s resolve -s recursive D^0
+'
+
+test_expect_success 'with multiple strategies, recursive or ort failure do not early abort' '
+       git reset --hard &&
+       git checkout B^0 &&
+
+       test_seq 0 10 >a &&
+       git add a &&
+       git rev-parse :a >expect &&
+
+       sane_unset GIT_TEST_MERGE_ALGORITHM &&
+       test_must_fail git merge -s recursive -s ort -s octopus C^0 >output 2>&1 &&
+
+       grep "Trying merge strategy recursive..." output &&
+       grep "Trying merge strategy ort..." output &&
+       grep "Trying merge strategy octopus..." output &&
+       grep "No merge strategy handled the merge." output &&
+
+       # Changes to "a" should remain staged
+       git rev-parse :a >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 459b431a60d83c9f1e7c052b9c41491854f9997d..93cd2869b12897b5246a3a977f0cdaf1b2911663 100755 (executable)
@@ -4,6 +4,7 @@ test_description='Merge-recursive rename/delete conflict message'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'rename/delete' '
index 7b5f1c1dcd1f68c74646a5983b6b0d53bd9b4a92..2bb8e7f09bb5897fa670aaf808e84ac7bc3516d3 100755 (executable)
@@ -38,7 +38,7 @@ test_description="merge cases"
 #   Expected: b_2
 
 test_setup_1a () {
-       test_create_repo 1a_$1 &&
+       git init 1a_$1 &&
        (
                cd 1a_$1 &&
 
@@ -136,7 +136,7 @@ test_expect_success '1a-R: Modify(A)/Modify(B), change on B subset of A' '
 #   Expected: c_2
 
 test_setup_2a () {
-       test_create_repo 2a_$1 &&
+       git init 2a_$1 &&
        (
                cd 2a_$1 &&
 
@@ -229,7 +229,7 @@ test_expect_success '2a-R: Modify/rename, merge into rename side' '
 #   Expected: c_2
 
 test_setup_2b () {
-       test_create_repo 2b_$1 &&
+       git init 2b_$1 &&
        (
                cd 2b_$1 &&
 
@@ -336,7 +336,7 @@ test_expect_success '2b-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
 #         not make that particular mistake.
 
 test_setup_2c () {
-       test_create_repo 2c &&
+       git init 2c &&
        (
                cd 2c &&
 
@@ -437,7 +437,7 @@ test_expect_success '2c: Modify b & add c VS rename b->c' '
 #   Expected: bar/{bq_2, whatever}
 
 test_setup_3a () {
-       test_create_repo 3a_$1 &&
+       git init 3a_$1 &&
        (
                cd 3a_$1 &&
 
@@ -537,7 +537,7 @@ test_expect_success '3a-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
 #   Expected: bar/{bq_2, whatever}
 
 test_setup_3b () {
-       test_create_repo 3b_$1 &&
+       git init 3b_$1 &&
        (
                cd 3b_$1 &&
 
@@ -642,7 +642,7 @@ test_expect_success '3b-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
 #   Expected: b_2 for merge, b_4 in working copy
 
 test_setup_4a () {
-       test_create_repo 4a &&
+       git init 4a &&
        (
                cd 4a &&
 
@@ -714,7 +714,7 @@ test_expect_merge_algorithm failure success '4a: Change on A, change on B subset
 #   Expected: c_2
 
 test_setup_4b () {
-       test_create_repo 4b &&
+       git init 4b &&
        (
                cd 4b &&
 
index a9ee4cb207a140eb3c93614f25b9625f43553d59..dd5fe6a402196270fba03fadff55d1e39fa64f02 100755 (executable)
@@ -19,7 +19,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 #
 
 test_expect_success 'setup no merge base' '
-       test_create_repo no_merge_base &&
+       git init no_merge_base &&
        (
                cd no_merge_base &&
 
@@ -55,7 +55,7 @@ test_expect_success 'check no merge base' '
 #
 
 test_expect_success 'setup unique merge base' '
-       test_create_repo unique_merge_base &&
+       git init unique_merge_base &&
        (
                cd unique_merge_base &&
 
@@ -116,7 +116,7 @@ test_expect_success 'check unique merge base' '
 #
 
 test_expect_success 'setup multiple merge bases' '
-       test_create_repo multiple_merge_bases &&
+       git init multiple_merge_bases &&
        (
                cd multiple_merge_bases &&
 
@@ -190,7 +190,7 @@ test_expect_success 'check multiple merge bases' '
 '
 
 test_expect_success 'rebase --merge describes parent of commit being picked' '
-       test_create_repo rebase &&
+       git init rebase &&
        (
                cd rebase &&
                test_commit base file &&
@@ -212,7 +212,7 @@ test_expect_success 'rebase --apply describes fake ancestor base' '
 '
 
 test_setup_zdiff3 () {
-       test_create_repo zdiff3 &&
+       git init zdiff3 &&
        (
                cd zdiff3 &&
 
index 064be1b629e318bb571f1dca2d8ac9c26f86adf9..9919c3fa7cd4359ebe36e3b4b1cbbe99da227905 100755 (executable)
@@ -29,7 +29,7 @@ test_description="merge cases"
 # Testcase basic, conflicting changes in 'numerals'
 
 test_setup_numerals () {
-       test_create_repo numerals_$1 &&
+       git init numerals_$1 &&
        (
                cd numerals_$1 &&
 
index e1ce9199164806abc23955530e4681d1f3cf671e..d02fa16614e0622585a7732942ee9d5b515e6afa 100755 (executable)
@@ -35,7 +35,7 @@ test_description="remember regular & dir renames in sequence of merges"
 # preventing us from finding new renames.
 #
 test_expect_success 'caching renames does not preclude finding new ones' '
-       test_create_repo caching-renames-and-new-renames &&
+       git init caching-renames-and-new-renames &&
        (
                cd caching-renames-and-new-renames &&
 
@@ -106,7 +106,7 @@ test_expect_success 'caching renames does not preclude finding new ones' '
 # should be able to only run rename detection on the upstream side one
 # time.)
 test_expect_success 'cherry-pick both a commit and its immediate revert' '
-       test_create_repo pick-commit-and-its-immediate-revert &&
+       git init pick-commit-and-its-immediate-revert &&
        (
                cd pick-commit-and-its-immediate-revert &&
 
@@ -162,7 +162,7 @@ test_expect_success 'cherry-pick both a commit and its immediate revert' '
 # could cause a spurious rename/add conflict.
 #
 test_expect_success 'rename same file identically, then reintroduce it' '
-       test_create_repo rename-rename-1to1-then-add-old-filename &&
+       git init rename-rename-1to1-then-add-old-filename &&
        (
                cd rename-rename-1to1-then-add-old-filename &&
 
@@ -229,7 +229,7 @@ test_expect_success 'rename same file identically, then reintroduce it' '
 # cached, the directory rename could put newfile in the wrong directory.
 #
 test_expect_success 'rename same file identically, then add file to old dir' '
-       test_create_repo rename-rename-1to1-then-add-file-to-old-dir &&
+       git init rename-rename-1to1-then-add-file-to-old-dir &&
        (
                cd rename-rename-1to1-then-add-file-to-old-dir &&
 
@@ -311,7 +311,7 @@ test_expect_success 'rename same file identically, then add file to old dir' '
 # should avoid the need to re-detect upstream renames.)
 #
 test_expect_success 'cached dir rename does not prevent noticing later conflict' '
-       test_create_repo dir-rename-cache-not-occluding-later-conflict &&
+       git init dir-rename-cache-not-occluding-later-conflict &&
        (
                cd dir-rename-cache-not-occluding-later-conflict &&
 
@@ -365,7 +365,7 @@ test_expect_success 'cached dir rename does not prevent noticing later conflict'
 
 # Helper for the next two tests
 test_setup_upstream_rename () {
-       test_create_repo $1 &&
+       git init $1 &&
        (
                cd $1 &&
 
@@ -537,7 +537,7 @@ test_expect_success 'dir rename unneeded, then rename existing file into old dir
 
 # Helper for the next two tests
 test_setup_topic_rename () {
-       test_create_repo $1 &&
+       git init $1 &&
        (
                cd $1 &&
 
@@ -725,7 +725,7 @@ test_expect_success 'avoid assuming we detected renames' '
                mkdir unrelated &&
                for i in $(test_seq 1 10)
                do
-                       >unrelated/$i
+                       >unrelated/$i || exit 1
                done &&
                test_seq  2 10 >numbers &&
                test_seq 12 20 >values &&
index 3824756a02ec31c228e2eeda92fc13a33b1e4b75..3fe14cd73e895fde51b4f711865553e7a142a2ea 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='merge-recursive backend test'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 #         A      <- create some files
index 74562e1235666ffe49e0978b78dbfb06e416cd2e..fde4aa3cd1ab66a13c61234155da0c2bacb851a9 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='merge with sparse files'
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 # test_file $filename $content
@@ -26,6 +27,7 @@ test_expect_success 'setup' '
        git rm modify_delete &&
        test_commit_this ours &&
        git config core.sparseCheckout true &&
+       mkdir .git/info &&
        echo "/checked-out" >.git/info/sparse-checkout &&
        git reset --hard &&
        test_must_fail git merge theirs
index 178413c22f0dc1dd03152ec1d84843e070d1d843..c9a86f2e947e4a2943438cc5adcaaeab39a465d9 100755 (executable)
@@ -103,8 +103,25 @@ test_expect_success 'setup for merge search' '
         echo "file-c" > file-c &&
         git add file-c &&
         git commit -m "sub-c") &&
-       git commit -a -m "c" &&
+       git commit -a -m "c")
+'
 
+test_expect_success 'merging should conflict for non fast-forward' '
+       test_when_finished "git -C merge-search reset --hard" &&
+       (cd merge-search &&
+        git checkout -b test-nonforward-a b &&
+         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
+         then
+               test_must_fail git merge c >actual &&
+               sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
+               grep "$sub_expect" actual
+         else
+               test_must_fail git merge c 2> actual
+         fi)
+'
+
+test_expect_success 'finish setup for merge-search' '
+       (cd merge-search &&
        git checkout -b d a &&
        (cd sub &&
         git checkout -b sub-d sub-b &&
@@ -129,14 +146,16 @@ test_expect_success 'merge with one side as a fast-forward of the other' '
         test_cmp expect actual)
 '
 
-test_expect_success 'merging should conflict for non fast-forward' '
+test_expect_success 'merging should conflict for non fast-forward (resolution exists)' '
        (cd merge-search &&
-        git checkout -b test-nonforward b &&
+        git checkout -b test-nonforward-b b &&
         (cd sub &&
-         git rev-parse sub-d > ../expect) &&
+         git rev-parse --short sub-d > ../expect) &&
          if test "$GIT_TEST_MERGE_ALGORITHM" = ort
          then
-               test_must_fail git merge c >actual
+               test_must_fail git merge c >actual &&
+               sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
+               grep "$sub_expect" actual
          else
                test_must_fail git merge c 2> actual
          fi &&
@@ -161,7 +180,9 @@ test_expect_success 'merging should fail for ambiguous common parent' '
         ) &&
         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
         then
-               test_must_fail git merge c >actual
+               test_must_fail git merge c >actual &&
+               sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
+               grep "$sub_expect" actual
         else
                test_must_fail git merge c 2> actual
         fi &&
@@ -205,7 +226,12 @@ test_expect_success 'merging should fail for changes that are backwards' '
        git commit -a -m "f" &&
 
        git checkout -b test-backward e &&
-       test_must_fail git merge f)
+       test_must_fail git merge f >actual &&
+       if test "$GIT_TEST_MERGE_ALGORITHM" = ort
+    then
+               sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)" &&
+               grep "$sub_expect" actual
+       fi)
 '
 
 
@@ -310,7 +336,7 @@ test_expect_success 'recursive merge with submodule' '
 #   Expected: path/ is submodule and file contents for B's path are somewhere
 
 test_expect_success 'setup file/submodule conflict' '
-       test_create_repo file-submodule &&
+       git init file-submodule &&
        (
                cd file-submodule &&
 
@@ -325,7 +351,7 @@ test_expect_success 'setup file/submodule conflict' '
                git commit -m B &&
 
                git checkout A &&
-               test_create_repo path &&
+               git init path &&
                test_commit -C path world &&
                git submodule add ./path &&
                git commit -m A
@@ -385,7 +411,7 @@ test_expect_success 'file/submodule conflict; merge --abort works afterward' '
 #     under the submodule to be treated as untracked or in the way.
 
 test_expect_success 'setup directory/submodule conflict' '
-       test_create_repo directory-submodule &&
+       git init directory-submodule &&
        (
                cd directory-submodule &&
 
@@ -408,7 +434,7 @@ test_expect_success 'setup directory/submodule conflict' '
                git commit -m B2 &&
 
                git checkout A &&
-               test_create_repo path &&
+               git init path &&
                test_commit -C path hello world &&
                git submodule add ./path &&
                git commit -m A
@@ -476,4 +502,44 @@ test_expect_failure 'directory/submodule conflict; merge --abort works afterward
        )
 '
 
+# Setup:
+#   - Submodule has 2 commits: a and b
+#   - Superproject branch 'a' adds and commits submodule pointing to 'commit a'
+#   - Superproject branch 'b' adds and commits submodule pointing to 'commit b'
+# If these two branches are now merged, there is no merge base
+test_expect_success 'setup for null merge base' '
+       mkdir no-merge-base &&
+       (cd no-merge-base &&
+       git init &&
+       mkdir sub &&
+       (cd sub &&
+        git init &&
+        echo "file-a" > file-a &&
+        git add file-a &&
+        git commit -m "commit a") &&
+       git commit --allow-empty -m init &&
+       git branch init &&
+       git checkout -b a init &&
+       git add sub &&
+       git commit -m "a" &&
+       git switch main &&
+       (cd sub &&
+        echo "file-b" > file-b &&
+        git add file-b &&
+        git commit -m "commit b"))
+'
+
+test_expect_success 'merging should fail with no merge base' '
+       (cd no-merge-base &&
+       git checkout -b b init &&
+       git add sub &&
+       git commit -m "b" &&
+       test_must_fail git merge a >actual &&
+       if test "$GIT_TEST_MERGE_ALGORITHM" = ort
+    then
+               sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)" &&
+               grep "$sub_expect" actual
+       fi)
+'
+
 test_done
index 5bfb027099a6d22849739075de82f3c0af7ca513..52cf0c87690be83e758b97c12b0ab00fa77613a2 100755 (executable)
@@ -47,6 +47,7 @@ test_expect_success 'untracked files overwritten by merge (fast and non-fast for
                export GIT_MERGE_VERBOSITY &&
                test_must_fail git merge branch 2>out2
        ) &&
+       echo "Merge with strategy ${GIT_TEST_MERGE_ALGORITHM:-ort} failed." >>expect &&
        test_cmp out2 expect &&
        git reset --hard HEAD^
 '
index f0f7cbfcdb7fa523ee3693501324cde8591a25d9..26582ae4e5fb5ebb6aebb6239ecd3ab711b119ed 100755 (executable)
@@ -4,6 +4,18 @@ test_description='git mv in sparse working trees'
 
 . ./test-lib.sh
 
+setup_sparse_checkout () {
+       mkdir folder1 &&
+       touch folder1/file1 &&
+       git add folder1 &&
+       git sparse-checkout set --cone sub
+}
+
+cleanup_sparse_checkout () {
+       git sparse-checkout disable &&
+       git reset --hard
+}
+
 test_expect_success 'setup' "
        mkdir -p sub/dir sub/dir2 &&
        touch a b c sub/d sub/dir/e sub/dir2/e &&
@@ -16,12 +28,25 @@ test_expect_success 'setup' "
        updated in the index:
        EOF
 
-       cat >sparse_hint <<-EOF
+       cat >sparse_hint <<-EOF &&
        hint: If you intend to update such entries, try one of the following:
        hint: * Use the --sparse option.
        hint: * Disable or modify the sparsity rules.
        hint: Disable this message with \"git config advice.updateSparsePath false\"
        EOF
+
+       cat >dirty_error_header <<-EOF &&
+       The following paths have been moved outside the
+       sparse-checkout definition but are not sparse due to local
+       modifications.
+       EOF
+
+       cat >dirty_hint <<-EOF
+       hint: To correct the sparsity of these paths, do the following:
+       hint: * Use \"git add --sparse <paths>\" to update the index
+       hint: * Use \"git sparse-checkout reapply\" to apply the sparsity rules
+       hint: Disable this message with \"git config advice.updateSparsePath false\"
+       EOF
 "
 
 test_expect_success 'mv refuses to move sparse-to-sparse' '
@@ -196,6 +221,7 @@ test_expect_success 'can move files to non-sparse dir' '
 '
 
 test_expect_success 'refuse to move file to non-skip-worktree sparse path' '
+       test_when_finished "cleanup_sparse_checkout" &&
        git reset --hard &&
        git sparse-checkout init --no-cone &&
        git sparse-checkout set a !/x y/ !x/y/z &&
@@ -206,4 +232,286 @@ test_expect_success 'refuse to move file to non-skip-worktree sparse path' '
        test_cmp expect stderr
 '
 
+test_expect_success 'refuse to move out-of-cone directory without --sparse' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+
+       test_must_fail git mv folder1 sub 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo folder1/file1 >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr
+'
+
+test_expect_success 'can move out-of-cone directory with --sparse' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+
+       git mv --sparse folder1 sub 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_dir sub/folder1 &&
+       test_path_is_file sub/folder1/file1
+'
+
+test_expect_success 'refuse to move out-of-cone file without --sparse' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+
+       test_must_fail git mv folder1/file1 sub 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo folder1/file1 >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr
+'
+
+test_expect_success 'can move out-of-cone file with --sparse' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+
+       git mv --sparse folder1/file1 sub 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_file sub/file1
+'
+
+test_expect_success 'refuse to move sparse file to existing destination' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       mkdir folder1 &&
+       touch folder1/file1 &&
+       touch sub/file1 &&
+       git add folder1 sub/file1 &&
+       git sparse-checkout set --cone sub &&
+
+       test_must_fail git mv --sparse folder1/file1 sub 2>stderr &&
+       echo "fatal: destination exists, source=folder1/file1, destination=sub/file1" >expect &&
+       test_cmp expect stderr
+'
+
+test_expect_success 'move sparse file to existing destination with --force and --sparse' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       mkdir folder1 &&
+       touch folder1/file1 &&
+       touch sub/file1 &&
+       echo "overwrite" >folder1/file1 &&
+       git add folder1 sub/file1 &&
+       git sparse-checkout set --cone sub &&
+
+       git mv --sparse --force folder1/file1 sub 2>stderr &&
+       test_must_be_empty stderr &&
+       echo "overwrite" >expect &&
+       test_cmp expect sub/file1
+'
+
+test_expect_success 'move clean path from in-cone to out-of-cone' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+
+       test_must_fail git mv sub/d folder1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/d" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse sub/d folder1 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_missing sub/d &&
+       test_path_is_missing folder1/d &&
+       git ls-files -t >actual &&
+       ! grep "^H sub/d\$" actual &&
+       grep "S folder1/d" actual
+'
+
+test_expect_success 'move clean path from in-cone to out-of-cone overwrite' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+       echo "sub/file1 overwrite" >sub/file1 &&
+       git add sub/file1 &&
+
+       test_must_fail git mv sub/file1 folder1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/file1" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       test_must_fail git mv --sparse sub/file1 folder1 2>stderr &&
+       echo "fatal: destination exists in the index, source=sub/file1, destination=folder1/file1" \
+       >expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse -f sub/file1 folder1 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_missing sub/file1 &&
+       test_path_is_missing folder1/file1 &&
+       git ls-files -t >actual &&
+       ! grep "H sub/file1" actual &&
+       grep "S folder1/file1" actual &&
+
+       # compare file content before move and after move
+       echo "sub/file1 overwrite" >expect &&
+       git ls-files -s -- folder1/file1 | awk "{print \$2}" >oid &&
+       git cat-file blob $(cat oid) >actual &&
+       test_cmp expect actual
+'
+
+# This test is testing the same behavior as the
+# "move clean path from in-cone to out-of-cone overwrite" above.
+# The only difference is the <destination> changes from "folder1" to "folder1/file1"
+test_expect_success 'move clean path from in-cone to out-of-cone file overwrite' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+       echo "sub/file1 overwrite" >sub/file1 &&
+       git add sub/file1 &&
+
+       test_must_fail git mv sub/file1 folder1/file1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/file1" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       test_must_fail git mv --sparse sub/file1 folder1/file1 2>stderr &&
+       echo "fatal: destination exists in the index, source=sub/file1, destination=folder1/file1" \
+       >expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse -f sub/file1 folder1/file1 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_missing sub/file1 &&
+       test_path_is_missing folder1/file1 &&
+       git ls-files -t >actual &&
+       ! grep "H sub/file1" actual &&
+       grep "S folder1/file1" actual &&
+
+       # compare file content before move and after move
+       echo "sub/file1 overwrite" >expect &&
+       git ls-files -s -- folder1/file1 | awk "{print \$2}" >oid &&
+       git cat-file blob $(cat oid) >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'move directory with one of the files overwrite' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       mkdir -p folder1/dir &&
+       touch folder1/dir/file1 &&
+       git add folder1 &&
+       git sparse-checkout set --cone sub &&
+
+       echo test >sub/dir/file1 &&
+       git add sub/dir/file1 &&
+
+       test_must_fail git mv sub/dir folder1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/dir/e" >>expect &&
+       echo "folder1/dir/file1" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       test_must_fail git mv --sparse sub/dir folder1 2>stderr &&
+       echo "fatal: destination exists in the index, source=sub/dir/file1, destination=folder1/dir/file1" \
+       >expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse -f sub/dir folder1 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_missing sub/dir/file1 &&
+       test_path_is_missing sub/dir/e &&
+       test_path_is_missing folder1/file1 &&
+       git ls-files -t >actual &&
+       ! grep "H sub/dir/file1" actual &&
+       ! grep "H sub/dir/e" actual &&
+       grep "S folder1/dir/file1" actual &&
+
+       # compare file content before move and after move
+       echo test >expect &&
+       git ls-files -s -- folder1/dir/file1 | awk "{print \$2}" >oid &&
+       git cat-file blob $(cat oid) >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'move dirty path from in-cone to out-of-cone' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+       echo "modified" >>sub/d &&
+
+       test_must_fail git mv sub/d folder1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/d" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse sub/d folder1 2>stderr &&
+       cat dirty_error_header >expect &&
+       echo "folder1/d" >>expect &&
+       cat dirty_hint >>expect &&
+       test_cmp expect stderr &&
+
+       test_path_is_missing sub/d &&
+       test_path_is_file folder1/d &&
+       git ls-files -t >actual &&
+       ! grep "^H sub/d\$" actual &&
+       grep "H folder1/d" actual
+'
+
+test_expect_success 'move dir from in-cone to out-of-cone' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+       mkdir sub/dir/deep &&
+
+       test_must_fail git mv sub/dir folder1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/dir/e" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse sub/dir folder1 2>stderr &&
+       test_must_be_empty stderr &&
+
+       test_path_is_missing sub/dir &&
+       test_path_is_missing folder1 &&
+       git ls-files -t >actual &&
+       ! grep "H sub/dir/e" actual &&
+       grep "S folder1/dir/e" actual
+'
+
+test_expect_success 'move partially-dirty dir from in-cone to out-of-cone' '
+       test_when_finished "cleanup_sparse_checkout" &&
+       setup_sparse_checkout &&
+       mkdir sub/dir/deep &&
+       touch sub/dir/e2 sub/dir/e3 &&
+       git add sub/dir/e2 sub/dir/e3 &&
+       echo "modified" >>sub/dir/e2 &&
+       echo "modified" >>sub/dir/e3 &&
+
+       test_must_fail git mv sub/dir folder1 2>stderr &&
+       cat sparse_error_header >expect &&
+       echo "folder1/dir/e" >>expect &&
+       echo "folder1/dir/e2" >>expect &&
+       echo "folder1/dir/e3" >>expect &&
+       cat sparse_hint >>expect &&
+       test_cmp expect stderr &&
+
+       git mv --sparse sub/dir folder1 2>stderr &&
+       cat dirty_error_header >expect &&
+       echo "folder1/dir/e2" >>expect &&
+       echo "folder1/dir/e3" >>expect &&
+       cat dirty_hint >>expect &&
+       test_cmp expect stderr &&
+
+       test_path_is_missing sub/dir &&
+       test_path_is_missing folder1/dir/e &&
+       test_path_is_file folder1/dir/e2 &&
+       test_path_is_file folder1/dir/e3 &&
+       git ls-files -t >actual &&
+       ! grep "H sub/dir/e" actual &&
+       ! grep "H sub/dir/e2" actual &&
+       ! grep "H sub/dir/e3" actual &&
+       grep "S folder1/dir/e" actual &&
+       grep "H folder1/dir/e2" actual &&
+       grep "H folder1/dir/e3" actual
+'
+
 test_done
index e18a218952385984944eaaab369af051873d0363..f6aebe92ff9d94b20670f7436c57f8107bb3404a 100755 (executable)
@@ -49,7 +49,7 @@ test_expect_success 'result is really identical' '
 test_expect_success 'rewrite bare repository identically' '
        (git config core.bare true && cd .git &&
         git filter-branch branch > filter-output 2>&1 &&
-       ! fgrep fatal filter-output)
+       ! grep fatal filter-output)
 '
 git config core.bare false
 test_expect_success 'result is really identical' '
@@ -506,7 +506,7 @@ test_expect_success 'rewrite repository including refs that point at non-commit
        git tag -a -m "tag to a tree" treetag $new_tree &&
        git reset --hard HEAD &&
        git filter-branch -f -- --all >filter-output 2>&1 &&
-       ! fgrep fatal filter-output
+       ! grep fatal filter-output
 '
 
 test_expect_success 'filter-branch handles ref deletion' '
index d6cc69e0f2cbd576ff6ff81720de63f1e9cf86bf..f908a4d1abc5dc6608b4473937a614267013f3a2 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git show'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 0f4344c55e6421d605ab7364bc2fedfe9165b02b..aaeb4a533440df495d99e3b123f1640afe4374e7 100755 (executable)
@@ -5,6 +5,7 @@ test_description='basic work tree status reporting'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index 73709dbeee287932b3d925aad78f5c2d3f216a52..caf372a3d42ac362c96bbbdf340f27688a565130 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git-status with core.ignorecase=true'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'status with hash collisions' '
index c1f0d950363d311a4b8da3b6fde00b69cb2bdd74..8929ef481f926ce8eee1414b852c3e14538afa9c 100755 (executable)
@@ -86,7 +86,7 @@ test_expect_success 'core.untrackedCache is unset' '
 '
 
 test_expect_success 'setup' '
-       git init worktree &&
+       git init --template= worktree &&
        cd worktree &&
        mkdir done dtwo dthree &&
        touch one two three done/one dtwo/two dthree/three &&
@@ -94,6 +94,7 @@ test_expect_success 'setup' '
        test-tool chmtime =-300 done dtwo dthree &&
        test-tool chmtime =-300 . &&
        git add one two done/one &&
+       mkdir .git/info &&
        : >.git/info/exclude &&
        git update-index --untracked-cache &&
        test_oid_cache <<-EOF
index 3d62e10b53fe16fd2eae0d0fa0363d8839f97b95..eb881be95b615f53867dbe8f56c6b0f9cc7a9d3c 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='Tests for "git reset" with "--merge" and "--keep" options'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
index ce421ad5ac4b3a17d0e347a7d86a386e2b14547b..78f25c1c7ead9820ed647711e4749d7e9d444c52 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='Tests to check that "reset" options follow a known table'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
index e7cec2e457af7767a1fbda11535ed4c855f09db7..b50db3f1031339b62071bd28b52094f90c644cb5 100755 (executable)
@@ -14,6 +14,32 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
+test_expect_success 'submodule usage: -h' '
+       git submodule -h >out 2>err &&
+       grep "^usage: git submodule" out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'submodule usage: --recursive' '
+       test_expect_code 1 git submodule --recursive >out 2>err &&
+       grep "^usage: git submodule" err &&
+       test_must_be_empty out
+'
+
+test_expect_success 'submodule usage: status --' '
+       test_expect_code 1 git submodule -- &&
+       test_expect_code 1 git submodule --end-of-options
+'
+
+for opt in '--quiet' '--cached'
+do
+       test_expect_success "submodule usage: status $opt" '
+               git submodule $opt &&
+               git submodule status $opt &&
+               git submodule $opt status
+       '
+done
+
 test_expect_success 'submodule deinit works on empty repository' '
        git submodule deinit --all
 '
@@ -152,6 +178,11 @@ test_expect_success 'submodule add' '
        test_must_be_empty untracked
 '
 
+test_expect_success !WINDOWS 'submodule add (absolute path)' '
+       test_when_finished "git reset --hard" &&
+       git submodule add "$submodurl" "$submodurl/add-abs"
+'
+
 test_expect_success 'setup parent and one repository' '
        test_create_repo parent &&
        test_commit -C parent one
@@ -1224,31 +1255,6 @@ test_expect_success 'submodule add clone shallow submodule' '
        )
 '
 
-test_expect_success 'submodule helper list is not confused by common prefixes' '
-       mkdir -p dir1/b &&
-       (
-               cd dir1/b &&
-               git init &&
-               echo hi >testfile2 &&
-               git add . &&
-               git commit -m "test1"
-       ) &&
-       mkdir -p dir2/b &&
-       (
-               cd dir2/b &&
-               git init &&
-               echo hello >testfile1 &&
-               git add .  &&
-               git commit -m "test2"
-       ) &&
-       git submodule add /dir1/b dir1/b &&
-       git submodule add /dir2/b dir2/b &&
-       git commit -m "first submodule commit" &&
-       git submodule--helper list dir1/b | cut -f 2 >actual &&
-       echo "dir1/b" >expect &&
-       test_cmp expect actual
-'
-
 test_expect_success 'setup superproject with submodules' '
        git init sub1 &&
        test_commit -C sub1 test &&
index 9c3cc4cf4046befd76e0239c831d61b33196ee86..542b3331a78f4db27dc5d99d3364f780f4db4548 100755 (executable)
@@ -17,6 +17,7 @@ This test script tries to verify the sanity of summary subcommand of git submodu
 # various reasons, one of them being that there are lots of commands taking place
 # outside of 'test_expect_success' block, which is no longer in good-style.
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 add_file () {
index 8e32f190077474274dc5046df5a64f837ee696f3..ebeca12a71115f60d10fa3ffa4725b1c7080f6f0 100755 (executable)
@@ -104,7 +104,7 @@ test_expect_success 'rebasing submodule that should conflict' '
        test_tick &&
        git commit -m fourth &&
 
-       test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 &&
+       test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 >actual_output &&
        git ls-files -s submodule >actual &&
        (
                cd submodule &&
@@ -112,7 +112,12 @@ test_expect_success 'rebasing submodule that should conflict' '
                echo "160000 $(git rev-parse HEAD^^) 2  submodule" &&
                echo "160000 $(git rev-parse HEAD) 3    submodule"
        ) >expect &&
-       test_cmp expect actual
+       test_cmp expect actual &&
+       if test "$GIT_TEST_MERGE_ALGORITHM" = ort
+    then
+               sub_expect="go to submodule (submodule), and either merge commit $(git -C submodule rev-parse --short HEAD^0)" &&
+               grep "$sub_expect" actual_output
+       fi
 '
 
 test_done
index 43f779d751cfe2645b038811e69b6f67fee2ed34..c5f5dbe55e0a91e24589c8c9d85ba53995091b36 100755 (executable)
@@ -769,7 +769,7 @@ test_expect_success 'submodule update continues after recursive checkout error'
           echo "" > file
          )
         ) &&
-        test_must_fail git submodule update --recursive &&
+        test_expect_code 1 git submodule update --recursive &&
         (cd submodule2 &&
          git rev-parse --verify HEAD >../actual
         ) &&
@@ -1074,7 +1074,7 @@ test_expect_success 'submodule update --quiet passes quietness to merge/rebase'
         git submodule update --rebase --quiet >out 2>err &&
         test_must_be_empty out &&
         test_must_be_empty err &&
-        git submodule update --rebase -v >out 2>err &&
+        git submodule update --rebase >out 2>err &&
         test_file_not_empty out &&
         test_must_be_empty err
        )
@@ -1116,4 +1116,66 @@ test_expect_success 'submodule update --filter sets partial clone settings' '
        test_cmp_config -C super-filter/submodule blob:none remote.origin.partialclonefilter
 '
 
+# NEEDSWORK: Clean up the tests so that we can reuse the test setup.
+# Don't reuse the existing repos because the earlier tests have
+# intentionally disruptive configurations.
+test_expect_success 'setup clean recursive superproject' '
+       git init bottom &&
+       test_commit -C bottom "bottom" &&
+       git init middle &&
+       git -C middle submodule add ../bottom bottom &&
+       git -C middle commit -m "middle" &&
+       git init top &&
+       git -C top submodule add ../middle middle &&
+       git -C top commit -m "top" &&
+       git clone --recurse-submodules top top-clean
+'
+
+test_expect_success 'submodule update should skip unmerged submodules' '
+       test_when_finished "rm -fr top-cloned" &&
+       cp -r top-clean top-cloned &&
+
+       # Create an upstream commit in each repo, starting with bottom
+       test_commit -C bottom upstream_commit &&
+       # Create middle commit
+       git -C middle/bottom fetch &&
+       git -C middle/bottom checkout -f FETCH_HEAD &&
+       git -C middle add bottom &&
+       git -C middle commit -m "upstream_commit" &&
+       # Create top commit
+       git -C top/middle fetch &&
+       git -C top/middle checkout -f FETCH_HEAD &&
+       git -C top add middle &&
+       git -C top commit -m "upstream_commit" &&
+
+       # Create a downstream conflict
+       test_commit -C top-cloned/middle/bottom downstream_commit &&
+       git -C top-cloned/middle add bottom &&
+       git -C top-cloned/middle commit -m "downstream_commit" &&
+       git -C top-cloned/middle fetch --recurse-submodules origin &&
+       test_must_fail git -C top-cloned/middle merge origin/main &&
+
+       # Make the update of "middle" a no-op, otherwise we error out
+       # because of its unmerged state
+       test_config -C top-cloned submodule.middle.update !true &&
+       git -C top-cloned submodule update --recursive 2>actual.err &&
+       cat >expect.err <<-\EOF &&
+       Skipping unmerged submodule middle/bottom
+       EOF
+       test_cmp expect.err actual.err
+'
+
+test_expect_success 'submodule update --recursive skip submodules with strategy=none' '
+       test_when_finished "rm -fr top-cloned" &&
+       cp -r top-clean top-cloned &&
+
+       test_commit -C top-cloned/middle/bottom downstream_commit &&
+       git -C top-cloned/middle config submodule.bottom.update none &&
+       git -C top-cloned submodule update --recursive 2>actual.err &&
+       cat >expect.err <<-\EOF &&
+       Skipping submodule '\''middle/bottom'\''
+       EOF
+       test_cmp expect.err actual.err
+'
+
 test_done
index 1cfa150768d7f813ba9943b4bd17887469cb1c04..2859695c6d208341f5ba1de01e1cfe4131388a2b 100755 (executable)
@@ -6,6 +6,7 @@ This test verifies that `git submodue absorbgitdirs` moves a submodules git
 directory into the superproject.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup a real submodule' '
index c8e7e983317610b54da89101bea8f7c59a4dcec3..4dc7d089423be4acd3c83ceb4055d77fbc11ba70 100755 (executable)
@@ -1,11 +1,15 @@
 #!/bin/sh
 
-test_description='Test submodule--helper is-active
+test_description='Test with test-tool submodule is-active
 
-This test verifies that `git submodue--helper is-active` correctly identifies
+This test verifies that `test-tool submodule is-active` correctly identifies
 submodules which are "active" and interesting to the user.
+
+This is a unit test of the submodule.c is_submodule_active() function,
+which is also indirectly tested elsewhere.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -25,13 +29,13 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'is-active works with urls' '
-       git -C super submodule--helper is-active sub1 &&
-       git -C super submodule--helper is-active sub2 &&
+       test-tool -C super submodule is-active sub1 &&
+       test-tool -C super submodule is-active sub2 &&
 
        git -C super config --unset submodule.sub1.URL &&
-       test_must_fail git -C super submodule--helper is-active sub1 &&
+       test_must_fail test-tool -C super submodule is-active sub1 &&
        git -C super config submodule.sub1.URL ../sub &&
-       git -C super submodule--helper is-active sub1
+       test-tool -C super submodule is-active sub1
 '
 
 test_expect_success 'is-active works with submodule.<name>.active config' '
@@ -39,11 +43,11 @@ test_expect_success 'is-active works with submodule.<name>.active config' '
        test_when_finished "git -C super config submodule.sub1.URL ../sub" &&
 
        git -C super config --bool submodule.sub1.active "false" &&
-       test_must_fail git -C super submodule--helper is-active sub1 &&
+       test_must_fail test-tool -C super submodule is-active sub1 &&
 
        git -C super config --bool submodule.sub1.active "true" &&
        git -C super config --unset submodule.sub1.URL &&
-       git -C super submodule--helper is-active sub1
+       test-tool -C super submodule is-active sub1
 '
 
 test_expect_success 'is-active works with basic submodule.active config' '
@@ -53,17 +57,17 @@ test_expect_success 'is-active works with basic submodule.active config' '
        git -C super config --add submodule.active "." &&
        git -C super config --unset submodule.sub1.URL &&
 
-       git -C super submodule--helper is-active sub1 &&
-       git -C super submodule--helper is-active sub2
+       test-tool -C super submodule is-active sub1 &&
+       test-tool -C super submodule is-active sub2
 '
 
 test_expect_success 'is-active correctly works with paths that are not submodules' '
        test_when_finished "git -C super config --unset-all submodule.active" &&
 
-       test_must_fail git -C super submodule--helper is-active not-a-submodule &&
+       test_must_fail test-tool -C super submodule is-active not-a-submodule &&
 
        git -C super config --add submodule.active "." &&
-       test_must_fail git -C super submodule--helper is-active not-a-submodule
+       test_must_fail test-tool -C super submodule is-active not-a-submodule
 '
 
 test_expect_success 'is-active works with exclusions in submodule.active config' '
@@ -72,8 +76,8 @@ test_expect_success 'is-active works with exclusions in submodule.active config'
        git -C super config --add submodule.active "." &&
        git -C super config --add submodule.active ":(exclude)sub1" &&
 
-       test_must_fail git -C super submodule--helper is-active sub1 &&
-       git -C super submodule--helper is-active sub2
+       test_must_fail test-tool -C super submodule is-active sub1 &&
+       test-tool -C super submodule is-active sub2
 '
 
 test_expect_success 'is-active with submodule.active and submodule.<name>.active' '
@@ -85,8 +89,8 @@ test_expect_success 'is-active with submodule.active and submodule.<name>.active
        git -C super config --bool submodule.sub1.active "false" &&
        git -C super config --bool submodule.sub2.active "true" &&
 
-       test_must_fail git -C super submodule--helper is-active sub1 &&
-       git -C super submodule--helper is-active sub2
+       test_must_fail test-tool -C super submodule is-active sub1 &&
+       test-tool -C super submodule is-active sub2
 '
 
 test_expect_success 'is-active, submodule.active and submodule add' '
index f2e7df59cf24c254440a8bc1c7d5c195c8bfcd5b..3269298197c2c2dcf92a780d401d212101c8475f 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='handling of common mistakes people may make with submodules'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'create embedded repository' '
index f87e524d6d467fd723c083c105f092850051f566..57d7ab3eced2970791021caa9855e1ed0c1d2712 100755 (executable)
@@ -31,8 +31,9 @@ test_expect_success 'sparse checkout setup which hides .gitmodules' '
                test_tick &&
                git commit -m "Add submodule"
        ) &&
-       git clone upstream super &&
+       git clone --template= upstream super &&
        (cd super &&
+               mkdir .git/info &&
                cat >.git/info/sparse-checkout <<-\EOF &&
                /*
                !/.gitmodules
index 3b925c302fc4e2194a2e0ad10c0b48823f2cf021..96e984232144c60743d59150c68461e5b1e779eb 100755 (executable)
@@ -9,6 +9,7 @@ This test verifies that the set-branch subcommand of git-submodule is working
 as expected.
 '
 
+TEST_PASSES_SANITIZE_LEAK=true
 TEST_NO_CREATE_REPO=1
 . ./test-lib.sh
 
index 41706c1c9ff91d4ac11d9af9f8acdd7f587b896d..2c24f120da3591305b073d247e21e3c07cff9386 100755 (executable)
@@ -21,7 +21,7 @@ test_expect_success 'check names' '
        valid/with/paths
        EOF
 
-       git submodule--helper check-name >actual <<-\EOF &&
+       test-tool submodule check-name >actual <<-\EOF &&
        valid
        valid/with/paths
 
index ad1eb64ba0db16d4f1452961c0a226fdf2e5cce0..aa004b70a8d1f1ab093b962a232524eaf4e851a1 100755 (executable)
@@ -5,6 +5,7 @@ test_description='pre-commit and pre-merge-commit hooks'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'root commit' '
index 3fcb44767f51052f637683a34cbb8a2f21c777cc..f5426a8e589fb6a0beadd9ef793ed6be66b69355 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git status for submodule'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_create_repo_with_commit () {
index ed2653d46fe6cd0ed1dd5dc2dfd73f7340b8fe31..92462a22374042603a885c4b52fb49b3d16e0373 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='verbose commit template'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 write_script "check-for-diff" <<\EOF &&
index 56c0dfffea6e73e54120e61cd752dda78ae15ad3..1746d30cf6a0979e0e74577b67b9ae35253ff9d6 100755 (executable)
@@ -939,9 +939,9 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' '
        # directories and files that we touched.  We may or may not get a
        # trailing slash on modified directories.
        #
-       egrep "^event: abc/?$"       ./insensitive.trace &&
-       egrep "^event: abc/def/?$"   ./insensitive.trace &&
-       egrep "^event: abc/def/xyz$" ./insensitive.trace
+       grep -E "^event: abc/?$"       ./insensitive.trace &&
+       grep -E "^event: abc/def/?$"   ./insensitive.trace &&
+       grep -E "^event: abc/def/xyz$" ./insensitive.trace
 '
 
 # The variable "unicode_debug" is defined in the following library
@@ -983,20 +983,20 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' '
        then
                # We should have seen NFC event from OS.
                # We should not have synthesized an NFD event.
-               egrep    "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace &&
-               egrep -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace
+               grep -E    "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace &&
+               grep -E -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace
        else
                # We should have seen NFD event from OS.
                # We should have synthesized an NFC event.
-               egrep "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace &&
-               egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace
+               grep -E "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace &&
+               grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace
        fi &&
 
        # We assume UNICODE_NFD_PRESERVED.
        # We should have seen explicit NFD from OS.
        # We should have synthesized an NFC event.
-       egrep "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace &&
-       egrep "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
+       grep -E "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace &&
+       grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
 '
 
 test_done
diff --git a/t/t7607-merge-state.sh b/t/t7607-merge-state.sh
new file mode 100755 (executable)
index 0000000..89a62ac
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+test_description="Test that merge state is as expected after failed merge"
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+. ./test-lib.sh
+
+test_expect_success 'Ensure we restore original state if no merge strategy handles it' '
+       test_commit --no-tag "Initial" base base &&
+
+       for b in branch1 branch2 branch3
+       do
+               git checkout -b $b main &&
+               test_commit --no-tag "Change on $b" base $b || return 1
+       done &&
+
+       git checkout branch1 &&
+       # This is a merge that octopus cannot handle.  Note, that it does not
+       # just hit conflicts, it completely fails and says that it cannot
+       # handle this type of merge.
+       test_expect_code 2 git merge branch2 branch3 >output 2>&1 &&
+       grep "fatal: merge program failed" output &&
+       grep "Should not be doing an octopus" output &&
+
+       # Make sure we did not leave stray changes around when no appropriate
+       # merge strategy was found
+       git diff --exit-code --name-status &&
+       test_path_is_missing .git/MERGE_HEAD
+'
+
+test_done
index 330d6d603d77236788ee932cdcc288731a7aa388..8b1c3bd39f2249417099ea2f24218268925909af 100755 (executable)
@@ -4,6 +4,7 @@ test_description='git mergetool
 
 Testing basic merge tools options'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'mergetool --tool=vimdiff creates the expected layout' '
index 937f89ee8c8aa0afd4db98fe4bbe9b63b333d77a..b7ac4f598a85c47b360b50726ca3d7b04840ff96 100755 (executable)
@@ -35,7 +35,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' '
        git repack -A -d -l &&
        # verify objects are packed in repository
        test 3 = $(git verify-pack -v -- .git/objects/pack/*.idx |
-                  egrep "^($fsha1|$csha1|$tsha1) " |
+                  grep -E "^($fsha1|$csha1|$tsha1) " |
                   sort | uniq | wc -l) &&
        git show $fsha1 &&
        git show $csha1 &&
@@ -49,7 +49,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' '
        git repack -A -d -l &&
        # verify objects are retained unpacked
        test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx |
-                  egrep "^($fsha1|$csha1|$tsha1) " |
+                  grep -E "^($fsha1|$csha1|$tsha1) " |
                   sort | uniq | wc -l) &&
        git show $fsha1 &&
        git show $csha1 &&
index 69356011713fad1add8044471f01f9d6d3dee892..8eded6ab274fafe636151b7903bae3351a27df5c 100755 (executable)
@@ -18,6 +18,9 @@ test_invalid_grep_expression() {
        '
 }
 
+LC_ALL=en_US.UTF-8 test-tool regex '^.$' '¿' &&
+  test_set_prereq MB_REGEX
+
 cat >hello.c <<EOF
 #include <assert.h>
 #include <stdio.h>
@@ -77,6 +80,7 @@ test_expect_success setup '
        # Say hello.
        function hello() {
          echo "Hello world."
+         echo "Hello again."
        } # hello
 
        # Still a no-op.
@@ -87,6 +91,10 @@ test_expect_success setup '
                echo unusual >"\"unusual\" pathname" &&
                echo unusual >"t/nested \"unusual\" pathname"
        fi &&
+       if test_have_prereq MB_REGEX
+       then
+               echo "¿" >reverse-question-mark
+       fi &&
        git add . &&
        test_tick &&
        git commit -m initial
@@ -568,6 +576,14 @@ do
        '
 done
 
+test_expect_success MB_REGEX 'grep exactly one char in single-char multibyte file' '
+       LC_ALL=en_US.UTF-8 git grep "^.$" reverse-question-mark
+'
+
+test_expect_success MB_REGEX 'grep two chars in single-char multibyte file' '
+       LC_ALL=en_US.UTF-8 test_expect_code 1 git grep ".." reverse-question-mark
+'
+
 cat >expected <<EOF
 file
 EOF
@@ -595,6 +611,92 @@ test_expect_success 'grep --files-without-match --quiet' '
        test_must_be_empty actual
 '
 
+test_expect_success 'grep --max-count 0 (must exit with non-zero)' '
+       test_must_fail git grep --max-count 0 foo >actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success 'grep --max-count 3' '
+       cat >expected <<-EOF &&
+       file:foo mmap bar
+       file:foo_mmap bar
+       file:foo_mmap bar mmap
+       EOF
+       git grep --max-count 3 foo >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count -1 (no limit)' '
+       cat >expected <<-EOF &&
+       file:foo mmap bar
+       file:foo_mmap bar
+       file:foo_mmap bar mmap
+       file:foo mmap bar_mmap
+       file:foo_mmap bar mmap baz
+       EOF
+       git grep --max-count -1 foo >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count 1 --context 2' '
+       cat >expected <<-EOF &&
+       file-foo mmap bar
+       file:foo_mmap bar
+       file-foo_mmap bar mmap
+       EOF
+       git grep --max-count 1 --context 1 foo_mmap >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count 1 --show-function' '
+       cat >expected <<-EOF &&
+       hello.ps1=function hello() {
+       hello.ps1:  echo "Hello world."
+       EOF
+       git grep --max-count 1 --show-function Hello hello.ps1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count 2 --show-function' '
+       cat >expected <<-EOF &&
+       hello.ps1=function hello() {
+       hello.ps1:  echo "Hello world."
+       hello.ps1:  echo "Hello again."
+       EOF
+       git grep --max-count 2 --show-function Hello hello.ps1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count 1 --count' '
+       cat >expected <<-EOF &&
+       hello.ps1:1
+       EOF
+       git grep --max-count 1 --count Hello hello.ps1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count 1 (multiple files)' '
+       cat >expected <<-EOF &&
+       hello.c:#include <stdio.h>
+       hello.ps1:# No-op.
+       EOF
+       git grep --max-count 1 -e o -- hello.\* >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep --max-count 1 --context 1 (multiple files)' '
+       cat >expected <<-EOF &&
+       hello.c-#include <assert.h>
+       hello.c:#include <stdio.h>
+       hello.c-
+       --
+       hello.ps1:# No-op.
+       hello.ps1-function dummy() {}
+       EOF
+       git grep --max-count 1 --context 1 -e o -- hello.\* >actual &&
+       test_cmp expected actual
+'
+
 cat >expected <<EOF
 file:foo mmap bar_mmap
 EOF
index ac7be5471452a0a8b2123dc39be80caf3520e9db..31c66b63c2cb008979cc64c3f9df203ce5ed1aeb 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='grep icase on non-English locales'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./lib-gettext.sh
 
 doalarm () {
index a4476dc492204297d3b91b3d3d79a7769f4d38b9..3ad80526c4c426b1ebeb94ee0730ff9ec79a4ef2 100755 (executable)
@@ -6,6 +6,7 @@ This test verifies the recurse-submodules feature correctly greps across
 submodules.
 '
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
@@ -471,8 +472,10 @@ test_expect_failure 'grep --textconv: superproject .gitattributes (from index) d
 test_expect_failure 'grep --textconv: superproject .git/info/attributes does not affect submodules' '
        reset_and_clean &&
        test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
-       super_attr="$(git rev-parse --git-path info/attributes)" &&
+       super_info="$(git rev-parse --git-path info)" &&
+       super_attr="$super_info/attributes" &&
        test_when_finished "rm -f \"$super_attr\"" &&
+       mkdir "$super_info" &&
        echo "a diff=d2x" >"$super_attr" &&
 
        cat >expect <<-\EOF &&
@@ -516,7 +519,8 @@ test_expect_failure 'grep --textconv correctly reads submodule .git/info/attribu
        reset_and_clean &&
        test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
 
-       submodule_attr="$(git -C submodule rev-parse --path-format=absolute --git-path info/attributes)" &&
+       submodule_info="$(git -C submodule rev-parse --path-format=absolute --git-path info)" &&
+       submodule_attr="$submodule_info/attributes" &&
        test_when_finished "rm -f \"$submodule_attr\"" &&
        echo "a diff=d2x" >"$submodule_attr" &&
 
index 74aa6384755ec6d53cf061a48dbe2cdfc93725f9..2724a44fe3ef240aa09077f770706ed022a99b7e 100755 (executable)
@@ -32,11 +32,13 @@ test_systemd_analyze_verify () {
 }
 
 test_expect_success 'help text' '
-       test_expect_code 129 git maintenance -h 2>err &&
-       test_i18ngrep "usage: git maintenance <subcommand>" err &&
-       test_expect_code 128 git maintenance barf 2>err &&
-       test_i18ngrep "invalid subcommand: barf" err &&
+       test_expect_code 129 git maintenance -h >actual &&
+       test_i18ngrep "usage: git maintenance <subcommand>" actual &&
+       test_expect_code 129 git maintenance barf 2>err &&
+       test_i18ngrep "unknown subcommand: \`barf'\''" err &&
+       test_i18ngrep "usage: git maintenance" err &&
        test_expect_code 129 git maintenance 2>err &&
+       test_i18ngrep "error: need a subcommand" err &&
        test_i18ngrep "usage: git maintenance" err
 '
 
@@ -162,7 +164,6 @@ test_expect_success 'prefetch multiple remotes' '
        test_cmp_rev refs/remotes/remote1/one refs/prefetch/remotes/remote1/one &&
        test_cmp_rev refs/remotes/remote2/two refs/prefetch/remotes/remote2/two &&
 
-       test_cmp_config refs/prefetch/ log.excludedecoration &&
        git log --oneline --decorate --all >log &&
        ! grep "prefetch" log &&
 
@@ -173,26 +174,6 @@ test_expect_success 'prefetch multiple remotes' '
        test_subcommand git fetch remote2 $fetchargs <skip-remote1.txt
 '
 
-test_expect_success 'prefetch and existing log.excludeDecoration values' '
-       git config --unset-all log.excludeDecoration &&
-       git config log.excludeDecoration refs/remotes/remote1/ &&
-       git maintenance run --task=prefetch &&
-
-       git config --get-all log.excludeDecoration >out &&
-       grep refs/remotes/remote1/ out &&
-       grep refs/prefetch/ out &&
-
-       git log --oneline --decorate --all >log &&
-       ! grep "prefetch" log &&
-       ! grep "remote1" log &&
-       grep "remote2" log &&
-
-       # a second run does not change the config
-       git maintenance run --task=prefetch &&
-       git log --oneline --decorate --all >log2 &&
-       test_cmp log log2
-'
-
 test_expect_success 'loose-objects task' '
        # Repack everything so we know the state of the object dir
        git repack -adk &&
index a536a621b24a4ee0a010fd5a3e565d2711d67806..d7167f55397f57f35a75eccff662c13b4f712ec8 100755 (executable)
@@ -4,6 +4,7 @@ test_description='git annotate'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 PROG='git annotate'
index ee4fdd8f18d572f82392b6ed2e4b4da9837b63b5..0147de304b4d104cc7f05ea1f8d68f1a07ceb80d 100755 (executable)
@@ -4,6 +4,7 @@ test_description='git blame'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 PROG='git blame -c'
index b067983ba1c6adf152131c96a67fc7a709e6666b..c8266f17f14af3c1af34661ccf9c039d04cfbe31 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git cat-file textconv support'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 cat >helper <<'EOF'
index 31de4b64dc06c1aad760dfc4ad585d11b46a65d8..ca04242ca016368a5644ef7d04c8b3dab0569260 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git cat-file filters support'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup ' '
index 90c75dbb283fce796847f51546a04691e0521de8..c3a5f6d01ffe5cff12b868e7cbe5a09dacbef011 100755 (executable)
@@ -4,6 +4,7 @@ test_description='colored git blame'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_CREATE_REPO_NO_TEMPLATE=1
 . ./test-lib.sh
 
 PROG='git blame -c'
index 01c74b8b0756caf01483f8cafbdda55eeb7d0ddb..1130ef21b342a83f02f7d5865fa726b80fd4ce01 100755 (executable)
@@ -1519,7 +1519,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
        grep "do not declare a Content-Transfer-Encoding" stdout &&
        grep email-using-8bit stdout &&
        grep "Which 8bit encoding" stdout &&
-       egrep "Content|MIME" msgtxt1 >actual &&
+       grep -E "Content|MIME" msgtxt1 >actual &&
        test_cmp content-type-decl actual
 '
 
@@ -1530,7 +1530,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
        git send-email --from=author@example.com --to=nobody@example.com \
                        --smtp-server="$(pwd)/fake.sendmail" \
                        email-using-8bit >stdout &&
-       egrep "Content|MIME" msgtxt1 >actual &&
+       grep -E "Content|MIME" msgtxt1 >actual &&
        test_cmp content-type-decl actual
 '
 
@@ -1545,7 +1545,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding in .git/config overrides --g
        git send-email --from=author@example.com --to=nobody@example.com \
                        --smtp-server="$(pwd)/fake.sendmail" \
                        email-using-8bit >stdout &&
-       egrep "Content|MIME" msgtxt1 >actual &&
+       grep -E "Content|MIME" msgtxt1 >actual &&
        test_cmp content-type-decl actual
 '
 
@@ -1557,7 +1557,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
                        --smtp-server="$(pwd)/fake.sendmail" \
                        --8bit-encoding=UTF-8 \
                        email-using-8bit >stdout &&
-       egrep "Content|MIME" msgtxt1 >actual &&
+       grep -E "Content|MIME" msgtxt1 >actual &&
        test_cmp content-type-decl actual
 '
 
index 7c5b847f58424dc62c330674971d2d849f77ac4e..fea41b3c3606df1fc6d8111cdd74522532ca8b0b 100755 (executable)
@@ -8,7 +8,6 @@ test_description='git svn basic tests'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 prepare_utf8_locale
index d043e80fc349f85e1cd4168c9bf4d343dfeee0d5..52046e60d5150d0ee71bcbb515277b4bf1e6969d 100755 (executable)
@@ -5,7 +5,6 @@
 
 test_description='git svn property tests'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 mkdir import
index 5cf2ef4b8b0fc3a9a587baea4e8421893c90bd14..85d735861fc9f500561e9f5fb4baa131657752c0 100755 (executable)
@@ -5,7 +5,6 @@
 
 test_description='git svn fetching'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'initialize repo' '
index 527ba3d29322a14d609ea57e3740672f144f3182..0fc289ae0f02c064586b5ff9f1cab0ff0976814f 100755 (executable)
@@ -2,7 +2,6 @@
 
 test_description='git svn authorship'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'setup svn repository' '
index 4d8d0584b795d21fab8ba7dcbd47b50c178c2757..aeceffaf7b0824b8da673261f523589d3b141619 100755 (executable)
@@ -2,7 +2,6 @@
 
 test_description='test that git handles an svn repository with empty symlinks'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 test_expect_success 'load svn dumpfile' '
        svnadmin load "$rawsvnrepo" <<EOF
index f894860867a1398555876ce0586479157189a376..d8d536269cf73d64d9d2df593667c17c826479c5 100755 (executable)
@@ -35,7 +35,7 @@ test_expect_success 'SVN-side change outside of .git' '
                echo b >> a &&
                svn_cmd commit -m "SVN-side change outside of .git" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change outside of .git"
+               svn_cmd log -v | grep -F "SVN-side change outside of .git"
        )
 '
 
@@ -59,7 +59,7 @@ test_expect_success 'SVN-side change inside of .git' '
                svn_cmd add --force .git &&
                svn_cmd commit -m "SVN-side change inside of .git" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change inside of .git"
+               svn_cmd log -v | grep -F "SVN-side change inside of .git"
        )
 '
 
@@ -82,7 +82,7 @@ test_expect_success 'SVN-side change in and out of .git' '
                git commit -m "add a inside an SVN repo" &&
                svn_cmd commit -m "SVN-side change in and out of .git" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change in and out of .git"
+               svn_cmd log -v | grep -F "SVN-side change in and out of .git"
        )
 '
 
index 4a77eb9f60da3ade87ed701ecb0dca7f7ad13d87..31884002263fcf0b245bcf5231d65554911b698c 100755 (executable)
@@ -43,7 +43,7 @@ test_expect_success 'init+fetch an SVN repository with ignored www directory' '
 test_expect_success 'verify ignore-paths config saved by clone' '
        (
            cd g &&
-           git config --get svn-remote.svn.ignore-paths | fgrep "www"
+           git config --get svn-remote.svn.ignore-paths | grep www
        )
 '
 
@@ -53,7 +53,7 @@ test_expect_success 'SVN-side change outside of www' '
                echo b >> qqq/test_qqq.txt &&
                svn_cmd commit -m "SVN-side change outside of www" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change outside of www"
+               svn_cmd log -v | grep "SVN-side change outside of www"
        )
 '
 
@@ -85,7 +85,7 @@ test_expect_success 'SVN-side change inside of ignored www' '
                echo zaq >> www/test_www.txt &&
                svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
+               svn_cmd log -v | grep -F "SVN-side change inside of www/test_www.txt"
        )
 '
 
@@ -118,7 +118,7 @@ test_expect_success 'SVN-side change in and out of ignored www' '
                echo ygg >> qqq/test_qqq.txt &&
                svn_cmd commit -m "SVN-side change in and out of ignored www" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
+               svn_cmd log -v | grep "SVN-side change in and out of ignored www"
        )
 '
 
index e8559046296ce5570ec46b2b3a9280f0a493bbc4..a420b2a87af10a9a3e6f6136d0ff53d5a466804f 100755 (executable)
@@ -43,7 +43,7 @@ test_expect_success 'fetch fails on modified hidden file' '
          git svn find-rev refs/remotes/git-svn > ../expect &&
          test_must_fail git svn fetch 2> ../errors &&
          git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
-       fgrep "not found in commit" errors &&
+       grep "not found in commit" errors &&
        test_cmp expect expect2
 '
 
@@ -59,7 +59,7 @@ test_expect_success 'refetch succeeds not ignoring any files' '
        ( cd g &&
          git svn fetch &&
          git svn rebase &&
-         fgrep "mod hidden" hid/hid.txt
+         grep "mod hidden" hid/hid.txt
        )
 '
 
index 257fc8f2f8d194bbf1a0bb151da1b80d85874e28..63fa0b6732e33e393d0c47b258239b841a8a4bb8 100755 (executable)
@@ -45,7 +45,7 @@ test_expect_success 'init+fetch an SVN repository with included qqq directory' '
 test_expect_success 'verify include-paths config saved by clone' '
        (
            cd g &&
-           git config --get svn-remote.svn.include-paths | fgrep "qqq"
+           git config --get svn-remote.svn.include-paths | grep qqq
        )
 '
 
@@ -55,7 +55,7 @@ test_expect_success 'SVN-side change outside of www' '
                echo b >> qqq/test_qqq.txt &&
                svn_cmd commit -m "SVN-side change outside of www" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change outside of www"
+               svn_cmd log -v | grep "SVN-side change outside of www"
        )
 '
 
@@ -87,7 +87,7 @@ test_expect_success 'SVN-side change inside of ignored www' '
                echo zaq >> www/test_www.txt &&
                svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
+               svn_cmd log -v | grep "SVN-side change inside of www/test_www.txt"
        )
 '
 
@@ -120,7 +120,7 @@ test_expect_success 'SVN-side change in and out of included qqq' '
                echo ygg >> qqq/test_qqq.txt &&
                svn_cmd commit -m "SVN-side change in and out of ignored www" &&
                svn_cmd up &&
-               svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
+               svn_cmd log -v | grep "SVN-side change in and out of ignored www"
        )
 '
 
index e2aa8ed88a96ec0b50fb33f31e2e6d232895067c..b3ce033a0d3dec9c27b3a5e9114e07f18f20f04d 100755 (executable)
@@ -4,7 +4,6 @@
 
 test_description='git svn dcommit --interactive series'
 
-TEST_FAILS_SANITIZE_LEAK=true
 . ./lib-git-svn.sh
 
 test_expect_success 'initialize repo' '
similarity index 51%
rename from contrib/scalar/t/t9099-scalar.sh
rename to t/t9210-scalar.sh
index 10b1172a8aa0d219f26a0f927c6bbf1800ba3a1c..14ca575a214f3b74409f89ada717277aeabe5e82 100755 (executable)
 
 test_description='test the `scalar` command'
 
-TEST_DIRECTORY=$PWD/../../../t
-export TEST_DIRECTORY
+. ./test-lib.sh
 
-# Make it work with --no-bin-wrappers
-PATH=$PWD/..:$PATH
-
-. ../../../t/test-lib.sh
-
-GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab ../cron.txt,launchctl:true,schtasks:true"
+GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt,launchctl:true,schtasks:true"
 export GIT_TEST_MAINT_SCHEDULER
 
 test_expect_success 'scalar shows a usage' '
        test_expect_code 129 scalar -h
 '
 
+test_expect_success 'scalar invoked on enlistment root' '
+       test_when_finished rm -rf test src deeper &&
+
+       for enlistment_root in test src deeper/test
+       do
+               git init ${enlistment_root}/src &&
+
+               # Register
+               scalar register ${enlistment_root} &&
+               scalar list >out &&
+               grep "$(pwd)/${enlistment_root}/src\$" out &&
+
+               # Delete (including enlistment root)
+               scalar delete $enlistment_root &&
+               test_path_is_missing $enlistment_root &&
+               scalar list >out &&
+               ! grep "^$(pwd)/${enlistment_root}/src\$" out || return 1
+       done
+'
+
+test_expect_success 'scalar invoked on enlistment src repo' '
+       test_when_finished rm -rf test src deeper &&
+
+       for enlistment_root in test src deeper/test
+       do
+               git init ${enlistment_root}/src &&
+
+               # Register
+               scalar register ${enlistment_root}/src &&
+               scalar list >out &&
+               grep "$(pwd)/${enlistment_root}/src\$" out &&
+
+               # Delete (will not include enlistment root)
+               scalar delete ${enlistment_root}/src &&
+               test_path_is_dir $enlistment_root &&
+               scalar list >out &&
+               ! grep "^$(pwd)/${enlistment_root}/src\$" out || return 1
+       done
+'
+
+test_expect_success 'scalar invoked when enlistment root and repo are the same' '
+       test_when_finished rm -rf test src deeper &&
+
+       for enlistment_root in test src deeper/test
+       do
+               git init ${enlistment_root} &&
+
+               # Register
+               scalar register ${enlistment_root} &&
+               scalar list >out &&
+               grep "$(pwd)/${enlistment_root}\$" out &&
+
+               # Delete (will not include enlistment root)
+               scalar delete ${enlistment_root} &&
+               test_path_is_missing $enlistment_root &&
+               scalar list >out &&
+               ! grep "^$(pwd)/${enlistment_root}\$" out &&
+
+               # Make sure we did not accidentally delete the trash dir
+               test_path_is_dir "$TRASH_DIRECTORY" || return 1
+       done
+'
+
+test_expect_success 'scalar repo search respects GIT_CEILING_DIRECTORIES' '
+       test_when_finished rm -rf test &&
+
+       git init test/src &&
+       mkdir -p test/src/deep &&
+       GIT_CEILING_DIRECTORIES="$(pwd)/test/src" &&
+       ! scalar register test/src/deep 2>err &&
+       grep "not a git repository" err
+'
+
+test_expect_success 'scalar enlistments need a worktree' '
+       test_when_finished rm -rf bare test &&
+
+       git init --bare bare/src &&
+       ! scalar register bare/src 2>err &&
+       grep "Scalar enlistments require a worktree" err &&
+
+       git init test/src &&
+       ! scalar register test/src/.git 2>err &&
+       grep "Scalar enlistments require a worktree" err
+'
+
+test_expect_success FSMONITOR_DAEMON 'scalar register starts fsmon daemon' '
+       git init test/src &&
+       test_must_fail git -C test/src fsmonitor--daemon status &&
+       scalar register test/src &&
+       git -C test/src fsmonitor--daemon status &&
+       test_cmp_config -C test/src true core.fsmonitor
+'
+
 test_expect_success 'scalar unregister' '
        git init vanish/src &&
        scalar register vanish/src &&
@@ -109,14 +196,14 @@ test_expect_success UNZIP 'scalar diagnose' '
        sed -n "s/.*$SQ\\(.*\\.zip\\)$SQ.*/\\1/p" <err >zip_path &&
        zip_path=$(cat zip_path) &&
        test -n "$zip_path" &&
-       unzip -v "$zip_path" &&
+       "$GIT_UNZIP" -v "$zip_path" &&
        folder=${zip_path%.zip} &&
        test_path_is_missing "$folder" &&
-       unzip -p "$zip_path" diagnostics.log >out &&
+       "$GIT_UNZIP" -p "$zip_path" diagnostics.log >out &&
        test_file_not_empty out &&
-       unzip -p "$zip_path" packs-local.txt >out &&
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
        grep "$(pwd)/.git/objects" out &&
-       unzip -p "$zip_path" objects-local.txt >out &&
+       "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
        grep "^Total: [1-9]" out
 '
 
diff --git a/t/t9211-scalar-clone.sh b/t/t9211-scalar-clone.sh
new file mode 100755 (executable)
index 0000000..dd33d87
--- /dev/null
@@ -0,0 +1,151 @@
+#!/bin/sh
+
+test_description='test the `scalar clone` subcommand'
+
+. ./test-lib.sh
+
+GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt,launchctl:true,schtasks:true"
+export GIT_TEST_MAINT_SCHEDULER
+
+test_expect_success 'set up repository to clone' '
+       rm -rf .git &&
+       git init to-clone &&
+       (
+               cd to-clone &&
+               git branch -m base &&
+
+               test_commit first &&
+               test_commit second &&
+               test_commit third &&
+
+               git switch -c parallel first &&
+               mkdir -p 1/2 &&
+               test_commit 1/2/3 &&
+
+               git switch base &&
+
+               # By default, permit
+               git config uploadpack.allowfilter true &&
+               git config uploadpack.allowanysha1inwant true
+       )
+'
+
+cleanup_clone () {
+       rm -rf "$1"
+}
+
+test_expect_success 'creates content in enlistment root' '
+       enlistment=cloned &&
+
+       scalar clone "file://$(pwd)/to-clone" $enlistment &&
+       ls -A $enlistment >enlistment-root &&
+       test_line_count = 1 enlistment-root &&
+       test_path_is_dir $enlistment/src &&
+       test_path_is_dir $enlistment/src/.git &&
+
+       cleanup_clone $enlistment
+'
+
+test_expect_success 'with spaces' '
+       enlistment="cloned with space" &&
+
+       scalar clone "file://$(pwd)/to-clone" "$enlistment" &&
+       test_path_is_dir "$enlistment" &&
+       test_path_is_dir "$enlistment/src" &&
+       test_path_is_dir "$enlistment/src/.git" &&
+
+       cleanup_clone "$enlistment"
+'
+
+test_expect_success 'partial clone if supported by server' '
+       enlistment=partial-clone &&
+
+       scalar clone "file://$(pwd)/to-clone" $enlistment &&
+
+       (
+               cd $enlistment/src &&
+
+               # Two promisor packs: one for refs, the other for blobs
+               ls .git/objects/pack/pack-*.promisor >promisorlist &&
+               test_line_count = 2 promisorlist
+       ) &&
+
+       cleanup_clone $enlistment
+'
+
+test_expect_success 'fall back on full clone if partial unsupported' '
+       enlistment=no-partial-support &&
+
+       test_config -C to-clone uploadpack.allowfilter false &&
+       test_config -C to-clone uploadpack.allowanysha1inwant false &&
+
+       scalar clone "file://$(pwd)/to-clone" $enlistment 2>err &&
+       grep "filtering not recognized by server, ignoring" err &&
+
+       (
+               cd $enlistment/src &&
+
+               # Still get a refs promisor file, but none for blobs
+               ls .git/objects/pack/pack-*.promisor >promisorlist &&
+               test_line_count = 1 promisorlist
+       ) &&
+
+       cleanup_clone $enlistment
+'
+
+test_expect_success 'initializes sparse-checkout by default' '
+       enlistment=sparse &&
+
+       scalar clone "file://$(pwd)/to-clone" $enlistment &&
+       (
+               cd $enlistment/src &&
+               test_cmp_config true core.sparseCheckout &&
+               test_cmp_config true core.sparseCheckoutCone
+       ) &&
+
+       cleanup_clone $enlistment
+'
+
+test_expect_success '--full-clone does not create sparse-checkout' '
+       enlistment=full-clone &&
+
+       scalar clone --full-clone "file://$(pwd)/to-clone" $enlistment &&
+       (
+               cd $enlistment/src &&
+               test_cmp_config "" --default "" core.sparseCheckout &&
+               test_cmp_config "" --default "" core.sparseCheckoutCone
+       ) &&
+
+       cleanup_clone $enlistment
+'
+
+test_expect_success '--single-branch clones HEAD only' '
+       enlistment=single-branch &&
+
+       scalar clone --single-branch "file://$(pwd)/to-clone" $enlistment &&
+       (
+               cd $enlistment/src &&
+               git for-each-ref refs/remotes/origin >out &&
+               test_line_count = 1 out &&
+               grep "refs/remotes/origin/base" out
+       ) &&
+
+       cleanup_clone $enlistment
+'
+
+test_expect_success '--no-single-branch clones all branches' '
+       enlistment=no-single-branch &&
+
+       scalar clone --no-single-branch "file://$(pwd)/to-clone" $enlistment &&
+       (
+               cd $enlistment/src &&
+               git for-each-ref refs/remotes/origin >out &&
+               test_line_count = 2 out &&
+               grep "refs/remotes/origin/base" out &&
+               grep "refs/remotes/origin/parallel" out
+       ) &&
+
+       cleanup_clone $enlistment
+'
+
+test_done
index 1ae4d7c0d37db2d10cbc08ce90505b291e70171b..58413221e6a73dcb464f0f226616b0bba4ea30dd 100755 (executable)
@@ -7,6 +7,7 @@ test_description='test git fast-import of notes objects'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
index 102c133112c7149258d123b95acec807006890b7..4aa5d90d328aca4adcac5f0d3a2ee4946a393812 100755 (executable)
@@ -4,17 +4,12 @@
 #
 
 test_description='perl interface (Git.pm)'
-. ./test-lib.sh
 
-if ! test_have_prereq PERL; then
-       skip_all='skipping perl interface tests, perl not available'
-       test_done
-fi
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-perl.sh
 
-perl -MTest::More -e 0 2>/dev/null || {
-       skip_all="Perl Test::More unavailable, skipping test"
-       test_done
-}
+skip_all_if_no_Test_More
 
 # set up test repository
 
@@ -50,11 +45,9 @@ test_expect_success \
      git config --add test.pathmulti bar
      '
 
-# The external test will outputs its own plan
-test_external_has_tap=1
-
-test_external_without_stderr \
-    'Perl API' \
-    perl "$TEST_DIRECTORY"/t9700/test.pl
+test_expect_success 'use t9700/test.pl to test Git.pm' '
+       "$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl 2>stderr &&
+       test_must_be_empty stderr
+'
 
 test_done
index 468767cbf4b93eb20f209fc25b46cc0f53d5b907..2a9838f37fe293738a75e626041531456c274f72 100755 (executable)
@@ -216,7 +216,7 @@ test_expect_success 'detect copies' '
 # variable exists, which allows admins to disable the "p4 move" command.
 test_lazy_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW '
        p4 configure show run.move.allow >out &&
-       egrep ^run.move.allow: out
+       grep -E ^run.move.allow: out
 '
 
 # If move can be disabled, turn it off and test p4 move handling
index 9779dc0d11f33b6d8a6c5b8d8ffded834eddd8b2..0ca9937de6cfcee5c762ab47dffdc6bd5e2195f5 100755 (executable)
@@ -417,8 +417,8 @@ test_expect_success 'cleanup chmod after submit cancel' '
                ! p4 fstat -T action text &&
                test_path_is_file text+x &&
                ! p4 fstat -T action text+x &&
-               ls -l text | egrep ^-r-- &&
-               ls -l text+x | egrep ^-r-x
+               ls -l text | grep -E ^-r-- &&
+               ls -l text+x | grep -E ^-r-x
        )
 '
 
index de7152f82713bf797aecd3f53bce6ef006524b7b..19f56e5680f678c22fc80a63907c804448c4b445 100755 (executable)
@@ -5,6 +5,7 @@ test_description='git web--browse basic tests
 
 This test checks that git web--browse can handle various valid URLs.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_web_browse () {
index 6a30f5719c33260cb57fca2112d77bc1f9515375..d459fae6551bd7b5812f8b76a5faae8ebd4075df 100755 (executable)
@@ -759,4 +759,20 @@ test_expect_success 'prompt - hide if pwd ignored - inside gitdir' '
        test_cmp expected "$actual"
 '
 
+test_expect_success 'prompt - conflict indicator' '
+       printf " (main|CONFLICT)" >expected &&
+       echo "stash" >file &&
+       git stash &&
+       test_when_finished "git stash drop" &&
+       echo "commit" >file &&
+       git commit -m "commit" file &&
+       test_when_finished "git reset --hard HEAD~" &&
+       test_must_fail git stash apply &&
+       (
+               GIT_PS1_SHOWCONFLICTSTATE="yes" &&
+               __git_ps1 >"$actual"
+       ) &&
+       test_cmp expected "$actual"
+'
+
 test_done
index 8c44856eaec0d8fed84f5a4959edce275c8b79eb..527a7145000f6414d7663f6ee6a1d7c1396d8fe4 100644 (file)
@@ -633,7 +633,7 @@ test_hook () {
 # - Explicitly using test_have_prereq.
 #
 # - Implicitly by specifying the prerequisite tag in the calls to
-#   test_expect_{success,failure} and test_external{,_without_stderr}.
+#   test_expect_{success,failure}
 #
 # The single parameter is the prerequisite tag (a simple word, in all
 # capital letters by convention).
@@ -835,93 +835,6 @@ test_expect_success () {
        test_finish_
 }
 
-# test_external runs external test scripts that provide continuous
-# test output about their progress, and succeeds/fails on
-# zero/non-zero exit code.  It outputs the test output on stdout even
-# in non-verbose mode, and announces the external script with "# run
-# <n>: ..." before running it.  When providing relative paths, keep in
-# mind that all scripts run in "trash directory".
-# Usage: test_external description command arguments...
-# Example: test_external 'Perl API' perl ../path/to/test.pl
-test_external () {
-       test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
-       test "$#" = 3 ||
-       BUG "not 3 or 4 parameters to test_external"
-       descr="$1"
-       shift
-       test_verify_prereq
-       export test_prereq
-       if ! test_skip "$descr" "$@"
-       then
-               # Announce the script to reduce confusion about the
-               # test output that follows.
-               say_color "" "# run $test_count: $descr ($*)"
-               # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
-               # to be able to use them in script
-               export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
-               # Run command; redirect its stderr to &4 as in
-               # test_run_, but keep its stdout on our stdout even in
-               # non-verbose mode.
-               "$@" 2>&4
-               if test "$?" = 0
-               then
-                       if test $test_external_has_tap -eq 0; then
-                               test_ok_ "$descr"
-                       else
-                               say_color "" "# test_external test $descr was ok"
-                               test_success=$(($test_success + 1))
-                       fi
-               else
-                       if test $test_external_has_tap -eq 0; then
-                               test_failure_ "$descr" "$@"
-                       else
-                               say_color error "# test_external test $descr failed: $@"
-                               test_failure=$(($test_failure + 1))
-                       fi
-               fi
-       fi
-}
-
-# Like test_external, but in addition tests that the command generated
-# no output on stderr.
-test_external_without_stderr () {
-       # The temporary file has no (and must have no) security
-       # implications.
-       tmp=${TMPDIR:-/tmp}
-       stderr="$tmp/git-external-stderr.$$.tmp"
-       test_external "$@" 4> "$stderr"
-       test -f "$stderr" || error "Internal error: $stderr disappeared."
-       descr="no stderr: $1"
-       shift
-       say >&3 "# expecting no stderr from previous command"
-       if test ! -s "$stderr"
-       then
-               rm "$stderr"
-
-               if test $test_external_has_tap -eq 0; then
-                       test_ok_ "$descr"
-               else
-                       say_color "" "# test_external_without_stderr test $descr was ok"
-                       test_success=$(($test_success + 1))
-               fi
-       else
-               if test "$verbose" = t
-               then
-                       output=$(echo; echo "# Stderr is:"; cat "$stderr")
-               else
-                       output=
-               fi
-               # rm first in case test_failure exits.
-               rm "$stderr"
-               if test $test_external_has_tap -eq 0; then
-                       test_failure_ "$descr" "$@" "$output"
-               else
-                       say_color error "# test_external_without_stderr test $descr failed: $@: $output"
-                       test_failure=$(($test_failure + 1))
-               fi
-       fi
-}
-
 # debugging-friendly alternatives to "test [-f|-d|-e]"
 # The commands test the existence or non-existence of $1
 test_path_is_file () {
@@ -984,7 +897,7 @@ test_path_is_symlink () {
 test_dir_is_empty () {
        test "$#" -ne 1 && BUG "1 param"
        test_path_is_dir "$1" &&
-       if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')"
+       if test -n "$(ls -a1 "$1" | grep -E -v '^\.\.?$')"
        then
                echo "Directory '$1' is not empty, it contains:"
                ls -la "$1"
index 120f11812c364ae6467e61cf8eac1f92cd73a385..a65df2fd22046586a714e2aa40482f022e8740f8 100644 (file)
@@ -238,6 +238,9 @@ parse_option () {
                        ;;
                esac
                ;;
+       --invert-exit-code)
+               invert_exit_code=t
+               ;;
        *)
                echo "error: unknown test option '$opt'" >&2; exit 1 ;;
        esac
@@ -302,6 +305,11 @@ TEST_NUMBER="${TEST_NAME%%-*}"
 TEST_NUMBER="${TEST_NUMBER#t}"
 TEST_RESULTS_DIR="$TEST_OUTPUT_DIRECTORY/test-results"
 TEST_RESULTS_BASE="$TEST_RESULTS_DIR/$TEST_NAME$TEST_STRESS_JOB_SFX"
+TEST_RESULTS_SAN_FILE_PFX=trace
+TEST_RESULTS_SAN_DIR_SFX=leak
+TEST_RESULTS_SAN_FILE=
+TEST_RESULTS_SAN_DIR="$TEST_RESULTS_DIR/$TEST_NAME.$TEST_RESULTS_SAN_DIR_SFX"
+TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=
 TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX"
 test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
 case "$TRASH_DIRECTORY" in
@@ -309,6 +317,16 @@ case "$TRASH_DIRECTORY" in
  *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
 esac
 
+# Utility functions using $TEST_RESULTS_* variables
+nr_san_dir_leaks_ () {
+       # stderr piped to /dev/null because the directory may have
+       # been "rmdir"'d already.
+       find "$TEST_RESULTS_SAN_DIR" \
+               -type f \
+               -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null |
+       wc -l
+}
+
 # If --stress was passed, run this test repeatedly in several parallel loops.
 if test "$GIT_TEST_STRESS_STARTED" = "done"
 then
@@ -793,15 +811,31 @@ test_ok_ () {
        finalize_test_case_output ok "$@"
 }
 
+_invert_exit_code_failure_end_blurb () {
+       say_color warn "# faked up failures as TODO & now exiting with 0 due to --invert-exit-code"
+}
+
 test_failure_ () {
        failure_label=$1
        test_failure=$(($test_failure + 1))
-       say_color error "not ok $test_count - $1"
+       local pfx=""
+       if test -n "$invert_exit_code" # && test -n "$HARNESS_ACTIVE"
+       then
+               pfx="# TODO induced breakage (--invert-exit-code):"
+       fi
+       say_color error "not ok $test_count - ${pfx:+$pfx }$1"
        shift
        printf '%s\n' "$*" | sed -e 's/^/#      /'
        if test -n "$immediate"
        then
                say_color error "1..$test_count"
+               if test -n "$invert_exit_code"
+               then
+                       finalize_test_output
+                       _invert_exit_code_failure_end_blurb
+                       GIT_EXIT_OK=t
+                       exit 0
+               fi
                _error_exit
        fi
        finalize_test_case_output failure "$failure_label" "$@"
@@ -809,14 +843,14 @@ test_failure_ () {
 
 test_known_broken_ok_ () {
        test_fixed=$(($test_fixed+1))
-       say_color error "ok $test_count - $@ # TODO known breakage vanished"
-       finalize_test_case_output fixed "$@"
+       say_color error "ok $test_count - $1 # TODO known breakage vanished"
+       finalize_test_case_output fixed "$1"
 }
 
 test_known_broken_failure_ () {
        test_broken=$(($test_broken+1))
-       say_color warn "not ok $test_count - $@ # TODO known breakage"
-       finalize_test_case_output broken "$@"
+       say_color warn "not ok $test_count - $1 # TODO known breakage"
+       finalize_test_case_output broken "$1"
 }
 
 test_debug () {
@@ -1057,11 +1091,7 @@ test_run_ () {
                trace=
                # 117 is magic because it is unlikely to match the exit
                # code of other programs
-               if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" ||
-                  {
-                       test "${GIT_TEST_CHAIN_LINT_HARDER:-${GIT_TEST_CHAIN_LINT_HARDER_DEFAULT:-1}}" != 0 &&
-                       $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!')
-                  }
+               if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
                then
                        BUG "broken &&-chain or run-away HERE-DOC: $1"
                fi
@@ -1173,9 +1203,67 @@ test_atexit_handler () {
        teardown_malloc_check
 }
 
-test_done () {
-       GIT_EXIT_OK=t
+sanitize_leak_log_message_ () {
+       local new="$1" &&
+       local old="$2" &&
+       local file="$3" &&
+
+       printf "With SANITIZE=leak at exit we have %d leak logs, but started with %d
+
+This means that we have a blindspot where git is leaking but we're
+losing the exit code somewhere, or not propagating it appropriately
+upwards!
+
+See the logs at \"%s.*\";
+those logs are reproduced below." \
+              "$new" "$old" "$file"
+}
 
+check_test_results_san_file_ () {
+       if test -z "$TEST_RESULTS_SAN_FILE"
+       then
+               return
+       fi &&
+       local old="$TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP" &&
+       local new="$(nr_san_dir_leaks_)" &&
+
+       if test $new -le $old
+       then
+               return
+       fi &&
+       local out="$(sanitize_leak_log_message_ "$new" "$old" "$TEST_RESULTS_SAN_FILE")" &&
+       say_color error "$out" &&
+       if test "$old" != 0
+       then
+               echo &&
+               say_color error "The logs include output from past runs to avoid" &&
+               say_color error "that remove 'test-results' between runs."
+       fi &&
+       say_color error "$(cat "$TEST_RESULTS_SAN_FILE".*)" &&
+
+       if test -n "$passes_sanitize_leak" && test "$test_failure" = 0
+       then
+               say "As TEST_PASSES_SANITIZE_LEAK=true and our logs show we're leaking, exit non-zero!" &&
+               invert_exit_code=t
+       elif test -n "$passes_sanitize_leak"
+       then
+               say "As TEST_PASSES_SANITIZE_LEAK=true and our logs show we're leaking, and we're failing for other reasons too..." &&
+               invert_exit_code=
+       elif test -n "$sanitize_leak_check" && test "$test_failure" = 0
+       then
+               say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" &&
+               invert_exit_code=
+       elif test -n "$sanitize_leak_check"
+       then
+               say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" &&
+               invert_exit_code=t
+       else
+               say "With GIT_TEST_SANITIZE_LEAK_LOG=true our logs revealed a memory leak, exit non-zero!" &&
+               invert_exit_code=t
+       fi
+}
+
+test_done () {
        # Run the atexit commands _before_ the trash directory is
        # removed, so the commands can access pidfiles and socket files.
        test_atexit_handler
@@ -1215,28 +1303,32 @@ test_done () {
        fi
        case "$test_failure" in
        0)
-               if test $test_external_has_tap -eq 0
+               if test $test_remaining -gt 0
                then
-                       if test $test_remaining -gt 0
-                       then
-                               say_color pass "# passed all $msg"
-                       fi
-
-                       # Maybe print SKIP message
-                       test -z "$skip_all" || skip_all="# SKIP $skip_all"
-                       case "$test_count" in
-                       0)
-                               say "1..$test_count${skip_all:+ $skip_all}"
-                               ;;
-                       *)
-                               test -z "$skip_all" ||
-                               say_color warn "$skip_all"
-                               say "1..$test_count"
-                               ;;
-                       esac
+                       say_color pass "# passed all $msg"
                fi
 
-               if test -z "$debug" && test -n "$remove_trash"
+               # Maybe print SKIP message
+               test -z "$skip_all" || skip_all="# SKIP $skip_all"
+               case "$test_count" in
+               0)
+                       say "1..$test_count${skip_all:+ $skip_all}"
+                       ;;
+               *)
+                       test -z "$skip_all" ||
+                       say_color warn "$skip_all"
+                       say "1..$test_count"
+                       ;;
+               esac
+
+               if test -n "$stress" && test -n "$invert_exit_code"
+               then
+                       # We're about to move our "$TRASH_DIRECTORY"
+                       # to "$TRASH_DIRECTORY.stress-failed" if
+                       # --stress is combined with
+                       # --invert-exit-code.
+                       say "with --stress and --invert-exit-code we're not removing '$TRASH_DIRECTORY'"
+               elif test -z "$debug" && test -n "$remove_trash"
                then
                        test -d "$TRASH_DIRECTORY" ||
                        error "Tests passed but trash directory already removed before test cleanup; aborting"
@@ -1249,17 +1341,35 @@ test_done () {
                        } ||
                        error "Tests passed but test cleanup failed; aborting"
                fi
+
+               check_test_results_san_file_ "$test_failure"
+
+               if test -z "$skip_all" && test -n "$invert_exit_code"
+               then
+                       say_color warn "# faking up non-zero exit with --invert-exit-code"
+                       GIT_EXIT_OK=t
+                       exit 1
+               fi
+
                test_at_end_hook_
 
+               GIT_EXIT_OK=t
                exit 0 ;;
 
        *)
-               if test $test_external_has_tap -eq 0
+               say_color error "# failed $test_failure among $msg"
+               say "1..$test_count"
+
+               check_test_results_san_file_ "$test_failure"
+
+               if test -n "$invert_exit_code"
                then
-                       say_color error "# failed $test_failure among $msg"
-                       say "1..$test_count"
+                       _invert_exit_code_failure_end_blurb
+                       GIT_EXIT_OK=t
+                       exit 0
                fi
 
+               GIT_EXIT_OK=t
                exit 1 ;;
 
        esac
@@ -1392,14 +1502,12 @@ fi
 GITPERLLIB="$GIT_BUILD_DIR"/perl/build/lib
 export GITPERLLIB
 test -d "$GIT_BUILD_DIR"/templates/blt || {
-       error "You haven't built things yet, have you?"
+       BAIL_OUT "You haven't built things yet, have you?"
 }
 
 if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool$X
 then
-       echo >&2 'You need to build test-tool:'
-       echo >&2 'Run "make t/helper/test-tool" in the source (toplevel) directory'
-       exit 1
+       BAIL_OUT 'You need to build test-tool; Run "make t/helper/test-tool" in the source (toplevel) directory'
 fi
 
 # Are we running this test at all?
@@ -1413,24 +1521,76 @@ then
        test_done
 fi
 
-# skip non-whitelisted tests when compiled with SANITIZE=leak
+BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK () {
+       BAIL_OUT "$1 has no effect except when compiled with SANITIZE=leak"
+}
+
 if test -n "$SANITIZE_LEAK"
 then
-       if test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
+       # Normalize with test_bool_env
+       passes_sanitize_leak=
+
+       # We need to see TEST_PASSES_SANITIZE_LEAK in "git
+       # env--helper" (via test_bool_env)
+       export TEST_PASSES_SANITIZE_LEAK
+       if test_bool_env TEST_PASSES_SANITIZE_LEAK false
        then
-               # We need to see it in "git env--helper" (via
-               # test_bool_env)
-               export TEST_PASSES_SANITIZE_LEAK
+               passes_sanitize_leak=t
+       fi
+
+       if test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check"
+       then
+               sanitize_leak_check=t
+               if test -n "$invert_exit_code"
+               then
+                       BAIL_OUT "cannot use --invert-exit-code under GIT_TEST_PASSING_SANITIZE_LEAK=check"
+               fi
 
-               if ! test_bool_env TEST_PASSES_SANITIZE_LEAK false
+               if test -z "$passes_sanitize_leak"
                then
-                       skip_all="skipping $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=true"
-                       test_done
+                       say "in GIT_TEST_PASSING_SANITIZE_LEAK=check mode, setting --invert-exit-code for TEST_PASSES_SANITIZE_LEAK != true"
+                       invert_exit_code=t
                fi
+       elif test -z "$passes_sanitize_leak" &&
+            test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
+       then
+               skip_all="skipping $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=true"
+               test_done
        fi
-elif test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
+
+       if test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false
+       then
+               if ! mkdir -p "$TEST_RESULTS_SAN_DIR"
+               then
+                       BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR"
+               fi &&
+               TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX"
+
+               # In case "test-results" is left over from a previous
+               # run: Only report if new leaks show up.
+               TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_)
+
+               # Don't litter *.leak dirs if there was nothing to report
+               test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :"
+
+               prepend_var LSAN_OPTIONS : dedup_token_length=9999
+               prepend_var LSAN_OPTIONS : log_exe_name=1
+               prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\"
+               export LSAN_OPTIONS
+       fi
+elif test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" ||
+     test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
 then
-       BAIL_OUT "GIT_TEST_PASSING_SANITIZE_LEAK=true has no effect except when compiled with SANITIZE=leak"
+       BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_PASSING_SANITIZE_LEAK=true"
+elif test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false
+then
+       BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true"
+fi
+
+if test "${GIT_TEST_CHAIN_LINT:-1}" != 0
+then
+       "$PERL_PATH" "$TEST_DIRECTORY/chainlint.pl" "$0" ||
+               BUG "lint error (see '?!...!? annotations above)"
 fi
 
 # Last-minute variable setup
@@ -1453,15 +1613,15 @@ remove_trash_directory () {
 
 # Test repository
 remove_trash_directory "$TRASH_DIRECTORY" || {
-       GIT_EXIT_OK=t
-       echo >&5 "FATAL: Cannot prepare test area"
-       exit 1
+       BAIL_OUT 'cannot prepare test area'
 }
 
 remove_trash=t
 if test -z "$TEST_NO_CREATE_REPO"
 then
-       git init "$TRASH_DIRECTORY" >&3 2>&4 ||
+       git init \
+           ${TEST_CREATE_REPO_NO_TEMPLATE:+--template=} \
+           "$TRASH_DIRECTORY" >&3 2>&4 ||
        error "cannot run git init"
 else
        mkdir -p "$TRASH_DIRECTORY"
@@ -1469,7 +1629,7 @@ fi
 
 # Use -P to resolve symlinks in our working directory so that the cwd
 # in subprocesses like git equals our $PWD (for pathname comparisons).
-cd -P "$TRASH_DIRECTORY" || exit 1
+cd -P "$TRASH_DIRECTORY" || BAIL_OUT "cannot cd -P to \"$TRASH_DIRECTORY\""
 
 start_test_output "$0"
 
index 2024c82691fe4a1a1c9b5c8ebd31d6c382fe8bfc..e27048f970ba3a22823a0a7eab870c424d2e3e1d 100644 (file)
  *
  * The possible states of a `tempfile` object are as follows:
  *
- * - Uninitialized. In this state the object's `on_list` field must be
- *   zero but the rest of its contents need not be initialized. As
- *   soon as the object is used in any way, it is irrevocably
- *   registered in `tempfile_list`, and `on_list` is set.
+ * - Inactive/unallocated. The only way to get a tempfile is via a creation
+ *   function like create_tempfile(). Once allocated, the tempfile is on the
+ *   global tempfile_list and considered active.
  *
  * - Active, file open (after `create_tempfile()` or
  *   `reopen_tempfile()`). In this state:
  *
  *   - the temporary file exists
- *   - `active` is set
  *   - `filename` holds the filename of the temporary file
  *   - `fd` holds a file descriptor open for writing to it
  *   - `fp` holds a pointer to an open `FILE` object if and only if
  *   `fd` is -1, and `fp` is `NULL`.
  *
  * - Inactive (after `delete_tempfile()`, `rename_tempfile()`, or a
- *   failed attempt to create a temporary file). In this state:
- *
- *   - `active` is unset
- *   - `filename` is empty (usually, though there are transitory
- *     states in which this condition doesn't hold). Client code should
- *     *not* rely on the filename being empty in this state.
- *   - `fd` is -1 and `fp` is `NULL`
- *   - the object is removed from `tempfile_list` (but could be used again)
+ *   failed attempt to create a temporary file). The struct is removed from
+ *   the global tempfile_list and deallocated.
  *
  * A temporary file is owned by the process that created it. The
  * `tempfile` has an `owner` field that records the owner's PID. This
@@ -59,14 +51,11 @@ static VOLATILE_LIST_HEAD(tempfile_list);
 static void remove_template_directory(struct tempfile *tempfile,
                                      int in_signal_handler)
 {
-       if (tempfile->directorylen > 0 &&
-           tempfile->directorylen < tempfile->filename.len &&
-           tempfile->filename.buf[tempfile->directorylen] == '/') {
-               strbuf_setlen(&tempfile->filename, tempfile->directorylen);
+       if (tempfile->directory) {
                if (in_signal_handler)
-                       rmdir(tempfile->filename.buf);
+                       rmdir(tempfile->directory);
                else
-                       rmdir_or_warn(tempfile->filename.buf);
+                       rmdir_or_warn(tempfile->directory);
        }
 }
 
@@ -89,8 +78,6 @@ static void remove_tempfiles(int in_signal_handler)
                else
                        unlink_or_warn(p->filename.buf);
                remove_template_directory(p, in_signal_handler);
-
-               p->active = 0;
        }
 }
 
@@ -111,11 +98,10 @@ static struct tempfile *new_tempfile(void)
        struct tempfile *tempfile = xmalloc(sizeof(*tempfile));
        tempfile->fd = -1;
        tempfile->fp = NULL;
-       tempfile->active = 0;
        tempfile->owner = 0;
        INIT_LIST_HEAD(&tempfile->list);
        strbuf_init(&tempfile->filename, 0);
-       tempfile->directorylen = 0;
+       tempfile->directory = NULL;
        return tempfile;
 }
 
@@ -123,9 +109,6 @@ static void activate_tempfile(struct tempfile *tempfile)
 {
        static int initialized;
 
-       if (is_tempfile_active(tempfile))
-               BUG("activate_tempfile called for active object");
-
        if (!initialized) {
                sigchain_push_common(remove_tempfiles_on_signal);
                atexit(remove_tempfiles_on_exit);
@@ -134,14 +117,13 @@ static void activate_tempfile(struct tempfile *tempfile)
 
        volatile_list_add(&tempfile->list, &tempfile_list);
        tempfile->owner = getpid();
-       tempfile->active = 1;
 }
 
 static void deactivate_tempfile(struct tempfile *tempfile)
 {
-       tempfile->active = 0;
-       strbuf_release(&tempfile->filename);
        volatile_list_del(&tempfile->list);
+       strbuf_release(&tempfile->filename);
+       free(tempfile->directory);
        free(tempfile);
 }
 
@@ -254,7 +236,7 @@ struct tempfile *mks_tempfile_dt(const char *directory_template,
 
        tempfile = new_tempfile();
        strbuf_swap(&tempfile->filename, &sb);
-       tempfile->directorylen = directorylen;
+       tempfile->directory = xmemdupz(tempfile->filename.buf, directorylen);
        tempfile->fd = fd;
        activate_tempfile(tempfile);
        return tempfile;
index d7804a214abb60ee60496ef34a9fc8be110344ea..d0413af733c81ad895669aab30937435cae0f2af 100644 (file)
 
 struct tempfile {
        volatile struct volatile_list_head list;
-       volatile sig_atomic_t active;
        volatile int fd;
        FILE *volatile fp;
        volatile pid_t owner;
        struct strbuf filename;
-       size_t directorylen;
+       char *directory;
 };
 
 /*
@@ -221,7 +220,7 @@ FILE *fdopen_tempfile(struct tempfile *tempfile, const char *mode);
 
 static inline int is_tempfile_active(struct tempfile *tempfile)
 {
-       return tempfile && tempfile->active;
+       return !!tempfile;
 }
 
 /*
index c5c8cfbbaa065bccfbc058efd9eaffc71507d011..37a3163be12110ef9e830eba534d19064408c581 100644 (file)
@@ -479,9 +479,12 @@ static void fn_param_fl(const char *file, int line, const char *param,
 {
        const char *event_name = "def_param";
        struct json_writer jw = JSON_WRITER_INIT;
+       enum config_scope scope = current_config_scope();
+       const char *scope_name = config_scope_name(scope);
 
        jw_object_begin(&jw, 0);
        event_fmt_prepare(event_name, file, line, NULL, &jw);
+       jw_object_string(&jw, "scope", scope_name);
        jw_object_string(&jw, "param", param);
        jw_object_string(&jw, "value", value);
        jw_end(&jw);
index c42fbade7f0381d4ca80c562f51a7864ceb5449e..69f80330778b40e8293b46ed1a49bdb9feedfeff 100644 (file)
@@ -298,8 +298,11 @@ static void fn_param_fl(const char *file, int line, const char *param,
                        const char *value)
 {
        struct strbuf buf_payload = STRBUF_INIT;
+       enum config_scope scope = current_config_scope();
+       const char *scope_name = config_scope_name(scope);
 
-       strbuf_addf(&buf_payload, "def_param %s=%s", param, value);
+       strbuf_addf(&buf_payload, "def_param scope:%s %s=%s", scope_name, param,
+                   value);
        normal_io_write_fl(file, line, &buf_payload);
        strbuf_release(&buf_payload);
 }
index a1eff8bea3101aab10a2b2c4e2a655f2f498a5df..8cb792488c8feee60df3c0e38301d4008b14c50c 100644 (file)
@@ -441,12 +441,17 @@ static void fn_param_fl(const char *file, int line, const char *param,
 {
        const char *event_name = "def_param";
        struct strbuf buf_payload = STRBUF_INIT;
+       struct strbuf scope_payload = STRBUF_INIT;
+       enum config_scope scope = current_config_scope();
+       const char *scope_name = config_scope_name(scope);
 
        strbuf_addf(&buf_payload, "%s:%s", param, value);
+       strbuf_addf(&scope_payload, "%s:%s", "scope", scope_name);
 
-       perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
-                        &buf_payload);
+       perf_io_write_fl(file, line, event_name, NULL, NULL, NULL,
+                        scope_payload.buf, &buf_payload);
        strbuf_release(&buf_payload);
+       strbuf_release(&scope_payload);
 }
 
 static void fn_repo_fl(const char *file, int line,
index d419c20735e993d5812f396428e7727533d56768..0fd5b142a377056d1e45f8dfd1ff6ae7a9c40097 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -478,7 +478,8 @@ static struct {
        { "ifmissing", TRAILER_IF_MISSING }
 };
 
-static int git_trailer_default_config(const char *conf_key, const char *value, void *cb)
+static int git_trailer_default_config(const char *conf_key, const char *value,
+                                     void *cb UNUSED)
 {
        const char *trailer_item, *variable_name;
 
@@ -509,7 +510,8 @@ static int git_trailer_default_config(const char *conf_key, const char *value, v
        return 0;
 }
 
-static int git_trailer_config(const char *conf_key, const char *value, void *cb)
+static int git_trailer_config(const char *conf_key, const char *value,
+                             void *cb UNUSED)
 {
        const char *trailer_item, *variable_name;
        struct arg_item *item;
index 322c7224782fbef8c9bdc7af4088b00f361a539d..e95267a4ab54dc12318435d157d1fdd37821f567 100644 (file)
@@ -1286,6 +1286,8 @@ int transport_helper_init(struct transport *transport, const char *name)
        if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
                debug = 1;
 
+       list_objects_filter_init(&data->transport_options.filter_options);
+
        transport->data = data;
        transport->vtable = &vtable;
        transport->smart_options = &(data->transport_options);
index b51e991e4439467c3cb2fc15381c259e135f5139..f78e29058fc272d2345c9d4c7d4026da9e1b1bc2 100644 (file)
@@ -142,7 +142,7 @@ static void get_refs_from_bundle_inner(struct transport *transport)
 
 static struct ref *get_refs_from_bundle(struct transport *transport,
                                        int for_push,
-                                       struct transport_ls_refs_options *transport_options)
+                                       struct transport_ls_refs_options *transport_options UNUSED)
 {
        struct bundle_transport_data *data = transport->data;
        struct ref *result = NULL;
@@ -386,7 +386,8 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.cloning = transport->cloning;
        args.update_shallow = data->options.update_shallow;
        args.from_promisor = data->options.from_promisor;
-       args.filter_options = data->options.filter_options;
+       list_objects_filter_copy(&args.filter_options,
+                                &data->options.filter_options);
        args.refetch = data->options.refetch;
        args.stateless_rpc = transport->stateless_rpc;
        args.server_options = transport->server_options;
@@ -453,6 +454,7 @@ cleanup:
 
        free_refs(refs_tmp);
        free_refs(refs);
+       list_objects_filter_release(&args.filter_options);
        return ret;
 }
 
@@ -893,6 +895,7 @@ static int disconnect_git(struct transport *transport)
                finish_connect(data->conn);
        }
 
+       list_objects_filter_release(&data->options.filter_options);
        free(data);
        return 0;
 }
@@ -1110,6 +1113,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
                 * will be checked individually in git_connect.
                 */
                struct git_transport_data *data = xcalloc(1, sizeof(*data));
+               list_objects_filter_init(&data->options.filter_options);
                ret->data = data;
                ret->vtable = &builtin_smart_vtable;
                ret->smart_options = &(data->options);
index 90b92114be8558b63371531aecfa246829317840..bae812156c4fedb8e296e422d4cb6a8af1a2dada 100644 (file)
@@ -1423,7 +1423,7 @@ static void debug_unpack_callback(int n,
  * from the tree walk at the given traverse_info.
  */
 static int is_sparse_directory_entry(struct cache_entry *ce,
-                                    struct name_entry *name,
+                                    const struct name_entry *name,
                                     struct traverse_info *info)
 {
        if (!ce || !name || !S_ISSPARSEDIR(ce->ce_mode))
@@ -1562,7 +1562,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
                        }
                }
 
-               if (!is_sparse_directory_entry(src[0], names, info) &&
+               if (!is_sparse_directory_entry(src[0], p, info) &&
                    !is_new_sparse_dir &&
                    traverse_trees_recursive(n, dirmask, mask & ~dirmask,
                                                    names, info) < 0) {
index 3a851b360663a56bc2ad0d7beed0cc566d581546..0b8311bd685f002ffb38672c670372b7e698de95 100644 (file)
@@ -141,6 +141,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
        data->allow_filter_fallback = 1;
        data->tree_filter_max_depth = ULONG_MAX;
        packet_writer_init(&data->writer, 1);
+       list_objects_filter_init(&data->filter_options);
 
        data->keepalive = 5;
        data->advertise_sid = 0;
@@ -455,6 +456,7 @@ static void create_pack_file(struct upload_pack_data *pack_data,
        return;
 
  fail:
+       free(output_state);
        send_client_data(3, abort_msg, sizeof(abort_msg),
                         pack_data->use_sideband);
        die("git upload-pack: %s", abort_msg);
@@ -1169,7 +1171,7 @@ static int mark_our_ref(const char *refname, const char *refname_full,
 }
 
 static int check_ref(const char *refname_full, const struct object_id *oid,
-                    int flag, void *cb_data)
+                    int flag UNUSED, void *cb_data UNUSED)
 {
        const char *refname = strip_namespace(refname_full);
 
@@ -1193,7 +1195,7 @@ static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) {
 }
 
 static int send_ref(const char *refname, const struct object_id *oid,
-                   int flag, void *cb_data)
+                   int flag UNUSED, void *cb_data)
 {
        static const char *capabilities = "multi_ack thin-pack side-band"
                " side-band-64k ofs-delta shallow deepen-since deepen-not"
@@ -1235,7 +1237,8 @@ static int send_ref(const char *refname, const struct object_id *oid,
        return 0;
 }
 
-static int find_symref(const char *refname, const struct object_id *oid,
+static int find_symref(const char *refname,
+                      const struct object_id *oid UNUSED,
                       int flag, void *cb_data)
 {
        const char *symref_target;
@@ -1321,18 +1324,27 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data)
                data->advertise_sid = git_config_bool(var, value);
        }
 
-       if (current_config_scope() != CONFIG_SCOPE_LOCAL &&
-           current_config_scope() != CONFIG_SCOPE_WORKTREE) {
-               if (!strcmp("uploadpack.packobjectshook", var))
-                       return git_config_string(&data->pack_objects_hook, var, value);
-       }
-
        if (parse_object_filter_config(var, value, data) < 0)
                return -1;
 
        return parse_hide_refs_config(var, value, "uploadpack");
 }
 
+static int upload_pack_protected_config(const char *var, const char *value, void *cb_data)
+{
+       struct upload_pack_data *data = cb_data;
+
+       if (!strcmp("uploadpack.packobjectshook", var))
+               return git_config_string(&data->pack_objects_hook, var, value);
+       return 0;
+}
+
+static void get_upload_pack_config(struct upload_pack_data *data)
+{
+       git_config(upload_pack_config, data);
+       git_protected_config(upload_pack_protected_config, data);
+}
+
 void upload_pack(const int advertise_refs, const int stateless_rpc,
                 const int timeout)
 {
@@ -1340,8 +1352,7 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
        struct upload_pack_data data;
 
        upload_pack_data_init(&data);
-
-       git_config(upload_pack_config, &data);
+       get_upload_pack_config(&data);
 
        data.stateless_rpc = stateless_rpc;
        data.timeout = timeout;
@@ -1400,18 +1411,14 @@ static int parse_want(struct packet_writer *writer, const char *line,
        const char *arg;
        if (skip_prefix(line, "want ", &arg)) {
                struct object_id oid;
-               struct commit *commit;
                struct object *o;
 
                if (get_oid_hex(arg, &oid))
                        die("git upload-pack: protocol error, "
                            "expected to get oid, not '%s'", line);
 
-               commit = lookup_commit_in_graph(the_repository, &oid);
-               if (commit)
-                       o = &commit->object;
-               else
-                       o = parse_object(the_repository, &oid);
+               o = parse_object_with_flags(the_repository, &oid,
+                                           PARSE_OBJECT_SKIP_HASH_CHECK);
 
                if (!o) {
                        packet_writer_error(writer,
@@ -1695,8 +1702,7 @@ int upload_pack_v2(struct repository *r, struct packet_reader *request)
 
        upload_pack_data_init(&data);
        data.use_sideband = LARGE_PACKET_MAX;
-
-       git_config(upload_pack_config, &data);
+       get_upload_pack_config(&data);
 
        while (state != FETCH_DONE) {
                switch (state) {
index c5e292197956487c2a44f84f7839126d3a796cfc..99d0e0eae047410660f0bf3b0d3f487d45c1134d 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -215,8 +215,10 @@ static int interpret_target(struct walker *walker, char *target, struct object_i
        return -1;
 }
 
-static int mark_complete(const char *path, const struct object_id *oid,
-                        int flag, void *cb_data)
+static int mark_complete(const char *path UNUSED,
+                        const struct object_id *oid,
+                        int flag UNUSED,
+                        void *cb_data UNUSED)
 {
        struct commit *commit = lookup_commit_reference_gently(the_repository,
                                                               oid, 1);
index f52f3e21cc7506c05cc9a31b6b06088e21f13f70..299d6489a6b0a148b57fa6c8a11f9245e1dfd0dd 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -594,10 +594,16 @@ int git_fsync(int fd, enum fsync_action action)
        }
 }
 
+static void log_trace_fsync_if(const char *key, intmax_t value)
+{
+       if (value)
+               trace2_data_intmax("fsync", the_repository, key, value);
+}
+
 void trace_git_fsync_stats(void)
 {
-       trace2_data_intmax("fsync", the_repository, "fsync/writeout-only", count_fsync_writeout_only);
-       trace2_data_intmax("fsync", the_repository, "fsync/hardware-flush", count_fsync_hardware_flush);
+       log_trace_fsync_if("fsync/writeout-only", count_fsync_writeout_only);
+       log_trace_fsync_if("fsync/hardware-flush", count_fsync_hardware_flush);
 }
 
 static int warn_if_unremovable(const char *op, const char *file, int rc)
index 867e3e417e9d4d26036a15a2034018529ce6dec7..5813174896cc9ae5fa9287c8bcc432dc8cf2ef47 100644 (file)
@@ -947,9 +947,11 @@ static void wt_longstatus_print_changed(struct wt_status *s)
        wt_longstatus_print_trailer(s);
 }
 
-static int stash_count_refs(struct object_id *ooid, struct object_id *noid,
-                           const char *email, timestamp_t timestamp, int tz,
-                           const char *message, void *cb_data)
+static int stash_count_refs(struct object_id *ooid UNUSED,
+                           struct object_id *noid UNUSED,
+                           const char *email UNUSED,
+                           timestamp_t timestamp UNUSED, int tz UNUSED,
+                           const char *message UNUSED, void *cb_data)
 {
        int *c = cb_data;
        (*c)++;
@@ -1612,8 +1614,10 @@ struct grab_1st_switch_cbdata {
        struct object_id noid;
 };
 
-static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,
-                          const char *email, timestamp_t timestamp, int tz,
+static int grab_1st_switch(struct object_id *ooid UNUSED,
+                          struct object_id *noid,
+                          const char *email UNUSED,
+                          timestamp_t timestamp UNUSED, int tz UNUSED,
                           const char *message, void *cb_data)
 {
        struct grab_1st_switch_cbdata *cb = cb_data;
index 72e25a9ffa56fbeebefbd2e9904b3957d0a8610d..bb56b23f34c96ceec169d39b829e89cd512d7e39 100644 (file)
@@ -120,6 +120,7 @@ typedef struct s_bdiffparam {
 
 
 #define xdl_malloc(x) xmalloc(x)
+#define xdl_calloc(n, sz) xcalloc(n, sz)
 #define xdl_free(ptr) free(ptr)
 #define xdl_realloc(ptr,x) xrealloc(ptr,x)
 
index 758410c11ac286adc77c6f992e51822def202a40..32652ded2d7c5cad87f120a13c3c6c84d6def61f 100644 (file)
@@ -321,12 +321,12 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
                return -1;
 
        if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF) {
-               res = xdl_do_patience_diff(mf1, mf2, xpp, xe);
+               res = xdl_do_patience_diff(xpp, xe);
                goto out;
        }
 
        if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) {
-               res = xdl_do_histogram_diff(mf1, mf2, xpp, xe);
+               res = xdl_do_histogram_diff(xpp, xe);
                goto out;
        }
 
@@ -337,7 +337,7 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
         * One is to store the forward path and one to store the backward path.
         */
        ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
-       if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) {
+       if (!XDL_ALLOC_ARRAY(kvd, 2 * ndiags + 2)) {
 
                xdl_free_env(xe);
                return -1;
index 8f1c7c8b0445f88514d0cb0ce868380d1711ccd2..126c9d8ff4e4147e0f4e96ddb9debfde17d9b637 100644 (file)
@@ -56,9 +56,7 @@ int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr);
 void xdl_free_script(xdchange_t *xscr);
 int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                  xdemitconf_t const *xecfg);
-int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
-               xdfenv_t *env);
-int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
-               xdfenv_t *env);
+int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env);
+int xdl_do_histogram_diff(xpparam_t const *xpp, xdfenv_t *env);
 
 #endif /* #if !defined(XDIFFI_H) */
index 01decffc332629dd9dcfd79c904187b7cc6d0943..16a8fe2f3f3df3fe52fee0ed6d527682a61a0dc8 100644 (file)
@@ -251,7 +251,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
                    int line1, int count1, int line2, int count2)
 {
        int b_ptr;
-       int sz, ret = -1;
+       int ret = -1;
        struct histindex index;
 
        memset(&index, 0, sizeof(index));
@@ -265,23 +265,16 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
        index.rcha.head = NULL;
 
        index.table_bits = xdl_hashbits(count1);
-       sz = index.records_size = 1 << index.table_bits;
-       sz *= sizeof(struct record *);
-       if (!(index.records = (struct record **) xdl_malloc(sz)))
+       index.records_size = 1 << index.table_bits;
+       if (!XDL_CALLOC_ARRAY(index.records, index.records_size))
                goto cleanup;
-       memset(index.records, 0, sz);
 
-       sz = index.line_map_size = count1;
-       sz *= sizeof(struct record *);
-       if (!(index.line_map = (struct record **) xdl_malloc(sz)))
+       index.line_map_size = count1;
+       if (!XDL_CALLOC_ARRAY(index.line_map, index.line_map_size))
                goto cleanup;
-       memset(index.line_map, 0, sz);
 
-       sz = index.line_map_size;
-       sz *= sizeof(unsigned int);
-       if (!(index.next_ptrs = (unsigned int *) xdl_malloc(sz)))
+       if (!XDL_CALLOC_ARRAY(index.next_ptrs, index.line_map_size))
                goto cleanup;
-       memset(index.next_ptrs, 0, sz);
 
        /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */
        if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0)
@@ -369,8 +362,7 @@ out:
        return result;
 }
 
-int xdl_do_histogram_diff(mmfile_t *file1, mmfile_t *file2,
-       xpparam_t const *xpp, xdfenv_t *env)
+int xdl_do_histogram_diff(xpparam_t const *xpp, xdfenv_t *env)
 {
        return histogram_diff(xpp, env,
                env->xdf1.dstart + 1, env->xdf1.dend - env->xdf1.dstart + 1,
index ae4636c2477cc640eae84578805d9722d5e28d1b..8487bb396faa5c6ac984e8295b737b4fbab3f92c 100644 (file)
@@ -49,5 +49,23 @@ do { \
                ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \
 } while (0)
 
+/* Allocate an array of nr elements, returns NULL on failure */
+#define XDL_ALLOC_ARRAY(p, nr)                         \
+       ((p) = SIZE_MAX / sizeof(*(p)) >= (size_t)(nr)  \
+               ? xdl_malloc((nr) * sizeof(*(p)))       \
+               : NULL)
+
+/* Allocate an array of nr zeroed out elements, returns NULL on failure */
+#define XDL_CALLOC_ARRAY(p, nr)        ((p) = xdl_calloc(nr, sizeof(*(p))))
+
+/*
+ * Ensure array p can accommodate at least nr elements, growing the
+ * array and updating alloc (which is the number of allocated
+ * elements) as necessary. Frees p and returns -1 on failure, returns
+ * 0 on success
+ */
+#define XDL_ALLOC_GROW(p, nr, alloc)   \
+       (-!((nr) <= (alloc) ||          \
+           ((p) = xdl_alloc_grow_helper((p), (nr), &(alloc), sizeof(*(p))))))
 
 #endif /* #if !defined(XMACROS_H) */
index 1a21c6a74b368cb094e20c708a43071c72558d7e..a2d8955537f566458b6e912ff5fb8496fa7fe85a 100644 (file)
@@ -69,7 +69,6 @@ struct hashmap {
        } *entries, *first, *last;
        /* were common records found? */
        unsigned long has_matches;
-       mmfile_t *file1, *file2;
        xdfenv_t *env;
        xpparam_t const *xpp;
 };
@@ -139,23 +138,17 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
  *
  * It is assumed that env has been prepared using xdl_prepare().
  */
-static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
-               xpparam_t const *xpp, xdfenv_t *env,
+static int fill_hashmap(xpparam_t const *xpp, xdfenv_t *env,
                struct hashmap *result,
                int line1, int count1, int line2, int count2)
 {
-       result->file1 = file1;
-       result->file2 = file2;
        result->xpp = xpp;
        result->env = env;
 
        /* We know exactly how large we want the hash map */
        result->alloc = count1 * 2;
-       result->entries = (struct entry *)
-               xdl_malloc(result->alloc * sizeof(struct entry));
-       if (!result->entries)
+       if (!XDL_CALLOC_ARRAY(result->entries, result->alloc))
                return -1;
-       memset(result->entries, 0, result->alloc * sizeof(struct entry));
 
        /* First, fill with entries from the first file */
        while (count1--)
@@ -200,7 +193,7 @@ static int binary_search(struct entry **sequence, int longest,
  */
 static int find_longest_common_sequence(struct hashmap *map, struct entry **res)
 {
-       struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *));
+       struct entry **sequence;
        int longest = 0, i;
        struct entry *entry;
 
@@ -211,7 +204,7 @@ static int find_longest_common_sequence(struct hashmap *map, struct entry **res)
         */
        int anchor_i = -1;
 
-       if (!sequence)
+       if (!XDL_ALLOC_ARRAY(sequence, map->nr))
                return -1;
 
        for (entry = map->first; entry; entry = entry->next) {
@@ -257,8 +250,7 @@ static int match(struct hashmap *map, int line1, int line2)
        return record1->ha == record2->ha;
 }
 
-static int patience_diff(mmfile_t *file1, mmfile_t *file2,
-               xpparam_t const *xpp, xdfenv_t *env,
+static int patience_diff(xpparam_t const *xpp, xdfenv_t *env,
                int line1, int count1, int line2, int count2);
 
 static int walk_common_sequence(struct hashmap *map, struct entry *first,
@@ -289,8 +281,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
 
                /* Recurse */
                if (next1 > line1 || next2 > line2) {
-                       if (patience_diff(map->file1, map->file2,
-                                       map->xpp, map->env,
+                       if (patience_diff(map->xpp, map->env,
                                        line1, next1 - line1,
                                        line2, next2 - line2))
                                return -1;
@@ -329,8 +320,7 @@ static int fall_back_to_classic_diff(struct hashmap *map,
  *
  * This function assumes that env was prepared with xdl_prepare_env().
  */
-static int patience_diff(mmfile_t *file1, mmfile_t *file2,
-               xpparam_t const *xpp, xdfenv_t *env,
+static int patience_diff(xpparam_t const *xpp, xdfenv_t *env,
                int line1, int count1, int line2, int count2)
 {
        struct hashmap map;
@@ -349,7 +339,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2,
        }
 
        memset(&map, 0, sizeof(map));
-       if (fill_hashmap(file1, file2, xpp, env, &map,
+       if (fill_hashmap(xpp, env, &map,
                        line1, count1, line2, count2))
                return -1;
 
@@ -377,9 +367,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2,
        return result;
 }
 
-int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2,
-               xpparam_t const *xpp, xdfenv_t *env)
+int xdl_do_patience_diff(xpparam_t const *xpp, xdfenv_t *env)
 {
-       return patience_diff(file1, file2, xpp, env,
-                       1, env->xdf1.nrec, 1, env->xdf2.nrec);
+       return patience_diff(xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec);
 }
index 105752758f2f3870448f1ec1cf0070c3a29b36e6..c84549f6c5089ea08c7bc1daad3ef57dd3fceb77 100644 (file)
@@ -78,15 +78,14 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
 
                return -1;
        }
-       if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) {
+       if (!XDL_CALLOC_ARRAY(cf->rchash, cf->hsize)) {
 
                xdl_cha_free(&cf->ncha);
                return -1;
        }
-       memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *));
 
        cf->alloc = size;
-       if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) {
+       if (!XDL_ALLOC_ARRAY(cf->rcrecs, cf->alloc)) {
 
                xdl_free(cf->rchash);
                xdl_cha_free(&cf->ncha);
@@ -112,7 +111,6 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t
        long hi;
        char const *line;
        xdlclass_t *rcrec;
-       xdlclass_t **rcrecs;
 
        line = rec->ptr;
        hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
@@ -128,14 +126,8 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t
                        return -1;
                }
                rcrec->idx = cf->count++;
-               if (cf->count > cf->alloc) {
-                       cf->alloc *= 2;
-                       if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
-
+               if (XDL_ALLOC_GROW(cf->rcrecs, cf->count, cf->alloc))
                                return -1;
-                       }
-                       cf->rcrecs = rcrecs;
-               }
                cf->rcrecs[rcrec->idx] = rcrec;
                rcrec->line = line;
                rcrec->size = rec->size;
@@ -164,7 +156,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
        unsigned long hav;
        char const *blk, *cur, *top, *prev;
        xrecord_t *crec;
-       xrecord_t **recs, **rrecs;
+       xrecord_t **recs;
        xrecord_t **rhash;
        unsigned long *ha;
        char *rchg;
@@ -178,26 +170,21 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
 
        if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0)
                goto abort;
-       if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *))))
+       if (!XDL_ALLOC_ARRAY(recs, narec))
                goto abort;
 
        hbits = xdl_hashbits((unsigned int) narec);
        hsize = 1 << hbits;
-       if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *))))
+       if (!XDL_CALLOC_ARRAY(rhash, hsize))
                goto abort;
-       memset(rhash, 0, hsize * sizeof(xrecord_t *));
 
        nrec = 0;
        if ((cur = blk = xdl_mmfile_first(mf, &bsize))) {
                for (top = blk + bsize; cur < top; ) {
                        prev = cur;
                        hav = xdl_hash_record(&cur, top, xpp->flags);
-                       if (nrec >= narec) {
-                               narec *= 2;
-                               if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *))))
-                                       goto abort;
-                               recs = rrecs;
-                       }
+                       if (XDL_ALLOC_GROW(recs, nrec + 1, narec))
+                               goto abort;
                        if (!(crec = xdl_cha_alloc(&xdf->rcha)))
                                goto abort;
                        crec->ptr = prev;
@@ -209,15 +196,14 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
                }
        }
 
-       if (!(rchg = (char *) xdl_malloc((nrec + 2) * sizeof(char))))
+       if (!XDL_CALLOC_ARRAY(rchg, nrec + 2))
                goto abort;
-       memset(rchg, 0, (nrec + 2) * sizeof(char));
 
        if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) &&
            (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF)) {
-               if (!(rindex = xdl_malloc((nrec + 1) * sizeof(*rindex))))
+               if (!XDL_ALLOC_ARRAY(rindex, nrec + 1))
                        goto abort;
-               if (!(ha = xdl_malloc((nrec + 1) * sizeof(*ha))))
+               if (!XDL_ALLOC_ARRAY(ha, nrec + 1))
                        goto abort;
        }
 
@@ -383,11 +369,8 @@ static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xd
        xdlclass_t *rcrec;
        char *dis, *dis1, *dis2;
 
-       if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
-
+       if (!XDL_CALLOC_ARRAY(dis, xdf1->nrec + xdf2->nrec + 2))
                return -1;
-       }
-       memset(dis, 0, xdf1->nrec + xdf2->nrec + 2);
        dis1 = dis;
        dis2 = dis1 + xdf1->nrec + 1;
 
index 115b2b1640b4504d1b7eb1bc4dc1428b109f6380..9e36f24875d20711b61d243994f324d00a1b211e 100644 (file)
@@ -432,3 +432,20 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
 
        return 0;
 }
+
+void* xdl_alloc_grow_helper(void *p, long nr, long *alloc, size_t size)
+{
+       void *tmp = NULL;
+       size_t n = ((LONG_MAX - 16) / 2 >= *alloc) ? 2 * *alloc + 16 : LONG_MAX;
+       if (nr > n)
+               n = nr;
+       if (SIZE_MAX / size >= n)
+               tmp = xdl_realloc(p, n * size);
+       if (tmp) {
+               *alloc = n;
+       } else {
+               xdl_free(p);
+               *alloc = 0;
+       }
+       return tmp;
+}
index fba7bae03c7855ca90aff3f238321581a91a6676..fd0bba94e8b4d2442ba59d0a4327d2d53e10210a 100644 (file)
@@ -42,6 +42,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
 int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
                       int line1, int count1, int line2, int count2);
 
-
+/* Do not call this function, use XDL_ALLOC_GROW instead */
+void* xdl_alloc_grow_helper(void* p, long nr, long* alloc, size_t size);
 
 #endif /* #if !defined(XUTILS_H) */