]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'ms/send-email-validate-fix'
authorJunio C Hamano <gitster@pobox.com>
Tue, 7 Nov 2023 01:26:44 +0000 (10:26 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 7 Nov 2023 01:26:44 +0000 (10:26 +0900)
"git send-email" did not have certain pieces of data computed yet
when it tried to validate the outging messages and its recipient
addresses, which has been sorted out.

* ms/send-email-validate-fix:
  send-email: move validation code below process_address_list

900 files changed:
.github/workflows/coverity.yml [new file with mode: 0644]
.github/workflows/main.yml
.gitignore
.mailmap
Documentation/CodingGuidelines
Documentation/MyFirstContribution.txt
Documentation/MyFirstObjectWalk.txt
Documentation/RelNotes/2.42.0.txt [new file with mode: 0644]
Documentation/RelNotes/2.42.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.43.0.txt [new file with mode: 0644]
Documentation/ReviewingGuidelines.txt
Documentation/SubmittingPatches
Documentation/ToolsForGit.txt
Documentation/config.txt
Documentation/config/advice.txt
Documentation/config/alias.txt
Documentation/config/apply.txt
Documentation/config/attr.txt [new file with mode: 0644]
Documentation/config/branch.txt
Documentation/config/checkout.txt
Documentation/config/clean.txt
Documentation/config/clone.txt
Documentation/config/color.txt
Documentation/config/column.txt
Documentation/config/commit.txt
Documentation/config/core.txt
Documentation/config/credential.txt
Documentation/config/diff.txt
Documentation/config/fastimport.txt
Documentation/config/feature.txt
Documentation/config/fetch.txt
Documentation/config/format.txt
Documentation/config/fsck.txt
Documentation/config/fsmonitor--daemon.txt
Documentation/config/gc.txt
Documentation/config/gpg.txt
Documentation/config/gui.txt
Documentation/config/http.txt
Documentation/config/i18n.txt
Documentation/config/imap.txt
Documentation/config/index.txt
Documentation/config/log.txt
Documentation/config/mailinfo.txt
Documentation/config/maintenance.txt
Documentation/config/man.txt
Documentation/config/merge.txt
Documentation/config/mergetool.txt
Documentation/config/notes.txt
Documentation/config/pack.txt
Documentation/config/push.txt
Documentation/config/rebase.txt
Documentation/config/receive.txt
Documentation/config/rerere.txt
Documentation/config/safe.txt
Documentation/config/sendemail.txt
Documentation/config/sequencer.txt
Documentation/config/splitindex.txt
Documentation/config/stash.txt
Documentation/config/status.txt
Documentation/config/submodule.txt
Documentation/config/trace2.txt
Documentation/config/transfer.txt
Documentation/config/user.txt
Documentation/config/versionsort.txt
Documentation/diff-generate-patch.txt
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/fsck-msgids.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-archive.txt
Documentation/git-bisect.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-bugreport.txt
Documentation/git-cat-file.txt
Documentation/git-check-attr.txt
Documentation/git-check-ignore.txt
Documentation/git-check-ref-format.txt
Documentation/git-checkout-index.txt
Documentation/git-checkout.txt
Documentation/git-clean.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-count-objects.txt
Documentation/git-credential-cache.txt
Documentation/git-credential-store.txt
Documentation/git-credential.txt
Documentation/git-cvsserver.txt
Documentation/git-daemon.txt
Documentation/git-describe.txt
Documentation/git-diff-files.txt
Documentation/git-diff-index.txt
Documentation/git-diff-tree.txt
Documentation/git-diff.txt
Documentation/git-difftool.txt
Documentation/git-fast-import.txt
Documentation/git-fetch-pack.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-fsck.txt
Documentation/git-fsmonitor--daemon.txt
Documentation/git-gc.txt
Documentation/git-get-tar-commit-id.txt
Documentation/git-grep.txt
Documentation/git-hash-object.txt
Documentation/git-help.txt
Documentation/git-hook.txt
Documentation/git-http-backend.txt
Documentation/git-http-fetch.txt
Documentation/git-http-push.txt
Documentation/git-index-pack.txt
Documentation/git-init.txt
Documentation/git-interpret-trailers.txt
Documentation/git-log.txt
Documentation/git-ls-files.txt
Documentation/git-ls-remote.txt
Documentation/git-ls-tree.txt
Documentation/git-mailsplit.txt
Documentation/git-maintenance.txt
Documentation/git-merge-base.txt
Documentation/git-merge-tree.txt
Documentation/git-merge.txt
Documentation/git-mergetool--lib.txt
Documentation/git-mergetool.txt
Documentation/git-mktag.txt
Documentation/git-mktree.txt
Documentation/git-mv.txt
Documentation/git-name-rev.txt
Documentation/git-notes.txt
Documentation/git-pack-objects.txt
Documentation/git-pack-refs.txt
Documentation/git-prune-packed.txt
Documentation/git-prune.txt
Documentation/git-push.txt
Documentation/git-quiltimport.txt
Documentation/git-range-diff.txt
Documentation/git-read-tree.txt
Documentation/git-rebase.txt
Documentation/git-receive-pack.txt
Documentation/git-remote-ext.txt
Documentation/git-remote-fd.txt
Documentation/git-repack.txt
Documentation/git-replace.txt
Documentation/git-request-pull.txt
Documentation/git-restore.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-rm.txt
Documentation/git-send-email.txt
Documentation/git-send-pack.txt
Documentation/git-sh-setup.txt
Documentation/git-show-branch.txt
Documentation/git-show-ref.txt
Documentation/git-show.txt
Documentation/git-sparse-checkout.txt
Documentation/git-stash.txt
Documentation/git-status.txt
Documentation/git-stripspace.txt
Documentation/git-submodule.txt
Documentation/git-symbolic-ref.txt
Documentation/git-tag.txt
Documentation/git-update-index.txt
Documentation/git-update-ref.txt
Documentation/git-update-server-info.txt
Documentation/git-upload-pack.txt
Documentation/git-var.txt
Documentation/git-verify-pack.txt
Documentation/git-whatchanged.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcli.txt
Documentation/gitcredentials.txt
Documentation/gitdiffcore.txt
Documentation/giteveryday.txt
Documentation/gitformat-bundle.txt
Documentation/gitformat-chunk.txt
Documentation/gitformat-pack.txt
Documentation/githooks.txt
Documentation/gitignore.txt
Documentation/gitk.txt
Documentation/gitmodules.txt
Documentation/gitprotocol-capabilities.txt
Documentation/gitprotocol-common.txt
Documentation/gitprotocol-http.txt
Documentation/gitprotocol-pack.txt
Documentation/gitprotocol-v2.txt
Documentation/gitsubmodules.txt
Documentation/gittutorial.txt
Documentation/gitweb.conf.txt
Documentation/gitweb.txt
Documentation/glossary-content.txt
Documentation/howto/coordinate-embargoed-releases.txt
Documentation/howto/maintain-git.txt
Documentation/howto/use-git-daemon.txt
Documentation/howto/using-merge-subtree.txt
Documentation/i18n.txt
Documentation/mergetools/vimdiff.txt
Documentation/object-format-disclaimer.txt
Documentation/pretty-formats.txt
Documentation/pretty-options.txt
Documentation/pull-fetch-param.txt
Documentation/rev-list-options.txt
Documentation/revisions.txt
Documentation/scalar.txt
Documentation/technical/api-index-skel.txt
Documentation/technical/api-merge.txt
Documentation/technical/api-simple-ipc.txt
Documentation/technical/bitmap-format.txt
Documentation/technical/commit-graph.txt
Documentation/technical/parallel-checkout.txt
Documentation/technical/partial-clone.txt
Documentation/technical/racy-git.txt
Documentation/technical/reftable.txt
Documentation/technical/remembering-renames.txt
Documentation/technical/repository-version.txt
Documentation/technical/rerere.txt
Documentation/urls-remotes.txt
Documentation/urls.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
abspath.c
abspath.h
add-interactive.c
add-patch.c
advice.c
advice.h
alias.c
alloc.h
apply.c
archive-tar.c
archive-zip.c
archive.c
attr.c
attr.h
bisect.c
blame.c
blame.h
bloom.c
branch.c
builtin.h
builtin/add.c
builtin/am.c
builtin/apply.c
builtin/archive.c
builtin/bisect.c
builtin/blame.c
builtin/branch.c
builtin/bugreport.c
builtin/bundle.c
builtin/cat-file.c
builtin/check-attr.c
builtin/check-ignore.c
builtin/check-mailmap.c
builtin/check-ref-format.c
builtin/checkout--worker.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/column.c
builtin/commit-graph.c
builtin/commit-tree.c
builtin/commit.c
builtin/config.c
builtin/count-objects.c
builtin/credential-cache--daemon.c
builtin/credential-cache.c
builtin/credential-store.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/diff.c
builtin/difftool.c
builtin/fast-export.c
builtin/fast-import.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/for-each-repo.c
builtin/fsck.c
builtin/fsmonitor--daemon.c
builtin/gc.c
builtin/get-tar-commit-id.c
builtin/grep.c
builtin/hash-object.c
builtin/help.c
builtin/hook.c
builtin/index-pack.c
builtin/init-db.c
builtin/interpret-trailers.c
builtin/log.c
builtin/ls-files.c
builtin/ls-remote.c
builtin/ls-tree.c
builtin/mailinfo.c
builtin/mailsplit.c
builtin/merge-base.c
builtin/merge-file.c
builtin/merge-index.c
builtin/merge-ours.c
builtin/merge-recursive.c
builtin/merge-tree.c
builtin/merge.c
builtin/mktag.c
builtin/mktree.c
builtin/multi-pack-index.c
builtin/mv.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-objects.c
builtin/pack-redundant.c
builtin/pack-refs.c
builtin/patch-id.c
builtin/prune.c
builtin/pull.c
builtin/push.c
builtin/range-diff.c
builtin/read-tree.c
builtin/rebase.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/rerere.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/revert.c
builtin/rm.c
builtin/send-pack.c
builtin/shortlog.c
builtin/show-branch.c
builtin/show-index.c
builtin/show-ref.c
builtin/sparse-checkout.c
builtin/stash.c
builtin/stripspace.c
builtin/submodule--helper.c
builtin/symbolic-ref.c
builtin/tag.c
builtin/unpack-file.c
builtin/unpack-objects.c
builtin/update-index.c
builtin/update-ref.c
builtin/update-server-info.c
builtin/upload-archive.c
builtin/upload-pack.c
builtin/var.c
builtin/verify-commit.c
builtin/verify-pack.c
builtin/verify-tag.c
builtin/worktree.c
builtin/write-tree.c
bulk-checkin.c
bulk-checkin.h
bundle-uri.c
bundle.c
cache-tree.c
chunk-format.c
chunk-format.h
ci/config/README [new file with mode: 0644]
ci/config/allow-ref.sample [deleted file]
ci/lib.sh
ci/run-build-and-tests.sh
color.c
color.h
combine-diff.c
commit-graph.c
commit-graph.h
commit-reach.c
commit.c
compat/fsmonitor/fsm-health-darwin.c
compat/fsmonitor/fsm-health-win32.c
compat/fsmonitor/fsm-ipc-darwin.c
compat/fsmonitor/fsm-ipc-win32.c
compat/fsmonitor/fsm-listen-darwin.c
compat/fsmonitor/fsm-listen-win32.c
compat/fsmonitor/fsm-path-utils-darwin.c
compat/fsmonitor/fsm-path-utils-win32.c
compat/fsmonitor/fsm-settings-darwin.c
compat/fsmonitor/fsm-settings-win32.c
compat/mingw.c
compat/mingw.h
compat/precompose_utf8.c
compat/sha1-chunked.c
compat/simple-ipc/ipc-win32.c
compat/terminal.c
compat/win32/headless.c [new file with mode: 0644]
compat/win32/trace2_win32_process_info.c
config.c
config.h
config.mak.uname
configure.ac
connect.c
connected.c
contrib/README
contrib/buildsystems/CMakeLists.txt
contrib/buildsystems/Generators/Vcxproj.pm
contrib/buildsystems/engine.pl
contrib/coccinelle/README
contrib/coccinelle/config_fn_ctx.pending.cocci [new file with mode: 0644]
contrib/coccinelle/git_config_number.cocci [new file with mode: 0644]
contrib/completion/git-completion.bash
contrib/credential/libsecret/git-credential-libsecret.c
contrib/credential/wincred/git-credential-wincred.c
contrib/git-jump/git-jump
contrib/subtree/git-subtree.sh
contrib/subtree/t/t7900-subtree.sh
convert.c
copy.c
credential.c
credential.h
csum-file.c
ctype.c
daemon.c
decorate.c
decorate.h
delta-islands.c
diagnose.c
diff-lib.c
diff-merges.c
diff-no-index.c
diff.c
diff.h
diffcore-break.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
dir-iterator.c
dir.c
dir.h
editor.c
entry.c
entry.h
environment.c
environment.h
ewah/bitmap.c
ewah/ewah_bitmap.c
exec-cmd.c
fetch-pack.c
fmt-merge-msg.c
fmt-merge-msg.h
fsck.c
fsck.h
fsmonitor--daemon.h
fsmonitor-ipc.c
fsmonitor-ll.h [new file with mode: 0644]
fsmonitor-settings.c
fsmonitor.c
fsmonitor.h
git-compat-util.h
git-gui/Makefile
git-gui/README.md
git-gui/git-gui.sh
git-gui/lib/choose_repository.tcl
git-gui/lib/shortcut.tcl
git-p4.py
git-send-email.perl
git-svn.perl
git.c
gpg-interface.c
graph.c
grep.c
grep.h
hash-ll.h
hash-lookup.c
hashmap.h
help.c
hex-ll.c [new file with mode: 0644]
hex-ll.h [new file with mode: 0644]
hex.c
hex.h
hook.c
http-backend.c
http-push.c
http-walker.c
http.c
ident.c
ident.h
imap-send.c
khash.h
kwset.c
kwset.h
line-log.c
line-log.h
list-objects-filter-options.c
list-objects-filter-options.h
list-objects-filter.c
list-objects.c
log-tree.c
log-tree.h
ls-refs.c
mailinfo.c
mailmap.c
match-trees.c
merge-blobs.c
merge-ll.c [moved from ll-merge.c with 92% similarity]
merge-ll.h [moved from ll-merge.h with 100% similarity]
merge-ort-wrappers.c
merge-ort.c
merge-recursive.c
merge-recursive.h
merge.c
merge.h [new file with mode: 0644]
midx.c
midx.h
name-hash.c
name-hash.h [new file with mode: 0644]
negotiator/noop.c
notes-cache.c
notes-merge.c
notes-utils.c
notes.c
notes.h
object-file.c
object-name.c
object-name.h
object-store-ll.h [new file with mode: 0644]
object-store.h
object.c
object.h
oid-array.c
oidmap.h
oidtree.c
oss-fuzz/fuzz-pack-idx.c
pack-bitmap-write.c
pack-bitmap.c
pack-bitmap.h
pack-check.c
pack-mtimes.c
pack-objects.c
pack-objects.h
pack-revindex.c
pack-write.c
packfile.c
pager.c
parallel-checkout.c
parse-options-cb.c
parse-options.c
parse-options.h
parse.c [new file with mode: 0644]
parse.h [new file with mode: 0644]
patch-ids.c
path.c
path.h
pathspec.c
pathspec.h
pkt-line.c
pkt-line.h
po/README.md
po/ca.po
po/de.po
po/fr.po
po/id.po
po/ru.po
po/sv.po
po/tr.po
po/uk.po
po/zh_CN.po
po/zh_TW.po
preload-index.c
preload-index.h [new file with mode: 0644]
pretty.c
prio-queue.c
progress.c
promisor-remote.c
prompt.c
protocol-caps.c
prune-packed.c
quote.c
range-diff.c
reachable.c
read-cache-ll.h [moved from cache.h with 79% similarity]
read-cache.c
read-cache.h [new file with mode: 0644]
rebase-interactive.c
rebase.c
ref-filter.c
ref-filter.h
reflog-walk.c
reflog.c
refs.c
refs.h
refs/debug.c
refs/files-backend.c
refs/packed-backend.c
refs/ref-cache.c
refs/refs-internal.h
refspec.c
remote-curl.c
remote.c
remote.h
replace-object.c
replace-object.h
repo-settings.c
repository.c
repository.h
rerere.c
resolve-undo.c
resolve-undo.h
revision.c
revision.h
run-command.c
run-command.h
sane-ctype.h [new file with mode: 0644]
scalar.c
send-pack.c
sequencer.c
serve.c
server-info.c
setup.c
setup.h
sha1/openssl.h [new file with mode: 0644]
sha256/gcrypt.h
sha256/openssl.h [new file with mode: 0644]
shallow.c
sigchain.c
sparse-index.c
sparse-index.h
split-index.c
statinfo.c [new file with mode: 0644]
statinfo.h
strbuf.c
strbuf.h
streaming.c
string-list.c
strvec.c
submodule-config.c
submodule-config.h
submodule.c
t/.gitattributes
t/README
t/annotate-tests.sh
t/helper/test-cache-tree.c
t/helper/test-config.c
t/helper/test-delta.c
t/helper/test-dump-cache-tree.c
t/helper/test-dump-fsmonitor.c
t/helper/test-dump-split-index.c
t/helper/test-dump-untracked-cache.c
t/helper/test-env-helper.c
t/helper/test-example-decorate.c
t/helper/test-fast-rebase.c
t/helper/test-find-pack.c [new file with mode: 0644]
t/helper/test-fsmonitor-client.c
t/helper/test-hash-speed.c
t/helper/test-index-version.c [deleted file]
t/helper/test-lazy-init-name-hash.c
t/helper/test-oid-array.c
t/helper/test-pack-mtimes.c
t/helper/test-parse-options.c
t/helper/test-partial-clone.c
t/helper/test-path-utils.c
t/helper/test-reach.c
t/helper/test-read-cache.c
t/helper/test-read-graph.c
t/helper/test-read-midx.c
t/helper/test-ref-store.c
t/helper/test-repository.c
t/helper/test-revision-walking.c
t/helper/test-scrap-cache-tree.c
t/helper/test-sha1.c
t/helper/test-sha256.c
t/helper/test-simple-ipc.c
t/helper/test-strcmp-offset.c
t/helper/test-tool.c
t/helper/test-tool.h
t/helper/test-trace2.c
t/helper/test-truncate.c [new file with mode: 0644]
t/helper/test-userdiff.c
t/helper/test-wildmatch.c
t/helper/test-write-cache.c
t/lib-chunk.sh [new file with mode: 0644]
t/lib-chunk/corrupt-chunk-file.pl [new file with mode: 0644]
t/lib-commit-graph.sh
t/lib-credential.sh
t/lib-gpg.sh
t/lib-httpd/apache.conf
t/lib-rebase.sh
t/perf/p2000-sparse-operations.sh
t/t0000-basic.sh
t/t0003-attributes.sh
t/t0007-git-var.sh
t/t0030-stripspace.sh
t/t0040-parse-options.sh
t/t0041-usage.sh
t/t0081-find-pack.sh [new file with mode: 0755]
t/t0091-bugreport.sh
t/t0211-trace2-perf.sh
t/t0301-credential-cache.sh
t/t0303-credential-external.sh
t/t1001-read-tree-m-2way.sh
t/t1002-read-tree-m-u-2way.sh
t/t1006-cat-file.sh
t/t1092-sparse-checkout-compatibility.sh
t/t1300-config.sh
t/t1301-shared-repo.sh
t/t1410-reflog.sh
t/t1419-exclude-refs.sh [new file with mode: 0755]
t/t1450-fsck.sh
t/t1500-rev-parse.sh
t/t1502-rev-parse-parseopt.sh
t/t1502/.gitattributes [new file with mode: 0644]
t/t1502/optionspec-neg [new file with mode: 0644]
t/t1502/optionspec-neg.help [new file with mode: 0644]
t/t1502/optionspec.help [new file with mode: 0755]
t/t1507-rev-parse-upstream.sh
t/t1508-at-combinations.sh
t/t1514-rev-parse-push.sh
t/t1600-index.sh
t/t1700-split-index.sh
t/t1800-hook.sh
t/t2004-checkout-cache-temp.sh
t/t2027-checkout-track.sh
t/t2030-unresolve-info.sh
t/t2070-restore.sh
t/t2104-update-index-skip-worktree.sh
t/t2107-update-index-basic.sh
t/t2200-add-update.sh
t/t2400-worktree-add.sh
t/t2407-worktree-heads.sh
t/t3007-ls-files-recurse-submodules.sh
t/t3013-ls-files-format.sh
t/t3101-ls-tree-dirname.sh
t/t3200-branch.sh
t/t3202-show-branch.sh
t/t3203-branch-output.sh
t/t3204-branch-name-interpretation.sh
t/t3206-range-diff.sh
t/t3210-pack-refs.sh
t/t3301-notes.sh
t/t3321-notes-stripspace.sh [new file with mode: 0755]
t/t3400-rebase.sh
t/t3402-rebase-merge.sh
t/t3404-rebase-interactive.sh
t/t3418-rebase-continue.sh
t/t3430-rebase-merges.sh
t/t3437-rebase-fixup-options.sh
t/t3500-cherry.sh
t/t3501-revert-cherry-pick.sh
t/t3700-add.sh
t/t3701-add-interactive.sh
t/t3903-stash.sh
t/t4000-diff-format.sh
t/t4002-diff-basic.sh
t/t4003-diff-rename-1.sh
t/t4004-diff-rename-symlink.sh
t/t4013-diff-various.sh
t/t4014-format-patch.sh
t/t4015-diff-whitespace.sh
t/t4017-diff-retval.sh
t/t4040-whitespace-status.sh
t/t4052-stat-output.sh
t/t4053-diff-no-index.sh
t/t4068-diff-symmetric-merge-base.sh
t/t4141-apply-too-large.sh
t/t4202-log.sh
t/t4203-mailmap.sh
t/t4205-log-pretty-formats.sh
t/t4206-log-follow-harder-copies.sh
t/t4207-log-decoration-colors.sh
t/t4214-log-graph-octopus.sh
t/t4215-log-skewed-merges.sh
t/t4216-log-bloom.sh
t/t4217-log-limit.sh
t/t4300-merge-tree.sh
t/t4301-merge-tree-write-tree.sh
t/t5001-archive-attr.sh
t/t5300-pack-object.sh
t/t5301-sliding-window.sh
t/t5303-pack-corruption-resilience.sh
t/t5304-prune.sh
t/t5306-pack-nobase.sh
t/t5310-pack-bitmaps.sh
t/t5317-pack-objects-filter-objects.sh
t/t5318-commit-graph.sh
t/t5319-multi-pack-index.sh
t/t5324-split-commit-graph.sh
t/t5326-multi-pack-bitmaps.sh
t/t5328-commit-graph-64bit-time.sh
t/t5329-pack-objects-cruft.sh
t/t5351-unpack-large-objects.sh
t/t5404-tracking-branches.sh
t/t5407-post-rewrite-hook.sh
t/t5510-fetch.sh
t/t5516-fetch-push.sh
t/t5517-push-mirror.sh
t/t5521-pull-options.sh
t/t5525-fetch-tagopt.sh
t/t5546-receive-limits.sh
t/t5571-pre-push-hook.sh
t/t5583-push-branches.sh
t/t5606-clone-options.sh
t/t5616-partial-clone.sh
t/t5811-proto-disable-git.sh
t/t6009-rev-list-parent.sh
t/t6017-rev-list-stdin.sh
t/t6020-bundle-misc.sh
t/t6040-tracking-info.sh
t/t6050-replace.sh
t/t6120-describe.sh
t/t6135-pathspec-with-attrs.sh
t/t6300-for-each-ref.sh
t/t6302-for-each-ref-filter.sh
t/t6406-merge-attr.sh
t/t6416-recursive-corner-cases.sh
t/t6433-merge-toplevel.sh
t/t6437-submodule-merge.sh
t/t6500-gc.sh
t/t6700-tree-depth.sh [new file with mode: 0755]
t/t7001-mv.sh
t/t7004-tag.sh
t/t7101-reset-empty-subdirs.sh
t/t7102-reset.sh
t/t7110-reset-merge.sh
t/t7111-reset-table.sh
t/t7201-co.sh
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t7419-submodule-set-branch.sh
t/t7420-submodule-set-url.sh
t/t7502-commit-porcelain.sh
t/t7508-status.sh
t/t7510-signed-commit.sh
t/t7512-status-help.sh
t/t7513-interpret-trailers.sh
t/t7516-commit-races.sh
t/t7518-ident-corner-cases.sh
t/t7527-builtin-fsmonitor.sh
t/t7600-merge.sh
t/t7601-merge-pull-config.sh
t/t7602-merge-octopus-many.sh
t/t7603-merge-reduce-heads.sh
t/t7607-merge-state.sh
t/t7608-merge-messages.sh
t/t7700-repack.sh
t/t7701-repack-unpack-unreachable.sh
t/t7704-repack-cruft.sh [new file with mode: 0755]
t/t7810-grep.sh
t/t7814-grep-recurse-submodules.sh
t/t7900-maintenance.sh
t/t9001-send-email.sh
t/t9004-example.sh
t/t9100-git-svn-basic.sh
t/t9104-git-svn-follow-parent.sh
t/t9200-git-cvsexportcommit.sh
t/t9211-scalar-clone.sh
t/t9400-git-cvsserver-server.sh
t/t9902-completion.sh
t/test-lib-functions.sh
t/test-lib.sh
tag.c
tempfile.c
tmp-objdir.c
trace.c
trace2.c
trace2.h
trace2/tr2_cfg.c
trace2/tr2_ctr.c
trace2/tr2_sysenv.c
trace2/tr2_tgt.h
trace2/tr2_tgt_event.c
trace2/tr2_tgt_normal.c
trace2/tr2_tgt_perf.c
trace2/tr2_tls.c
trailer.c
trailer.h
transport-helper.c
transport.c
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unicode-width.h
unpack-trees.c
unpack-trees.h
upload-pack.c
url.c
urlmatch.c
urlmatch.h
usage.c
userdiff.c
versioncmp.c
walker.c
worktree.c
wrapper.c
wrapper.h
write-or-die.c
wt-status.c
xdiff-interface.c
xdiff-interface.h

diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
new file mode 100644 (file)
index 0000000..e5532d3
--- /dev/null
@@ -0,0 +1,163 @@
+name: Coverity
+
+# This GitHub workflow automates submitting builds to Coverity Scan. To enable it,
+# set the repository variable `ENABLE_COVERITY_SCAN_FOR_BRANCHES` (for details, see
+# https://docs.github.com/en/actions/learn-github-actions/variables) to a JSON
+# string array containing the names of the branches for which the workflow should be
+# run, e.g. `["main", "next"]`.
+#
+# In addition, two repository secrets must be set (for details how to add secrets, see
+# https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions):
+# `COVERITY_SCAN_EMAIL` and `COVERITY_SCAN_TOKEN`. The former specifies the
+# email to which the Coverity reports should be sent and the latter can be
+# obtained from the Project Settings tab of the Coverity project).
+#
+# The workflow runs on `ubuntu-latest` by default. This can be overridden by setting
+# the repository variable `ENABLE_COVERITY_SCAN_ON_OS` to a JSON string array specifying
+# the operating systems, e.g. `["ubuntu-latest", "windows-latest"]`.
+#
+# By default, the builds are submitted to the Coverity project `git`. To override this,
+# set the repository variable `COVERITY_PROJECT`.
+
+on:
+  push:
+
+defaults:
+  run:
+    shell: bash
+
+jobs:
+  coverity:
+    if: contains(fromJSON(vars.ENABLE_COVERITY_SCAN_FOR_BRANCHES || '[""]'), github.ref_name)
+    strategy:
+      matrix:
+        os: ${{ fromJSON(vars.ENABLE_COVERITY_SCAN_ON_OS || '["ubuntu-latest"]') }}
+    runs-on: ${{ matrix.os }}
+    env:
+      COVERITY_PROJECT: ${{ vars.COVERITY_PROJECT || 'git' }}
+      COVERITY_LANGUAGE: cxx
+      COVERITY_PLATFORM: overridden-below
+    steps:
+      - uses: actions/checkout@v3
+      - name: install minimal Git for Windows SDK
+        if: contains(matrix.os, 'windows')
+        uses: git-for-windows/setup-git-for-windows-sdk@v1
+      - run: ci/install-dependencies.sh
+        if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos')
+        env:
+          runs_on_pool: ${{ matrix.os }}
+
+      # The Coverity site says the tool is usually updated twice yearly, so the
+      # MD5 of download can be used to determine whether there's been an update.
+      - name: get the Coverity Build Tool hash
+        id: lookup
+        run: |
+          case "${{ matrix.os }}" in
+          *windows*)
+            COVERITY_PLATFORM=win64
+            COVERITY_TOOL_FILENAME=cov-analysis.zip
+            MAKEFLAGS=-j$(nproc)
+            ;;
+          *macos*)
+            COVERITY_PLATFORM=macOSX
+            COVERITY_TOOL_FILENAME=cov-analysis.dmg
+            MAKEFLAGS=-j$(sysctl -n hw.physicalcpu)
+            ;;
+          *ubuntu*)
+            COVERITY_PLATFORM=linux64
+            COVERITY_TOOL_FILENAME=cov-analysis.tgz
+            MAKEFLAGS=-j$(nproc)
+            ;;
+          *)
+            echo '::error::unhandled OS ${{ matrix.os }}' >&2
+            exit 1
+            ;;
+          esac
+          echo "COVERITY_PLATFORM=$COVERITY_PLATFORM" >>$GITHUB_ENV
+          echo "COVERITY_TOOL_FILENAME=$COVERITY_TOOL_FILENAME" >>$GITHUB_ENV
+          echo "MAKEFLAGS=$MAKEFLAGS" >>$GITHUB_ENV
+          MD5=$(curl https://scan.coverity.com/download/$COVERITY_LANGUAGE/$COVERITY_PLATFORM \
+                   --fail \
+                   --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+                   --form project="$COVERITY_PROJECT" \
+                   --form md5=1)
+          case $? in
+          0) ;; # okay
+          22) # 40x, i.e. access denied
+            echo "::error::incorrect token or project?" >&2
+            exit 1
+            ;;
+          *) # other error
+            echo "::error::Failed to retrieve MD5" >&2
+            exit 1
+            ;;
+          esac
+          echo "hash=$MD5" >>$GITHUB_OUTPUT
+
+      # Try to cache the tool to avoid downloading 1GB+ on every run.
+      # A cache miss will add ~30s to create, but a cache hit will save minutes.
+      - name: restore the Coverity Build Tool
+        id: cache
+        uses: actions/cache/restore@v3
+        with:
+          path: ${{ runner.temp }}/cov-analysis
+          key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
+      - name: download the Coverity Build Tool (${{ env.COVERITY_LANGUAGE }} / ${{ env.COVERITY_PLATFORM}})
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: |
+          curl https://scan.coverity.com/download/$COVERITY_LANGUAGE/$COVERITY_PLATFORM \
+            --fail --no-progress-meter \
+            --output $RUNNER_TEMP/$COVERITY_TOOL_FILENAME \
+            --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+            --form project="$COVERITY_PROJECT"
+      - name: extract the Coverity Build Tool
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: |
+          case "$COVERITY_TOOL_FILENAME" in
+          *.tgz)
+            mkdir $RUNNER_TEMP/cov-analysis &&
+            tar -xzf $RUNNER_TEMP/$COVERITY_TOOL_FILENAME --strip 1 -C $RUNNER_TEMP/cov-analysis
+            ;;
+          *.dmg)
+            cd $RUNNER_TEMP &&
+            attach="$(hdiutil attach $COVERITY_TOOL_FILENAME)" &&
+            volume="$(echo "$attach" | cut -f 3 | grep /Volumes/)" &&
+            mkdir cov-analysis &&
+            cd cov-analysis &&
+            sh "$volume"/cov-analysis-macosx-*.sh &&
+            ls -l &&
+            hdiutil detach "$volume"
+            ;;
+          *.zip)
+            cd $RUNNER_TEMP &&
+            mkdir cov-analysis-tmp &&
+            unzip -d cov-analysis-tmp $COVERITY_TOOL_FILENAME &&
+            mv cov-analysis-tmp/* cov-analysis
+            ;;
+          *)
+            echo "::error::unhandled archive type: $COVERITY_TOOL_FILENAME" >&2
+            exit 1
+            ;;
+          esac
+      - name: cache the Coverity Build Tool
+        if: steps.cache.outputs.cache-hit != 'true'
+        uses: actions/cache/save@v3
+        with:
+          path: ${{ runner.temp }}/cov-analysis
+          key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
+      - name: build with cov-build
+        run: |
+          export PATH="$RUNNER_TEMP/cov-analysis/bin:$PATH" &&
+          cov-configure --gcc &&
+          cov-build --dir cov-int make
+      - name: package the build
+        run: tar -czvf cov-int.tgz cov-int
+      - name: submit the build to Coverity Scan
+        run: |
+          curl \
+            --fail \
+            --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+            --form email='${{ secrets.COVERITY_SCAN_EMAIL }}' \
+            --form file=@cov-int.tgz \
+            --form version='${{ github.sha }}' \
+            "https://scan.coverity.com/builds?project=$COVERITY_PROJECT"
index 30492eacddfc7db484e9c73af3ba49960d77f5cb..dcf7d78f1d004c54c412973e04a76e92a2287c67 100644 (file)
@@ -5,9 +5,23 @@ on: [push, pull_request]
 env:
   DEVELOPER: 1
 
+# If more than one workflow run is triggered for the very same commit hash
+# (which happens when multiple branches pointing to the same commit), only
+# the first one is allowed to run, the second will be kept in the "queued"
+# state. This allows a successful completion of the first run to be reused
+# in the second run via the `skip-if-redundant` logic in the `config` job.
+#
+# The only caveat is that if a workflow run is triggered for the same commit
+# hash that another run is already being held, that latter run will be
+# canceled. For more details about the `concurrency` attribute, see:
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency
+concurrency:
+  group: ${{ github.sha }}
+
 jobs:
   ci-config:
     name: config
+    if: vars.CI_BRANCHES == '' || contains(vars.CI_BRANCHES, github.ref_name)
     runs-on: ubuntu-latest
     outputs:
       enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }}
@@ -30,10 +44,13 @@ jobs:
         name: check whether CI is enabled for ref
         run: |
           enabled=yes
-          if test -x config-repo/ci/config/allow-ref &&
-             ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+          if test -x config-repo/ci/config/allow-ref
           then
-            enabled=no
+            echo "::warning::ci/config/allow-ref is deprecated; use CI_BRANCHES instead"
+            if ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+            then
+              enabled=no
+            fi
           fi
 
           skip_concurrent=yes
@@ -246,9 +263,6 @@ jobs:
       fail-fast: false
       matrix:
         vector:
-          - jobname: linux-clang
-            cc: clang
-            pool: ubuntu-latest
           - jobname: linux-sha256
             cc: clang
             pool: ubuntu-latest
@@ -273,11 +287,8 @@ jobs:
           - jobname: linux-leaks
             cc: gcc
             pool: ubuntu-latest
-          - jobname: linux-asan
-            cc: gcc
-            pool: ubuntu-latest
-          - jobname: linux-ubsan
-            cc: gcc
+          - jobname: linux-asan-ubsan
+            cc: clang
             pool: ubuntu-latest
     env:
       CC: ${{matrix.vector.cc}}
index e875c5905455885b174a4591aa5bb3cc2fd0bae2..5e56e471b344ef45e026847a6865645d61908be7 100644 (file)
 /TAGS
 /cscope*
 /compile_commands.json
+/.cache/
 *.hcc
 *.obj
 *.lib
index 733e047aa82507d28b525dc7a08f3239c70f8ecb..82129be449f94b9872087717a03f1e3d5e2fac1a 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -59,9 +59,9 @@ David Reiss <dreiss@facebook.com> <dreiss@dreiss-vmware.(none)>
 David S. Miller <davem@davemloft.net>
 David Turner <novalis@novalis.org> <dturner@twopensource.com>
 David Turner <novalis@novalis.org> <dturner@twosigma.com>
-Derrick Stolee <derrickstolee@github.com> <stolee@gmail.com>
-Derrick Stolee <derrickstolee@github.com> Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
-Derrick Stolee <derrickstolee@github.com> <dstolee@microsoft.com>
+Derrick Stolee <stolee@gmail.com> <derrickstolee@github.com>
+Derrick Stolee <stolee@gmail.com> Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
+Derrick Stolee <stolee@gmail.com> <dstolee@microsoft.com>
 Deskin Miller <deskinm@umich.edu>
 Đoàn Trần Công Danh <congdanhqx@gmail.com> Doan Tran Cong Danh
 Dirk Süsserott <newsletter@dirk.my1.cc>
@@ -80,6 +80,7 @@ Frank Lichtenheld <frank@lichtenheld.de> <flichtenheld@astaro.com>
 Fredrik Kuivinen <frekui@gmail.com> <freku045@student.liu.se>
 Frédéric Heitzmann <frederic.heitzmann@gmail.com>
 Garry Dolley <gdolley@ucla.edu> <gdolley@arpnetworks.com>
+Glen Choo <glencbz@gmail.com> <chooglen@google.com>
 Greg Price <price@mit.edu> <price@MIT.EDU>
 Greg Price <price@mit.edu> <price@ksplice.com>
 Heiko Voigt <hvoigt@hvoigt.net> <git-list@hvoigt.net>
index 003393ed161dab04a5c73269d49fa2e2f2fdd1f6..8d3a467c0135319162b71290810917cca5f8316f 100644 (file)
@@ -1,5 +1,5 @@
-Like other projects, we also have some guidelines to keep to the
-code.  For Git in general, a few rough rules are:
+Like other projects, we also have some guidelines for our code.  For
+Git in general, a few rough rules are:
 
  - Most importantly, we never say "It's in POSIX; we'll happily
    ignore your needs should your system not conform to it."
@@ -24,7 +24,7 @@ code.  For Git in general, a few rough rules are:
 
    "Once it _is_ in the tree, it's not really worth the patch noise to
    go and fix it up."
-   Cf. http://lkml.iu.edu/hypermail/linux/kernel/1001.3/01069.html
+   Cf. https://lore.kernel.org/all/20100126160632.3bdbe172.akpm@linux-foundation.org/
 
  - Log messages to explain your changes are as important as the
    changes themselves.  Clearly written code and in-code comments
@@ -40,7 +40,7 @@ As for more concrete guidelines, just imitate the existing code
 contributing to). It is always preferable to match the _local_
 convention. New code added to Git suite is expected to match
 the overall style of existing code. Modifications to existing
-code is expected to match the style the surrounding code already
+code are expected to match the style the surrounding code already
 uses (even if it doesn't match the overall style of existing code).
 
 But if you must have a list of rules, here are some language
@@ -188,6 +188,10 @@ For shell scripts specifically (not exhaustive):
    hopefully nobody starts using "local" before they are reimplemented
    in C ;-)
 
+ - Use octal escape sequences (e.g. "\302\242"), not hexadecimal (e.g.
+   "\xc2\xa2") in printf format strings, since hexadecimal escape
+   sequences are not portable.
+
 
 For C programs:
 
@@ -444,7 +448,7 @@ For C programs:
  - The first #include in C files, except in platform specific compat/
    implementations and sha1dc/, must be either "git-compat-util.h" or
    one of the approved headers that includes it first for you.  (The
-   approved headers currently include "cache.h", "builtin.h",
+   approved headers currently include "builtin.h",
    "t/helper/test-tool.h", "xdiff/xinclude.h", or
    "reftable/system.h").  You do not have to include more than one of
    these.
@@ -687,7 +691,7 @@ Writing Documentation:
    Do: [-q | --quiet]
    Don't: [-q|--quiet]
 
- Don't use spacing around "|" tokens when they're used to seperate the
+ Don't use spacing around "|" tokens when they're used to separate the
  alternate arguments of an option:
     Do: --track[=(direct|inherit)]
     Don't: --track[=(direct | inherit)]
index 56130e4becf68f14a4f5de2c12e4fc0556bb2d91..62d11a5cd7f909e2e038e1f768bafddc82be210d 100644 (file)
@@ -1256,6 +1256,38 @@ index 88f126184c..38da593a60 100644
 [[now-what]]
 == My Patch Got Emailed - Now What?
 
+Please give reviewers enough time to process your initial patch before
+sending an updated version. That is, resist the temptation to send a new
+version immediately, because others may have already started reviewing
+your initial version.
+
+While waiting for review comments, you may find mistakes in your initial
+patch, or perhaps realize a different and better way to achieve the goal
+of the patch. In this case you may communicate your findings to other
+reviewers as follows:
+
+ - If the mistakes you found are minor, send a reply to your patch as if
+   you were a reviewer and mention that you will fix them in an
+   updated version.
+
+ - On the other hand, if you think you want to change the course so
+   drastically that reviews on the initial patch would be a waste of
+   time (for everyone involved), retract the patch immediately with
+   a reply like "I am working on a much better approach, so please
+   ignore this patch and wait for the updated version."
+
+Now, the above is a good practice if you sent your initial patch
+prematurely without polish.  But a better approach of course is to avoid
+sending your patch prematurely in the first place.
+
+Please be considerate of the time needed by reviewers to examine each
+new version of your patch. Rather than seeing the initial version right
+now (followed by several "oops, I like this version better than the
+previous one" patches over 2 days), reviewers would strongly prefer if a
+single polished version came 2 days later instead, and that version with
+fewer mistakes were the only one they would need to review.
+
+
 [[reviewing]]
 === Responding to Reviews
 
index eee513e86f4d645a47afcae4921de89b413fc1be..c68cdb11b9d5a53ddc11361d0f1c889edeb24536 100644 (file)
@@ -41,6 +41,7 @@ Open up a new file `builtin/walken.c` and set up the command handler:
  */
 
 #include "builtin.h"
+#include "trace.h"
 
 int cmd_walken(int argc, const char **argv, const char *prefix)
 {
@@ -49,12 +50,13 @@ int cmd_walken(int argc, const char **argv, const char *prefix)
 }
 ----
 
-NOTE: `trace_printf()` differs from `printf()` in that it can be turned on or
-off at runtime. For the purposes of this tutorial, we will write `walken` as
-though it is intended for use as a "plumbing" command: that is, a command which
-is used primarily in scripts, rather than interactively by humans (a "porcelain"
-command). So we will send our debug output to `trace_printf()` instead. When
-running, enable trace output by setting the environment variable `GIT_TRACE`.
+NOTE: `trace_printf()`, defined in `trace.h`, differs from `printf()` in
+that it can be turned on or off at runtime. For the purposes of this
+tutorial, we will write `walken` as though it is intended for use as
+a "plumbing" command: that is, a command which is used primarily in
+scripts, rather than interactively by humans (a "porcelain" command).
+So we will send our debug output to `trace_printf()` instead.
+When running, enable trace output by setting the environment variable `GIT_TRACE`.
 
 Add usage text and `-h` handling, like all subcommands should consistently do
 (our test suite will notice and complain if you fail to do so).
@@ -124,7 +126,7 @@ parameters provided by the user over the CLI.
 
 `nr` represents the number of `rev_cmdline_entry` present in the array.
 
-`alloc` is used by the `ALLOC_GROW` macro. Check `cache.h` - this variable is
+`alloc` is used by the `ALLOC_GROW` macro. Check `alloc.h` - this variable is
 used to track the allocated size of the list.
 
 Per entry, we find:
@@ -341,6 +343,10 @@ the walk loop below the `prepare_revision_walk()` call within your
 `walken_commit_walk()`:
 
 ----
+#include "pretty.h"
+
+...
+
 static void walken_commit_walk(struct rev_info *rev)
 {
        struct commit *commit;
@@ -754,6 +760,10 @@ reachable objects are walked in order to populate the list.
 First, add the `struct oidset` and related items we will use to iterate it:
 
 ----
+#include "oidset.h"
+
+...
+
 static void walken_object_walk(
        ...
 
@@ -805,6 +815,10 @@ just walks of commits. First, we'll make our handlers chattier - modify
 go:
 
 ----
+#include "hex.h"
+
+...
+
 static void walken_show_commit(struct commit *cmt, void *buf)
 {
        trace_printf("commit: %s\n", oid_to_hex(&cmt->object.oid));
diff --git a/Documentation/RelNotes/2.42.0.txt b/Documentation/RelNotes/2.42.0.txt
new file mode 100644 (file)
index 0000000..0f1897a
--- /dev/null
@@ -0,0 +1,329 @@
+Git v2.42 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "git pack-refs" learns "--include" and "--exclude" to tweak the ref
+   hierarchy to be packed using pattern matching.
+
+ * 'git worktree add' learned how to create a worktree based on an
+   orphaned branch with `--orphan`.
+
+ * "git pack-objects" learned to invoke a new hook program that
+   enumerates extra objects to be used as anchoring points to keep
+   otherwise unreachable objects in cruft packs.
+
+ * Add more "git var" for toolsmiths to learn various locations Git is
+   configured with either via the configuration or hard-coded defaults.
+
+ * 'git notes append' was taught '--separator' to specify string to insert
+   between paragraphs.
+
+ * The "git for-each-ref" family of commands learned placeholders
+   related to GPG signature verification.
+
+ * "git diff --no-index" learned to read from named pipes as if they
+   were regular files, to allow "git diff <(process) <(substitution)"
+   some shells support.
+
+ * Help newbies by suggesting that there are cases where force-pushing
+   is a valid and sensible thing to update a branch at a remote
+   repository, rather than reconciling with merge/rebase.
+
+ * "git blame --contents=file" has been taught to work in a bare
+   repository.
+
+ * "git branch -f X" to repoint the branch X said that X was "checked
+   out" in another worktree, even when branch X was not and instead
+   being bisected or rebased.  The message was reworded to say the
+   branch was "in use".
+
+ * Tone down the warning on SHA-256 repositories being an experimental
+   curiosity.  We do not have support for them to interoperate with
+   traditional SHA-1 repositories, but at this point, we do not plan
+   to make breaking changes to SHA-256 repositories and there is no
+   longer need for such a strongly phrased warning.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git diff-tree" has been taught to take advantage of the
+   sparse-index feature.
+
+ * Clang's sanitizer implementation seems to work better than GCC's.
+   (merge d88d727143 jk/ci-use-clang-for-sanitizer-jobs later to maint).
+
+ * The object traversal using reachability bitmap done by
+   "pack-object" has been tweaked to take advantage of the fact that
+   using "boundary" commits as representative of all the uninteresting
+   ones can save quite a lot of object enumeration.
+
+ * discover_git_directory() no longer touches the_repository.
+
+ * "git worktree" learned to work better with sparse index feature.
+
+ * When the external merge driver is killed by a signal, its output
+   should not be trusted as a resolution with conflicts that is
+   proposed by the driver, but the code did.
+
+ * The set-up code for the get_revision() API now allows feeding
+   options like --all and --not in the --stdin mode.
+
+ * Move functions that are not about pure string manipulation out of
+   strbuf.[ch]
+
+ * "imap-send" codepaths got cleaned up to get rid of unused
+   parameters.
+
+ * Enumerating refs in the packed-refs file, while excluding refs that
+   match certain patterns, has been optimized.
+
+ * Mark-up unused parameters in the code so that we can eventually
+   enable -Wunused-parameter by default.
+
+ * Instead of inventing a custom counter variables for debugging,
+   use existing trace2 facility in the fsync customization codepath.
+
+ * "git branch --list --format=<format>" and friends are taught
+   a new "%(describe)" placeholder.
+
+ * Clarify how to choose the starting point for a new topic in
+   developer guidance document.
+
+ * The implementation of "get_sha1_hex()" that reads a hexadecimal
+   string that spells a full object name has been extended to cope
+   with any hash function used in the repository, but the "sha1" in
+   its name survived.  Rename it to get_hash_hex(), a name that is
+   more consistent within its friends like get_hash_hex_algop().
+
+ * Command line parser fix, and a small parse-options API update.
+
+
+Fixes since v2.41
+-----------------
+
+ * "git tag" learned to leave the "$GIT_DIR/TAG_EDITMSG" file when the
+   command failed, so that the user can salvage what they typed.
+   (merge 08c12ec1d0 kh/keep-tag-editmsg-upon-failure later to maint).
+
+ * The "-s" (silent, squelch) option of the "diff" family of commands
+   did not interact with other options that specify the output format
+   well.  This has been cleaned up so that it will clear all the
+   formatting options given before.
+   (merge 9d484b92ed jc/diff-s-with-other-options later to maint).
+
+ * Update documentation regarding Coccinelle patches.
+   (merge 3bd0097cfc gc/doc-cocci-updates later to maint).
+
+ * Some atoms that can be used in "--format=<format>" for "git ls-tree"
+   were not supported by "git ls-files", even though they were relevant
+   in the context of the latter.
+   (merge 4d28c4f75f zh/ls-files-format-atoms later to maint).
+
+ * Document more pseudo-refs and teach the command line completion
+   machinery to complete AUTO_MERGE.
+   (merge 982ff3a649 pb/complete-and-document-auto-merge-and-friends later to maint).
+
+ * "git submodule" code trusted the data coming from the config (and
+   the in-tree .gitmodules file) too much without validating, leading
+   to NULL dereference if the user mucks with a repository (e.g.
+   submodule.<name>.url is removed).  This has been corrected.
+   (merge fbc806acd1 tb/submodule-null-deref-fix later to maint).
+
+ * The value of config.worktree is per-repository, but has been kept
+   in a singleton global variable per process. This has been OK as
+   most Git operations interacted with a single repository at a time,
+   but not right for operations like recursive "grep" that want to
+   access multiple repositories from a single process without forking.
+
+   The global variable has been eliminated and made into a member in
+   the per-repository data structure.
+   (merge 3867f6d650 vd/worktree-config-is-per-repository later to maint).
+
+ * "git [-c log.follow=true] log [--follow] ':(glob)f**'" used to barf.
+   (merge 8260bc5902 jk/log-follow-with-non-literal-pathspec later to maint).
+
+ * Introduce a mechanism to disable replace refs globally and per
+   repository.
+   (merge 9c7d1b057f ds/disable-replace-refs later to maint).
+
+ * "git cat-file --batch" and friends learned "-Z" that uses NUL
+   delimiter for both input and output.
+   (merge f79e18849b ps/cat-file-null-output later to maint).
+
+ * The reimplemented "git add -i" did not honor color.ui configuration.
+   (merge 6f74648cea ds/add-i-color-configuration-fix later to maint).
+
+ * Compilation fix for platforms without D_TYPE in struct dirent.
+   (merge 03bf92b9bf as/dtype-compilation-fix later to maint).
+
+ * Suggest to refrain from using hex literals that are non-portable
+   when writing printf(1) format strings.
+   (merge f0b68f0546 jt/doc-use-octal-with-printf later to maint).
+
+ * Simplify error message when run-command fails to start a command.
+   (merge 6d224ac286 rs/run-command-exec-error-on-noent later to maint).
+
+ * Gracefully deal with a stale MIDX file that lists a packfile that
+   no longer exists.
+   (merge 06f3867865 tb/open-midx-bitmap-fallback later to maint).
+
+ * Even when diff.ignoreSubmodules tells us to ignore submodule
+   changes, "git commit" with an index that already records changes to
+   submodules should include the submodule changes in the resulting
+   commit, but it did not.
+   (merge 5768478edc js/defeat-ignore-submodules-config-with-explicit-addition later to maint).
+
+ * When "git commit --trailer=..." invokes the interpret-trailers
+   machinery, it knows what it feeds to interpret-trailers is a full
+   log message without any patch, but failed to express that by
+   passing the "--no-divider" option, which has been corrected.
+   (merge be3d654343 jk/commit-use-no-divider-with-interpret-trailers later to maint).
+
+ * Avoid breakage of "git pack-objects --cruft" due to inconsistency
+   between the way the code enumerates packfiles in the repository.
+   (merge 73320e49ad tb/collect-pack-filenames-fix later to maint).
+
+ * We create .pack and then .idx, we consider only packfiles that have
+   .idx usable (those with only .pack are not ready yet), so we should
+   remove .idx before removing .pack for consistency.
+   (merge 0dd1324a73 ds/remove-idx-before-pack later to maint).
+
+ * Partially revert a sanity check that the rest of the config code
+   was not ready, to avoid triggering it in a corner case.
+   (merge a53f43f900 gc/config-partial-submodule-kvi-fix later to maint).
+
+ * "git apply" punts when it is fed too large a patch input; the error
+   message it gives when it happens has been clarified.
+   (merge 42612e18d2 pw/apply-too-large later to maint).
+
+ * During a cherry-pick or revert session that works on multiple
+   commits, "git status" did not give correct information, which has
+   been corrected.
+   (merge a096a889f4 jk/cherry-pick-revert-status later to maint).
+
+ * A few places failed to differentiate the case where the index is
+   truly empty (nothing added) and we haven't yet read from the
+   on-disk index file, which have been corrected.
+   (merge 2ee045eea1 js/empty-index-fixes later to maint).
+
+ * "git bugreport" tests did not test what it wanted to test, which
+   has been corrected.
+   (merge 1aa92b8500 ma/t0091-fixup later to maint).
+
+ * Code snippets in a tutorial document no longer compiled after
+   recent header shuffling, which have been corrected.
+   (merge bbd7c7b7c0 vd/adjust-mfow-doc-to-updated-headers later to maint).
+
+ * "git ls-files '(attr:X)D/'" that triggers the common prefix
+   optimization codepath failed to read from "D/.gitattributes",
+   which has been corrected.
+   (merge f4a8fde057 jc/pathspec-match-with-common-prefix later to maint).
+
+ * "git fsck --no-progress" still spewed noise from the commit-graph
+   subsystem, which has been corrected.
+   (merge 9281cd07f0 tb/fsck-no-progress later to maint).
+
+ * Various offset computation in the code that accesses the packfiles
+   and other data in the object layer has been hardened against
+   arithmetic overflow, especially on 32-bit systems.
+   (merge 9a25cad7e0 tb/object-access-overflow-protection later to maint).
+
+ * Names of MinGW header files are spelled in mixed case in some
+   source files, but the build host can be using case sensitive
+   filesystem with header files with their name spelled in all
+   lowercase.
+   (merge 4a53d0d0bc mh/mingw-case-sensitive-build later to maint).
+
+ * Update message mark-up for i18n in "git bundle".
+   (merge bbb6acd998 dk/bundle-i18n-more later to maint).
+
+ * "git tag --list --points-at X" showed tags that directly refers to
+   object X, but did not list a tag that points at such a tag, which
+   has been corrected.
+
+ * "./configure --with-expat=no" did not work as a way to refuse use
+   of the expat library on a system with the library installed, which
+   has been corrected.
+   (merge fb8f7269c2 ah/autoconf-fixes later to maint).
+
+ * When the user edits "rebase -i" todo file so that it starts with a
+   "fixup", which would make it invalid, the command truncated the
+   rest of the file before giving an error and returning the control
+   back to the user.  Stop truncating to make it easier to correct
+   such a malformed todo file.
+   (merge 9645a087c2 ah/sequencer-rewrite-todo-fix later to maint).
+
+ * Rewrite the description of giving a custom command to the
+   submodule.<name>.update configuration variable.
+   (merge 7cebc5bd78 pv/doc-submodule-update-settings later to maint).
+
+ * Adjust to OpenSSL 3+, which deprecates its SHA-1 functions based on
+   its traditional API, by using its EVP API instead.
+   (merge bda9c12073 ew/hash-with-openssl-evp later to maint).
+
+ * Exclude "." from the set of characters to be removed from the
+   beginning and the end of the human-readable name.
+   (merge 1c04cb0744 bc/ident-dot-is-no-longer-crud-letter later to maint).
+
+ * "git bisect visualize" stopped running "gitk" on Git for Windows
+   when the command was reimplemented in C around Git 2.34 timeframe.
+   This has been corrected.
+   (merge fff1594fa7 ma/locate-in-path-for-windows later to maint).
+
+ * "git rebase -i" with a series of squash/fixup, when one of the
+   steps stopped in conflicts and ended up getting skipped, did not
+   handle the accumulated commit log messages, which has been
+   corrected.
+   (merge 6ce7afe163 pw/rebase-skip-commit-message-fix later to maint).
+
+ * Adjust to newer Term::ReadLine to prevent it from breaking
+   the interactive prompt code in send-email.
+   (merge c016726c2d jk/send-email-with-new-readline later to maint).
+
+ * Windows updates.
+   (merge 0050f8e401 ds/maintenance-on-windows-fix later to maint).
+
+ * Correct use of lstat() that assumed a failing call would not
+   clobber the statbuf.
+   (merge 72695d8214 st/mv-lstat-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 51f9d2e563 sa/doc-ls-remote later to maint).
+   (merge c6d26a9dda jk/format-patch-message-id-unleak later to maint).
+   (merge f7e063f326 ps/fetch-cleanups later to maint).
+   (merge e4cf013468 tl/quote-problematic-arg-for-clarity later to maint).
+   (merge 20025fdfc7 tz/test-ssh-verifytime-fix later to maint).
+   (merge e48a21df65 tz/test-fix-pthreads-prereq later to maint).
+   (merge 68b51172e3 mh/commit-reach-get-reachable-plug-leak later to maint).
+   (merge aeee1408ce kh/use-default-notes-doc later to maint).
+   (merge 3b8724bce6 jc/test-modernization later to maint).
+   (merge 447a3b7331 jc/test-modernization-2 later to maint).
+   (merge d57fa7fc73 la/doc-interpret-trailers later to maint).
+   (merge 548afb0d9a la/docs-typofixes later to maint).
+   (merge 3744ffcbcd rs/doc-ls-tree-hex-literal later to maint).
+   (merge 6c26da8404 mh/credential-erase-improvements later to maint).
+   (merge 78e56cff69 tz/lib-gpg-prereq-fix later to maint).
+   (merge 80d32e84b5 rj/leakfixes later to maint).
+   (merge 0a868031ed pb/complete-diff-options later to maint).
+   (merge d4f28279ad jc/doc-hash-object-types later to maint).
+   (merge 1876a5ae15 ks/t4205-test-describe-with-abbrev-fix later to maint).
+   (merge 6e6a529b57 jk/fsck-indices-in-worktrees later to maint).
+   (merge 3e81b896f7 rs/packet-length-simplify later to maint).
+   (merge 4c9cb51fe7 mh/doc-credential-helpers later to maint).
+   (merge 3437f549dd jr/gitignore-doc-example-markup later to maint).
+   (merge 947ebd62a0 jc/am-parseopt-fix later to maint).
+   (merge e12cb98e1e jc/branch-parseopt-fix later to maint).
+   (merge d6f598e443 jc/gitignore-doc-pattern-markup later to maint).
+   (merge a2dad4868b jc/transport-parseopt-fix later to maint).
+   (merge 68cbb20e73 jc/parse-options-show-branch later to maint).
+   (merge 3821eb6c3d jc/parse-options-reset later to maint).
+   (merge c48af99a3e bb/trace2-comment-fix later to maint).
+   (merge c95ae3ff9c rs/describe-parseopt-fix later to maint).
+   (merge 36f76d2a25 rs/pack-objects-parseopt-fix later to maint).
+   (merge 30c8c55cbf jc/tree-walk-drop-base-offset later to maint).
+   (merge d089a06421 rs/bundle-parseopt-cleanup later to maint).
+   (merge 823839bda1 ew/sha256-gcrypt-leak-fixes later to maint).
+   (merge a5c01603b3 bc/ignore-clangd-cache later to maint).
+   (merge 12009a182b js/allow-t4000-to-be-indented-with-spaces later to maint).
+   (merge b3dcd24b8a jc/send-email-pre-process-fix later to maint).
diff --git a/Documentation/RelNotes/2.42.1.txt b/Documentation/RelNotes/2.42.1.txt
new file mode 100644 (file)
index 0000000..3d391b7
--- /dev/null
@@ -0,0 +1,88 @@
+Git 2.42.1 Release Notes
+========================
+
+There is nothing exciting to see here.  Relative to Git 2.42, this
+release contains the fixes that have already been merged to the
+'master' branch of the development towards Git 2.43 that has been
+tagged as Git 2.43.0-rc0.
+
+Fixes since Git 2.42.0
+----------------------
+
+ * Tests that are known to pass with LSan are now marked as such.
+
+ * Flaky "git p4" tests, as well as "git svn" tests, are now skipped
+   in the (rather expensive) sanitizer CI job.
+
+ * Tests with LSan from time to time seem to emit harmless message
+   that makes our tests unnecessarily flaky; we work it around by
+   filtering the uninteresting output.
+
+ * GitHub CI workflow has learned to trigger Coverity check.
+
+ * Overly long label names used in the sequencer machinery are now
+   chopped to fit under filesystem limitation.
+
+ * Scalar updates.
+
+ * Tweak GitHub Actions CI so that pushing the same commit to multiple
+   branch tips at the same time will not waste building and testing
+   the same thing twice.
+
+ * The commit-graph verification code that detects mixture of zero and
+   non-zero generation numbers has been updated.
+
+ * "git diff -w --exit-code" with various options did not work
+   correctly, which is being addressed.
+
+ * transfer.unpackLimit ought to be used as a fallback, but overrode
+   fetch.unpackLimit and receive.unpackLimit instead.
+
+ * The use of API between two calls to require_clean_work_tree() from
+   the sequencer code has been cleaned up for consistency.
+
+ * "git diff --no-such-option" and other corner cases around the exit
+   status of the "diff" command has been corrected.
+
+ * "git for-each-ref --sort='contents:size'" sorts the refs according
+   to size numerically, giving a ref that points at a blob twelve-byte
+   (12) long before showing a blob hundred-byte (100) long.
+
+ * Various fixes to the behavior of "rebase -i" when the command got
+   interrupted by conflicting changes.
+
+ * References from description of the `--patch` option in various
+   manual pages have been simplified and improved.
+
+ * "git grep -e A --no-or -e B" is accepted, even though the negation
+   of "or" did not mean anything, which has been tightened.
+
+ * The completion script (in contrib/) has been taught to treat the
+   "-t" option to "git checkout" and "git switch" just like the
+   "--track" option, to complete remote-tracking branches.
+
+ * "git diff --no-index -R <(one) <(two)" did not work correctly,
+   which has been corrected.
+
+ * Update "git maintenance" timers' implementation based on systemd
+   timers to work with WSL.
+
+ * "git diff --cached" codepath did not fill the necessary stat
+   information for a file when fsmonitor knows it is clean and ended
+   up behaving as if it is not clean, which has been corrected.
+
+ * Clarify how "alias.foo = : git cmd ; aliased-command-string" should
+   be spelled with necessary whitespaces around punctuation marks to
+   work.
+
+ * HTTP Header redaction code has been adjusted for a newer version of
+   cURL library that shows its traces differently from earlier
+   versions.
+
+ * An error message given by "git send-email" when given a malformed
+   address did not give correct information, which has been corrected.
+
+ * UBSan options were not propagated through the test framework to git
+   run via the httpd, unlike ASan options, which has been corrected.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.43.0.txt b/Documentation/RelNotes/2.43.0.txt
new file mode 100644 (file)
index 0000000..ad3b82f
--- /dev/null
@@ -0,0 +1,324 @@
+Git v2.43 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+ * The "--rfc" option of "git format-patch" used to be a valid way to
+   override an earlier "--subject-prefix=<something>" on the command
+   line and replace it with "[RFC PATCH]", but from this release, it
+   merely prefixes the string "RFC " in front of the given subject
+   prefix.  If you are negatively affected by this change, please use
+   "--subject-prefix=PATCH --rfc" as a replacement.
+
+ * "git rev-list --stdin" learned to take non-revisions (like "--not")
+   recently from the standard input, but the way such a "--not" was
+   handled was quite confusing, which has been rethought.  The updated
+   rule is that "--not" given from the command line only affects revs
+   given from the command line that comes but not revs read from the
+   standard input, and "--not" read from the standard input affects
+   revs given from the stanrdard input and not revs given from the
+   command line.
+
+UI, Workflows & Features
+
+ * A message written in olden time prevented a branch from getting
+   checked out saying it is already checked out elsewhere, but these
+   days, we treat a branch that is being bisected or rebased just like
+   a branch that is checked out and protect it.  Rephrase the message
+   to say that the branch is in use.
+
+ * Hourly and other schedule of "git maintenance" jobs are randomly
+   distributed now.
+
+ * "git cmd -h" learned to signal which options can be negated by
+   listing such options like "--[no-]opt".
+
+ * The way authentication related data other than passwords (e.g.
+   oath token and password expiration data) are stored in libsecret
+   keyrings has been rethought.
+
+ * Update two credential helpers to correctly match which credential
+   to erase; they dropped not the ones with stale password.
+
+ * Git GUI updates.
+
+ * "git format-patch" learns a way to feed cover letter description,
+   that (1) can be used on detached HEAD where there is no branch
+   description available, and (2) also can override the branch
+   description if there is one.
+
+ * Use of --max-pack-size to allow multiple packfiles to be created is
+   now supported even when we are sending unreachable objects to cruft
+   packs.
+
+ * "git format-patch --rfc --subject-prefix=<foo>" used to ignore the
+   "--subject-prefix" option and used "[RFC PATCH]"; now we will add
+   "RFC" prefix to whatever subject prefix is specified.
+
+ * "git log --format" has been taught the %(decorate) placeholder.
+
+ * The default log message created by "git revert", when reverting a
+   commit that records a revert, has been tweaked, to encourage people
+   describe complex "revert of revert of revert" situation better in
+   their own words.
+
+ * The command-line complation support (in contrib/) learned to
+   complete "git commit --trailer=" for possible trailer keys.
+
+ * "git update-index" learns "--show-index-version" to inspect
+   the index format version used by the on-disk index file.
+
+ * "git diff" learned diff.statNameWidth configuration variable, to
+   give the default width for the name part in the "--stat" output.
+
+ * "git range-diff --notes=foo" compared "log --notes=foo --notes" of
+   the two ranges, instead of using just the specified notes tree.
+
+ * The command line completion script (in contrib/) can be told to
+   complete aliases by including ": git <cmd> ;" in the alias to tell
+   it that the alias should be completed similar to how "git <cmd>" is
+   completed.  The parsing code for the alias as been loosened to
+   allow ';' without an extra space before it.
+
+ * "git for-each-ref" and friends learned to apply mailmap to
+   authorname and other fields.
+
+ * "git repack" machinery learns to pay attention to the "--filter="
+   option.
+
+ * "git repack" learned "--max-cruft-size" to prevent cruft packs from
+   growing without bounds.
+
+ * "git merge-tree" learned to take strategy backend specific options
+   via the "-X" option, like "git merge" does.
+
+ * "git log" and friends learned "--dd" that is a short-hand for
+   "--diff-merges=first-parent -p".
+
+ * The attribute subsystem learned to honor `attr.tree` configuration
+   that specifies which tree to read the .gitattributes files from.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git check-attr" has been taught to work better with sparse-index.
+
+ * It may be tempting to leave the help text NULL for a command line
+   option that is either hidden or too obvious, but "git subcmd -h"
+   and "git subcmd --help-all" would have segfaulted if done so.  Now
+   the help text is optional.
+
+ * Tests that are known to pass with LSan are now marked as such.
+   (merge 5fafe8c95f tb/mark-more-tests-as-leak-free later to maint).
+
+ * Flaky "git p4" tests, as well as "git svn" tests, are now skipped
+   in the (rather expensive) sanitizer CI job.
+   (merge 6ba913629f js/ci-san-skip-p4-and-svn-tests later to maint).
+
+ * Tests with LSan from time to time seem to emit harmless message
+   that makes our tests unnecessarily flaky; we work it around by
+   filtering the uninteresting output.
+   (merge 370ef7e40d jk/test-lsan-denoise-output later to maint).
+
+ * Unused parameters to functions are marked as such, and/or removed,
+   in order to bring us closer to -Wunused-parameter clean.
+
+ * The code to keep track of existing packs in the repository while
+   repacking has been refactored.
+
+ * The "streaming" interface used for bulk-checkin codepath has been
+   narrowed to take only blob objects for now, with no real loss of
+   functionality.
+
+ * GitHub CI workflow has learned to trigger Coverity check.
+   (merge 3349520e1a js/ci-coverity later to maint).
+
+ * Test coverage for trailers has been improved.
+
+ * The code to iterate over loose references have been optimized to
+   reduce the number of lstat() system calls.
+   (merge 2cdb796101 vd/loose-ref-iteration-optimization later to maint).
+
+ * The codepaths that read "chunk" formatted files have been corrected
+   to pay attention to the chunk size and notice broken files.
+
+
+Fixes since v2.42
+-----------------
+
+ * Overly long label names used in the sequencer machinery are now
+   chopped to fit under filesystem limitation.
+   (merge ac300bda10 mp/rebase-label-length-limit later to maint).
+
+ * Scalar updates.
+   (merge f9a547d3a7 ds/scalar-updates later to maint).
+
+ * Tweak GitHub Actions CI so that pushing the same commit to multiple
+   branch tips at the same time will not waste building and testing
+   the same thing twice.
+   (merge 99fe06cbfd jc/ci-skip-same-commit later to maint).
+
+ * The commit-graph verification code that detects mixture of zero and
+   non-zero generation numbers has been updated.
+   (merge db6044d762 tb/commit-graph-verify-fix later to maint).
+
+ * "git diff -w --exit-code" with various options did not work
+   correctly, which is being addressed.
+   (merge a64f8b2595 jc/diff-exit-code-with-w-fixes later to maint).
+
+ * transfer.unpackLimit ought to be used as a fallback, but overrode
+   fetch.unpackLimit and receive.unpackLimit instead.
+   (merge f3d33f8cfe ts/unpacklimit-config-fix later to maint).
+
+ * The use of API between two calls to require_clean_work_tree() from
+   the sequencer code has been cleaned up for consistency.
+   (merge a9b5955e07 ob/sequencer-empty-hint-fix later to maint).
+
+ * "git diff --no-such-option" and other corner cases around the exit
+   status of the "diff" command has been corrected.
+   (merge 5cc6b2d70b jk/diff-result-code-cleanup later to maint).
+
+ * "git for-each-ref --sort='contents:size'" sorts the refs according
+   to size numerically, giving a ref that points at a blob twelve-byte
+   (12) long before showing a blob hundred-byte (100) long.
+   (merge 6d79cd8474 ks/ref-filter-sort-numerically later to maint).
+
+ * We now limit depth of the tree objects and maximum length of
+   pathnames recorded in tree objects.
+   (merge 4d5693ba05 jk/tree-name-and-depth-limit later to maint).
+
+ * Various fixes to the behavior of "rebase -i" when the command got
+   interrupted by conflicting changes.
+   (merge 203573b024 pw/rebase-i-after-failure later to maint).
+
+ * References from description of the `--patch` option in various
+   manual pages have been simplified and improved.
+   (merge 11422f23e3 so/diff-doc-for-patch-update later to maint).
+
+ * "git grep -e A --no-or -e B" is accepted, even though the negation
+   of "or" did not mean anything, which has been tightened.
+   (merge aae8558b10 rs/grep-no-no-or later to maint).
+
+ * The completion script (in contrib/) has been taught to treat the
+   "-t" option to "git checkout" and "git switch" just like the
+   "--track" option, to complete remote-tracking branches.
+   (merge 9f892830d6 js/complete-checkout-t later to maint).
+
+ * "git diff --no-index -R <(one) <(two)" did not work correctly,
+   which has been corrected.
+   (merge 48944f214c pw/diff-no-index-from-named-pipes later to maint).
+
+ * Update "git maintenance" timers' implementation based on systemd
+   timers to work with WSL.
+   (merge 5e8515e8e8 js/systemd-timers-wsl-fix later to maint).
+
+ * "git diff --cached" codepath did not fill the necessary stat
+   information for a file when fsmonitor knows it is clean and ended
+   up behaving as if it is not clean, which has been corrected.
+   (merge 6a044a2048 js/diff-cached-fsmonitor-fix later to maint).
+
+ * Clarify how "alias.foo = : git cmd ; aliased-command-string" should
+   be spelled with necessary whitespaces around punctuation marks to
+   work.
+   (merge 4333267995 pb/completion-aliases-doc later to maint).
+
+ * HTTP Header redaction code has been adjusted for a newer version of
+   cURL library that shows its traces differently from earlier
+   versions.
+   (merge 0763c3a2c4 jk/redact-h2h3-headers-fix later to maint).
+
+ * An error message given by "git send-email" when given a malformed
+   address did not give correct information, which has been corrected.
+   (merge 12288cc44e tb/send-email-extract-valid-address-error-message-fix later to maint).
+
+ * UBSan options were not propagated through the test framework to git
+   run via the httpd, unlike ASan options, which has been corrected.
+   (merge 252d693797 jk/test-pass-ubsan-options-to-http-test later to maint).
+
+ * "checkout --merge -- path" and "update-index --unresolve path" did
+   not resurrect conflicted state that was resolved to remove path,
+   but now they do.
+   (merge 5bdedac3c7 jc/unresolve-removal later to maint).
+
+ * The display width table for unicode characters has been updated for
+   Unicode 15.1
+   (merge 872976c37e bb/unicode-width-table-15 later to maint).
+
+ * Update mailmap entry for Derrick.
+   (merge 6e5457d8c7 ds/mailmap-entry-update later to maint).
+
+ * In .gitmodules files, submodules are keyed by their names, and the
+   path to the submodule whose name is $name is specified by the
+   submodule.$name.path variable.  There were a few codepaths that
+   mixed the name and path up when consulting the submodule database,
+   which have been corrected.  It took long for these bugs to be found
+   as the name of a submodule initially is the same as its path, and
+   the problem does not surface until it is moved to a different path,
+   which apparently happens very rarely.
+
+ * "git diff --merge-base X other args..." insisted that X must be a
+   commit and errored out when given an annotated tag that peels to a
+   commit, but we only need it to be a committish.  This has been
+   corrected.
+   (merge 4adceb5a29 ar/diff-index-merge-base-fix later to maint).
+
+ * Fix "git merge-tree" to stop segfaulting when the --attr-source
+   option is used.
+   (merge e95bafc52f jc/merge-ort-attr-index-fix later to maint).
+
+ * Unlike "git log --pretty=%D", "git log --pretty="%(decorate)" did
+   not auto-initialize the decoration subsystem, which has been
+   corrected.
+
+ * Feeding "git stash store" with a random commit that was not created
+   by "git stash create" now errors out.
+   (merge d9b6634589 jc/fail-stash-to-store-non-stash later to maint).
+
+ * The index file has room only for lower 32-bit of the file size in
+   the cached stat information, which means cached stat information
+   will have 0 in its sd_size member for a file whose size is multiple
+   of 4GiB.  This is mistaken for a racily clean path.  Avoid it by
+   storing a bogus sd_size value instead for such files.
+   (merge 5143ac07b1 bc/racy-4gb-files later to maint).
+
+ * "git p4" tried to store symlinks to LFS when told, but has been
+   fixed not to do so, because it does not make sense.
+   (merge 10c89a02b0 mm/p4-symlink-with-lfs later to maint).
+
+ * The codepath to handle recipient addresses `git send-email
+   --compose` learns from the user was completely broken, which has
+   been corrected.
+   (merge 3ec6167567 jk/send-email-fix-addresses-from-composed-messages later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge fd3ba590d8 ws/git-push-doc-grammofix later to maint).
+   (merge 5f33a843de ds/upload-pack-error-sequence-fix later to maint).
+   (merge beaa1d952b jk/function-pointer-mismatches-fix later to maint).
+   (merge b46d806ea5 ob/t9001-indent-fix later to maint).
+   (merge fdc9914c28 ja/worktree-orphan later to maint).
+   (merge c2cbefc510 jc/mv-d-to-d-error-message-fix later to maint).
+   (merge d0fc552bfc ch/t6300-verify-commit-test-cleanup later to maint).
+   (merge aa4b83dd5e ws/git-svn-retire-faketerm later to maint).
+   (merge edf80d23f1 jk/ci-retire-allow-ref later to maint).
+   (merge 256a94ef6c bc/more-git-var later to maint).
+   (merge 82af2c639c ob/sequencer-reword-error-message later to maint).
+   (merge 2a63c79dae rs/grep-parseopt-simplify later to maint).
+   (merge 078c42531e rs/name-rev-use-opt-hidden-bool later to maint).
+   (merge 63642d58b4 ob/sequencer-remove-dead-code later to maint).
+   (merge 8aae489756 ob/t3404-typofix later to maint).
+   (merge 58be11432e eg/config-type-path-docfix later to maint).
+   (merge 563f339d98 ch/clean-docfix later to maint).
+   (merge 4fbe83fcd9 hy/doc-show-is-like-log-not-diff-tree later to maint).
+   (merge 43abaaf008 ob/am-msgfix later to maint).
+   (merge c2c349a15c xz/commit-title-soft-limit-doc later to maint).
+   (merge f4cbb32c27 rs/parse-opt-ctx-cleanup later to maint).
+   (merge badf2fe1c3 jk/decoration-and-other-leak-fixes later to maint).
+   (merge cebfaaa333 sn/cat-file-doc-update later to maint).
+   (merge 8b3aa36f5a ps/rewritten-is-per-worktree-doc later to maint).
+   (merge ffbf6a748d jc/update-list-references-to-lore later to maint).
+   (merge 14d569b1a7 jc/am-doc-whitespace-action-fix later to maint).
+   (merge 48399e9cf0 ni/die-message-fix-for-git-add later to maint).
+   (merge ca3285dd69 ps/git-repack-doc-fixes later to maint).
+   (merge 243c79fdc7 wx/merge-ort-comment-typofix later to maint).
+   (merge a060705d94 jc/commit-new-underscore-index-fix later to maint).
+   (merge f6d83e2115 ms/doc-push-fix later to maint).
index 0e323d54779a7c680ee8471330c85609f4644d43..515d470d23c1f178a60a2ea7734ba8930da42cba 100644 (file)
@@ -19,7 +19,7 @@ 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
+the 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];
@@ -126,7 +126,7 @@ Terminology
 -----------
 nit: ::
        Denotes a small issue that should be fixed, such as a typographical error
-       or mis-alignment of conditions in an `if()` statement.
+       or misalignment of conditions in an `if()` statement.
 
 aside: ::
 optional: ::
index b218e273570158fa6a3e9863398295b1e3ab7016..bce7f97815cb52a5ebbba4289b4b5013929b99ee 100644 (file)
@@ -3,45 +3,101 @@ Submitting Patches
 
 == Guidelines
 
-Here are some guidelines for people who want to contribute their code to this
-software. There is also a link:MyFirstContribution.html[step-by-step tutorial]
+Here are some guidelines for contributing back to this
+project. There is also a link:MyFirstContribution.html[step-by-step tutorial]
 available which covers many of these same guidelines.
 
-[[base-branch]]
-=== Decide what to base your work on.
-
-In general, always base your work on the oldest branch that your
-change is relevant to.
-
-* A bugfix should be based on `maint` in general. If the bug is not
-  present in `maint`, base it on `master`. For a bug that's not yet
-  in `master`, find the topic that introduces the regression, and
-  base your work on the tip of the topic.
-
-* A new feature should be based on `master` in general. If the new
-  feature depends on other topics that are in `next`, but not in
-  `master`, fork a branch from the tip of `master`, merge these topics
-  to the branch, and work on that branch.  You can remind yourself of
-  how you prepared the base with `git log --first-parent master..`.
-
-* Corrections and enhancements to a topic not yet in `master` should
-  be based on the tip of that topic. If the topic has not been merged
-  to `next`, it's alright to add a note to squash minor corrections
-  into the series.
-
-* In the exceptional case that a new feature depends on several topics
-  not in `master`, start working on `next` or `seen` privately and
-  send out patches only for discussion. Once your new feature starts
-  to stabilize, you would have to rebase it (see the "depends on other
-  topics" above).
-
-* Some parts of the system have dedicated maintainers with their own
-  repositories (see the section "Subsystems" below).  Changes to
-  these parts should be based on their trees.
-
-To find the tip of a topic branch, run `git log --first-parent
-master..seen` and look for the merge commit. The second parent of this
-commit is the tip of the topic branch.
+[[choose-starting-point]]
+=== Choose a starting point.
+
+As a preliminary step, you must first choose a starting point for your
+work. Typically this means choosing a branch, although technically
+speaking it is actually a particular commit (typically the HEAD, or tip,
+of the branch).
+
+There are several important branches to be aware of. Namely, there are
+four integration branches as discussed in linkgit:gitworkflows[7]:
+
+* maint
+* master
+* next
+* seen
+
+The branches lower on the list are typically descendants of the ones
+that come before it. For example, `maint` is an "older" branch than
+`master` because `master` usually has patches (commits) on top of
+`maint`.
+
+There are also "topic" branches, which contain work from other
+contributors.  Topic branches are created by the Git maintainer (in
+their fork) to organize the current set of incoming contributions on
+the mailing list, and are itemized in the regular "What's cooking in
+git.git" announcements.  To find the tip of a topic branch, run `git log
+--first-parent master..seen` and look for the merge commit. The second
+parent of this commit is the tip of the topic branch.
+
+There is one guiding principle for choosing the right starting point: in
+general, always base your work on the oldest integration branch that
+your change is relevant to (see "Merge upwards" in
+linkgit:gitworkflows[7]).  What this principle means is that for the
+vast majority of cases, the starting point for new work should be the
+latest HEAD commit of `maint` or `master` based on the following cases:
+
+* If you are fixing bugs in the released version, use `maint` as the
+  starting point (which may mean you have to fix things without using
+  new API features on the cutting edge that recently appeared in
+  `master` but were not available in the released version).
+
+* Otherwise (such as if you are adding new features) use `master`.
+
+
+NOTE: In exceptional cases, a bug that was introduced in an old
+version may have to be fixed for users of releases that are much older
+than the recent releases.  `git describe --contains X` may describe
+`X` as `v2.30.0-rc2-gXXXXXX` for the commit `X` that introduced the
+bug, and the bug may be so high-impact that we may need to issue a new
+maintenance release for Git 2.30.x series, when "Git 2.41.0" is the
+current release.  In such a case, you may want to use the tip of the
+maintenance branch for the 2.30.x series, which may be available in the
+`maint-2.30` branch in https://github.com/gitster/git[the maintainer's
+"broken out" repo].
+
+This also means that `next` or `seen` are inappropriate starting points
+for your work, if you want your work to have a realistic chance of
+graduating to `master`.  They are simply not designed to be used as a
+base for new work; they are only there to make sure that topics in
+flight work well together. This is why both `next` and `seen` are
+frequently re-integrated with incoming patches on the mailing list and
+force-pushed to replace previous versions of themselves. A topic that is
+literally built on top of `next` cannot be merged to `master` without
+dragging in all the other topics in `next`, some of which may not be
+ready.
+
+For example, if you are making tree-wide changes, while somebody else is
+also making their own tree-wide changes, your work may have severe
+overlap with the other person's work.  This situation may tempt you to
+use `next` as your starting point (because it would have the other
+person's work included in it), but doing so would mean you'll not only
+depend on the other person's work, but all the other random things from
+other contributors that are already integrated into `next`.  And as soon
+as `next` is updated with a new version, all of your work will need to
+be rebased anyway in order for them to be cleanly applied by the
+maintainer.
+
+Under truly exceptional circumstances where you absolutely must depend
+on a select few topic branches that are already in `next` but not in
+`master`, you may want to create your own custom base-branch by forking
+`master` and merging the required topic branches into it. You could then
+work on top of this base-branch.  But keep in mind that this base-branch
+would only be known privately to you.  So when you are ready to send
+your patches to the list, be sure to communicate how you created it in
+your cover letter.  This critical piece of information would allow
+others to recreate your base-branch on their end in order for them to
+try out your work.
+
+Finally, note that some parts of the system have dedicated maintainers
+with their own separate source code repositories (see the section
+"Subsystems" below).
 
 [[separate-commits]]
 === Make separate commits for logically separate changes.
@@ -210,7 +266,7 @@ date)", like this:
        noticed that ...
 ....
 
-The "Copy commit summary" command of gitk can be used to obtain this
+The "Copy commit reference" command of gitk can be used to obtain this
 format (with the subject enclosed in a pair of double-quotes), or this
 invocation of `git show`:
 
@@ -317,10 +373,13 @@ Please make sure your patch does not add commented out debugging code,
 or include any extra files which do not relate to what your patch
 is trying to achieve. Make sure to review
 your patch after generating it, to ensure accuracy.  Before
-sending out, please make sure it cleanly applies to the base you
-have chosen in the "Decide what to base your work on" section,
-and unless it targets the `master` branch (which is the default),
-mark your patches as such.
+sending out, please make sure it cleanly applies to the starting point you
+have chosen in the "Choose a starting point" section.
+
+NOTE: From the perspective of those reviewing your patch, the `master`
+branch is the default expected starting point.  So if you have chosen a
+different starting point, please communicate this choice in your cover
+letter.
 
 
 [[send-patches]]
@@ -334,8 +393,8 @@ mailing list{security-ml}, instead of the public mailing list.
 
 Learn to use format-patch and send-email if possible.  These commands
 are optimized for the workflow of sending patches, avoiding many ways
-your existing e-mail client that is optimized for "multipart/*" mime
-type e-mails to corrupt and render your patches unusable.
+your existing e-mail client (often optimized for "multipart/*" MIME
+type e-mails) might render your patches unusable.
 
 People on the Git mailing list need to be able to read and
 comment on the changes you are submitting.  It is important for
@@ -456,8 +515,8 @@ repositories.
 
        git://git.ozlabs.org/~paulus/gitk
 
-   Those who are interested in improve gitk can volunteer to help Paul
-   in maintaining it cf. <YntxL/fTplFm8lr6@cleo>.
+   Those who are interested in improving gitk can volunteer to help Paul
+   maintain it, cf. <YntxL/fTplFm8lr6@cleo>.
 
 - `po/` comes from the localization coordinator, Jiang Xin:
 
@@ -497,7 +556,7 @@ help you find out who they are.
 
 In any time between the (2)-(3) cycle, the maintainer may pick it up
 from the list and queue it to `seen`, in order to make it easier for
-people play with it without having to pick up and apply the patch to
+people to play with it without having to pick up and apply the patch to
 their trees themselves.
 
 [[patch-status]]
index 5060d0d2314c316364b7579236a1c2572c62ba64..ae7690b45d08b3c3ba9775d17d43d0f658a71360 100644 (file)
@@ -5,7 +5,7 @@ Tools for developing Git
 [[summary]]
 == Summary
 
-This document gathers tips, scripts and configuration file to help people
+This document gathers tips, scripts, and configuration files to help people
 working on Git's codebase use their favorite tools while following Git's
 coding style.
 
@@ -32,7 +32,7 @@ information on using the script.
 
 This is adapted from Linux's suggestion in its CodingStyle document:
 
-- To follow rules of the CodingGuideline, it's useful to put the following in
+- To follow the rules in CodingGuidelines, it's useful to put the following in
 GIT_CHECKOUT/.dir-locals.el, assuming you use cperl-mode:
 ----
 ;; note the first part is useful for C editing, too
index 0e93aef86264dbe5c7af33e66a13778c160b24ba..e3a74dd1c19db44b3a0980cc778bf0ab4ba60b07 100644 (file)
@@ -11,7 +11,7 @@ file. The file `/etc/gitconfig` can be used to store a system-wide
 default configuration.
 
 The configuration variables are used by both the Git plumbing
-and the porcelains. The variables are divided into sections, wherein
+and the porcelain commands. The variables are divided into sections, wherein
 the fully qualified variable name of the variable itself is the last
 dot-separated segment and the section name is everything before the last
 dot. The variable names are case-insensitive, allow only alphanumeric
@@ -103,7 +103,7 @@ was found.  See below for examples.
 Conditional includes
 ~~~~~~~~~~~~~~~~~~~~
 
-You can include a config file from another conditionally by setting a
+You can conditionally include a config file from another by setting an
 `includeIf.<condition>.path` variable to the name of the file to be
 included.
 
@@ -118,7 +118,7 @@ are:
        pattern, the include condition is met.
 +
 The .git location may be auto-discovered, or come from `$GIT_DIR`
-environment variable. If the repository is auto discovered via a .git
+environment variable. If the repository is auto-discovered via a .git
 file (e.g. from submodules, or a linked worktree), the .git location
 would be the final location where the .git directory is, not where the
 .git file is.
@@ -182,7 +182,7 @@ included, Git breaks the cycle by prohibiting these files from affecting
 the resolution of these conditions (thus, prohibiting them from
 declaring remote URLs).
 +
-As for the naming of this keyword, it is for forwards compatibiliy with
+As for the naming of this keyword, it is for forwards compatibility with
 a naming scheme that supports more variable-based include conditions,
 but currently Git only supports the exact keyword described above.
 
@@ -371,6 +371,8 @@ other popular tools, and describe them in your documentation.
 
 include::config/advice.txt[]
 
+include::config/attr.txt[]
+
 include::config/core.txt[]
 
 include::config/add.txt[]
index c96b5b2e5d2160c3f6b1147fc6500f22acf06a55..2737381a11a1b40dfb2ec3f6f6b182f83a91c9fd 100644 (file)
@@ -5,7 +5,7 @@ advice.*::
 +
 --
        ambiguousFetchRefspec::
-               Advice shown when fetch refspec for multiple remotes map to
+               Advice shown when a fetch refspec for multiple remotes maps to
                the same remote-tracking branch namespace and causes branch
                tracking set-up to fail.
        fetchShowForcedUpdates::
@@ -63,7 +63,7 @@ advice.*::
                the template shown when writing commit messages in
                linkgit:git-commit[1], and in the help message shown
                by linkgit:git-switch[1] or
-               linkgit:git-checkout[1] when switching branch.
+               linkgit:git-checkout[1] when switching branches.
        statusUoption::
                Advise to consider using the `-u` option to linkgit:git-status[1]
                when the command takes more than 2 seconds to enumerate untracked
@@ -87,7 +87,7 @@ advice.*::
        detachedHead::
                Advice shown when you used
                linkgit:git-switch[1] or linkgit:git-checkout[1]
-               to move to the detach HEAD state, to instruct how to
+               to move to the detached HEAD state, to instruct how to
                create a local branch after the fact.
        suggestDetachingHead::
                Advice shown when linkgit:git-switch[1] refuses to detach HEAD
@@ -101,7 +101,7 @@ advice.*::
                otherwise caused a remote-tracking branch to be
                checked out. See the `checkout.defaultRemote`
                configuration variable for how to set a given remote
-               to used by default in some situations where this
+               to be used by default in some situations where this
                advice would be printed.
        amWorkDir::
                Advice that shows the location of the patch file when
@@ -138,4 +138,8 @@ advice.*::
                checkout.
        diverging::
                Advice shown when a fast-forward is not possible.
+       worktreeAddOrphan::
+               Advice shown when a user tries to create a worktree from an
+               invalid reference, to instruct how to create a new orphan
+               branch instead.
 --
index f1ca739d574293fd001322a2cc272e2cc0510344..01df96fab3df11f1c804e26ed7c312cd7490e2fd 100644 (file)
@@ -4,7 +4,7 @@ alias.*::
        `git last` is equivalent to `git cat-file commit HEAD`. To avoid
        confusion and troubles with script usage, aliases that
        hide existing Git commands are ignored. Arguments are split by
-       spaces, the usual shell quoting and escaping is supported.
+       spaces, the usual shell quoting and escaping are supported.
        A quote pair or a backslash can be used to quote them.
 +
 Note that the first word of an alias does not necessarily have to be a
index 8fb8ef763dfdf2475af3addafa3cefd7d859ad8a..f9908e210a838dfaf78315b1ce146655a7cf19ca 100644 (file)
@@ -2,10 +2,10 @@ apply.ignoreWhitespace::
        When set to 'change', tells 'git apply' to ignore changes in
        whitespace, in the same way as the `--ignore-space-change`
        option.
-       When set to one of: no, none, never, false tells 'git apply' to
+       When set to one of: no, none, never, false, it tells 'git apply' to
        respect all whitespace differences.
        See linkgit:git-apply[1].
 
 apply.whitespace::
-       Tells 'git apply' how to handle whitespaces, in the same way
+       Tells 'git apply' how to handle whitespace, in the same way
        as the `--whitespace` option. See linkgit:git-apply[1].
diff --git a/Documentation/config/attr.txt b/Documentation/config/attr.txt
new file mode 100644 (file)
index 0000000..1a482d6
--- /dev/null
@@ -0,0 +1,7 @@
+attr.tree::
+       A reference to a tree in the repository from which to read attributes,
+       instead of the `.gitattributes` file in the working tree. In a bare
+       repository, this defaults to `HEAD:.gitattributes`. If the value does
+       not resolve to a valid tree object, an empty tree is used instead.
+       When the `GIT_ATTR_SOURCE` environment variable or `--attr-source`
+       command line option are used, this configuration variable has no effect.
index 445341a906b241ab1ed11093b1b0fa908e0954da..432b9cd2c0e66721c135a14bd4e3f09dee6bcc92 100644 (file)
@@ -36,7 +36,7 @@ branch.sort::
 
 branch.<name>.remote::
        When on branch <name>, it tells 'git fetch' and 'git push'
-       which remote to fetch from/push to.  The remote to push to
+       which remote to fetch from or push to.  The remote to push to
        may be overridden with `remote.pushDefault` (for all branches).
        The remote to push to, for the current branch, may be further
        overridden by `branch.<name>.pushRemote`.  If no remote is
@@ -64,7 +64,7 @@ branch.<name>.merge::
        handled like the remote part of a refspec, and must match a
        ref which is fetched from the remote given by
        "branch.<name>.remote".
-       The merge information is used by 'git pull' (which at first calls
+       The merge information is used by 'git pull' (which first calls
        'git fetch') to lookup the default branch for merging. Without
        this option, 'git pull' defaults to merge the first refspec fetched.
        Specify multiple values to get an octopus merge.
@@ -99,5 +99,5 @@ for details).
 branch.<name>.description::
        Branch description, can be edited with
        `git branch --edit-description`. Branch description is
-       automatically added in the format-patch cover letter or
+       automatically added to the format-patch cover letter or
        request-pull summary.
index bfbca90f0e90bdcac2fb814ab90c74d2d7f1b0d7..a3230229938055323ead98e6d6bdfd032b911b1b 100644 (file)
@@ -30,7 +30,7 @@ checkout.workers::
        all commands that perform checkout. E.g. checkout, clone, reset,
        sparse-checkout, etc.
 +
-Note: parallel checkout usually delivers better performance for repositories
+Note: Parallel checkout usually delivers better performance for repositories
 located on SSDs or over NFS. For repositories on spinning disks and/or machines
 with a small number of cores, the default sequential checkout often performs
 better. The size and compression level of a repository might also influence how
@@ -39,6 +39,6 @@ well the parallel version performs.
 checkout.thresholdForParallelism::
        When running parallel checkout with a small number of files, the cost
        of subprocess spawning and inter-process communication might outweigh
-       the parallelization gains. This setting allows to define the minimum
+       the parallelization gains. This setting allows you to define the minimum
        number of files for which parallel checkout should be attempted. The
        default is 100.
index a807c925b9ca8ce4ca783fe2880ec986ef0d5b83..f05b9403b5ad903ea68d68e896acaff253bfde37 100644 (file)
@@ -1,3 +1,3 @@
 clean.requireForce::
        A boolean to make git-clean do nothing unless given -f,
-       -i or -n.   Defaults to true.
+       -i, or -n.  Defaults to true.
index 26f4fb137a738ead96e0a9848df9a383aa432305..d037b57f729e5e10549235b6278c123754d0aee8 100644 (file)
@@ -4,8 +4,8 @@ clone.defaultRemoteName::
        option to linkgit:git-clone[1].
 
 clone.rejectShallow::
-       Reject to clone a repository if it is a shallow one, can be overridden by
-       passing option `--reject-shallow` in command line. See linkgit:git-clone[1]
+       Reject cloning a repository if it is a shallow one; this can be overridden by
+       passing the `--reject-shallow` option on the command line. See linkgit:git-clone[1]
 
 clone.filterSubmodules::
        If a partial clone filter is provided (see `--filter` in
index 1795b2d16be2f01ba10ecfd6a2128444b99a85ec..2f2275ac6975f2a47cafc719d886e2f2b8c71a71 100644 (file)
@@ -106,7 +106,7 @@ color.grep.<slot>::
        matching text in context lines
 `matchSelected`;;
        matching text in selected lines. Also, used to customize the following
-       linkgit:git-log[1] subcommands: `--grep`, `--author` and `--committer`.
+       linkgit:git-log[1] subcommands: `--grep`, `--author`, and `--committer`.
 `selected`;;
        non-matching text in selected lines. Also, used to customize the
        following linkgit:git-log[1] subcommands: `--grep`, `--author` and
index 76aa2f29dc2108fa20d575c4bc49791bc9c02c96..01e4198429ed46c96b7e25a70ed7b58c4844a29a 100644 (file)
@@ -43,7 +43,7 @@ column.branch::
        See `column.ui` for details.
 
 column.clean::
-       Specify the layout when list items in `git clean -i`, which always
+       Specify the layout when listing items in `git clean -i`, which always
        shows files and directories in columns. See `column.ui` for details.
 
 column.status::
@@ -51,5 +51,5 @@ column.status::
        See `column.ui` for details.
 
 column.tag::
-       Specify whether to output tag listing in `git tag` in columns.
+       Specify whether to output tag listings in `git tag` in columns.
        See `column.ui` for details.
index 2c95573930bedf8d5aed0a0b19927c73ac8e39f7..62f0d92fda51de04a75b4fc074befaa96c554851 100644 (file)
@@ -2,7 +2,7 @@ commit.cleanup::
        This setting overrides the default of the `--cleanup` option in
        `git commit`. See linkgit:git-commit[1] for details. Changing the
        default can be useful when you always want to keep lines that begin
-       with comment character `#` in your log message, in which case you
+       with the comment character `#` in your log message, in which case you
        would do `git config commit.cleanup whitespace` (note that you will
        have to remove the help lines that begin with `#` in the commit log
        template yourself, if you do this).
@@ -25,5 +25,5 @@ commit.template::
        new commit messages.
 
 commit.verbose::
-       A boolean or int to specify the level of verbose with `git commit`.
+       A boolean or int to specify the level of verbosity with `git commit`.
        See linkgit:git-commit[1].
index dfbdaf00b8bc2239e7e106c8b78a2dd90d44ac9b..0e8c2832bf9b8a5251c51f346ecfcf47c7e8d530 100644 (file)
@@ -736,3 +736,9 @@ core.abbrev::
        If set to "no", no abbreviation is made and the object names
        are shown in their full length.
        The minimum length is 4.
+
+core.maxTreeDepth::
+       The maximum depth Git is willing to recurse while traversing a
+       tree (e.g., "a/b/cde/f" has a depth of 4). This is a fail-safe
+       to allow Git to abort cleanly, and should not generally need to
+       be adjusted. The default is 4096.
index 512f31876e17ed6892ff7f1858a891f0f7938b29..0221c3e620da89abb62f26110f400ecb0d6ff71a 100644 (file)
@@ -21,7 +21,7 @@ credential.username::
 
 credential.<url>.*::
        Any of the credential.* options above can be applied selectively to
-       some credentials. For example "credential.https://example.com.username"
+       some credentials. For example, "credential.https://example.com.username"
        would set the default username only for https connections to
        example.com. See linkgit:gitcredentials[7] for details on how URLs are
        matched.
@@ -31,6 +31,6 @@ credentialCache.ignoreSIGHUP::
 
 credentialStore.lockTimeoutMS::
        The length of time, in milliseconds, for git-credential-store to retry
-       when trying to lock the credentials file. Value 0 means not to retry at
+       when trying to lock the credentials file. A value of 0 means not to retry at
        all; -1 means to try indefinitely. Default is 1000 (i.e., retry for
        1s).
index 35a7bf86d7774c67dbd129cc29b009aae46c81a9..bd5ae0c3378adbd5661a202dc1f8fcfbf27ac4a1 100644 (file)
@@ -1,6 +1,6 @@
 diff.autoRefreshIndex::
        When using 'git diff' to compare with work tree
-       files, do not consider stat-only change as changed.
+       files, do not consider stat-only changes as changed.
        Instead, silently run `git update-index --refresh` to
        update the cached stat information for paths whose
        contents in the work tree match the contents in the
@@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files,
 and accumulating child directory counts in the parent directories:
 `files,10,cumulative`.
 
+diff.statNameWidth::
+       Limit the width of the filename part in --stat output. If set, applies
+       to all commands generating --stat output except format-patch.
+
 diff.statGraphWidth::
        Limit the width of the graph part in --stat output. If set, applies
        to all commands generating --stat output except format-patch.
index c1166e330d55da332d4fa591b4083f86f2adb606..903677d7efefa03d607c9b076ac1a7bf14304105 100644 (file)
@@ -1,8 +1,8 @@
 fastimport.unpackLimit::
        If the number of objects imported by linkgit:git-fast-import[1]
        is below this limit, then the objects will be unpacked into
-       loose object files.  However if the number of imported objects
-       equals or exceeds this limit then the pack will be stored as a
+       loose object files.  However, if the number of imported objects
+       equals or exceeds this limit, then the pack will be stored as a
        pack.  Storing the pack from a fast-import can make the import
        operation complete faster, especially on slow filesystems.  If
        not set, the value of `transfer.unpackLimit` is used instead.
index 17b4d39f894c12a32da93f69006b59b2434f0775..bf9546fca4f693f01b39252d12def7df9b51a52f 100644 (file)
@@ -14,6 +14,9 @@ feature.experimental::
 +
 * `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
 skipping more commits at a time, reducing the number of round trips.
++
+* `pack.useBitmapBoundaryTraversal=true` may improve bitmap traversal times by
+walking fewer objects.
 
 feature.manyFiles::
        Enable config options that optimize for repos with many files in the
index 568f0f75b3027d374a53857c06cf481ff376c6b7..aea5b97477b64ef664b6b35faad78b2eb618db9a 100644 (file)
@@ -52,8 +52,8 @@ fetch.pruneTags::
 
 fetch.output::
        Control how ref update status is printed. Valid values are
-       `full` and `compact`. Default value is `full`. See section
-       OUTPUT in linkgit:git-fetch[1] for detail.
+       `full` and `compact`. Default value is `full`. See the
+       OUTPUT section in linkgit:git-fetch[1] for details.
 
 fetch.negotiationAlgorithm::
        Control how information about the commits in the local repository
index 8cf6f00d9365cf19b6244ba005d078c5ebed8a05..c98412b697efea446b5291c0bc52af3611ade5e0 100644 (file)
@@ -68,7 +68,7 @@ format.encodeEmailHeaders::
        Defaults to true.
 
 format.pretty::
-       The default pretty format for log/show/whatchanged command,
+       The default pretty format for log/show/whatchanged command.
        See linkgit:git-log[1], linkgit:git-show[1],
        linkgit:git-whatchanged[1].
 
index a3c865df5679e32958b8351076aa80579a067ffb..8e9e508933f8949ff6aa738d3f7460faeaa289db 100644 (file)
@@ -11,13 +11,13 @@ to clone or fetch it set `fetch.fsck.<msg-id>`.
 +
 The rest of the documentation discusses `fsck.*` for brevity, but the
 same applies for the corresponding `receive.fsck.*` and
-`fetch.<msg-id>.*`. variables.
+`fetch.fsck.*`. variables.
 +
-Unlike variables like `color.ui` and `core.editor` the
+Unlike variables like `color.ui` and `core.editor`, the
 `receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>` variables will not
 fall back on the `fsck.<msg-id>` configuration if they aren't set. To
-uniformly configure the same fsck settings in different circumstances
-all three of them they must all set to the same values.
+uniformly configure the same fsck settings in different circumstances,
+all three of them must be set to the same values.
 +
 When `fsck.<msg-id>` is set, errors can be switched to warnings and
 vice versa by configuring the `fsck.<msg-id>` setting where the
@@ -36,19 +36,19 @@ Setting an unknown `fsck.<msg-id>` value will cause fsck to die, but
 doing the same for `receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>`
 will only cause git to warn.
 +
-See `Fsck Messages` section of linkgit:git-fsck[1] for supported
+See the `Fsck Messages` section of linkgit:git-fsck[1] for supported
 values of `<msg-id>`.
 
 
 fsck.skipList::
        The path to a list of object names (i.e. one unabbreviated SHA-1 per
        line) that are known to be broken in a non-fatal way and should
-       be ignored. On versions of Git 2.20 and later comments ('#'), empty
-       lines, and any leading and trailing whitespace is ignored. Everything
+       be ignored. On versions of Git 2.20 and later, comments ('#'), empty
+       lines, and any leading and trailing whitespace are ignored. Everything
        but a SHA-1 per line will error out on older versions.
 +
 This feature is useful when an established project should be accepted
-despite early commits containing errors that can be safely ignored
+despite early commits containing errors that can be safely ignored,
 such as invalid committer email addresses.  Note: corrupt objects
 cannot be skipped with this setting.
 +
@@ -58,11 +58,11 @@ Like `fsck.<msg-id>` this variable has corresponding
 Unlike variables like `color.ui` and `core.editor` the
 `receive.fsck.skipList` and `fetch.fsck.skipList` variables will not
 fall back on the `fsck.skipList` configuration if they aren't set. To
-uniformly configure the same fsck settings in different circumstances
-all three of them they must all set to the same values.
+uniformly configure the same fsck settings in different circumstances,
+all three of them must be set to the same values.
 +
 Older versions of Git (before 2.20) documented that the object names
-list should be sorted. This was never a requirement, the object names
+list should be sorted. This was never a requirement; the object names
 could appear in any order, but when reading the list we tracked whether
 the list was sorted for the purposes of an internal binary search
 implementation, which could save itself some work with an already sorted
index c225c6c9e74cbd043489108ca843c129f0aa98de..671f9b94628446b1ee4704d6e6730c22719ebcaf 100644 (file)
@@ -1,5 +1,5 @@
 fsmonitor.allowRemote::
-    By default, the fsmonitor daemon refuses to work against network-mounted
+    By default, the fsmonitor daemon refuses to work with network-mounted
     repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
     behavior.  Only respected when `core.fsmonitor` is set to `true`.
 
index 7f95c866e1dee036adaeb94f68a5286bad669652..664a3c28747c8e508e78caa97a607aa909e3efa1 100644 (file)
@@ -24,7 +24,7 @@ gc.auto::
        default value is 6700.
 +
 Setting this to 0 disables not only automatic packing based on the
-number of loose objects, but any other heuristic `git gc --auto` will
+number of loose objects, but also any other heuristic `git gc --auto` will
 otherwise use to determine if there's work to do, such as
 `gc.autoPackLimit`.
 
@@ -39,7 +39,7 @@ See the `gc.bigPackThreshold` configuration variable below. When in
 use, it'll affect how the auto pack limit works.
 
 gc.autoDetach::
-       Make `git gc --auto` return immediately and run in background
+       Make `git gc --auto` return immediately and run in the background
        if the system supports it. Default is true.
 
 gc.bigPackThreshold::
@@ -86,6 +86,12 @@ gc.cruftPacks::
        linkgit:git-repack[1]) instead of as loose objects. The default
        is `true`.
 
+gc.maxCruftSize::
+       Limit the size of new cruft packs when repacking. When
+       specified in addition to `--max-cruft-size`, the command line
+       option takes priority. See the `--max-cruft-size` option of
+       linkgit:git-repack[1].
+
 gc.pruneExpire::
        When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
        (and 'repack --cruft --cruft-expiration 2.weeks.ago' if using
@@ -130,6 +136,37 @@ or rebase occurring.  Since these changes are not part of the current
 project most users will want to expire them sooner, which is why the
 default is more aggressive than `gc.reflogExpire`.
 
+gc.recentObjectsHook::
+       When considering whether or not to remove an object (either when
+       generating a cruft pack or storing unreachable objects as
+       loose), use the shell to execute the specified command(s).
+       Interpret their output as object IDs which Git will consider as
+       "recent", regardless of their age. By treating their mtimes as
+       "now", any objects (and their descendants) mentioned in the
+       output will be kept regardless of their true age.
++
+Output must contain exactly one hex object ID per line, and nothing
+else. Objects which cannot be found in the repository are ignored.
+Multiple hooks are supported, but all must exit successfully, else the
+operation (either generating a cruft pack or unpacking unreachable
+objects) will be halted.
+
+gc.repackFilter::
+       When repacking, use the specified filter to move certain
+       objects into a separate packfile.  See the
+       `--filter=<filter-spec>` option of linkgit:git-repack[1].
+
+gc.repackFilterTo::
+       When repacking and using a filter, see `gc.repackFilter`, the
+       specified location will be used to create the packfile
+       containing the filtered out objects. **WARNING:** The
+       specified location should be accessible, using for example the
+       Git alternates mechanism, otherwise the repo could be
+       considered corrupt by Git as it migh not be able to access the
+       objects in that packfile. See the `--filter-to=<dir>` option
+       of linkgit:git-repack[1] and the `objects/info/alternates`
+       section of linkgit:gitrepository-layout[5].
+
 gc.rerereResolved::
        Records of conflicted merge you resolved earlier are
        kept for this many days when 'git rerere gc' is run.
index 37e2831cd511c8a6f00112f9e357ab58c44ddf98..5cf32b179dc8bd5559be08e040b14a96ce158fd7 100644 (file)
@@ -4,7 +4,7 @@ gpg.program::
        same command-line interface as GPG, namely, to verify a detached
        signature, "`gpg --verify $signature - <$file`" is run, and the
        program is expected to signal a good signature by exiting with
-       code 0, and to generate an ASCII-armored detached signature, the
+       code 0.  To generate an ASCII-armored detached signature, the
        standard input of "`gpg -bsau $key`" is fed with the contents to be
        signed, and the program is expected to send the result to its
        standard output.
@@ -25,7 +25,7 @@ gpg.<format>.program::
 gpg.minTrustLevel::
        Specifies a minimum trust level for signature verification.  If
        this option is unset, then signature verification for merge
-       operations require a key with at least `marginal` trust.  Other
+       operations requires a key with at least `marginal` trust.  Other
        operations that perform signature verification require a key
        with at least `undefined` trust.  Setting this option overrides
        the required trust-level for all operations.  Supported values,
@@ -38,7 +38,7 @@ gpg.minTrustLevel::
 * `ultimate`
 
 gpg.ssh.defaultKeyCommand::
-       This command that will be run when user.signingkey is not set and a ssh
+       This command will be run when user.signingkey is not set and a ssh
        signature is requested. On successful exit a valid ssh public key
        prefixed with `key::` is expected in the first line of its output.
        This allows for a script doing a dynamic lookup of the correct public
index 0c087fd8c9313e5e68dcd7cd7a91b6900936febc..171be774d243fd2822fa51875feab38618d82193 100644 (file)
@@ -24,7 +24,7 @@ gui.matchTrackingBranch::
        not. Default: "false".
 
 gui.newBranchTemplate::
-       Is used as suggested name when creating new branches using the
+       Is used as suggested name when creating new branches using the
        linkgit:git-gui[1].
 
 gui.pruneDuringFetch::
index 51a70781e58cf9923cb0b1b84104c6d011dbd5f8..2d4e0c9b869b567200cfc5805600b51deaa41669 100644 (file)
@@ -254,13 +254,13 @@ http.lowSpeedLimit, http.lowSpeedTime::
 
 http.noEPSV::
        A boolean which disables using of EPSV ftp command by curl.
-       This can helpful with some "poor" ftp servers which don't
+       This can be helpful with some "poor" ftp servers which don't
        support EPSV mode. Can be overridden by the `GIT_CURL_FTP_NO_EPSV`
        environment variable. Default is false (curl will use EPSV).
 
 http.userAgent::
        The HTTP USER_AGENT string presented to an HTTP server.  The default
-       value represents the version of the client Git such as git/1.7.1.
+       value represents the version of the Git client such as git/1.7.1.
        This option allows you to override this value to a more common value
        such as Mozilla/4.0.  This may be necessary, for instance, if
        connecting through a firewall that restricts HTTP connections to a set
index cc256217317c666f79cc8d39604643d1fcb32b6a..6e72fdb45bd0cde5ca5e90ba189d8a6696df8ef2 100644 (file)
@@ -2,7 +2,7 @@ i18n.commitEncoding::
        Character encoding the commit messages are stored in; Git itself
        does not care per se, but this information is necessary e.g. when
        importing commits from emails or in the gitk graphical history
-       browser (and possibly at other places in the future or in other
+       browser (and possibly in other places in the future or in other
        porcelains). See e.g. linkgit:git-mailinfo[1]. Defaults to 'utf-8'.
 
 i18n.logOutputEncoding::
index 06166fb5c04fe9e1d83d51990f945b11ce1877e9..3d28f7264374e69f45afc9efb201136cb2049c8b 100644 (file)
@@ -4,7 +4,7 @@ imap.folder::
        "[Gmail]/Drafts". Required.
 
 imap.tunnel::
-       Command used to setup a tunnel to the IMAP server through which
+       Command used to set up a tunnel to the IMAP server through which
        commands will be piped instead of using a direct network connection
        to the server. Required when imap.host is not set.
 
@@ -37,7 +37,7 @@ imap.preformattedHTML::
        format=fixed email.  Default is `false`.
 
 imap.authMethod::
-       Specify authenticate method for authentication with IMAP server.
+       Specify the authentication method for authenticating with the IMAP server.
        If Git was built with the NO_CURL option, or if your curl version is older
        than 7.34.0, or if you're running git-imap-send with the `--no-curl`
        option, the only supported method is 'CRAM-MD5'. If this is not set
index 23c7985eb40974e2557c8bd3d271073c0b49bc58..3eff42036033ea90fb751b364a14ced17f5a25ad 100644 (file)
@@ -23,7 +23,7 @@ index.threads::
        Specifies the number of threads to spawn when loading the index.
        This is meant to reduce index load time on multiprocessor machines.
        Specifying 0 or 'true' will cause Git to auto-detect the number of
-       CPU's and set the number of threads accordingly. Specifying 1 or
+       CPUs and set the number of threads accordingly. Specifying 1 or
        'false' will disable multithreading. Defaults to 'true'.
 
 index.version::
index 5f96cf87fb96ce7366f11f80b48f9c9bf9fd13f6..9003a8219143ab75524391303df2f88ca8922e86 100644 (file)
@@ -9,7 +9,7 @@ log.date::
        `--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
+"foo" will be used for the date format. Otherwise, "default" will
 be used.
 
 log.decorate::
index 3854d4ae37cd77efca402a3911220baf4f0eb37d..ec3a5d81f7255aab044eea2b3667bb35c01236f2 100644 (file)
@@ -1,6 +1,6 @@
 mailinfo.scissors::
        If true, makes linkgit:git-mailinfo[1] (and therefore
        linkgit:git-am[1]) act by default as if the --scissors option
-       was provided on the command-line. When active, this features
+       was provided on the command-line. When active, this feature
        removes everything from the message body before a scissors
        line (i.e. consisting mainly of ">8", "8<" and "-").
index 18f056213145e595d0a57792e716f29521122997..69a4f05153e3ba08fda7d181d5d8defc3351cbd4 100644 (file)
@@ -12,7 +12,7 @@ maintenance.strategy::
        then that value is used instead of the one provided by
        `maintenance.strategy`. The possible strategy strings are:
 +
-* `none`: This default setting implies no task are run at any schedule.
+* `none`: This default setting implies no tasks are run at any schedule.
 * `incremental`: This setting optimizes for performing small maintenance
   activities that do not delete any data. This does not schedule the `gc`
   task, but runs the `prefetch` and `commit-graph` tasks hourly, the
index a727d987a8d48c3f4e6b43acd852d77da8f8b108..5a0f82cc2327a2007df24f4582e05a223959e7a0 100644 (file)
@@ -5,7 +5,7 @@ man.viewer::
 man.<tool>.cmd::
        Specify the command to invoke the specified man viewer. The
        specified command is evaluated in shell with the man page
-       passed as argument. (See linkgit:git-help[1].)
+       passed as an argument. (See linkgit:git-help[1].)
 
 man.<tool>.path::
        Override the path for the given tool that may be used to
index 99e83dd36e53e6079721a5a123fdf6392f4fc2b8..8851b6cedef980c106b9e86541862b517aa1f2ad 100644 (file)
@@ -7,7 +7,7 @@ merge.conflictStyle::
        marker and the original text before the `=======` marker.  The
        "merge" style tends to produce smaller conflict regions than diff3,
        both because of the exclusion of the original text, and because
-       when a subset of lines match on the two sides they are just pulled
+       when a subset of lines match on the two sides, they are just pulled
        out of the conflict region.  Another alternate style, "zdiff3", is
        similar to diff3 but removes matching lines on the two sides from
        the conflict region when those matching lines appear near either
index 56a7eeeffb4336ec05c52e96df59b501a41460bf..294f61efd12fdf863e648b076462f4a9a1aa75b7 100644 (file)
@@ -22,8 +22,8 @@ mergetool.<tool>.trustExitCode::
        For a custom merge command, specify whether the exit code of
        the merge command can be used to determine whether the merge was
        successful.  If this is not set to true then the merge target file
-       timestamp is checked and the merge assumed to have been successful
-       if the file has been updated, otherwise the user is prompted to
+       timestamp is checked, and the merge is assumed to have been successful
+       if the file has been updated; otherwise, the user is prompted to
        indicate the success of the merge.
 
 mergetool.meld.hasOutput::
@@ -37,7 +37,7 @@ mergetool.meld.hasOutput::
 
 mergetool.meld.useAutoMerge::
        When the `--auto-merge` is given, meld will merge all non-conflicting
-       parts automatically, highlight the conflicting parts and wait for
+       parts automatically, highlight the conflicting parts, and wait for
        user decision.  Setting `mergetool.meld.useAutoMerge` to `true` tells
        Git to unconditionally use the `--auto-merge` option with `meld`.
        Setting this value to `auto` makes git detect whether `--auto-merge`
@@ -47,7 +47,7 @@ mergetool.meld.useAutoMerge::
 
 mergetool.vimdiff.layout::
        The vimdiff backend uses this variable to control how its split
-       windows look like. Applies even if you are using Neovim (`nvim`) or
+       windows appear. Applies even if you are using Neovim (`nvim`) or
        gVim (`gvim`) as the merge tool. See BACKEND SPECIFIC HINTS section
 ifndef::git-mergetool[]
        in linkgit:git-mergetool[1].
@@ -55,7 +55,7 @@ endif::[]
        for details.
 
 mergetool.hideResolved::
-       During a merge Git will automatically resolve as many conflicts as
+       During a merge, Git will automatically resolve as many conflicts as
        possible and write the 'MERGED' file containing conflict markers around
        any conflicts that it cannot resolve; 'LOCAL' and 'REMOTE' normally
        represent the versions of the file from before Git's conflict
@@ -74,7 +74,7 @@ mergetool.keepTemporaries::
        When invoking a custom merge tool, Git uses a set of temporary
        files to pass to the tool. If the tool returns an error and this
        variable is set to `true`, then these temporary files will be
-       preserved, otherwise they will be removed after the tool has
+       preserved; otherwise, they will be removed after the tool has
        exited. Defaults to `false`.
 
 mergetool.writeToTemp::
index c7c4811734b5c935c89b52eb3b3ddef58f49689d..43db8e808d7ab763898ce5a860b8d4644bbc9f69 100644 (file)
@@ -1,7 +1,7 @@
 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"
+       `cat_sort_uniq`.  Defaults to `manual`.  See the "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
index d4c7c9d4e4e5d217d72cc90a02dbcb86e39971ca..f50df9dbce89891f0c6d4a5563c5ab73be4325df 100644 (file)
@@ -74,7 +74,7 @@ pack.threads::
        warning. This is meant to reduce packing time on multiprocessor
        machines. The required amount of memory for the delta search window
        is however multiplied by the number of threads.
-       Specifying 0 will cause Git to auto-detect the number of CPU's
+       Specifying 0 will cause Git to auto-detect the number of CPUs
        and set the number of threads accordingly.
 
 pack.indexVersion::
@@ -83,11 +83,11 @@ pack.indexVersion::
        the new pack index with capabilities for packs larger than 4 GB
        as well as proper protection against the repacking of corrupted
        packs.  Version 2 is the default.  Note that version 2 is enforced
-       and this config option ignored whenever the corresponding pack is
+       and this config option is ignored whenever the corresponding pack is
        larger than 2 GB.
 +
 If you have an old Git that does not understand the version 2 `*.idx` file,
-cloning or fetching over a non native protocol (e.g. "http")
+cloning or fetching over a non-native protocol (e.g. "http")
 that will copy both `*.pack` file and corresponding `*.idx` file from the
 other side may give you a repository that cannot be accessed with your
 older version of Git. If the `*.pack` file is smaller than 2 GB, however,
@@ -102,8 +102,8 @@ pack.packSizeLimit::
        in the creation of multiple packfiles.
 +
 Note that this option is rarely useful, and may result in a larger total
-on-disk size (because Git will not store deltas between packs), as well
-as worse runtime performance (object lookup within multiple packs is
+on-disk size (because Git will not store deltas between packs) and
+worse runtime performance (object lookup within multiple packs is
 slower than a single pack, and optimizations like reachability bitmaps
 cannot cope with multiple packs).
 +
@@ -123,6 +123,23 @@ pack.useBitmaps::
        true. You should not generally need to turn this off unless
        you are debugging pack bitmaps.
 
+pack.useBitmapBoundaryTraversal::
+       When true, Git will use an experimental algorithm for computing
+       reachability queries with bitmaps. Instead of building up
+       complete bitmaps for all of the negated tips and then OR-ing
+       them together, consider negated tips with existing bitmaps as
+       additive (i.e. OR-ing them into the result if they exist,
+       ignoring them otherwise), and build up a bitmap at the boundary
+       instead.
++
+When using this algorithm, Git may include too many objects as a result
+of not opening up trees belonging to certain UNINTERESTING commits. This
+inexactness matches the non-bitmap traversal algorithm.
++
+In many cases, this can provide a speed-up over the exact algorithm,
+particularly when there is poor bitmap coverage of the negated side of
+the query.
+
 pack.useSparse::
        When true, git will default to using the '--sparse' option in
        'git pack-objects' when the '--revs' option is present. This
index 43338b65e843dd93b6373cc2edfe3600f7bf200d..0acbbea18a320f8adabf08db4f4570ef58a5edaf 100644 (file)
@@ -35,7 +35,7 @@ push.default::
 
 * `tracking` - This is a deprecated synonym for `upstream`.
 
-* `simple` - pushes the current branch with the same name on the remote.
+* `simple` - push the current branch with the same name on the remote.
 +
 If you are working on a centralized workflow (pushing to the same repository you
 pull from, which is typically `origin`), then you need to configure an upstream
@@ -67,7 +67,7 @@ new default).
 --
 
 push.followTags::
-       If set to true enable `--follow-tags` option by default.  You
+       If set to true, enable `--follow-tags` option by default.  You
        may override this configuration at time of push by specifying
        `--no-follow-tags`.
 
index afaf6dad99b5542ab06c31e4276a695128ee6b8a..9c248accec2c5d572cf11f26ffcbfe8e7eab1465 100644 (file)
@@ -77,3 +77,9 @@ rebase.rebaseMerges::
        equivalent to `--no-rebase-merges`. Passing `--rebase-merges` on the
        command line, with or without an argument, overrides any
        `rebase.rebaseMerges` configuration.
+
+rebase.maxLabelLength::
+       When generating label names from commit subjects, truncate the names to
+       this length. By default, the names are truncated to a little less than
+       `NAME_MAX` (to allow e.g. `.lock` files to be written for the
+       corresponding loose refs).
index 85d5b5a3d2d8bf3952398628c188e4030cc3312d..c77e55b1cdd217e062450679920223a733995f77 100644 (file)
@@ -14,12 +14,12 @@ receive.autogc::
 
 receive.certNonceSeed::
        By setting this variable to a string, `git receive-pack`
-       will accept a `git push --signed` and verifies it by using
+       will accept a `git push --signed` and verify it by using
        a "nonce" protected by HMAC using this string as a secret
        key.
 
 receive.certNonceSlop::
-       When a `git push --signed` sent a push certificate with a
+       When a `git push --signed` sends a push certificate with a
        "nonce" that was issued by a receive-pack serving the same
        repository within this many seconds, export the "nonce"
        found in the certificate to `GIT_PUSH_CERT_NONCE` to the
index 40abdf6a6b5d8872772991c167c879cbb63f0ce5..3a78b5ebb1dc02e1f6cec1647ab94709018df7ff 100644 (file)
@@ -1,7 +1,7 @@
 rerere.autoUpdate::
        When set to true, `git-rerere` updates the index with the
        resulting contents after it cleanly resolves conflicts using
-       previously recorded resolution.  Defaults to false.
+       previously recorded resolutions.  Defaults to false.
 
 rerere.enabled::
        Activate recording of resolved conflicts, so that identical
index bde7f31459b98136a31a7eb1d457c5c43fddea54..577df40223a095b999b38a41df6c3a1cd1252de2 100644 (file)
@@ -14,7 +14,7 @@ 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
+<<SCOPES>>). This prevents untrusted repositories from tampering with
 this value.
 
 safe.directory::
@@ -32,7 +32,7 @@ override any such directories specified in the system config), add a
 `safe.directory` entry with an empty value.
 +
 This config setting is only respected in protected configuration (see
-<<SCOPES>>). This prevents the untrusted repository from tampering with this
+<<SCOPES>>). This prevents untrusted repositories from tampering with this
 value.
 +
 The value of this setting is interpolated, i.e. `~/<path>` expands to a
index 92a9ebe98c63e5fe75eb98237543d41d9f15c502..7fc770ee9e69d77b3743c8bff1b8bef35bb96f36 100644 (file)
@@ -36,7 +36,7 @@ sendemail.aliasesFile::
 
 sendemail.aliasFileType::
        Format of the file(s) specified in sendemail.aliasesFile. Must be
-       one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus', or 'sendmail'.
+       one of 'mutt', 'mailrc', 'pine', 'elm', '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
@@ -91,7 +91,7 @@ sendemail.smtpBatchSize::
        See also the `--batch-size` option of linkgit:git-send-email[1].
 
 sendemail.smtpReloginDelay::
-       Seconds wait before reconnecting to smtp server.
+       Seconds to wait before reconnecting to the smtp server.
        See also the `--relogin-delay` option of linkgit:git-send-email[1].
 
 sendemail.forbidSendmailVariables::
index b48d532a96976ba2b9d967212f9ec2943291375f..e664eef01d10dede9b6a334e84635346e539955a 100644 (file)
@@ -2,4 +2,4 @@ sequence.editor::
        Text editor used by `git rebase -i` for editing the rebase instruction file.
        The value is meant to be interpreted by the shell when it is used.
        It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable.
-       When not configured the default commit message editor is used instead.
+       When not configured, the default commit message editor is used instead.
index afdb186df8ba6d39819d75b0542dcf4d89aafa18..cfaa29610b5a0051bed8119337c6f70ca994747d 100644 (file)
@@ -3,10 +3,10 @@ splitIndex.maxPercentChange::
        percent of entries the split index can contain compared to the
        total number of entries in both the split index and the shared
        index before a new shared index is written.
-       The value should be between 0 and 100. If the value is 0 then
-       a new shared index is always written, if it is 100 a new
+       The value should be between 0 and 100. If the value is 0, then
+       a new shared index is always written; if it is 100, a new
        shared index is never written.
-       By default the value is 20, so a new shared index is written
+       By default, the value is 20, so a new shared index is written
        if the number of entries in the split index would be greater
        than 20 percent of the total number of entries.
        See linkgit:git-update-index[1].
index b9f609ed76b7f3ff41aef03ecf0ea22fd1d355ea..ec1edaeba68aa3351331f03f981ceff9412d0899 100644 (file)
@@ -1,14 +1,14 @@
 stash.showIncludeUntracked::
        If this is set to true, the `git stash show` command will show
        the untracked files of a stash entry.  Defaults to false. See
-       description of 'show' command in linkgit:git-stash[1].
+       the description of the 'show' command in linkgit:git-stash[1].
 
 stash.showPatch::
        If this is set to true, the `git stash show` command without an
        option will show the stash entry in patch form.  Defaults to false.
-       See description of 'show' command in linkgit:git-stash[1].
+       See the description of the 'show' command in linkgit:git-stash[1].
 
 stash.showStat::
        If this is set to true, the `git stash show` command without an
-       option will show diffstat of the stash entry.  Defaults to true.
-       See description of 'show' command in linkgit:git-stash[1].
+       option will show diffstat of the stash entry.  Defaults to true.
+       See the description of the 'show' command in linkgit:git-stash[1].
index 0fc704ab80b2239ed03752846158c59dff56c31b..2ff8237f8fc4585e7a2a4c9e7a27f121bbd9d7e2 100644 (file)
@@ -47,7 +47,7 @@ status.showUntrackedFiles::
        contain only untracked files, are shown with the directory name
        only. Showing untracked files means that Git needs to lstat() all
        the files in the whole repository, which might be slow on some
-       systems. So, this variable controls how the commands displays
+       systems. So, this variable controls how the commands display
        the untracked files. Possible values are:
 +
 --
@@ -62,7 +62,7 @@ of linkgit:git-status[1] and linkgit:git-commit[1].
 
 status.submoduleSummary::
        Defaults to false.
-       If this is set to a non zero number or true (identical to -1 or an
+       If this is set to a non-zero number or true (identical to -1 or an
        unlimited number), the submodule summary will be enabled and a
        summary of commits for modified submodules will be shown (see
        --summary-limit option of linkgit:git-submodule[1]). Please note
index 6490527b45bcd4819be3fe412bcfc0aab7740ee6..0672d9911724d184b7b49ee0e50de3e992a0eac5 100644 (file)
@@ -2,7 +2,7 @@ submodule.<name>.url::
        The URL for a submodule. This variable is copied from the .gitmodules
        file to the git config via 'git submodule init'. The user can change
        the configured URL before obtaining the submodule via 'git submodule
-       update'. If neither submodule.<name>.active or submodule.active are
+       update'. If neither submodule.<name>.active nor submodule.active are
        set, the presence of this variable is used as a fallback to indicate
        whether the submodule is of interest to git commands.
        See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
@@ -35,7 +35,7 @@ submodule.<name>.ignore::
        a submodule as modified. When set to "all", it will never be considered
        modified (but it will nonetheless show up in the output of status and
        commit when it has been staged), "dirty" will ignore all changes
-       to the submodules work tree and
+       to the submodule's work tree and
        takes only differences between the HEAD of the submodule and the commit
        recorded in the superproject into account. "untracked" will additionally
        let submodules with modified tracked files in their work tree show up.
index fe1642f0d40251d466c78639fff44475edb6b25b..3b6bca2b7ae44c99404699745c4da3bfd2633681 100644 (file)
@@ -66,6 +66,6 @@ trace2.destinationDebug::
 
 trace2.maxFiles::
        Integer.  When writing trace files to a target directory, do not
-       write additional traces if we would exceed this many files. Instead,
+       write additional traces if doing so would exceed this many files. Instead,
        write a sentinel file that will block further tracing to this
        directory. Defaults to 0, which disables this check.
index c3ac767d1e4de152865ec82de6a995a9b4934834..a9cbdb88a1fe11f364da005bdfe490cd2e28dc0b 100644 (file)
@@ -7,7 +7,7 @@ transfer.credentialsInUrl::
        and any other direct use of the configured URL.
 +
 Note that this is currently limited to detecting credentials in
-`remote.<name>.url` configuration, it won't detect credentials in
+`remote.<name>.url` configuration; it won't detect credentials in
 `remote.<name>.pushurl` configuration.
 +
 You might want to enable this to prevent inadvertent credentials
@@ -21,12 +21,12 @@ exposure, e.g. because:
   system.
 * The git programs will pass the full URL to one another as arguments
   on the command-line, meaning the credentials will be exposed to other
-  users on OS's or systems that allow other users to see the full
+  unprivileged users on systems that allow them to see the full
   process list of other users. On linux the "hidepid" setting
   documented in procfs(5) allows for configuring this behavior.
 +
 If such concerns don't apply to you then you probably don't need to be
-concerned about credentials exposure due to storing that sensitive
+concerned about credentials exposure due to storing sensitive
 data in git's configuration files. If you do want to use this, set
 `transfer.credentialsInUrl` to one of these values:
 +
index ec9233b060a82c41dd9a01785a6f1e748ddf0ad9..2ffc38d164786fbe7be6a5d3ee770e6869ba7825 100644 (file)
@@ -5,14 +5,14 @@ author.email::
 committer.name::
 committer.email::
        The `user.name` and `user.email` variables determine what ends
-       up in the `author` and `committer` field of commit
+       up in the `author` and `committer` fields of commit
        objects.
        If you need the `author` or `committer` to be different, the
-       `author.name`, `author.email`, `committer.name` or
+       `author.name`, `author.email`, `committer.name`, or
        `committer.email` variables can be set.
-       Also, all of these can be overridden by the `GIT_AUTHOR_NAME`,
+       All of these can be overridden by the `GIT_AUTHOR_NAME`,
        `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,
-       `GIT_COMMITTER_EMAIL` and `EMAIL` environment variables.
+       `GIT_COMMITTER_EMAIL`, and `EMAIL` environment variables.
 +
 Note that the `name` forms of these variables conventionally refer to
 some form of a personal name.  See linkgit:git-commit[1] and the
@@ -40,7 +40,7 @@ user.signingKey::
        your private ssh key or the public key when ssh-agent is used.
        Alternatively it can contain a public key prefixed with `key::`
        directly (e.g.: "key::ssh-rsa XXXXXX identifier"). The private key
-       needs to be available via ssh-agent. If not set git will call
+       needs to be available via ssh-agent. If not set Git will call
        gpg.ssh.defaultKeyCommand (e.g.: "ssh-add -L") and try to use the
        first key available. For backward compatibility, a raw key which
        begins with "ssh-", such as "ssh-rsa XXXXXX identifier", is treated
index 6c7cc054fad2503dabf21073624875d2b6035abe..0cff0908193a29ff5e482cbd3a6780460b3399eb 100644 (file)
@@ -19,14 +19,14 @@ with those suffixes.  E.g. if "-pre" appears before "-rc" in the
 configuration, then all "1.0-preX" tags will be listed before any
 "1.0-rcX" tags.  The placement of the main release tag relative to tags
 with various suffixes can be determined by specifying the empty suffix
-among those other suffixes.  E.g. if the suffixes "-rc", "", "-ck" and
+among those other suffixes.  E.g. if the suffixes "-rc", "", "-ck", and
 "-bfs" appear in the configuration in this order, then all "v4.8-rcX" tags
 are listed first, followed by "v4.8", then "v4.8-ckX" and finally
 "v4.8-bfsX".
 +
-If more than one suffixes match the same tagname, then that tagname will
+If more than one suffix matches the same tagname, then that tagname will
 be sorted according to the suffix which starts at the earliest position in
-the tagname.  If more than one different matching suffixes start at
+the tagname.  If more than one different matching suffix starts at
 that earliest position, then that tagname will be sorted according to the
 longest of those suffixes.
 The sorting order between different suffixes is undefined if they are
index 546adf79e5a52cf100c71154bb9710cc5c68aaf6..4b5aa5c2e045f5c135b96fb9ec03b06aad0b91ea 100644 (file)
@@ -17,7 +17,7 @@ You can customize the creation of patch text via the
 What the -p option produces is slightly different from the traditional
 diff format:
 
-1.   It is preceded with a "git diff" header that looks like this:
+1.   It is preceded by a "git diff" header that looks like this:
 
        diff --git a/file1 b/file2
 +
@@ -25,9 +25,9 @@ The `a/` and `b/` filenames are the same unless rename/copy is
 involved.  Especially, even for a creation or a deletion,
 `/dev/null` is _not_ used in place of the `a/` or `b/` filenames.
 +
-When rename/copy is involved, `file1` and `file2` show the
+When rename/copy is involved, `file1` and `file2` show the
 name of the source file of the rename/copy and the name of
-the file that rename/copy produces, respectively.
+the file that the rename/copy produces, respectively.
 
 2.   It is followed by one or more extended header lines:
 
@@ -77,7 +77,7 @@ separate lines indicate the old and the new mode.
 
 5.  Hunk headers mention the name of the function to which the hunk
     applies.  See "Defining a custom hunk-header" in
-    linkgit:gitattributes[5] for details of how to tailor to this to
+    linkgit:gitattributes[5] for details of how to tailor this to
     specific languages.
 
 
@@ -89,7 +89,7 @@ produce a 'combined diff' when showing a merge. This is the default
 format when showing merges with linkgit:git-diff[1] or
 linkgit:git-show[1]. Note also that you can give suitable
 `--diff-merges` option to any of these commands to force generation of
-diffs in specific format.
+diffs in specific format.
 
 A "combined diff" format looks like this:
 
@@ -123,7 +123,7 @@ index fabadb8,cc95eb0..4866510
                for_each_ref(get_name);
 ------------
 
-1.   It is preceded with a "git diff" header, that looks like
+1.   It is preceded by a "git diff" header, that looks like
      this (when the `-c` option is used):
 
        diff --combined file
@@ -142,22 +142,22 @@ or like this (when the `--cc` option is used):
 +
 The `mode <mode>,<mode>..<mode>` line appears only if at least one of
 the <mode> is different from the rest. Extended headers with
-information about detected contents movement (renames and
-copying detection) are designed to work with diff of two
+information about detected content movement (renames and
+copying detection) are designed to work with the diff of two
 <tree-ish> and are not used by combined diff format.
 
-3.   It is followed by two-line from-file/to-file header
+3.   It is followed by a two-line from-file/to-file header:
 
        --- a/file
        +++ b/file
 +
-Similar to two-line header for traditional 'unified' diff
+Similar to the two-line header for the traditional 'unified' diff
 format, `/dev/null` is used to signal created or deleted
 files.
 +
 However, if the --combined-all-paths option is provided, instead of a
-two-line from-file/to-file you get a N+1 line from-file/to-file header,
-where N is the number of parents in the merge commit
+two-line from-file/to-file, you get an N+1 line from-file/to-file header,
+where N is the number of parents in the merge commit:
 
        --- a/file
        --- a/file
@@ -197,7 +197,7 @@ added, from the point of view of that parent).
 In the above example output, the function signature was changed
 from both files (hence two `-` removals from both file1 and
 file2, plus `++` to mean one line that was added does not appear
-in either file1 or file2).  Also eight other lines are the same
+in either file1 or file2).  Also, eight other lines are the same
 from file1 but do not appear in file2 (hence prefixed with `+`).
 
 When shown by `git diff-tree -c`, it compares the parents of a
index 08ab86189a7b62cf88898d04a57ed3e943bdc311..53ec3c9a3476bd12b8a8f4b6c31552b2767d8366 100644 (file)
@@ -22,84 +22,94 @@ ifndef::git-format-patch[]
 -p::
 -u::
 --patch::
-       Generate patch (see section titled
-ifdef::git-log[]
-<<generate_patch_text_with_p, "Generating patch text with -p">>).
-endif::git-log[]
-ifndef::git-log[]
-"Generating patch text with -p").
-endif::git-log[]
+       Generate patch (see <<generate_patch_text_with_p>>).
 ifdef::git-diff[]
        This is the default.
 endif::git-diff[]
 
 -s::
 --no-patch::
-       Suppress diff output. Useful for commands like `git show` that
-       show the patch by default, or to cancel the effect of `--patch`.
+       Suppress all output from the diff machinery.  Useful for
+       commands like `git show` that show the patch by default to
+       squelch their output, or to cancel the effect of options like
+       `--patch`, `--stat` earlier on the command line in an alias.
+
 endif::git-format-patch[]
 
 ifdef::git-log[]
---diff-merges=(off|none|on|first-parent|1|separate|m|combined|c|dense-combined|cc|remerge|r)::
+-m::
+       Show diffs for merge commits in the default format. This is
+       similar to '--diff-merges=on', except `-m` will
+       produce no output unless `-p` is given as well.
+
+-c::
+       Produce combined diff output for merge commits.
+       Shortcut for '--diff-merges=combined -p'.
+
+--cc::
+       Produce dense combined diff output for merge commits.
+       Shortcut for '--diff-merges=dense-combined -p'.
+
+--dd::
+       Produce diff with respect to first parent for both merge and
+       regular commits.
+       Shortcut for '--diff-merges=first-parent -p'.
+
+--remerge-diff::
+       Produce remerge-diff output for merge commits.
+       Shortcut for '--diff-merges=remerge -p'.
+
 --no-diff-merges::
+       Synonym for '--diff-merges=off'.
+
+--diff-merges=<format>::
        Specify diff format to be used for merge commits. Default is
-       {diff-merges-default} unless `--first-parent` is in use, in which case
-       `first-parent` is the default.
+       {diff-merges-default} unless `--first-parent` is in use, in
+       which case `first-parent` is the default.
 +
---diff-merges=(off|none):::
---no-diff-merges:::
+The following formats are supported:
++
+--
+off, none::
        Disable output of diffs for merge commits. Useful to override
        implied value.
 +
---diff-merges=on:::
---diff-merges=m:::
--m:::
-       This option makes diff output for merge commits to be shown in
-       the default format. `-m` will produce the output only if `-p`
-       is given as well. The default format could be changed using
-       `log.diffMerges` configuration parameter, which default value
+on, m::
+       Make diff output for merge commits to be shown in the default
+       format. The default format can be changed using
+       `log.diffMerges` configuration variable, whose default value
        is `separate`.
 +
---diff-merges=first-parent:::
---diff-merges=1:::
-       This option makes merge commits show the full diff with
-       respect to the first parent only.
+first-parent, 1::
+       Show full diff with respect to first parent. This is the same
+       format as `--patch` produces for non-merge commits.
 +
---diff-merges=separate:::
-       This makes merge commits show the full diff with respect to
-       each of the parents. Separate log entry and diff is generated
-       for each parent.
+separate::
+       Show full diff with respect to each of parents.
+       Separate log entry and diff is generated for each parent.
 +
---diff-merges=remerge:::
---diff-merges=r:::
---remerge-diff:::
-       With this option, two-parent merge commits are remerged to
-       create a temporary tree object -- potentially containing files
-       with conflict markers and such.  A diff is then shown between
-       that temporary tree and the actual merge commit.
+combined, c::
+       Show differences from each of the parents to the merge
+       result simultaneously instead of showing pairwise diff between
+       a parent and the result one at a time. Furthermore, it lists
+       only files which were modified from all parents.
++
+dense-combined, cc::
+       Further compress output produced by `--diff-merges=combined`
+       by omitting uninteresting hunks whose contents in the parents
+       have only two variants and the merge result picks one of them
+       without modification.
++
+remerge, r::
+       Remerge two-parent merge commits to create a temporary tree
+       object--potentially containing files with conflict markers
+       and such.  A diff is then shown between that temporary tree
+       and the actual merge commit.
 +
 The output emitted when this option is used is subject to change, and
 so is its interaction with other options (unless explicitly
 documented).
-+
---diff-merges=combined:::
---diff-merges=c:::
--c:::
-       With this option, diff output for a merge commit shows the
-       differences from each of the parents to the merge result
-       simultaneously instead of showing pairwise diff between a
-       parent and the result one at a time. Furthermore, it lists
-       only files which were modified from all parents. `-c` implies
-       `-p`.
-+
---diff-merges=dense-combined:::
---diff-merges=cc:::
---cc:::
-       With this option the output produced by
-       `--diff-merges=combined` is further compressed by omitting
-       uninteresting hunks whose contents in the parents have only
-       two variants and the merge result picks one of them without
-       modification.  `--cc` implies `-p`.
+--
 
 --combined-all-paths::
        This flag causes combined diffs (used for merge commits) to
@@ -207,14 +217,15 @@ have to use `--diff-algorithm=default` option.
        part. Maximum width defaults to terminal width, or 80 columns
        if not connected to a terminal, and can be overridden by
        `<width>`. The width of the filename part can be limited by
-       giving another width `<name-width>` after a comma. The width
-       of the graph part can be limited by using
-       `--stat-graph-width=<width>` (affects all commands generating
-       a stat graph) or by setting `diff.statGraphWidth=<width>`
-       (does not affect `git format-patch`).
-       By giving a third parameter `<count>`, you can limit the
-       output to the first `<count>` lines, followed by `...` if
-       there are more.
+       giving another width `<name-width>` after a comma or by setting
+       `diff.statNameWidth=<width>`. The width of the graph part can be
+       limited by using `--stat-graph-width=<width>` or by setting
+       `diff.statGraphWidth=<width>`. Using `--stat` or
+       `--stat-graph-width` affects all commands generating a stat graph,
+       while setting `diff.statNameWidth` or `diff.statGraphWidth`
+       does not affect `git format-patch`.
+       By giving a third parameter `<count>`, you can limit the output to
+       the first `<count>` lines, followed by `...` if there are more.
 +
 These parameters can also be set individually with `--stat-width=<width>`,
 `--stat-name-width=<name-width>` and `--stat-count=<count>`.
@@ -303,7 +314,7 @@ ifndef::git-format-patch[]
 
 -z::
 ifdef::git-log[]
-       Separate the commits with NULs instead of with new newlines.
+       Separate the commits with NULs instead of newlines.
 +
 Also, when `--raw` or `--numstat` has been given, do not munge
 pathnames and use NULs as output field terminators.
@@ -735,7 +746,7 @@ matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
 --rotate-to=<file>::
        Discard the files before the named <file> from the output
        (i.e. 'skip to'), or move them to the end of the output
-       (i.e. 'rotate to').  These were invented primarily for use
+       (i.e. 'rotate to').  These options were invented primarily for the use
        of the `git difftool` command, and may not be very useful
        otherwise.
 
index 41fc7ca3c67f5d31d5a771de906394480f265d9f..a1d6633a4f15b719a33615ca0ce2805ec2fa0b3e 100644 (file)
@@ -43,7 +43,7 @@ the current repository has the same history as the source repository.
 --update-shallow::
        By default when fetching from a shallow repository,
        `git fetch` refuses refs that require updating
-       .git/shallow. This option updates .git/shallow and accept such
+       .git/shallow. This option updates .git/shallow and accepts such
        refs.
 
 --negotiation-tip=<commit|glob>::
@@ -96,7 +96,7 @@ endif::git-pull[]
 
 -f::
 --force::
-       When 'git fetch' is used with `<src>:<dst>` refspec it may
+       When 'git fetch' is used with `<src>:<dst>` refspec, it may
        refuse to update the local branch as discussed
 ifdef::git-pull[]
        in the `<refspec>` part of the linkgit:git-fetch[1]
index 12eae8a2225a3c4d216fd05c874c1ed2930b5545..f643585a34e7617806c63b8f4afa7a4105bb989b 100644 (file)
 `hasDotgit`::
        (WARN) A tree contains an entry named `.git`.
 
+`largePathname`::
+       (WARN) A tree contains an entry with a very long path name. If
+       the value of `fsck.largePathname` contains a colon, that value
+       is used as the maximum allowable length (e.g., "warn:10" would
+       complain about any path component of 11 or more bytes). The
+       default value is 4096.
+
 `mailmapSymlink`::
        (INFO) `.mailmap` is a symlink.
 
        (ERROR) Missing space before date in an author/committer line.
 
 `missingSpaceBeforeEmail`::
-       (ERROR) Missing space before the email in author/committer line.
+       (ERROR) Missing space before the email in an author/committer line.
 
 `missingTag`::
        (ERROR) Unexpected end after `type` line in a tag object.
        (FATAL) Missing end-of-line in the object header.
 
 `zeroPaddedDate`::
-       (ERROR) Found a zero padded date in an author/commiter line.
+       (ERROR) Found a zero padded date in an author/committer line.
 
 `zeroPaddedFilemode`::
        (WARN) Found a zero padded filemode in a tree.
index 900be198b14e933d19f87febd9860cb0c67a6bf0..e080458d6c45891ec1db74b9df155aeab111e79f 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
         [--[no-]3way] [--interactive] [--committer-date-is-author-date]
         [--ignore-date] [--ignore-space-change | --ignore-whitespace]
-        [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
+        [--whitespace=<action>] [-C<n>] [-p<n>] [--directory=<dir>]
         [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
         [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
         [--quoted-cr=<action>]
@@ -22,8 +22,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Splits mail messages in a mailbox into commit log message,
-authorship information and patches, and applies them to the
+Splits mail messages in a mailbox into commit log messages,
+authorship information, and patches, and applies them to the
 current branch. You could think of it as a reverse operation
 of linkgit:git-format-patch[1] run on a branch with a straight
 history without merges.
@@ -69,7 +69,7 @@ OPTIONS
 --empty=(stop|drop|keep)::
        By default, or when the option is set to 'stop', the command
        errors out on an input e-mail message lacking a patch
-       and stops into the middle of the current am session. When this
+       and stops in the middle of the current am session. When this
        option is set to 'drop', skip such an e-mail message instead.
        When this option is set to 'keep', create an empty commit,
        recording the contents of the e-mail message as its log.
@@ -94,7 +94,7 @@ OPTIONS
        Pass `-u` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
        The proposed commit log message taken from the e-mail
        is re-coded into UTF-8 encoding (configuration variable
-       `i18n.commitEncoding` can be used to specify project's
+       `i18n.commitEncoding` can be used to specify the project's
        preferred encoding if it is not UTF-8).
 +
 This was optional in prior versions of git, but now it is the
@@ -118,7 +118,7 @@ include::rerere-options.txt[]
 
 --ignore-space-change::
 --ignore-whitespace::
---whitespace=<option>::
+--whitespace=<action>::
 -C<n>::
 -p<n>::
 --directory=<dir>::
@@ -134,7 +134,7 @@ include::rerere-options.txt[]
        automatically. This option allows the user to bypass the automatic
        detection and specify the patch format that the patch(es) should be
        interpreted as. Valid formats are mbox, mboxrd,
-       stgit, stgit-series and hg.
+       stgit, stgit-series, and hg.
 
 -i::
 --interactive::
@@ -192,7 +192,7 @@ include::rerere-options.txt[]
 
 --abort::
        Restore the original branch and abort the patching operation.
-       Revert contents of files involved in the am operation to their
+       Revert the contents of files involved in the am operation to their
        pre-am state.
 
 --quit::
index 5e16e6db7e2e0273dacbb76b5d7f4cd6ee0462ec..9cce68a38be10f3a4ff3130adb1a2b300835cdcb 100644 (file)
@@ -23,8 +23,8 @@ DESCRIPTION
 Reads the supplied diff output (i.e. "a patch") and applies it to files.
 When running from a subdirectory in a repository, patched paths
 outside the directory are ignored.
-With the `--index` option the patch is also applied to the index, and
-with the `--cached` option the patch is only applied to the index.
+With the `--index` option, the patch is also applied to the index, and
+with the `--cached` option, the patch is only applied to the index.
 Without these options, the command applies the patch only to files,
 and does not require them to be in a Git repository.
 
@@ -52,7 +52,7 @@ OPTIONS
 --summary::
        Instead of applying the patch, output a condensed
        summary of information obtained from git diff extended
-       headers, such as creations, renames and mode changes.
+       headers, such as creations, renames, and mode changes.
        Turns off "apply".
 
 --check::
@@ -140,7 +140,7 @@ linkgit:git-config[1]).
        applying a diff generated with `--unified=0`. To bypass these
        checks use `--unidiff-zero`.
 +
-Note, for the reasons stated above usage of context-free patches is
+Note, for the reasons stated above, the usage of context-free patches is
 discouraged.
 
 --apply::
@@ -159,9 +159,9 @@ discouraged.
 
 --allow-binary-replacement::
 --binary::
-       Historically we did not allow binary patch applied
+       Historically we did not allow binary patch application
        without an explicit permission from the user, and this
-       flag was the way to do so.  Currently we always allow binary
+       flag was the way to do so.  Currently, we always allow binary
        patch application, so this is a no-op.
 
 --exclude=<path-pattern>::
@@ -257,7 +257,7 @@ the `--unsafe-paths` option to override this safety check.  This option
 has no effect when `--index` or `--cached` is in use.
 
 --allow-empty::
-       Don't return error for patches containing no diff. This includes
+       Don't return an error for patches containing no diff. This includes
        empty patches and patches with commit text only.
 
 CONFIGURATION
index 6bab201d37548dd5c4f911baf981f3fc1995a889..98526f2bebad16e2814f084005c12c2359378ec2 100644 (file)
@@ -21,14 +21,14 @@ structure for the named tree, and writes it out to the standard
 output.  If <prefix> is specified it is
 prepended to the filenames in the archive.
 
-'git archive' behaves differently when given a tree ID versus when
-given a commit ID or tag ID.  In the first case the current time is
-used as the modification time of each file in the archive.  In the latter
-case the commit time as recorded in the referenced commit object is
-used instead.  Additionally the commit ID is stored in a global
-extended pax header if the tar format is used; it can be extracted
-using 'git get-tar-commit-id'. In ZIP files it is stored as a file
-comment.
+'git archive' behaves differently when given a tree ID as opposed to a
+commit ID or tag ID. When a tree ID is provided, the current time is
+used as the modification time of each file in the archive. On the
+other hand, when a commit ID or tag ID is provided, the commit time as
+recorded in the referenced commit object is used instead.
+Additionally the commit ID is stored in a global extended pax header
+if the tar format is used; it can be extracted using 'git
+get-tar-commit-id'. In ZIP files it is stored as a file comment.
 
 OPTIONS
 -------
index fbb39fbdf5d62a455c8b62d4870817998d0434ad..191b4a42b6dcca3f270e9087ad9f7aa6b214f0e0 100644 (file)
@@ -16,7 +16,7 @@ DESCRIPTION
 The command takes various subcommands, and different options depending
 on the subcommand:
 
- git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
+ git bisect start [--term-(new|bad)=<term-new> --term-(old|good)=<term-old>]
                  [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
  git bisect (bad|new|<term-new>) [<rev>]
  git bisect (good|old|<term-old>) [<rev>...]
@@ -26,7 +26,7 @@ on the subcommand:
  git bisect (visualize|view)
  git bisect replay <logfile>
  git bisect log
- git bisect run <cmd>...
+ git bisect run <cmd> [<arg>...]
  git bisect help
 
 This command uses a binary search algorithm to find which commit in
@@ -204,9 +204,14 @@ as an alternative to `visualize`):
 $ git bisect visualize
 ------------
 
-If the `DISPLAY` environment variable is not set, 'git log' is used
-instead.  You can also give command-line options such as `-p` and
-`--stat`.
+Git detects a graphical environment through various environment variables:
+`DISPLAY`, which is set in X Window System environments on Unix systems.
+`SESSIONNAME`, which is set under Cygwin in interactive desktop sessions.
+`MSYSTEM`, which is set under Msys2 and Git for Windows.
+`SECURITYSESSIONID`, which may be set on macOS in interactive desktop sessions.
+
+If none of these environment variables is set, 'git log' is used instead.
+You can also give command-line options such as `-p` and `--stat`.
 
 ------------
 $ git bisect visualize --stat
index f69a871a96f7589015c723ccdfdd95c6c1d610ed..5720d04ffe4e7434c1798cad4833e233fc71f534 100644 (file)
@@ -77,7 +77,7 @@ include::blame-options.txt[]
 
 -e::
 --show-email::
-       Show the author email instead of author name (Default: off).
+       Show the author email instead of the author name (Default: off).
        This can also be controlled via the `blame.showEmail` config
        option.
 
@@ -100,7 +100,7 @@ When neither `--porcelain` nor `--incremental` option is specified,
 `git blame` will output annotation for each line with:
 
 - abbreviated object name for the commit the line came from;
-- author ident (by default author name and date, unless `-s` or `-e`
+- author ident (by default the author name and date, unless `-s` or `-e`
   is specified); and
 - line number
 
@@ -128,7 +128,7 @@ at least once for each commit:
 - the filename in the commit that the line is attributed to.
 - the first line of the commit log message ("summary").
 
-The contents of the actual line is output after the above
+The contents of the actual line are output after the above
 header, prefixed by a TAB. This is to allow adding more
 header elements later.
 
@@ -170,7 +170,7 @@ which limits the annotation to the body of the `hello` subroutine.
 
 When you are not interested in changes older than version
 v2.6.18, or changes older than 3 weeks, you can use revision
-range specifiers  similar to 'git rev-list':
+range specifiers similar to 'git rev-list':
 
        git blame v2.6.18.. -- foo
        git blame --since=3.weeks -- foo
index d207da9101a5cfe6441a03360191d3b6b8a73a46..4395aa935438aaac47cfe41f5db7a1eadafe8a25 100644 (file)
@@ -324,7 +324,7 @@ superproject's "origin/main", but tracks the submodule's "origin/main".
        multiple times, in which case the last key becomes the primary
        key. The keys supported are the same as those in `git
        for-each-ref`. Sort order defaults to the value configured for the
-       `branch.sort` variable if exists, or to sorting based on the
+       `branch.sort` variable if it exists, or to sorting based on the
        full refname (including `refs/...` prefix). This lists
        detached HEAD (if present) first, then local branches and
        finally remote-tracking branches. See linkgit:git-config[1].
index eca726e57911af2cc1f0643cafdcf887c20bfa32..392d9eb6aec6b0d43930c93a322f415dc75b4c5c 100644 (file)
@@ -13,10 +13,11 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Captures information about the user's machine, Git client, and repository state,
-as well as a form requesting information about the behavior the user observed,
-into a single text file which the user can then share, for example to the Git
-mailing list, in order to report an observed bug.
+Collects information about the user's machine, Git client, and repository
+state, in addition to a form requesting information about the behavior the
+user observed, and stores it in a single text file which the user can then
+share, for example to the Git mailing list, in order to report an observed
+bug.
 
 The following information is requested from the user:
 
index 411de2e27ddc0db762ec9be6ceec18a7fc1bf069..bd95a6c10a7d0b1ee16b619c4b546c8d9c0b0e13 100644 (file)
@@ -3,8 +3,7 @@ git-cat-file(1)
 
 NAME
 ----
-git-cat-file - Provide content or type and size information for repository objects
-
+git-cat-file - Provide contents or details of repository objects
 
 SYNOPSIS
 --------
@@ -12,25 +11,24 @@ SYNOPSIS
 'git cat-file' <type> <object>
 'git cat-file' (-e | -p) <object>
 '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] [-z]
 'git cat-file' (--textconv | --filters)
             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
+'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
+            [--buffer] [--follow-symlinks] [--unordered]
+            [--textconv | --filters] [-Z]
 
 DESCRIPTION
 -----------
-In its first form, the command provides the content or the type of an object in
-the repository. The type is required unless `-t` or `-p` is used to find the
-object type, or `-s` is used to find the object size, or `--textconv` or
-`--filters` is used (which imply type "blob").
-
-In the second form, a list of objects (separated by linefeeds) is provided on
-stdin, and the SHA-1, type, and size of each object is printed on stdout. The
-output format can be overridden using the optional `<format>` argument. If
-either `--textconv` or `--filters` was specified, the input is expected to
-list the object names followed by the path name, separated by a single
-whitespace, so that the appropriate drivers can be determined.
+Output the contents or other properties such as size, type or delta
+information of one or more objects.
+
+This command can operate in two modes, depending on whether an option
+from the `--batch` family is specified.
+
+In non-batch mode, the command provides information on an object
+named on the command line.
+
+In batch mode, arguments are read from standard input.
 
 OPTIONS
 -------
@@ -51,8 +49,8 @@ OPTIONS
 
 -e::
        Exit with zero status if `<object>` exists and is a valid
-       object. If `<object>` is of an invalid format exit with non-zero and
-       emits an error on stderr.
+       object. If `<object>` is of an invalid format, exit with non-zero
+       status and emit an error on stderr.
 
 -p::
        Pretty-print the contents of `<object>` based on its type.
@@ -243,10 +241,16 @@ respectively print:
        /etc/passwd
 --
 
+-Z::
+       Only meaningful with `--batch`, `--batch-check`, or
+       `--batch-command`; input and output is NUL-delimited instead of
+       newline-delimited.
+
 -z::
        Only meaningful with `--batch`, `--batch-check`, or
        `--batch-command`; input is NUL-delimited instead of
-       newline-delimited.
+       newline-delimited. This option is deprecated in favor of
+       `-Z` as the output can otherwise be ambiguous.
 
 
 OUTPUT
@@ -384,6 +388,11 @@ notdir SP <size> LF
 is printed when, during symlink resolution, a file is used as a
 directory name.
 
+Alternatively, when `-Z` is passed, the line feeds in any of the above examples
+are replaced with NUL terminators. This ensures that output will be parsable if
+the output itself would contain a linefeed and is thus recommended for
+scripting purposes.
+
 CAVEATS
 -------
 
index 6e4f3aaf34c9579004be4c3f8d644287913f1505..cb5a6c8f335e128408e9b6b54cbb4037751e7932 100644 (file)
@@ -29,7 +29,7 @@ OPTIONS
 
 --stdin::
        Read pathnames from the standard input, one per line,
-       instead of from the command-line.
+       instead of from the command line.
 
 -z::
        The output format is modified to be machine-parsable.
@@ -38,7 +38,7 @@ OPTIONS
 
 --source=<tree-ish>::
        Check attributes against the specified tree-ish. It is common to
-       specify the source tree by naming a commit, branch or tag associated
+       specify the source tree by naming a commit, branch, or tag associated
        with it.
 
 \--::
@@ -60,7 +60,7 @@ unless `-z` is in effect, in which case NUL is used as delimiter:
 
 
 <path> is the path of a file being queried, <attribute> is an attribute
-being queried and <info> can be either:
+being queried, and <info> can be either:
 
 'unspecified';; when the attribute is not defined for the path.
 'unset';;      when the attribute is defined as false.
index 2892799e32f9855bba3b5244e7051d11618fa846..3e3b4e344629d951e7318dace83f38d5752fc76c 100644 (file)
@@ -50,7 +50,7 @@ linkgit:gitignore[5].
        with a NUL character instead of a linefeed character.
 
 -n, --non-matching::
-       Show given paths which don't match any pattern.  This only
+       Show given paths which don't match any pattern.  This only
        makes sense when `--verbose` is enabled, otherwise it would
        not be possible to distinguish between paths which match a
        pattern and those which don't.
index ee6a4144fbef1aebf422c2e393b6d38c8fb4fb60..2aacfd18088d6506bfd8aa3ca7380888e8dbcffa 100644 (file)
@@ -48,7 +48,7 @@ Git imposes the following rules on how references are named:
 
 . They cannot begin or end with a slash `/` or contain multiple
   consecutive slashes (see the `--normalize` option below for an
-  exception to this rule)
+  exception to this rule).
 
 . They cannot end with a dot `.`.
 
@@ -85,7 +85,7 @@ The rule `git check-ref-format --branch $name` implements
 may be stricter than what `git check-ref-format refs/heads/$name`
 says (e.g. a dash may appear at the beginning of a ref component,
 but it is explicitly forbidden at the beginning of a branch name).
-When run with `--branch` option in a repository, the input is first
+When run with the `--branch` option in a repository, the input is first
 expanded for the ``previous checkout syntax''
 `@{-n}`.  For example, `@{-1}` is a way to refer the last thing that
 was checked out using "git switch" or "git checkout" operation.
index 01dbd5cbf540ea96de2a1fd9b9ce0580077c29fa..faf8d6ca36fb7c3bfd7a8e880efe284746cdc94d 100644 (file)
@@ -18,7 +18,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Will copy all files listed from the index to the working directory
+Copies all listed files from the index to the working directory
 (not overwriting existing files).
 
 OPTIONS
@@ -53,11 +53,11 @@ OPTIONS
 
 --stage=<number>|all::
        Instead of checking out unmerged entries, copy out the
-       files from named stage.  <number> must be between 1 and 3.
+       files from the named stage.  <number> must be between 1 and 3.
        Note: --stage=all automatically implies --temp.
 
 --temp::
-       Instead of copying the files to the working directory
+       Instead of copying the files to the working directory,
        write the content to temporary files.  The temporary name
        associations will be written to stdout.
 
@@ -66,8 +66,8 @@ OPTIONS
        set.
 
 --stdin::
-       Instead of taking list of paths from the command line,
-       read list of paths from the standard input.  Paths are
+       Instead of taking list of paths from the command line,
+       read the list of paths from the standard input.  Paths are
        separated by LF (i.e. one path per line) by default.
 
 -z::
index 4af0904f4729b463d3b63bf3479f5e4b313773fd..240c54639e8e85b5a3ecf1fb8fec0266614ec9b5 100644 (file)
@@ -12,8 +12,10 @@ SYNOPSIS
 'git checkout' [-q] [-f] [-m] --detach [<branch>]
 'git checkout' [-q] [-f] [-m] [--detach] <commit>
 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new-branch>] [<start-point>]
-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...
-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' [-f] <tree-ish> [--] <pathspec>...
+'git checkout' [-f] <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>...
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]
 'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]
 
 DESCRIPTION
@@ -41,7 +43,7 @@ $ git checkout -b <branch> --track <remote>/<branch>
 You could omit `<branch>`, in which case the command degenerates to
 "check out the current branch", which is a glorified no-op with
 rather expensive side-effects to show only the tracking information,
-if exists, for the current branch.
+if it exists, for the current branch.
 
 'git checkout' -b|-B <new-branch> [<start-point>]::
 
@@ -260,7 +262,8 @@ and mark the resolved paths with `git add` (or `git rm` if the merge
 should result in deletion of the path).
 +
 When checking out paths from the index, this option lets you recreate
-the conflicted merge in the specified paths.
+the conflicted merge in the specified paths.  This option cannot be
+used when checking out paths from a tree-ish.
 +
 When switching branches with `--merge`, staged changes may be lost.
 
index 160d08b86bb8583e9464373aef9cafea638003cb..69331e3f05a13eed6ffb084e292f8452b241f13c 100644 (file)
@@ -103,7 +103,7 @@ filter by pattern::
    This shows the files and directories to be deleted and issues an
    "Input ignore patterns>>" prompt. You can input space-separated
    patterns to exclude files and directories from deletion.
-   E.g. "*.c *.h" will excludes files end with ".c" and ".h" from
+   E.g. "*.c *.h" will exclude files ending with ".c" and ".h" from
    deletion. When you are satisfied with the filtered result, press
    ENTER (empty) back to the main menu.
 
@@ -127,7 +127,7 @@ ask each::
 
 quit::
 
-  This lets you quit without do cleaning.
+  This lets you quit without doing any cleaning.
 
 help::
 
index 225c6c9f2e5f8f513e1e56ae77bc45d8c2097da4..a6cef5d82038771c5f7e91f788f14de6394de158 100644 (file)
@@ -541,7 +541,7 @@ DISCUSSION
 ----------
 
 Though not required, it's a good idea to begin the commit message
-with a single short (less than 50 character) line summarizing the
+with a single short (no more than 50 characters) line summarizing the
 change, followed by a blank line and then a more thorough description.
 The text up to the first blank line in a commit message is treated
 as the commit title, and that title is used throughout Git.
index 7a2bcb2f6cb6f94b677d47de49ae8c6d0b98f2b8..b1caac887ae2dc5ce683ab4c6d91eed849403afe 100644 (file)
@@ -201,7 +201,7 @@ Valid `<type>`'s include:
   1073741824 upon input.
 - 'bool-or-int': canonicalize according to either 'bool' or 'int', as described
   above.
-- 'path': canonicalize by adding a leading `~` to the value of `$HOME` and
+- 'path': canonicalize by expanding a leading `~` to the value of `$HOME` and
   `~user` to the home directory for the specified user. This specifier has no
   effect when setting the value (but you can use `git config section.variable
   ~/` from the command line to let your shell do the expansion.)
index cb9b4d2e460adaa46ee863c37283840c2bdb9333..97f9f1261010f5473b6748dc3dc0a2e0a93fd4f5 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This counts the number of unpacked object files and disk space consumed by
+Counts the number of unpacked object files and disk space consumed by
 them, to help you decide when it is a good time to repack.
 
 
@@ -20,7 +20,7 @@ OPTIONS
 -------
 -v::
 --verbose::
-       Report in more detail:
+       Provide more detailed reports:
 +
 count: the number of loose objects
 +
@@ -33,7 +33,7 @@ size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
 prune-packable: the number of loose objects that are also present in
 the packs. These objects could be pruned using `git prune-packed`.
 +
-garbage: the number of files in object database that are neither valid loose
+garbage: the number of files in the object database that are neither valid loose
 objects nor valid packs
 +
 size-garbage: disk space consumed by garbage files, in KiB (unless -H is
index f473994a864e9575d57844e1640e8dfb4eea00dd..487cc557a87feaa688d5e333dcecd2f83eb1ec48 100644 (file)
@@ -16,7 +16,7 @@ DESCRIPTION
 
 This command caches credentials for use by future Git programs.
 The stored credentials are kept in memory of the cache-daemon
-process (instead of written to a file) and are forgotten after a
+process (instead of being written to a file) and are forgotten after a
 configurable timeout. Credentials are forgotten sooner if the
 cache-daemon dies, for example if the system restarts. The cache
 is accessible over a Unix domain socket, restricted to the current
index 76b0798856336fe739e8325ed1b5716abb099bfe..71864a872642e85734d86f1c52479e7a22b1dfe0 100644 (file)
@@ -33,7 +33,7 @@ OPTIONS
 
        Use `<path>` to lookup and store credentials. The file will have its
        filesystem permissions set to prevent other users on the system
-       from reading it, but will not be encrypted or otherwise
+       from reading it, but it will not be encrypted or otherwise
        protected. If not specified, credentials will be searched for from
        `~/.git-credentials` and `$XDG_CONFIG_HOME/git/credentials`, and
        credentials will be written to `~/.git-credentials` if it exists, or
index 0e6d9e85ec7074986f5b081abc48a98d27fa5200..918a0aa42b24156ce814ba61cd2006928807ee08 100644 (file)
@@ -39,7 +39,7 @@ for later use.
 
 If the action is `reject`, git-credential will send the description to
 any configured credential helpers, which may erase any stored
-credential matching the description.
+credentials matching the description.
 
 If the action is `approve` or `reject`, no output should be emitted.
 
@@ -94,7 +94,7 @@ unlocked) before it returned `password=secr3t`.
      that `git credential` will ask for a new password in its next
      invocation. In either case, `git credential` should be fed with
      the credential description obtained from step (2) (which also
-     contain the ones provided in step (1)).
+     contains the fields provided in step (1)).
 
 [[IOFMT]]
 INPUT/OUTPUT FORMAT
index 53f111bc0acaf08a0a208501a32973cd420d0b35..cf4a5a283ecd68f49fb3051b2f27007074eac4ef 100644 (file)
@@ -118,7 +118,7 @@ for example:
    myuser:$5$.NqmNH1vwfzGpV8B$znZIcumu1tNLATgV2l6e1/mY8RzhUDHMOaVOeL1cxV3
 ------
 You can use the 'htpasswd' facility that comes with Apache to make these
-files, but only with the -d option (or -B if your system suports it).
+files, but only with the -d option (or -B if your system supports it).
 
 Preferably use the system specific utility that manages password hash
 creation in your platform (e.g. mkpasswd in Linux, encrypt in OpenBSD or
index 236df516c7313d702f9908229afa4d4030e154ab..e064f91c9e35899abd70f78a6f37158a0794f113 100644 (file)
@@ -138,7 +138,7 @@ otherwise `stderr`.
 --user-path::
 --user-path=<path>::
        Allow {tilde}user notation to be used in requests.  When
-       specified with no parameter, requests to
+       specified with no parameter, a request to
        git://host/{tilde}alice/foo is taken as a request to access
        'foo' repository in the home directory of user `alice`.
        If `--user-path=path` is specified, the same request is
index c6a79c2a0f29ccc1f87c331382b484ab9a1c5a62..08ff715709ccd1190cf9769c84a49322300a308e 100644 (file)
@@ -140,7 +140,7 @@ at the end.
 
 The number of additional commits is the number
 of commits which would be displayed by "git log v1.0.4..parent".
-The hash suffix is "-g" + an unambigous abbreviation for the tip commit
+The hash suffix is "-g" + an unambiguous abbreviation for the tip commit
 of parent (which was `2414721b194453f058079d897d13c4e377f92dc6`). The
 length of the abbreviation scales as the repository grows, using the
 approximate number of objects in the repository and a bit of math
@@ -203,7 +203,7 @@ BUGS
 
 Tree objects as well as tag objects not pointing at commits, cannot be described.
 When describing blobs, the lightweight tags pointing at blobs are ignored,
-but the blob is still described as <committ-ish>:<path> despite the lightweight
+but the blob is still described as <commit-ish>:<path> despite the lightweight
 tag being favorable.
 
 GIT
index 591e3801b7b164cfdf412864cee46a7612b21fd2..bf78e3143138136f4e2c3998799a16a19f2dc3bb 100644 (file)
@@ -26,7 +26,7 @@ include::diff-options.txt[]
 -2 --ours::
 -3 --theirs::
 -0::
-       Diff against the "base" version, "our branch" or "their
+       Diff against the "base" version, "our branch", or "their
        branch" respectively.  With these options, diffs for
        merged entries are not shown.
 +
@@ -37,12 +37,12 @@ omit diff output for unmerged entries and just show "Unmerged".
 -c::
 --cc::
        This compares stage 2 (our branch), stage 3 (their
-       branch) and the working tree file and outputs a combined
+       branch), and the working tree file and outputs a combined
        diff, similar to the way 'diff-tree' shows a merge
        commit with these flags.
 
 -q::
-       Remain silent even on nonexistent files
+       Remain silent even for nonexistent files
 
 
 include::diff-format.txt[]
index c30d8f0da8a28ff309185bf3878e3a462074d627..4de1d4c8f11e6065da2c60c0112b72f85af7daa3 100644 (file)
@@ -13,10 +13,10 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Compares the content and mode of the blobs found in a tree object
+Compare the content and mode of the blobs found in a tree object
 with the corresponding tracked files in the working tree, or with the
 corresponding paths in the index.  When <path> arguments are present,
-compares only paths matching those patterns.  Otherwise all tracked
+compare only paths matching those patterns.  Otherwise all tracked
 files are compared.
 
 OPTIONS
index 274d5eaba93dab2cb0374c64ea95934693c73ddf..143318c411a0761777d8a318450b4a71b69870d7 100644 (file)
@@ -15,7 +15,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Compares the content and mode of the blobs found via two tree objects.
+Compare the content and mode of blobs found via two tree objects.
 
 If there is only one <tree-ish> given, the commit is compared with its parents
 (see --stdin below).
@@ -34,10 +34,10 @@ include::diff-options.txt[]
        matching one of the provided pathspecs.
 
 -r::
-        recurse into sub-trees
+       Recurse into sub-trees.
 
 -t::
-       show tree entry itself as well as subtrees.  Implies -r.
+       Show tree entry itself as well as subtrees.  Implies -r.
 
 --root::
        When `--root` is specified the initial commit will be shown as a big
@@ -78,7 +78,7 @@ commits (but not trees).
        By default, 'git diff-tree --stdin' shows differences,
        either in machine-readable form (without `-p`) or in patch
        form (with `-p`).  This output can be suppressed.  It is
-       only useful with `-v` flag.
+       only useful with the `-v` flag.
 
 -v::
        This flag causes 'git diff-tree --stdin' to also show
@@ -104,10 +104,10 @@ include::pretty-options.txt[]
        This flag changes the way a merge commit patch is displayed,
        in a similar way to the `-c` option. It implies the `-c`
        and `-p` options and further compresses the patch output
-       by omitting uninteresting hunks whose the contents in the parents
+       by omitting uninteresting hunks whose contents in the parents
        have only two variants and the merge result picks one of them
        without modification.  When all hunks are uninteresting, the commit
-       itself and the commit log message is not shown, just like in any other
+       itself and the commit log message are not shown, just like in any other
        "empty diff" case.
 
 --combined-all-paths::
index 52b679256c430f582f70eac04004761fb4b5cfb8..08087ffad5fe9929cc04629ba4aeaa4240f457e4 100644 (file)
@@ -102,7 +102,11 @@ If --merge-base is given, use the merge base of the two commits for the
 Just in case you are doing something exotic, it should be
 noted that all of the <commit> in the above description, except
 in the `--merge-base` case and in the last two forms that use `..`
-notations, can be any <tree>.
+notations, can be any <tree>. A tree of interest is the one pointed to
+by the special ref `AUTO_MERGE`, which is written by the 'ort' merge
+strategy upon hitting merge conflicts (see linkgit:git-merge[1]).
+Comparing the working tree with `AUTO_MERGE` shows changes you've made
+so far to resolve textual conflicts (see the examples below).
 
 For a more complete list of ways to spell <commit>, see
 "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
@@ -152,6 +156,7 @@ Various ways to check your working tree::
 $ git diff            <1>
 $ git diff --cached   <2>
 $ git diff HEAD       <3>
+$ git diff AUTO_MERGE <4>
 ------------
 +
 <1> Changes in the working tree not yet staged for the next commit.
@@ -159,6 +164,8 @@ $ git diff HEAD       <3>
     would be committing if you run `git commit` without `-a` option.
 <3> Changes in the working tree since your last commit; what you
     would be committing if you run `git commit -a`
+<4> Changes in the working tree you've made to resolve textual
+    conflicts so far.
 
 Comparing with arbitrary commits::
 +
index ac0ac6fa02205a5946beaafc538c0764bee85cb4..50cb080085e7708eb117e58fc42920c710452b31 100644 (file)
@@ -36,7 +36,7 @@ OPTIONS
 
 --rotate-to=<file>::
        Start showing the diff for the given path,
-       the paths before it will move to end and output.
+       the paths before it will move to the end and output.
 
 --skip-to=<file>::
        Start showing the diff for the given path, skipping all
@@ -78,7 +78,7 @@ with custom merge tool commands and has the same value as `$MERGED`.
        Print a list of diff tools that may be used with `--tool`.
 
 --[no-]symlinks::
-       'git difftool''s default behavior is create symlinks to the
+       'git difftool''s default behavior is to create symlinks to the
        working tree when run in `--dir-diff` mode and the right-hand
        side of the comparison yields the same content as the file in
        the working tree.
index 8b5dd6add006d111688fc1193d77ebe6b45422a5..bd7b1e0a2eaf3ebf595475580d81d6771b8b4166 100644 (file)
@@ -622,7 +622,7 @@ in octal.  Git only supports the following modes:
 * `100755` or `755`: A normal, but executable, file.
 * `120000`: A symlink, the content of the file will be the link target.
 * `160000`: A gitlink, SHA-1 of the object refers to a commit in
-  another repository. Git links can only be specified by SHA or through
+  another repository. Git links can only be specified either by SHA or through
   a commit mark. They are used to implement submodules.
 * `040000`: A subdirectory.  Subdirectories can only be specified by
   SHA or through a tree mark set with `--import-marks`.
@@ -1353,7 +1353,7 @@ the marks back to the source repository, it is easy to verify the
 accuracy and completeness of the import by comparing each Git
 commit to the corresponding source revision.
 
-Coming from a system such as Perforce or Subversion this should be
+Coming from a system such as Perforce or Subversion, this should be
 quite simple, as the fast-import mark can also be the Perforce changeset
 number or the Subversion revision number.
 
index 46747d5f429164f817444cd502d8bff4dc5cbe4d..b3467664d30bde111af06ec0e915e6def2b1b4b2 100644 (file)
@@ -69,7 +69,7 @@ be in a separate packet, and the list must end with a flush packet.
 
 --upload-pack=<git-upload-pack>::
        Use this to specify the path to 'git-upload-pack' on the
-       remote side, if is not found on your $PATH.
+       remote side, if it is not found on your $PATH.
        Installations of sshd ignores the user's environment
        setup scripts for login shells (e.g. .bash_profile) and
        your privately installed git may not be found on the system
index 1e215d4e73451f2d8dc1e70d42d53475952910dd..e86d5700ddfe02e72e1cad809f29c555b15b6495 100644 (file)
@@ -14,6 +14,7 @@ SYNOPSIS
                   [--points-at=<object>]
                   [--merged[=<object>]] [--no-merged[=<object>]]
                   [--contains[=<object>]] [--no-contains[=<object>]]
+                  [--exclude=<pattern> ...]
 
 DESCRIPTION
 -----------
@@ -102,6 +103,11 @@ OPTIONS
        Do not print a newline after formatted refs where the format expands
        to the empty string.
 
+--exclude=<pattern>::
+       If one or more patterns are given, only refs which do not match
+       any excluded pattern(s) are shown. Matching is done using the
+       same rules as `<pattern>` above.
+
 FIELD NAMES
 -----------
 
@@ -221,6 +227,33 @@ symref::
        `:lstrip` and `:rstrip` options in the same way as `refname`
        above.
 
+signature::
+       The GPG signature of a commit.
+
+signature:grade::
+       Show "G" for a good (valid) signature, "B" for a bad
+       signature, "U" for a good signature with unknown validity, "X"
+       for a good signature that has expired, "Y" for a good
+       signature made by an expired key, "R" for a good signature
+       made by a revoked key, "E" if the signature cannot be
+       checked (e.g. missing key) and "N" for no signature.
+
+signature:signer::
+       The signer of the GPG signature of a commit.
+
+signature:key::
+       The key of the GPG signature of a commit.
+
+signature:fingerprint::
+       The fingerprint of the GPG signature of a commit.
+
+signature:primarykeyfingerprint::
+       The primary key fingerprint of the GPG signature of a commit.
+
+signature:trustlevel::
+       The trust level of the GPG signature of a commit. Possible
+       outputs are `ultimate`, `fully`, `marginal`, `never` and `undefined`.
+
 worktreepath::
        The absolute path to the worktree in which the ref is checked
        out, if it is checked out in any linked worktree. Empty string
@@ -231,6 +264,29 @@ ahead-behind:<committish>::
        commits ahead and behind, respectively, when comparing the output
        ref to the `<committish>` specified in the format.
 
+describe[:options]::
+       A human-readable name, like linkgit:git-describe[1];
+       empty string for undescribable commits. The `describe` string may
+       be followed by a colon and one or more comma-separated options.
++
+--
+tags=<bool-value>;;
+       Instead of only considering annotated tags, consider
+       lightweight tags as well; see the corresponding option in
+       linkgit:git-describe[1] for details.
+abbrev=<number>;;
+       Use at least <number> hexadecimal digits; see the corresponding
+       option in linkgit:git-describe[1] for details.
+match=<pattern>;;
+       Only consider tags matching the given `glob(7)` pattern,
+       excluding the "refs/tags/" prefix; see the corresponding option
+       in linkgit:git-describe[1] for details.
+exclude=<pattern>;;
+       Do not consider tags matching the given `glob(7)` pattern,
+       excluding the "refs/tags/" prefix; see the corresponding option
+       in linkgit:git-describe[1] for details.
+--
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
@@ -247,7 +303,11 @@ Fields that have name-email-date tuple as its value (`author`,
 and `date` to extract the named component.  For email fields (`authoremail`,
 `committeremail` and `taggeremail`), `:trim` can be appended to get the email
 without angle brackets, and `:localpart` to get the part before the `@` symbol
-out of the trimmed email.
+out of the trimmed email. In addition to these, the `:mailmap` option and the
+corresponding `:mailmap,trim` and `:mailmap,localpart` can be used (order does
+not matter) to get values of the name and email according to the .mailmap file
+or according to the file set in the mailmap.file or mailmap.blob configuration
+variable (see linkgit:gitmailmap[5]).
 
 The raw data in an object is `raw`.
 
index b1c13fb39a03dacf6180c4963d605f09d9b76c14..aaafce24be20c5690adeb9d9e59133285fa10f96 100644 (file)
@@ -55,7 +55,7 @@ A "message" generated by the command consists of three parts:
 * The "patch", which is the "diff -p --stat" output (see
   linkgit:git-diff[1]) between the commit and its parent.
 
-The log message and the patch is separated by a line with a
+The log message and the patch are separated by a line with a
 three-dash line.
 
 There are two ways to specify which commits to operate on.
@@ -215,11 +215,21 @@ is greater than 100 bytes, then the mode will be `message`, otherwise
 If `<mode>` is `none`, both the cover letter subject and body will be
 populated with placeholder text.
 
+--description-file=<file>::
+       Use the contents of <file> instead of the branch's description
+       for generating the cover letter.
+
 --subject-prefix=<subject prefix>::
        Instead of the standard '[PATCH]' prefix in the subject
-       line, instead use '[<subject prefix>]'. This
-       allows for useful naming of a patch series, and can be
-       combined with the `--numbered` option.
+       line, instead use '[<subject prefix>]'. This can be used
+       to name a patch series, and can be combined with the
+       `--numbered` option.
++
+The configuration variable `format.subjectPrefix` may also be used
+to configure a subject prefix to apply to a given repository for
+all patches. This is often useful on mailing lists which receive
+patches for several repositories and can be used to disambiguate
+the patches (with a value of e.g. "PATCH my-project").
 
 --filename-max-length=<n>::
        Instead of the standard 64 bytes, chomp the generated output
@@ -229,9 +239,9 @@ populated with placeholder text.
        variable, or 64 if unconfigured.
 
 --rfc::
-       Alias for `--subject-prefix="RFC PATCH"`. RFC means "Request For
-       Comments"; use this when sending an experimental patch for
-       discussion rather than application.
+       Prepends "RFC" to the subject prefix (producing "RFC PATCH" by
+       default). RFC means "Request For Comments"; use this when sending
+       an experimental patch for discussion rather than application.
 
 -v <n>::
 --reroll-count=<n>::
@@ -245,7 +255,7 @@ populated with placeholder text.
        or "--reroll-count=4rev2" are allowed), but the downside of
        using such a reroll-count is that the range-diff/interdiff
        with the previous version does not state exactly which
-       version the new interation is compared against.
+       version the new iteration is compared against.
 
 --to=<email>::
        Add a `To:` header to the email headers. This is in addition
index b6a0f8a085ca14060681b6ed1ec812728d6e799f..5b82e4605c2e91dc647330409af81728b665a80a 100644 (file)
@@ -24,7 +24,7 @@ OPTIONS
        An object to treat as the head of an unreachability trace.
 +
 If no objects are given, 'git fsck' defaults to using the
-index file, all SHA-1 references in `refs` namespace, and all reflogs
+index file, all SHA-1 references in the `refs` namespace, and all reflogs
 (unless --no-reflogs is given) as heads.
 
 --unreachable::
@@ -64,7 +64,7 @@ index file, all SHA-1 references in `refs` namespace, and all reflogs
 --connectivity-only::
        Check only the connectivity of reachable objects, making sure
        that any objects referenced by a reachable tag, commit, or tree
-       is present. This speeds up the operation by avoiding reading
+       are present. This speeds up the operation by avoiding reading
        blobs entirely (though it does still check that referenced blobs
        exist). This will detect corruption in commits and trees, but
        not do any semantic checks (e.g., for format errors). Corruption
@@ -79,7 +79,7 @@ care about this output and want to speed it up further.
        recorded with g+w bit set, which was created by older
        versions of Git.  Existing repositories, including the
        Linux kernel, Git itself, and sparse repository have old
-       objects that triggers this check, but it is recommended
+       objects that trigger this check, but it is recommended
        to check new projects with this flag.
 
 --verbose::
index 8238eadb0e166a97537fdfd28296df6c31e7e342..8585d19f4d89870027df745197d6dc85a1944db4 100644 (file)
@@ -70,10 +70,10 @@ the change (as happening against the super repo).  However, the client
 will properly ignore these extra events, so performance may be affected
 but it will not cause an incorrect result.
 
-By default, the fsmonitor daemon refuses to work against network-mounted
+By default, the fsmonitor daemon refuses to work with network-mounted
 repositories; this may be overridden by setting `fsmonitor.allowRemote` to
 `true`. Note, however, that the fsmonitor daemon is not guaranteed to work
-correctly with all network-mounted repositories and such use is considered
+correctly with all network-mounted repositories, so such use is considered
 experimental.
 
 On Mac OS, the inter-process communication (IPC) between various Git
@@ -83,10 +83,10 @@ but not on network-mounted filesystems, NTFS, or FAT32.  Other filesystems
 may or may not have the needed support; the fsmonitor daemon is not guaranteed
 to work with these filesystems and such use is considered experimental.
 
-By default, the socket is created in the `.git` directory, however, if the
-`.git` directory is on a network-mounted filesystem, it will be instead be
+By default, the socket is created in the `.git` directory.  However, if the
+`.git` directory is on a network-mounted filesystem, it will instead be
 created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
-network-mounted filesystem in which case you must set the configuration
+network-mounted filesystem, in which case you must set the configuration
 variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
 filesystem in which to create the socket file.
 
index 90806fd26aa4ac0d1fef93d25384af3799818896..b5561c458a101c32a51ccca8599d4898e166b174 100644 (file)
@@ -59,6 +59,13 @@ be performed as well.
        cruft pack instead of storing them as loose objects. `--cruft`
        is on by default.
 
+--max-cruft-size=<n>::
+       When packing unreachable objects into a cruft pack, limit the
+       size of new cruft packs to be at most `<n>` bytes. Overrides any
+       value specified via the `gc.maxCruftSize` configuration. See
+       the `--max-cruft-size` option of linkgit:git-repack[1] for
+       more.
+
 --prune=<date>::
        Prune loose objects older than date (default is 2 weeks ago,
        overridable by the config variable `gc.pruneExpire`).
index ac44d85b0b5c7f12a2d5473b3be0b0e4511cf58f..b537bb45b138f49e8298a9fdf8f26866fe8e9b72 100644 (file)
@@ -20,7 +20,7 @@ and extract the commit ID stored in it.  It reads only the first
 1024 bytes of input, thus its runtime is not influenced by the size
 of the tar archive very much.
 
-If no commit ID is found, 'git get-tar-commit-id' quietly exists with a
+If no commit ID is found, 'git get-tar-commit-id' quietly exits with a
 return code of 1.  This can happen if the archive had not been created
 using 'git archive' or if the first parameter of 'git archive' had been
 a tree ID instead of a commit ID or tag.
index dabdbe8471de5d36bf55589aa74a270901ff882e..0d0103c780af8c454db02a33c909343fb7bd51be 100644 (file)
@@ -337,7 +337,7 @@ The `--threads` option (and the grep.threads configuration) will be ignored when
 
 When grepping the object store (with `--cached` or giving tree objects), running
 with multiple threads might perform slower than single threaded if `--textconv`
-is given and there're too many text conversions. So if you experience low
+is given and there are too many text conversions. So if you experience low
 performance in this case, it might be desirable to use `--threads=1`.
 
 CONFIGURATION
index 472b5bb995be278415daede21a5489ed2d4c01da..ef4719ae41c700f5dde933a69ae6c8cf8c5fd3bf 100644 (file)
@@ -3,7 +3,7 @@ git-hash-object(1)
 
 NAME
 ----
-git-hash-object - Compute object ID and optionally creates a blob from a file
+git-hash-object - Compute object ID and optionally create an object from a file
 
 
 SYNOPSIS
@@ -25,7 +25,8 @@ OPTIONS
 -------
 
 -t <type>::
-       Specify the type (default: "blob").
+       Specify the type of object to be created (default: "blob"). Possible
+       values are `commit`, `tree`, `blob`, and `tag`.
 
 -w::
        Actually write the object into the object database.
@@ -38,10 +39,10 @@ OPTIONS
        of from the command-line.
 
 --path::
-       Hash object as it were located at the given path. The location of
-       file does not directly influence on the hash value, but path is
-       used to determine what Git filters should be applied to the object
-       before it can be placed to the object database, and, as result of
+       Hash object as if it were located at the given path. The location of
+       the file does not directly influence the hash value, but the path is
+       used to determine which Git filters should be applied to the object
+       before it can be placed in the object database.  As a result of
        applying filters, the actual blob put into the object database may
        differ from the given file. This option is mainly useful for hashing
        temporary files located outside of the working directory or files
index 2b0b5e390dcb94a651ca92ded8c1542a175f7f09..f0bedc1f96433e6d7667519c1c7d307c46d17dc3 100644 (file)
@@ -42,13 +42,13 @@ former is internally converted into the latter.
 
 To display the linkgit:git[1] man page, use `git help git`.
 
-This page can be displayed with 'git help help' or `git help --help`
+This page can be displayed with 'git help help' or `git help --help`.
 
 OPTIONS
 -------
 -a::
 --all::
-       Prints all the available commands on the standard output.
+       Print all the available commands on the standard output.
 
 --no-external-commands::
        When used with `--all`, exclude the listing of external "git-*"
@@ -59,7 +59,7 @@ OPTIONS
        aliases.
 
 --verbose::
-       When used with `--all` print description for all recognized
+       When used with `--all`, print description for all recognized
        commands. This is the default.
 
 -c::
@@ -69,10 +69,10 @@ OPTIONS
 
 -g::
 --guides::
-       Prints a list of the Git concept guides on the standard output.
+       Print a list of the Git concept guides on the standard output.
 
 --user-interfaces::
-       Prints a list of the repository, command and file interfaces
+       Print a list of the repository, command and file interfaces
        documentation on the standard output.
 +
 In-repository file interfaces such as `.git/info/exclude` are
@@ -85,7 +85,7 @@ 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
+       Print list of file formats, protocols and other developer
        interfaces documentation on the standard output.
 
 -i::
@@ -109,7 +109,7 @@ other display programs (see below).
        format. A web browser will be used for that purpose.
 +
 The web browser can be specified using the configuration variable
-`help.browser`, or `web.browser` if the former is not set. If none of
+`help.browser`, or `web.browser` if the former is not set. If neither of
 these config variables is set, the 'git web{litdd}browse' helper script
 (called by 'git help') will pick a suitable default. See
 linkgit:git-web{litdd}browse[1] for more information about this.
@@ -129,8 +129,8 @@ line option:
 * "info" corresponds to '-i|--info',
 * "web" or "html" correspond to '-w|--web'.
 
-help.browser, web.browser and browser.<tool>.path
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help.browser, web.browser, and browser.<tool>.path
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The `help.browser`, `web.browser` and `browser.<tool>.path` will also
 be checked if the 'web' format is chosen (either by command-line
index 3407f3c2c078264505d28455c93c6ec5424234b1..f6cc72d2ca9c7090c5391618d67abbfe1a1dd8e6 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-A command interface to running git hooks (see linkgit:githooks[5]),
+A command interface for running git hooks (see linkgit:githooks[5]),
 for use by other scripted git commands.
 
 SUBCOMMANDS
@@ -32,7 +32,7 @@ OPTIONS
 -------
 
 --to-stdin::
-       For "run"; Specify a file which will be streamed into the
+       For "run"; specify a file which will be streamed into the
        hook's stdin. The hook will receive the entire file from
        beginning to EOF.
 
index 0c5c0dde19f0b0f4fe271c1d9e7a5dcc01efe48e..f37ddaded82b42b5093ad9b1ea791c2979d743f1 100644 (file)
@@ -23,7 +23,7 @@ discussion of `GIT_PROTOCOL` in the ENVIRONMENT section below.
 It verifies that the directory has the magic file
 "git-daemon-export-ok", and it will refuse to export any Git directory
 that hasn't explicitly been marked for export this way (unless the
-`GIT_HTTP_EXPORT_ALL` environmental variable is set).
+`GIT_HTTP_EXPORT_ALL` environment variable is set).
 
 By default, only the `upload-pack` service is enabled, which serves
 'git fetch-pack' and 'git ls-remote' clients, which are invoked from
@@ -42,12 +42,12 @@ http.getanyfile::
        any file within the repository, including objects that are
        no longer reachable from a branch but are still present.
        It is enabled by default, but a repository can disable it
-       by setting this configuration item to `false`.
+       by setting this configuration value to `false`.
 
 http.uploadpack::
        This serves 'git fetch-pack' and 'git ls-remote' clients.
        It is enabled by default, but a repository can disable it
-       by setting this configuration item to `false`.
+       by setting this configuration value to `false`.
 
 http.receivepack::
        This serves 'git send-pack' clients, allowing push.  It is
@@ -265,12 +265,12 @@ by the invoking web server, including:
 * QUERY_STRING
 * REQUEST_METHOD
 
-The `GIT_HTTP_EXPORT_ALL` environmental variable may be passed to
+The `GIT_HTTP_EXPORT_ALL` environment variable may be passed to
 'git-http-backend' to bypass the check for the "git-daemon-export-ok"
 file in each repository before allowing export of that repository.
 
 The `GIT_HTTP_MAX_REQUEST_BUFFER` environment variable (or the
-`http.maxRequestBuffer` config variable) may be set to change the
+`http.maxRequestBuffer` config option) may be set to change the
 largest ref negotiation request that git will handle during a fetch; any
 fetch requiring a larger buffer will not succeed.  This value should not
 normally need to be changed, but may be helpful if you are fetching from
index 319062c021bb2c44686cd993898d502405531646..4ec7c68d3b9ecd18b3358563c2c1de4addff6eb0 100644 (file)
@@ -31,7 +31,7 @@ commit-id::
        Report what is downloaded.
 
 -w <filename>::
-        Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
+       Writes the commit-id into the specified filename under $GIT_DIR/refs/<filename> on
         the local end after the transfer is complete.
 
 --stdin::
index 7c6a6dd7f6a7fc9c75bf0ae595b12732d5c17765..ce0d80821259277f9112ad28b002f4c72bdb8348 100644 (file)
@@ -13,12 +13,12 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Sends missing objects to remote repository, and updates the
+Sends missing objects to the remote repository, and updates the
 remote branch.
 
 *NOTE*: This command is temporarily disabled if your libcurl
 is older than 7.16, as the combination has been reported
-not to work and sometimes corrupts repository.
+not to work and sometimes corrupts the repository.
 
 OPTIONS
 -------
@@ -44,7 +44,7 @@ OPTIONS
 -d::
 -D::
        Remove <ref> from remote repository.  The specified branch
-       cannot be the remote HEAD.  If -d is specified the following
+       cannot be the remote HEAD.  If -d is specified, the following
        other conditions must also be met:
 
        - Remote HEAD must resolve to an object that exists locally
@@ -83,8 +83,8 @@ and where it is pushed is determined by using the destination side.
 Without `--force`, the <src> ref is stored at the remote only if
 <dst> does not exist, or <dst> is a proper subset (i.e. an
 ancestor) of <src>.  This check, known as "fast-forward check",
-is performed in order to avoid accidentally overwriting the
-remote ref and lose other peoples' commits from there.
+is performed to avoid accidentally overwriting the
+remote ref and losing other peoples' commits from there.
 
 With `--force`, the fast-forward check is disabled for all refs.
 
index 4e71c256ecb08fe44ef656c85b7246e6f2f458b1..6486620c3d8f2a2d7a9bb623c362d02465b06be4 100644 (file)
@@ -16,10 +16,10 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Reads a packed archive (.pack) from the specified file, and
-builds a pack index file (.idx) for it. Optionally writes a
+Reads a packed archive (.pack) from the specified file,
+builds a pack index file (.idx) for it, and optionally writes a
 reverse-index (.rev) for the specified pack. The packed
-archive together with the pack index can then be placed in
+archive, together with the pack index, can then be placed in
 the objects/pack/ directory of a Git repository.
 
 
@@ -68,8 +68,8 @@ OPTIONS
        updated to use objects contained in the pack.
 
 --keep=<msg>::
-       Like --keep create a .keep file before moving the index into
-       its final destination, but rather than creating an empty file
+       Like --keep, create a .keep file before moving the index into
+       its final destination.  However, instead of creating an empty file
        place '<msg>' followed by an LF into the .keep file.  The '<msg>'
        message can later be searched for within all .keep files to
        locate any which have outlived their usefulness.
index 160dea1372cd9ae87f1bad9744e2ae045ed1b5b6..6f0d2973bf444a510ae4989dee9aa1e360eee247 100644 (file)
@@ -29,7 +29,7 @@ to use instead of `./.git` for the base of the repository.
 
 If the object storage directory is specified via the
 `$GIT_OBJECT_DIRECTORY` environment variable then the sha1 directories
-are created underneath - otherwise the default `$GIT_DIR/objects`
+are created underneath; otherwise, the default `$GIT_DIR/objects`
 directory is used.
 
 Running 'git init' in an existing repository is safe. It will not
@@ -66,10 +66,10 @@ DIRECTORY" section below.)
 
 Instead of initializing the repository as a directory to either `$GIT_DIR` or
 `./.git/`, create a text file there containing the path to the actual
-repository.  This file acts as filesystem-agnostic Git symbolic link to the
+repository.  This file acts as filesystem-agnostic Git symbolic link to the
 repository.
 +
-If this is reinitialization, the repository will be moved to the specified path.
+If this is reinitialization, the repository will be moved to the specified path.
 
 -b <branch-name>::
 --initial-branch=<branch-name>::
@@ -99,7 +99,7 @@ specified.
 
 'group' (or 'true')::
 
-Make the repository group-writable, (and g+sx, since the git group may be not
+Make the repository group-writable, (and g+sx, since the git group may not be
 the primary group of all users). This is used to loosen the permissions of an
 otherwise safe umask(2) value. Note that the umask still applies to the other
 permission bits (e.g. if umask is '0022', using 'group' will not remove read
@@ -115,7 +115,7 @@ Same as 'group', but make the repository readable by all users.
 '<perm>' is a 3-digit octal number prefixed with `0` and each file
 will have mode '<perm>'. '<perm>' will override users' umask(2)
 value (and not only loosen permissions as 'group' and 'all'
-does). '0640' will create a repository which is group-readable, but
+do). '0640' will create a repository which is group-readable, but
 not group-writable or accessible to others. '0660' will create a repo
 that is readable and writable to the current user and group, but
 inaccessible to others (directories and executable files get their
index 4b97f812be83d33dda7fd0ef12dca8b831279fb1..418265f044d65000e9ae22235b9801644f9c2170 100644 (file)
@@ -9,68 +9,105 @@ SYNOPSIS
 --------
 [verse]
 'git interpret-trailers' [--in-place] [--trim-empty]
-                       [(--trailer <token>[(=|:)<value>])...]
+                       [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]
                        [--parse] [<file>...]
 
 DESCRIPTION
 -----------
-Help parsing or adding 'trailers' lines, that look similar to RFC 822 e-mail
+Add or parse 'trailer' lines that look similar to RFC 822 e-mail
 headers, at the end of the otherwise free-form part of a commit
-message.
+message. For example, in the following commit message
 
-This command reads some patches or commit messages from either the
-<file> arguments or the standard input if no <file> is specified. If
-`--parse` is specified, the output consists of the parsed trailers.
+------------------------------------------------
+subject
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
+Signed-off-by: Alice <alice@example.com>
+Signed-off-by: Bob <bob@example.com>
+------------------------------------------------
+
+the last two lines starting with "Signed-off-by" are trailers.
+
+This command reads commit messages from either the
+<file> arguments or the standard input if no <file> is specified.
+If `--parse` is specified, the output consists of the parsed trailers
+coming from the input, without influencing them with any command line
+options or configuration variables.
+
+Otherwise, this command applies `trailer.*` configuration variables
+(which could potentially add new trailers, as well as reposition them),
+as well as any command line arguments that can override configuration
+variables (such as `--trailer=...` which could also add new trailers),
+to each input file. The result is emitted on the standard output.
 
-Otherwise, this command applies the arguments passed using the
-`--trailer` option, if any, to the commit message part of each input
-file. The result is emitted on the standard output.
+This command can also operate on the output of linkgit:git-format-patch[1],
+which is more elaborate than a plain commit message. Namely, such output
+includes a commit message (as above), a "---" divider line, and a patch part.
+For these inputs, the divider and patch parts are not modified by
+this command and are emitted as is on the output, unless
+`--no-divider` is specified.
 
 Some configuration variables control the way the `--trailer` arguments
-are applied to each commit message and the way any existing trailer in
-the commit message is changed. They also make it possible to
+are applied to each input and the way any existing trailer in
+the input is changed. They also make it possible to
 automatically add some trailers.
 
-By default, a '<token>=<value>' or '<token>:<value>' argument given
+By default, a '<key>=<value>' or '<key>:<value>' argument given
 using `--trailer` will be appended after the existing trailers only if
-the last trailer has a different (<token>, <value>) pair (or if there
-is no existing trailer). The <token> and <value> parts will be trimmed
+the last trailer has a different (<key>, <value>) pair (or if there
+is no existing trailer). The <key> and <value> parts will be trimmed
 to remove starting and trailing whitespace, and the resulting trimmed
-<token> and <value> will appear in the message like this:
+<key> and <value> will appear in the output like this:
 
 ------------------------------------------------
-token: value
+key: value
 ------------------------------------------------
 
-This means that the trimmed <token> and <value> will be separated by
+This means that the trimmed <key> and <value> will be separated by
 `': '` (one colon followed by one space).
 
+For convenience, a <keyAlias> can be configured to make using `--trailer`
+shorter to type on the command line. This can be configured using the
+'trailer.<keyAlias>.key' configuration variable. The <keyAlias> must be a prefix
+of the full <key> string, although case sensitivity does not matter. For
+example, if you have
+
+------------------------------------------------
+trailer.sign.key "Signed-off-by: "
+------------------------------------------------
+
+in your configuration, you only need to specify `--trailer="sign: foo"`
+on the command line instead of `--trailer="Signed-off-by: foo"`.
+
 By default the new trailer will appear at the end of all the existing
 trailers. If there is no existing trailer, the new trailer will appear
-after the commit message part of the output, and, if there is no line
-with only spaces at the end of the commit message part, one blank line
-will be added before the new trailer.
+at the end of the input. A blank line will be added before the new
+trailer if there isn't one already.
 
-Existing trailers are extracted from the input message by looking for
+Existing trailers are extracted from the input by looking for
 a group of one or more lines that (i) is all trailers, or (ii) contains at
 least one Git-generated or user-configured trailer and consists of at
 least 25% trailers.
 The group must be preceded by one or more empty (or whitespace-only) lines.
-The group must either be at the end of the message or be the last
+The group must either be at the end of the input or be the last
 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.
+space or the end of the line).
 
 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
+<key>, but any number of regular space and tab characters are allowed
+between the <key> 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.
+the "folding" in RFC 822. Example:
 
-Note that 'trailers' do not follow and are not intended to follow many
-rules for RFC 822 headers. For example they do not follow
-the encoding rules and probably many other rules.
+------------------------------------------------
+key: This is a very long value, with spaces and
+  newlines in it.
+------------------------------------------------
+
+Note that trailers do not follow (nor are they intended to follow) many of the
+rules for RFC 822 headers. For example they do not follow the encoding rule.
 
 OPTIONS
 -------
@@ -79,38 +116,47 @@ OPTIONS
 
 --trim-empty::
        If the <value> part of any trailer contains only whitespace,
-       the whole trailer will be removed from the resulting message.
+       the whole trailer will be removed from the output.
        This applies to existing trailers as well as new trailers.
 
---trailer <token>[(=|:)<value>]::
-       Specify a (<token>, <value>) pair that should be applied as a
-       trailer to the input messages. See the description of this
+--trailer <key>[(=|:)<value>]::
+       Specify a (<key>, <value>) pair that should be applied as a
+       trailer to the inputs. See the description of this
        command.
 
 --where <placement>::
 --no-where::
        Specify where all new trailers will be added.  A setting
-       provided with '--where' overrides all configuration variables
+       provided with '--where' overrides the `trailer.where` and any
+       applicable `trailer.<keyAlias>.where` configuration variables
        and applies to all '--trailer' options until the next occurrence of
-       '--where' or '--no-where'. Possible values are `after`, `before`,
-       `end` or `start`.
+       '--where' or '--no-where'. Upon encountering '--no-where', clear the
+       effect of any previous use of '--where', such that the relevant configuration
+       variables are no longer overridden. Possible placements are `after`,
+       `before`, `end` or `start`.
 
 --if-exists <action>::
 --no-if-exists::
        Specify what action will be performed when there is already at
-       least one trailer with the same <token> in the message.  A setting
-       provided with '--if-exists' overrides all configuration variables
+       least one trailer with the same <key> in the input.  A setting
+       provided with '--if-exists' overrides the `trailer.ifExists` and any
+       applicable `trailer.<keyAlias>.ifExists` configuration variables
        and applies to all '--trailer' options until the next occurrence of
-       '--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`,
+       '--if-exists' or '--no-if-exists'. Upon encountering '--no-if-exists, clear the
+       effect of any previous use of '--if-exists, such that the relevant configuration
+       variables are no longer overridden. Possible actions are `addIfDifferent`,
        `addIfDifferentNeighbor`, `add`, `replace` and `doNothing`.
 
 --if-missing <action>::
 --no-if-missing::
        Specify what action will be performed when there is no other
-       trailer with the same <token> in the message.  A setting
-       provided with '--if-missing' overrides all configuration variables
+       trailer with the same <key> in the input.  A setting
+       provided with '--if-missing' overrides the `trailer.ifMissing` and any
+       applicable `trailer.<keyAlias>.ifMissing` configuration variables
        and applies to all '--trailer' options until the next occurrence of
-       '--if-missing' or '--no-if-missing'. Possible actions are `doNothing`
+       '--if-missing' or '--no-if-missing'. Upon encountering '--no-if-missing,
+       clear the effect of any previous use of '--if-missing, such that the relevant
+       configuration variables are no longer overridden. Possible actions are `doNothing`
        or `add`.
 
 --only-trailers::
@@ -118,16 +164,19 @@ OPTIONS
 
 --only-input::
        Output only trailers that exist in the input; do not add any
-       from the command-line or by following configured `trailer.*`
-       rules.
+       from the command-line or by applying `trailer.*` configuration
+       variables.
 
 --unfold::
-       Remove any whitespace-continuation in trailers, so that each
-       trailer appears on a line by itself with its full content.
+       If a trailer has a value that runs over multiple lines (aka "folded"),
+       reformat the value into a single line.
 
 --parse::
        A convenience alias for `--only-trailers --only-input
-       --unfold`.
+       --unfold`. This makes it easier to only see the trailers coming from the
+       input without influencing them with any command line options or
+       configuration variables, while also making the output machine-friendly with
+       --unfold.
 
 --no-divider::
        Do not treat `---` as the end of the commit message. Use this
@@ -148,11 +197,11 @@ used when another separator is not specified in the config for this
 trailer.
 +
 For example, if the value for this option is "%=$", then only lines
-using the format '<token><sep><value>' with <sep> containing '%', '='
+using the format '<key><sep><value>' with <sep> containing '%', '='
 or '$' and then spaces will be considered trailers. And '%' will be
 the default separator used, so by default trailers will appear like:
-'<token>% <value>' (one percent sign and one space will appear between
-the token and the value).
+'<key>% <value>' (one percent sign and one space will appear between
+the key and the value).
 
 trailer.where::
        This option tells where a new trailer will be added.
@@ -166,41 +215,41 @@ If it is `start`, then each new trailer will appear at the start,
 instead of the end, of the existing trailers.
 +
 If it is `after`, then each new trailer will appear just after the
-last trailer with the same <token>.
+last trailer with the same <key>.
 +
 If it is `before`, then each new trailer will appear just before the
-first trailer with the same <token>.
+first trailer with the same <key>.
 
 trailer.ifexists::
        This option makes it possible to choose what action will be
        performed when there is already at least one trailer with the
-       same <token> in the message.
+       same <key> in the input.
 +
 The valid values for this option are: `addIfDifferentNeighbor` (this
 is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
 +
 With `addIfDifferentNeighbor`, a new trailer will be added only if no
-trailer with the same (<token>, <value>) pair is above or below the line
+trailer with the same (<key>, <value>) pair is above or below the line
 where the new trailer will be added.
 +
 With `addIfDifferent`, a new trailer will be added only if no trailer
-with the same (<token>, <value>) pair is already in the message.
+with the same (<key>, <value>) pair is already in the input.
 +
 With `add`, a new trailer will be added, even if some trailers with
-the same (<token>, <value>) pair are already in the message.
+the same (<key>, <value>) pair are already in the input.
 +
-With `replace`, an existing trailer with the same <token> will be
+With `replace`, an existing trailer with the same <key> will be
 deleted and the new trailer will be added. The deleted trailer will be
-the closest one (with the same <token>) to the place where the new one
+the closest one (with the same <key>) to the place where the new one
 will be added.
 +
 With `doNothing`, nothing will be done; that is no new trailer will be
-added if there is already one with the same <token> in the message.
+added if there is already one with the same <key> in the input.
 
 trailer.ifmissing::
        This option makes it possible to choose what action will be
        performed when there is not yet any trailer with the same
-       <token> in the message.
+       <key> in the input.
 +
 The valid values for this option are: `add` (this is the default) and
 `doNothing`.
@@ -209,100 +258,106 @@ With `add`, a new trailer will be added.
 +
 With `doNothing`, nothing will be done.
 
-trailer.<token>.key::
-       This `key` will be used instead of <token> in the trailer. At
-       the end of this key, a separator can appear and then some
-       space characters. By default the only valid separator is ':',
-       but this can be changed using the `trailer.separators` config
-       variable.
+trailer.<keyAlias>.key::
+       Defines a <keyAlias> for the <key>. The <keyAlias> must be a
+       prefix (case does not matter) of the <key>. For example, in `git
+       config trailer.ack.key "Acked-by"` the "Acked-by" is the <key> and
+       the "ack" is the <keyAlias>. This configuration allows the shorter
+       `--trailer "ack:..."` invocation on the command line using the "ack"
+       <keyAlias> instead of the longer `--trailer "Acked-by:..."`.
++
+At the end of the <key>, a separator can appear and then some
+space characters. By default the only valid separator is ':',
+but this can be changed using the `trailer.separators` config
+variable.
 +
-If there is a separator, then the key will be used instead of both the
-<token> and the default separator when adding the trailer.
+If there is a separator in the key, then it overrides the default
+separator when adding the trailer.
 
-trailer.<token>.where::
+trailer.<keyAlias>.where::
        This option takes the same values as the 'trailer.where'
        configuration variable and it overrides what is specified by
-       that option for trailers with the specified <token>.
+       that option for trailers with the specified <keyAlias>.
 
-trailer.<token>.ifexists::
+trailer.<keyAlias>.ifexists::
        This option takes the same values as the 'trailer.ifexists'
        configuration variable and it overrides what is specified by
-       that option for trailers with the specified <token>.
+       that option for trailers with the specified <keyAlias>.
 
-trailer.<token>.ifmissing::
+trailer.<keyAlias>.ifmissing::
        This option takes the same values as the 'trailer.ifmissing'
        configuration variable and it overrides what is specified by
-       that option for trailers with the specified <token>.
+       that option for trailers with the specified <keyAlias>.
 
-trailer.<token>.command::
-       This option behaves in the same way as 'trailer.<token>.cmd', except
+trailer.<keyAlias>.command::
+       Deprecated in favor of 'trailer.<keyAlias>.cmd'.
+       This option behaves in the same way as 'trailer.<keyAlias>.cmd', except
        that it doesn't pass anything as argument to the specified command.
        Instead the first occurrence of substring $ARG is replaced by the
-       value that would be passed as argument.
+       <value> that would be passed as argument.
 +
-The 'trailer.<token>.command' option has been deprecated in favor of
-'trailer.<token>.cmd' due to the fact that $ARG in the user's command is
+Note that $ARG in the user's command is
 only replaced once and that the original way of replacing $ARG is not safe.
 +
-When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given
-for the same <token>, 'trailer.<token>.cmd' is used and
-'trailer.<token>.command' is ignored.
-
-trailer.<token>.cmd::
-       This option can be used to specify a shell command that will be called:
-       once to automatically add a trailer with the specified <token>, and then
-       each time a '--trailer <token>=<value>' argument to modify the <value> of
-       the trailer that this option would produce.
+When both 'trailer.<keyAlias>.cmd' and 'trailer.<keyAlias>.command' are given
+for the same <keyAlias>, 'trailer.<keyAlias>.cmd' is used and
+'trailer.<keyAlias>.command' is ignored.
+
+trailer.<keyAlias>.cmd::
+       This option can be used to specify a shell command that will be called
+       once to automatically add a trailer with the specified <keyAlias>, and then
+       called each time a '--trailer <keyAlias>=<value>' argument is specified to
+       modify the <value> of the trailer that this option would produce.
 +
 When the specified command is first called to add a trailer
-with the specified <token>, the behavior is as if a special
-'--trailer <token>=<value>' argument was added at the beginning
+with the specified <keyAlias>, the behavior is as if a special
+'--trailer <keyAlias>=<value>' argument was added at the beginning
 of the "git interpret-trailers" command, where <value>
 is taken to be the standard output of the command with any
 leading and trailing whitespace trimmed off.
 +
-If some '--trailer <token>=<value>' arguments are also passed
+If some '--trailer <keyAlias>=<value>' arguments are also passed
 on the command line, the command is called again once for each
-of these arguments with the same <token>. And the <value> part
+of these arguments with the same <keyAlias>. And the <value> part
 of these arguments, if any, will be passed to the command as its
 first argument. This way the command can produce a <value> computed
-from the <value> passed in the '--trailer <token>=<value>' argument.
+from the <value> passed in the '--trailer <keyAlias>=<value>' argument.
 
 EXAMPLES
 --------
 
 * Configure a 'sign' trailer with a 'Signed-off-by' key, and then
-  add two of these trailers to a message:
+  add two of these trailers to a commit message file:
 +
 ------------
 $ git config trailer.sign.key "Signed-off-by"
 $ cat msg.txt
 subject
 
-message
+body text
 $ git interpret-trailers --trailer 'sign: Alice <alice@example.com>' --trailer 'sign: Bob <bob@example.com>' <msg.txt
 subject
 
-message
+body text
 
 Signed-off-by: Alice <alice@example.com>
 Signed-off-by: Bob <bob@example.com>
 ------------
 
-* Use the `--in-place` option to edit a message file in place:
+* Use the `--in-place` option to edit a commit message file in place:
 +
 ------------
 $ cat msg.txt
 subject
 
-message
+body text
 
 Signed-off-by: Bob <bob@example.com>
 $ git interpret-trailers --trailer 'Acked-by: Alice <alice@example.com>' --in-place msg.txt
 $ cat msg.txt
 subject
 
-message
+body text
 
 Signed-off-by: Bob <bob@example.com>
 Acked-by: Alice <alice@example.com>
@@ -325,7 +380,7 @@ $ git interpret-trailers --trailer 'Cc: Alice <alice@example.com>' --trailer 'Re
 $ cat msg1.txt
 subject
 
-message
+body text
 $ git config trailer.sign.key "Signed-off-by: "
 $ git config trailer.sign.ifmissing add
 $ git config trailer.sign.ifexists doNothing
@@ -333,19 +388,19 @@ $ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.
 $ git interpret-trailers --trailer sign <msg1.txt
 subject
 
-message
+body text
 
 Signed-off-by: Bob <bob@example.com>
 $ cat msg2.txt
 subject
 
-message
+body text
 
 Signed-off-by: Alice <alice@example.com>
 $ git interpret-trailers --trailer sign <msg2.txt
 subject
 
-message
+body text
 
 Signed-off-by: Alice <alice@example.com>
 ------------
@@ -373,14 +428,14 @@ test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true
 $ cat msg.txt
 subject
 
-message
+body text
 $ git config trailer.help.key "Helped-by: "
 $ git config trailer.help.ifExists "addIfDifferentNeighbor"
 $ git config trailer.help.cmd "~/bin/glog-find-author"
 $ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <msg.txt
 subject
 
-message
+body text
 
 Helped-by: Junio C Hamano <gitster@pobox.com>
 Helped-by: Christian Couder <christian.couder@gmail.com>
@@ -397,14 +452,14 @@ test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
 $ cat msg.txt
 subject
 
-message
+body text
 $ git config trailer.ref.key "Reference-to: "
 $ git config trailer.ref.ifExists "replace"
 $ git config trailer.ref.cmd "~/bin/glog-grep"
 $ git interpret-trailers --trailer="ref:Add copyright notices." <msg.txt
 subject
 
-message
+body text
 
 Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
 ------------
@@ -416,7 +471,7 @@ Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
 $ cat msg.txt
 subject
 
-message
+body text
 
 see: HEAD~2
 $ cat ~/bin/glog-ref
@@ -429,7 +484,7 @@ $ git config trailer.see.cmd "glog-ref"
 $ git interpret-trailers --trailer=see <msg.txt
 subject
 
-message
+body text
 
 See-also: fe3187489d69c4 (subject of related commit)
 ------------
index 2a66cf888074656ce775ad93551603c15fed4ddc..579682172fe45816403f4d5ceffc03949eac5b3a 100644 (file)
@@ -120,11 +120,11 @@ By default, `git log` does not generate any diff output. The options
 below can be used to show the changes made by each commit.
 
 Note that unless one of `--diff-merges` variants (including short
-`-m`, `-c`, and `--cc` options) is explicitly given, merge commits
+`-m`, `-c`, `--cc`, and `--dd` options) is explicitly given, merge commits
 will not show a diff, even if a diff format like `--patch` is
 selected, nor will they match search options like `-S`. The exception
 is when `--first-parent` is in use, in which case `first-parent` is
-the default format.
+the default format for merge commits.
 
 :git-log: 1
 :diff-merges-default: `off`
index 1abdd3c21c513c3c9f547e25c83d212ba1866b2b..f65a8cd91d4bb40e986c3610b6f1c2b89c719ace 100644 (file)
@@ -25,12 +25,12 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This merges the file listing in the index with the actual working
+This command merges the file listing in the index with the actual working
 directory list, and shows different combinations of the two.
 
-One or more of the options below may be used to determine the files
+Several flags can be used to determine which files are
 shown, and each file may be printed multiple times if there are
-multiple entries in the index or multiple statuses are applicable for
+multiple entries in the index or if multiple statuses are applicable for
 the relevant file selection options.
 
 OPTIONS
@@ -62,7 +62,7 @@ OPTIONS
        matching an exclude pattern.  When showing "other" files
        (i.e. when used with '-o'), show only those matched by an
        exclude pattern.  Standard ignore rules are not automatically
-       activated, therefore at least one of the `--exclude*` options
+       activated; therefore, at least one of the `--exclude*` options
        is required.
 
 -s::
@@ -141,7 +141,7 @@ OPTIONS
        Show status tags together with filenames.  Note that for
        scripting purposes, linkgit:git-status[1] `--porcelain` and
        linkgit:git-diff-files[1] `--name-status` are almost always
-       superior alternatives, and users should look at
+       superior alternatives; users should look at
        linkgit:git-status[1] `--short` or linkgit:git-diff[1]
        `--name-status` for more user-friendly alternatives.
 +
@@ -270,8 +270,14 @@ interpolated.  The following "fieldname" are understood:
 
 objectmode::
        The mode of the file which is recorded in the index.
+objecttype::
+       The object type of the file which is recorded in the index.
 objectname::
        The name of the file which is recorded in the index.
+objectsize[:padded]::
+       The object size of the file which is recorded in the index
+       ("-" if the object is a `commit` or `tree`).
+       It also supports a padded format of size with "%(objectsize:padded)".
 stage::
        The stage of the file which is recorded in the index.
 eolinfo:index::
index ff3da547ddb98a5493b5752a4b2b84bed7f799c5..1c4f696ab57e2a241bee0ebab07d0bb199e77b3e 100644 (file)
@@ -96,27 +96,51 @@ OPTIONS
        separator (so `bar` matches `refs/heads/bar` but not
        `refs/heads/foobar`).
 
+OUTPUT
+------
+
+The output is in the format:
+
+------------
+<oid> TAB <ref> LF
+------------
+
+When showing an annotated tag, unless `--refs` is given, two such
+lines are shown: one with the refname for the tag itself as `<ref>`,
+and another with `<ref>` followed by `^{}`. The `<oid>` on the latter
+line shows the name of the object the tag points at.
+
 EXAMPLES
 --------
 
+* List all references (including symbolics and pseudorefs), peeling
+  tags:
++
+----
+$ git ls-remote
+27d43aaaf50ef0ae014b88bba294f93658016a2e       HEAD
+950264636c68591989456e3ba0a5442f93152c1a       refs/heads/main
+d9ab777d41f92a8c1684c91cfb02053d7dd1046b       refs/heads/next
+d4ca2e3147b409459955613c152220f4db848ee1       refs/tags/v2.40.0
+73876f4861cd3d187a4682290ab75c9dccadbc56       refs/tags/v2.40.0^{}
 ----
-$ git ls-remote --tags .
-d6602ec5194c87b0fc87103ca4d67251c76f233a       refs/tags/v0.99
-f25a265a342aed6041ab0cc484224d9ca54b6f41       refs/tags/v0.99.1
-7ceca275d047c90c0c7d5afb13ab97efdf51bd6e       refs/tags/v0.99.3
-c5db5456ae3b0873fc659c19fafdde22313cc441       refs/tags/v0.99.2
-0918385dbd9656cab0d1d81ba7453d49bbc16250       refs/tags/junio-gpg-pub
 
+* List all references matching given patterns:
++
+----
 $ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
 5fe978a5381f1fbad26a80e682ddd2a401966740       refs/heads/master
 c781a84b5204fb294c9ccc79f8b3baceeb32c061       refs/heads/seen
+----
 
-$ git remote add korg http://www.kernel.org/pub/scm/git/git.git
-$ git ls-remote --tags korg v\*
-d6602ec5194c87b0fc87103ca4d67251c76f233a       refs/tags/v0.99
-f25a265a342aed6041ab0cc484224d9ca54b6f41       refs/tags/v0.99.1
-c5db5456ae3b0873fc659c19fafdde22313cc441       refs/tags/v0.99.2
-7ceca275d047c90c0c7d5afb13ab97efdf51bd6e       refs/tags/v0.99.3
+* List only tags matching a given wildcard pattern:
++
+----
+$ git ls-remote --tags http://www.kernel.org/pub/scm/git/git.git v\*
+485a869c64a68cc5795dd99689797c5900f4716d       refs/tags/v2.39.2
+cbf04937d5b9fcf0a76c28f69e6294e9e3ecd7e6       refs/tags/v2.39.2^{}
+d4ca2e3147b409459955613c152220f4db848ee1       refs/tags/v2.40.0
+73876f4861cd3d187a4682290ab75c9dccadbc56       refs/tags/v2.40.0^{}
 ----
 
 SEE ALSO
index 0240adb8eec96600572be6f3f8b988a5aa2eab45..6572095d8d69dca5ff044282b7e299060d83b7f4 100644 (file)
@@ -86,9 +86,9 @@ OPTIONS
 --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).
+       `%xNN` where `NN` are hex digits interpolates to character
+       with hex code `NN`; for example `%x00` interpolates to
+       `\0` (NUL), `%x09` to `\t` (TAB) and `%x0a` to `\n` (LF).
        When specified, `--format` cannot be combined with other
        format-altering options, including `--long`, `--name-only`
        and `--object-only`.
@@ -145,7 +145,7 @@ FIELD NAMES
 -----------
 
 Various values from structured fields can be used to interpolate
-into the resulting output. For each outputing line, the following
+into the resulting output. For each outputting line, the following
 names can be used:
 
 objectmode::
index e3b2a88c4b75f1f6e23feb8a09030469468d9ca8..3f0a6662c81efb6fee6589aa41c2b8e945c36644 100644 (file)
@@ -34,7 +34,7 @@ OPTIONS
 
 -b::
        If any file doesn't begin with a From line, assume it is a
-       single mail message instead of signaling error.
+       single mail message instead of signaling an error.
 
 -d<prec>::
        Instead of the default 4 digits with leading zeros,
index 805e5a2e3a044b4e1f5a345ecafa2dccb87565ce..51d0f7e94b6a0182089d5d7f48ab9f9d1cb9f572 100644 (file)
@@ -102,9 +102,9 @@ prefetch::
        requested refs within `refs/prefetch/`. Also, tags are not updated.
 +
 This is done to avoid disrupting the remote-tracking branches. The end users
-expect these refs to stay unmoved unless they initiate a fetch.  With prefetch
-task, however, the objects necessary to complete a later real fetch would
-already be obtained, so the real fetch would go faster.  In the ideal case,
+expect these refs to stay unmoved unless they initiate a fetch.  However,
+with the prefetch task, the objects necessary to complete a later real fetch
+would already be obtained, making the real fetch faster.  In the ideal case,
 it will just become an update to a bunch of remote-tracking branches without
 any object transfer.
 
index b01ba3d35650969ff446627e4f2f403eb84c7c0e..5ab957cfbc1420d5dca07a21dbf6708777ee754e 100644 (file)
@@ -18,7 +18,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-'git merge-base' finds best common ancestor(s) between two commits to use
+'git merge-base' finds the best common ancestor(s) between two commits to use
 in a three-way merge.  One common ancestor is 'better' than another common
 ancestor if the latter is an ancestor of the former.  A common ancestor
 that does not have any better common ancestor is a 'best common
@@ -28,7 +28,7 @@ merge base for a pair of commits.
 OPERATION MODES
 ---------------
 
-As the most common special case, specifying only two commits on the
+In the most common special case, specifying only two commits on the
 command line means computing the merge base between the given two commits.
 
 More generally, among the two commits to compute the merge base from,
@@ -64,7 +64,7 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option.
        the two commits, but also takes into account the reflog of
        <ref> to see if the history leading to <commit> forked from
        an earlier incarnation of the branch <ref> (see discussion
-       on this mode below).
+       of this mode below).
 
 OPTIONS
 -------
@@ -88,7 +88,7 @@ For example, with this topology:
 
 the merge base between 'A' and 'B' is '1'.
 
-Given three commits 'A', 'B' and 'C', `git merge-base A B C` will compute the
+Given three commits 'A', 'B', and 'C', `git merge-base A B C` will compute the
 merge base between 'A' and a hypothetical commit 'M', which is a merge
 between 'B' and 'C'.  For example, with this topology:
 
@@ -130,7 +130,7 @@ When the history involves criss-cross merges, there can be more than one
 ---2---o---o---B
 ....
 
-both '1' and '2' are merge-bases of A and B.  Neither one is better than
+both '1' and '2' are merge bases of A and B.  Neither one is better than
 the other (both are 'best' merge bases).  When the `--all` option is not given,
 it is unspecified which best one is output.
 
@@ -204,7 +204,7 @@ will find B0, and
 
     $ git rebase --onto origin/master $fork_point topic
 
-will replay D0, D1 and D on top of B to create a new history of this
+will replay D0, D1, and D on top of B to create a new history of this
 shape:
 
 ....
index ffc4fbf7e89a89b075bb00bafcb041c19adc271f..b50acace3bc367ad7b73d2da10252e6b5f2e0d07 100644 (file)
@@ -19,12 +19,12 @@ DESCRIPTION
 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.
+this documentation describes the 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"
+The performed merge will use the same features as the "real"
 linkgit:git-merge[1], including:
 
   * three way content merges of individual files
@@ -253,7 +253,7 @@ 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
+files 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.
@@ -263,7 +263,7 @@ 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
+Do NOT assume that each path 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
index 0aeff572a59d8fea319f334232deae4a9df4e464..e8ab34031919fa4d2ac920e1cd706c77c7c65138 100644 (file)
@@ -194,9 +194,13 @@ happens:
    versions: stage 1 stores the version from the common ancestor,
    stage 2 from `HEAD`, and stage 3 from `MERGE_HEAD` (you
    can inspect the stages with `git ls-files -u`).  The working
-   tree files contain the result of the "merge" program; i.e. 3-way
+   tree files contain the result of the merge operation; i.e. 3-way
    merge results with familiar conflict markers `<<<` `===` `>>>`.
-5. No other changes are made.  In particular, the local
+5. A special ref `AUTO_MERGE` is written, pointing to a tree
+   corresponding to the current content of the working tree (including
+   conflict markers for textual conflicts).  Note that this ref is only
+   written when the 'ort' merge strategy is used (the default).
+6. No other changes are made.  In particular, the local
    modifications you had before you started merge will stay the
    same and the index entries for them stay as they were,
    i.e. matching `HEAD`.
@@ -332,11 +336,12 @@ After seeing a conflict, you can do two things:
 You can work through the conflict with a number of tools:
 
  * Use a mergetool.  `git mergetool` to launch a graphical
-   mergetool which will work you through the merge.
+   mergetool which will work through the merge with you.
 
  * Look at the diffs.  `git diff` will show a three-way diff,
    highlighting changes from both the `HEAD` and `MERGE_HEAD`
-   versions.
+   versions. `git diff AUTO_MERGE` will show what changes you've
+   made so far to resolve textual conflicts.
 
  * Look at the diffs from each branch. `git log --merge -p <path>`
    will show diffs first for the `HEAD` version and then the
index 3e8f59ac0e46abc35b88723492fa2d411b2756ca..0726b560d432884eabc8834a51c2fbd68d74ad92 100644 (file)
@@ -28,22 +28,22 @@ to define the operation mode for the functions listed below.
 FUNCTIONS
 ---------
 get_merge_tool::
-       returns a merge tool. the return code is 1 if we returned a guessed
+       Returns a merge tool. The return code is 1 if we returned a guessed
        merge tool, else 0. '$GIT_MERGETOOL_GUI' may be set to 'true' to
        search for the appropriate guitool.
 
 get_merge_tool_cmd::
-       returns the custom command for a merge tool.
+       Returns the custom command for a merge tool.
 
 get_merge_tool_path::
-       returns the custom path for a merge tool.
+       Returns the custom path for a merge tool.
 
 initialize_merge_tool::
-       bring merge tool specific functions into scope so they can be used or
+       Brings merge tool specific functions into scope so they can be used or
        overridden.
 
 run_merge_tool::
-       launches a merge tool given the tool name and a true/false
+       Launches a merge tool given the tool name and a true/false
        flag to indicate whether a merge base is present.
        '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
        for use by the merge tool.
index 07535f6576e81a936c3b65481de7d1b53c4120a8..b9e20c5dcd8c52df8e0782bc5d92e3a5ac5361b2 100644 (file)
@@ -17,7 +17,7 @@ Use `git mergetool` to run one of several merge utilities to resolve
 merge conflicts.  It is typically run after 'git merge'.
 
 If one or more <file> parameters are given, the merge tool program will
-be run to resolve differences on each file (skipping those without
+be run to resolve differences in each file (skipping those without
 conflicts).  Specifying a directory will include all unresolved files in
 that path.  If no <file> names are specified, 'git mergetool' will run
 the merge tool program on every file with merge conflicts.
@@ -49,7 +49,7 @@ variable `mergetool.<tool>.cmd`.
 +
 When 'git mergetool' is invoked with this tool (either through the
 `-t` or `--tool` option or the `merge.tool` configuration
-variable) the configured command line will be invoked with `$BASE`
+variable), the configured command line will be invoked with `$BASE`
 set to the name of a temporary file containing the common base for
 the merge, if available; `$LOCAL` set to the name of a temporary
 file containing the contents of the file on the current branch;
@@ -81,7 +81,7 @@ success of the resolution after the custom tool has exited.
 
 -g::
 --gui::
-       When 'git-mergetool' is invoked with the `-g` or `--gui` option
+       When 'git-mergetool' is invoked with the `-g` or `--gui` option,
        the default merge tool will be read from the configured
        `merge.guitool` variable instead of `merge.tool`. If
        `merge.guitool` is not set, we will fallback to the tool
@@ -115,7 +115,7 @@ These are safe to remove once a file has been merged and its
 `git mergetool` session has completed.
 
 Setting the `mergetool.keepBackup` configuration variable to `false`
-causes `git mergetool` to automatically remove the backup as files
+causes `git mergetool` to automatically remove the backup files as files
 are successfully merged.
 
 BACKEND SPECIFIC HINTS
index 466a69751910e4d7d031725f8d52d41d1e7f98a3..006d759962ac61a927d2a08bfa831d1692cc63c4 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Reads a tag contents on standard input and creates a tag object. The
+Reads a tag's contents on standard input and creates a tag object. The
 output is the new tag's <object> identifier.
 
 This command is mostly equivalent to linkgit:git-hash-object[1]
@@ -27,13 +27,13 @@ write a tag found in `my-tag`:
 The difference is that mktag will die before writing the tag if the
 tag doesn't pass a linkgit:git-fsck[1] check.
 
-The "fsck" check done mktag is stricter than what linkgit:git-fsck[1]
+The "fsck" check done by mktag is stricter than what linkgit:git-fsck[1]
 would run by default in that all `fsck.<msg-id>` messages are promoted
 from warnings to errors (so e.g. a missing "tagger" line is an error).
 
 Extra headers in the object are also an error under mktag, but ignored
 by linkgit:git-fsck[1]. This extra check can be turned off by setting
-the appropriate `fsck.<msg-id>` varible:
+the appropriate `fsck.<msg-id>` variable:
 
     git -c fsck.extraHeaderEntry=ignore mktag <my-tag-with-headers
 
@@ -56,7 +56,7 @@ has a very simple fixed format: four lines of
   tagger <tagger>
 
 followed by some 'optional' free-form message (some tags created
-by older Git may not have `tagger` line).  The message, when it
+by older Git may not have `tagger` line).  The message, when it
 exists, is separated by a blank line from the header.  The
 message part may contain a signature that Git itself doesn't
 care about, but that can be verified with gpg.
index 76b44f4da103872d9b39c893b62286d37b159693..383f09dd333f86d96288a776a1395696473b0fdb 100644 (file)
@@ -25,13 +25,13 @@ OPTIONS
 
 --missing::
        Allow missing objects.  The default behaviour (without this option)
-       is to verify that each tree entry's sha1 identifies an existing
+       is to verify that each tree entry's hash identifies an existing
        object.  This option has no effect on the treatment of gitlink entries
        (aka "submodules") which are always allowed to be missing.
 
 --batch::
        Allow building of more than one tree object before exiting.  Each
-       tree is separated by a single blank line. The final new-line is
+       tree is separated by a single blank line. The final newline is
        optional.  Note - if the `-z` option is used, lines are terminated
        with NUL.
 
index fb0220fd18dc2b99cab472f5b52dfe9930d4bdf9..7f991a3380201fe4c9f66e9c99604dc16b467f73 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Move or rename a file, directory or symlink.
+Move or rename a file, directory, or symlink.
 
  git mv [-v] [-f] [-n] [-k] <source> <destination>
  git mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
index 5c56c870253505395ce3a68216b5b9d329fb02e0..d4f1c4d5945e8ed38c243ecee0920bd6e38219a5 100644 (file)
@@ -26,7 +26,7 @@ OPTIONS
 
 --refs=<pattern>::
        Only use refs whose names match a given shell pattern.  The pattern
-       can be one of branch name, tag name or fully qualified ref name. If
+       can be a branch name, a tag name, or a fully qualified ref name. If
        given multiple times, use refs whose names match any of the given shell
        patterns. Use `--no-refs` to clear any previous ref patterns given.
 
index efbc10f0f598eccd247f13c3e5d1ecf9473a6f78..f8310e56a85ab0f6f211d68b1886ec68ae126b9f 100644 (file)
@@ -9,10 +9,10 @@ SYNOPSIS
 --------
 [verse]
 'git notes' [list [<object>]]
-'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' add [-f] [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
 'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
-'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' edit [--allow-empty] [<object>]
+'git notes' append [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' edit [--allow-empty] [<object>] [--[no-]stripspace]
 'git notes' show [<object>]
 'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
 'git notes' merge --commit [-v | -q]
@@ -65,7 +65,9 @@ add::
        However, if you're using `add` interactively (using an editor
        to supply the notes contents), then - instead of aborting -
        the existing notes will be opened in the editor (like the `edit`
-       subcommand).
+       subcommand). If you specify multiple `-m` and `-F`, a blank
+       line will be inserted between the messages. Use the `--separator`
+       option to insert other delimiters.
 
 copy::
        Copy the notes for the first object onto the second object (defaults to
@@ -85,8 +87,12 @@ corresponding <to-object>.  (The optional `<rest>` is ignored so that
 the command can read the input given to the `post-rewrite` hook.)
 
 append::
-       Append to the notes of an existing object (defaults to HEAD).
-       Creates a new notes object if needed.
+       Append new message(s) given by `-m` or `-F` options to an
+       existing note, or add them as a new note if one does not
+       exist, for the object (defaults to HEAD).  When appending to
+       an existing note, a blank line is added before each new
+       message as an inter-paragraph separator.  The separator can
+       be customized with the `--separator` option.
 
 edit::
        Edit the notes for a given object (defaults to HEAD).
@@ -136,6 +142,7 @@ OPTIONS
        are concatenated as separate paragraphs.
        Lines starting with `#` and empty lines other than a
        single line between paragraphs will be stripped out.
+       If you wish to keep them verbatim, use `--no-stripspace`.
 
 -F <file>::
 --file=<file>::
@@ -143,12 +150,16 @@ OPTIONS
        read the note message from the standard input.
        Lines starting with `#` and empty lines other than a
        single line between paragraphs will be stripped out.
+       If you wish to keep them verbatim, use `--no-stripspace`.
 
 -C <object>::
 --reuse-message=<object>::
        Take the given blob object (for example, another note) as the
        note message. (Use `git notes copy <object>` instead to
-       copy notes between objects.)
+       copy notes between objects.).  By default, message will be
+       copied verbatim, but if you wish to strip out the lines
+       starting with `#` and empty lines other than a single line
+       between paragraphs, use with`--stripspace` option.
 
 -c <object>::
 --reedit-message=<object>::
@@ -159,6 +170,19 @@ OPTIONS
        Allow an empty note object to be stored. The default behavior is
        to automatically remove empty notes.
 
+--[no-]separator, --separator=<paragraph-break>::
+       Specify a string used as a custom inter-paragraph separator
+       (a newline is added at the end as needed). If `--no-separator`, no
+       separators will be added between paragraphs.  Defaults to a blank
+       line.
+
+--[no-]stripspace::
+       Strip leading and trailing whitespace from the note message.
+       Also strip out empty lines other than a single line between
+       paragraphs. Lines starting with `#` will be stripped out
+       in non-editor cases like `-m`, `-F` and `-C`, but not in
+       editor case like `git notes edit`, `-c`, etc.
+
 --ref <ref>::
        Manipulate the notes tree in <ref>.  This overrides
        `GIT_NOTES_REF` and the "core.notesRef" configuration.  The ref
index a9995a932ca2d246db2bf756792c92b2431970eb..e32404c6aaee30f39f3f128839171601999bccb3 100644 (file)
@@ -116,9 +116,7 @@ unreachable object whose mtime is newer than the `--cruft-expiration`).
 +
 Incompatible with `--unpack-unreachable`, `--keep-unreachable`,
 `--pack-loose-unreachable`, `--stdin-packs`, as well as any other
-options which imply `--revs`. Also incompatible with `--max-pack-size`;
-when this option is set, the maximum pack size is not inferred from
-`pack.packSizeLimit`.
+options which imply `--revs`.
 
 --cruft-expiration=<approxidate>::
        If specified, objects are eliminated from the cruft pack if they
@@ -298,8 +296,8 @@ So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle.
        nevertheless.
 
 --filter=<filter-spec>::
-       Requires `--stdout`.  Omits certain objects (usually blobs) from
-       the resulting packfile.  See linkgit:git-rev-list[1] for valid
+       Omits certain objects (usually blobs) from the resulting
+       packfile.  See linkgit:git-rev-list[1] for valid
        `<filter-spec>` forms.
 
 --no-filter::
index 154081f2de269975a09c1f5899dc7d5948c54ca7..284956acb3c5e8bb168626c9729a17a799c0afd7 100644 (file)
@@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
 SYNOPSIS
 --------
 [verse]
-'git pack-refs' [--all] [--no-prune]
+'git pack-refs' [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]
 
 DESCRIPTION
 -----------
@@ -51,14 +51,37 @@ The command by default packs all tags and refs that are already
 packed, and leaves other refs
 alone.  This is because branches are expected to be actively
 developed and packing their tips does not help performance.
-This option causes branch tips to be packed as well.  Useful for
-a repository with many branches of historical interests.
+This option causes all refs to be packed as well, with the exception
+of hidden refs, broken refs, and symbolic refs. Useful for a repository
+with many branches of historical interests.
 
 --no-prune::
 
 The command usually removes loose refs under `$GIT_DIR/refs`
 hierarchy after packing them.  This option tells it not to.
 
+--include <pattern>::
+
+Pack refs based on a `glob(7)` pattern. Repetitions of this option
+accumulate inclusion patterns. If a ref is both included in `--include` and
+`--exclude`, `--exclude` takes precedence. Using `--include` will preclude all
+tags from being included by default. Symbolic refs and broken refs will never
+be packed. When used with `--all`, it will be a noop. Use `--no-include` to clear
+and reset the list of patterns.
+
+--exclude <pattern>::
+
+Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option
+accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of
+patterns. If a ref is already packed, including it with `--exclude` will not
+unpack it.
+
+When used with `--all`, pack only loose refs which do not match any of
+the provided `--exclude` patterns.
+
+When used with `--include`, refs provided to `--include`, minus refs that are
+provided to `--exclude` will be packed.
+
 
 BUGS
 ----
index 844d6f808a0c2f740d62ac7dbe5ed0c328546262..db742dcfeea84f0afe1eef8a4fdeb939b4e0dadf 100644 (file)
@@ -15,7 +15,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 This program searches the `$GIT_OBJECT_DIRECTORY` for all objects that currently
-exist in a pack file as well as the independent object directories.
+exist in a pack file as well as in the independent object directories.
 
 All such extra objects are removed.
 
index 03552dd86fc412b622aff2bcf8feda8e71711b3e..9a45571b901b1579e6c377a73359d7e4002438db 100644 (file)
@@ -18,7 +18,7 @@ NOTE: In most cases, users should run 'git gc', which calls
 'git prune'. See the section "NOTES", below.
 
 This runs 'git fsck --unreachable' using all the refs
-available in `refs/`, optionally with additional set of
+available in `refs/`, optionally with an additional set of
 objects specified on the command line, and prunes all unpacked
 objects unreachable from any of these head objects from the object database.
 In addition, it
index 297927d866789c16fdb7f50bf05e735e376166bc..9b7cfbc5c1d8496c2649b4d6375e699b546fa6c5 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git push' [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
-          [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
+          [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose]
           [-u | --set-upstream] [-o <string> | --push-option=<string>]
           [--[no-]signed|--signed=(true|false|if-asked)]
           [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]]
@@ -37,7 +37,7 @@ the default `<refspec>` by consulting `remote.*.push` configuration,
 and if it is not found, honors `push.default` configuration to decide
 what to push (See linkgit:git-config[1] for the meaning of `push.default`).
 
-When neither the command-line nor the configuration specify what to
+When neither the command-line nor the configuration specifies what to
 push, the default behavior is used, which corresponds to the `simple`
 value for `push.default`: the current branch is pushed to the
 corresponding upstream branch, but as a safety measure, the push is
@@ -48,7 +48,7 @@ local one.
 OPTIONS[[OPTIONS]]
 ------------------
 <repository>::
-       The "remote" repository that is destination of a push
+       The "remote" repository that is the destination of a push
        operation.  This parameter can be either a URL
        (see the section <<URLS,GIT URLS>> below) or the name
        of a remote (see the section <<REMOTES,REMOTES>> below).
index 70562dc4c0235d53501bab56ff98af6169b8f968..40e02d92eb2419c32be66a69afb353c6d384c717 100644 (file)
@@ -38,14 +38,14 @@ OPTIONS
        a patch.  At the time of this writing only missing author
        information is warned about.
 
---author Author Name <Author Email>::
+--author 'Author Name <Author Email>'::
        The author name and email address to use when no author
        information can be found in the patch description.
 
 --patches <dir>::
        The directory to find the quilt patches.
 +
-The default for the patch directory is patches
+The default for the patch directory is 'patches'
 or the value of the `$QUILT_PATCHES` environment
 variable.
 
index 0b393715d707015a245eb1afe26dfbe044e8fcd6..fbdbe0befebab63b0316a29aaf420f9538cce43c 100644 (file)
@@ -70,7 +70,7 @@ to revert to color all lines according to the outer diff markers
        Defaults to 60. Try a larger value if `git range-diff` erroneously
        considers a large change a total rewrite (deletion of one commit
        and addition of another), and a smaller one in the reverse case.
-       See the ``Algorithm`` section below for an explanation why this is
+       See the ``Algorithm`` section below for an explanation of why this is
        needed.
 
 --left-only::
@@ -166,7 +166,7 @@ A typical output of `git range-diff` would look like this:
 
 In this example, there are 3 old and 3 new commits, where the developer
 removed the 3rd, added a new one before the first two, and modified the
-commit message of the 2nd commit as well its diff.
+commit message of the 2nd commit as well as its diff.
 
 When the output goes to a terminal, it is color-coded by default, just
 like regular `git diff`'s output. In addition, the first line (adding a
index b09707474df0ec523ac7e53192103a6edf0dca51..1c48c289963063c2e0db605bbb27c35dd803270c 100644 (file)
@@ -25,15 +25,15 @@ fast-forward (i.e. 2-way) merge, or a 3-way merge, with the `-m`
 flag.  When used with `-m`, the `-u` flag causes it to also update
 the files in the work tree with the result of the merge.
 
-Trivial merges are done by 'git read-tree' itself.  Only conflicting paths
-will be in unmerged state when 'git read-tree' returns.
+Only trivial merges are done by 'git read-tree' itself.  Only conflicting paths
+will be in an unmerged state when 'git read-tree' returns.
 
 OPTIONS
 -------
 -m::
        Perform a merge, not just a read.  The command will
        refuse to run if your index file has unmerged entries,
-       indicating that you have not finished previous merge you
+       indicating that you have not finished previous merge you
        started.
 
 --reset::
index e7b39ad244a4bebc90e9c1974e4239ae771c56d4..b4526ca24612803e7b9a5242d706afd0459b7089 100644 (file)
@@ -289,7 +289,7 @@ See also INCOMPATIBLE OPTIONS below.
 +
 See also INCOMPATIBLE OPTIONS below.
 
---empty={drop,keep,ask}::
+--empty=(drop|keep|ask)::
        How to handle commits that are not empty to start and are not
        clean cherry-picks of any upstream commit, but which become
        empty after rebasing (because they contain a subset of already
@@ -695,7 +695,7 @@ be dropped automatically with `--no-keep-empty`).
 Similar to the apply backend, by default the merge backend drops
 commits that become empty unless `-i`/`--interactive` is specified (in
 which case it stops and asks the user what to do).  The merge backend
-also has an `--empty={drop,keep,ask}` option for changing the behavior
+also has an `--empty=(drop|keep|ask)` option for changing the behavior
 of handling commits that become empty.
 
 Directory rename detection
index 65ff518ccff49ea65812b70e9e46fac75733b7e6..20aca92073d8c9d65fc78ce5f3f48a02239333f5 100644 (file)
@@ -18,10 +18,10 @@ information fed from the remote end.
 
 This command is usually not invoked directly by the end user.
 The UI for the protocol is on the 'git send-pack' side, and the
-program pair is meant to be used to push updates to remote
+program pair is meant to be used to push updates to remote
 repository.  For pull operations, see linkgit:git-fetch-pack[1].
 
-The command allows for creation and fast-forwarding of sha1 refs
+The command allows for the creation and fast-forwarding of sha1 refs
 (heads/tags) on the remote end (strictly speaking, it is the
 local end 'git-receive-pack' runs, but to the user who is sitting at
 the send-pack end, it is updating the remote.  Confused?)
index 88ea7e1cc01201ccf68ec1e2b8ccd2cda633903a..b33ee3c9e863b6bb3e5924ee021aeaa9b408466b 100644 (file)
@@ -44,15 +44,15 @@ The following sequences have a special meaning:
        This argument will not be passed to '<command>'. Instead, it
        will cause the helper to start by sending git:// service requests to
        the remote side with the service field set to an appropriate value and
-       the repository field set to rest of the argument. Default is not to send
+       the repository field set to the rest of the argument. Default is not to send
        such a request.
 +
-This is useful if remote side is git:// server accessed over
+This is useful if the remote side is git:// server accessed over
 some tunnel.
 
 '%V' (must be first characters in argument)::
        This argument will not be passed to '<command>'. Instead it sets
-       the vhost field in the git:// service request (to rest of the argument).
+       the vhost field in the git:// service request (to the rest of the argument).
        Default is not to send vhost in such request (if sent).
 
 ENVIRONMENT VARIABLES
@@ -82,12 +82,12 @@ begins with `ext::`.  Examples:
 
 "ext::ssh -i /home/foo/.ssh/somekey user&#64;host.example %S 'foo/repo'"::
        Like host.example:foo/repo, but use /home/foo/.ssh/somekey as
-       keypair and user as user on remote side. This avoids needing to
+       keypair and user as the user on the remote side. This avoids the need to
        edit .ssh/config.
 
 "ext::socat -t3600 - ABSTRACT-CONNECT:/git-server %G/somerepo"::
        Represents repository with path /somerepo accessible over
-       git protocol at abstract namespace address /git-server.
+       git protocol at the abstract namespace address /git-server.
 
 "ext::git-server-alias foo %G/repo"::
        Represents a repository with path /repo accessed using the
index 0451ceb8a26dfc0b4ef06dced69a2005bc4e5448..1dd2648a7904bb73c626019e9ab66e0db009ecf5 100644 (file)
@@ -13,19 +13,19 @@ DESCRIPTION
 -----------
 This helper uses specified file descriptors to connect to a remote Git server.
 This is not meant for end users but for programs and scripts calling git
-fetch, push or archive.
+fetch, push, or archive.
 
 If only <infd> is given, it is assumed to be a bidirectional socket connected
-to remote Git server (git-upload-pack, git-receive-pack or
+to a remote Git server (git-upload-pack, git-receive-pack, or
 git-upload-archive). If both <infd> and <outfd> are given, they are assumed
 to be pipes connected to a remote Git server (<infd> being the inbound pipe
-and <outfd> being the outbound pipe.
+and <outfd> being the outbound pipe).
 
 It is assumed that any handshaking procedures have already been completed
 (such as sending service request for git://) before this helper is started.
 
 <anything> can be any string. It is ignored. It is meant for providing
-information to user in the URL in case that URL is displayed in some
+information to the user in the URL in case that URL is displayed in some
 context.
 
 ENVIRONMENT VARIABLES
@@ -45,7 +45,7 @@ EXAMPLES
 `git push fd::7,8 master (as URL)`::
        Push master, using file descriptor #7 to read data from
        git-receive-pack and file descriptor #8 to write data to
-       same service.
+       the same service.
 
 `git push fd::7,8/bar master`::
        Same as above.
index 4017157949e6d764a619f870c0eed538d3e99f64..c902512a9e89b07446a606b95cdff52ecc385c44 100644 (file)
@@ -74,6 +74,17 @@ to the new separate pack will be written.
        immediately instead of waiting for the next `git gc` invocation.
        Only useful with `--cruft -d`.
 
+--max-cruft-size=<n>::
+       Repack cruft objects into packs as large as `<n>` bytes before
+       creating new packs. As long as there are enough cruft packs
+       smaller than `<n>`, repacking will cause a new cruft pack to
+       be created containing objects from any combined cruft packs,
+       along with any new unreachable objects. Cruft packs larger than
+       `<n>` will not be modified. When the new cruft pack is larger
+       than `<n>` bytes, it will be split into multiple packs, all of
+       which are guaranteed to be at most `<n>` bytes in size. Only
+       useful with `--cruft -d`.
+
 --expire-to=<dir>::
        Write a cruft pack containing pruned objects (if any) to the
        directory `<dir>`. This option is useful for keeping a copy of
@@ -143,6 +154,29 @@ depth is 4095.
        a larger and slower repository; see the discussion in
        `pack.packSizeLimit`.
 
+--filter=<filter-spec>::
+       Remove objects matching the filter specification from the
+       resulting packfile and put them into a separate packfile. Note
+       that objects used in the working directory are not filtered
+       out. So for the split to fully work, it's best to perform it
+       in a bare repo and to use the `-a` and `-d` options along with
+       this option.  Also `--no-write-bitmap-index` (or the
+       `repack.writebitmaps` config option set to `false`) should be
+       used otherwise writing bitmap index will fail, as it supposes
+       a single packfile containing all the objects. See
+       linkgit:git-rev-list[1] for valid `<filter-spec>` forms.
+
+--filter-to=<dir>::
+       Write the pack containing filtered out objects to the
+       directory `<dir>`. Only useful with `--filter`. This can be
+       used for putting the pack on a separate object directory that
+       is accessed through the Git alternates mechanism. **WARNING:**
+       If the packfile containing the filtered out objects is not
+       accessible, the repo can become corrupt as it might not be
+       possible to access the objects in that packfile. See the
+       `objects` and `objects/info/alternates` sections of
+       linkgit:gitrepository-layout[5].
+
 -b::
 --write-bitmap-index::
        Write a reachability bitmap index as part of the repack. This
@@ -165,7 +199,7 @@ depth is 4095.
        Exclude the given pack from repacking. This is the equivalent
        of having `.keep` file on the pack. `<pack-name>` is the
        pack file name without leading directory (e.g. `pack-123.pack`).
-       The option could be specified multiple times to keep multiple
+       The option can be specified multiple times to keep multiple
        packs.
 
 --unpack-unreachable=<when>::
@@ -186,7 +220,7 @@ depth is 4095.
        Pass the `--delta-islands` option to `git-pack-objects`, see
        linkgit:git-pack-objects[1].
 
--g=<factor>::
+-g<factor>::
 --geometric=<factor>::
        Arrange resulting pack structure so that each successive pack
        contains at least `<factor>` times the number of objects as the
@@ -203,11 +237,8 @@ uniquely by the set of packs being "rolled-up"; in other words, the
 packs determined to need to be combined in order to restore a geometric
 progression.
 +
-When `--unpacked` is specified, loose objects are implicitly included in
-this "roll-up", without respect to their reachability. This is subject
-to change in the future. This option (implying a drastically different
-repack mode) is not guaranteed to work with all other combinations of
-option to `git repack`.
+Loose objects are implicitly included in this "roll-up", without respect to
+their reachability. This is subject to change in the future.
 +
 When writing a multi-pack bitmap, `git repack` selects the largest resulting
 pack as the preferred pack for object selection by the MIDX (see
index f271d758c38230410165238de266db7de2d73f71..4f257126e33cc779d1f407ce61cdfbde3cf9ffad 100644 (file)
@@ -35,7 +35,7 @@ Replacement references will be used by default by all Git commands
 except those doing reachability traversal (prune, pack transfer and
 fsck).
 
-It is possible to disable use of replacement references for any
+It is possible to disable the use of replacement references for any
 command using the `--no-replace-objects` option just after 'git'.
 
 For example if commit 'foo' has been replaced by commit 'bar':
@@ -111,7 +111,7 @@ OPTIONS
 FORMATS
 -------
 
-The following format are available:
+The following formats are available:
 
 * 'short':
        <replaced sha1>
index fa5a42670929a9994b7d3580e1e3c76a69b0ab6a..15dcbb6d91c89eac48623f119e417824b5154e26 100644 (file)
@@ -16,7 +16,7 @@ DESCRIPTION
 Generate a request asking your upstream project to pull changes into
 their tree.  The request, printed to the standard output,
 begins with the branch description, summarizes
-the changes and indicates from where they can be pulled.
+the changes, and indicates from where they can be pulled.
 
 The upstream project is expected to have the commit named by
 `<start>` and the output asks it to integrate the changes you made
@@ -50,7 +50,7 @@ EXAMPLES
 --------
 
 Imagine that you built your work on your `master` branch on top of
-the `v1.0` release, and want it to be integrated to the project.
+the `v1.0` release, and want it to be integrated into the project.
 First you push that change to your public repository for others to
 see:
 
index 5964810caa4153a6628ca312669a77a90b41943a..975825b44aa4d01309c46c1923228c372a50e886 100644 (file)
@@ -78,6 +78,8 @@ all modified paths.
 --theirs::
        When restoring files in the working tree from the index, use
        stage #2 ('ours') or #3 ('theirs') for unmerged paths.
+       This option cannot be used when checking out paths from a
+       tree-ish (i.e. with the `--source` option).
 +
 Note that during `git rebase` and `git pull --rebase`, 'ours' and
 'theirs' may appear swapped. See the explanation of the same options
@@ -87,6 +89,8 @@ in linkgit:git-checkout[1] for details.
 --merge::
        When restoring files on the working tree from the index,
        recreate the conflicted merge in the unmerged paths.
+       This option cannot be used when checking out paths from a
+       tree-ish (i.e. with the `--source` option).
 
 --conflict=<style>::
        The same as `--merge` option above, but changes the way the
@@ -101,7 +105,7 @@ in linkgit:git-checkout[1] for details.
        specified. Unmerged paths on the working tree are left alone.
 
 --ignore-skip-worktree-bits::
-       In sparse checkout mode, by default is to only update entries
+       In sparse checkout mode, the default is to only update entries
        matched by `<pathspec>` and sparse patterns in
        $GIT_DIR/info/sparse-checkout. This option ignores the sparse
        patterns and unconditionally restores any files in
@@ -195,7 +199,7 @@ the same as using linkgit:git-reset[1])
 $ git restore --staged hello.c
 ------------
 
-or you can restore both the index and the working tree (this the same
+or you can restore both the index and the working tree (this is the same
 as using linkgit:git-checkout[1])
 
 ------------
index 51029a22715cb3b52fdad8cb868070d9ac626246..2e05c4b510927a66560ade549d9b7a05987e9d33 100644 (file)
@@ -17,9 +17,9 @@ DESCRIPTION
 :git-rev-list: 1
 include::rev-list-description.txt[]
 
-'rev-list' is a very essential Git command, since it
+'rev-list' is an essential Git command, since it
 provides the ability to build and traverse commit ancestry graphs. For
-this reason, it has a lot of different options that enables it to be
+this reason, it has a lot of different options that enable it to be
 used by commands as different as 'git bisect' and
 'git repack'.
 
index f26a7591e3737df6bcf190fc26f0fe2bf50fcd83..912fab9f5e00b6e286b1d80a8164d76224408682 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Many Git porcelainish commands take mixture of flags
+Many Git porcelainish commands take mixture of flags
 (i.e. parameters that begin with a dash '-') and parameters
 meant for the underlying 'git rev-list' command they use internally
 and flags and parameters for the other commands they use
@@ -36,7 +36,7 @@ Each of these options must appear first on the command line.
 --sq-quote::
        Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
        section below). In contrast to the `--sq` option below, this
-       mode does only quoting. Nothing else is done to command input.
+       mode only does quoting. Nothing else is done to command input.
 
 Options for --parseopt
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -156,7 +156,7 @@ for another option.
        are not refs (i.e. branch or tag names; or more
        explicitly disambiguating "heads/master" form, when you
        want to name the "master" branch when there is an
-       unfortunately named tag "master"), and show them as full
+       unfortunately named tag "master"), and shows them as full
        refnames (e.g. "refs/heads/master").
 
 Options for Objects
@@ -383,7 +383,7 @@ Each line of options has this format:
        dash to separate words in a multi-word argument hint.
 
 The remainder of the line, after stripping the spaces, is used
-as the help associated to the option.
+as the help associated with the option.
 
 Blank lines are ignored, and lines that don't match this specification are used
 as option group headers (start the line with a space to create such
@@ -398,7 +398,7 @@ some-command [<options>] <args>...
 
 some-command does foo and bar!
 --
-h,help    show the help
+h,help!   show the help
 
 foo       some nifty option --foo
 bar=      some cool option --bar with an argument
@@ -424,10 +424,10 @@ usage: some-command [<options>] <args>...
     some-command does foo and bar!
 
     -h, --help            show the help
-    --foo                 some nifty option --foo
-    --bar ...             some cool option --bar with an argument
-    --baz <arg>           another cool option --baz with a named argument
-    --qux[=<path>]        qux may take a path argument but has meaning by itself
+    --[no-]foo            some nifty option --foo
+    --[no-]bar ...        some cool option --bar with an argument
+    --[no-]baz <arg>      another cool option --baz with a named argument
+    --[no-]qux[=<path>]   qux may take a path argument but has meaning by itself
 
 An option group Header
     -C[...]               option C with an optional argument
index d2e10d3dceb60e0a6c8322a47f8017701338710e..cbe0208834d51f89cf9020bdf55ce96be4221ae5 100644 (file)
@@ -142,6 +142,16 @@ EXAMPLES
        changes. The revert only modifies the working tree and the
        index.
 
+DISCUSSION
+----------
+
+While git creates a basic commit message automatically, it is
+_strongly_ recommended to explain why the original commit is being
+reverted.
+In addition, repeatedly reverting reverts will result in increasingly
+unwieldy subject lines, for example 'Reapply "Reapply "<original subject>""'.
+Please consider rewording these to be shorter and more unique.
+
 CONFIGURATION
 -------------
 
index 81bc23f3cdbb56fbb8e0bd79c2bae40d35772cac..363a26934f54e06a4870cd1b7657082591f80f21 100644 (file)
@@ -163,7 +163,7 @@ will be staged (unless --cached or -n are used).
 
 A submodule is considered up to date when the HEAD is the same as
 recorded in the index, no tracked files are modified and no untracked
-files that aren't ignored are present in the submodules work tree.
+files that aren't ignored are present in the submodule's work tree.
 Ignored files are deemed expendable and won't stop a submodule's work
 tree from being removed.
 
index 492a82323dab8e144e96897a78e1daf22c76be6e..465011bad5021a602ef74169a499e29a61c32e1a 100644 (file)
@@ -68,11 +68,12 @@ This option may be specified multiple times.
        Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1])
        to edit an introductory message for the patch series.
 +
-When `--compose` is used, git send-email will use the From, Subject, and
-In-Reply-To headers specified in the message. If the body of the message
-(what you type after the headers and a blank line) only contains blank
-(or Git: prefixed) lines, the summary won't be sent, but From, Subject,
-and In-Reply-To headers will be used unless they are removed.
+When `--compose` is used, git send-email will use the From, To, Cc, Bcc,
+Subject, Reply-To, and In-Reply-To headers specified in the message. If
+the body of the message (what you type after the headers and a blank
+line) only contains blank (or Git: prefixed) lines, the summary won't be
+sent, but the headers mentioned above will be used unless they are
+removed.
 +
 Missing From or In-Reply-To headers will be prompted for.
 +
@@ -468,8 +469,8 @@ Information
 
 --dump-aliases::
        Instead of the normal operation, dump the shorthand alias names from
-       the configured alias file(s), one per line in alphabetical order. Note,
-       this only includes the alias name and not its expanded email addresses.
+       the configured alias file(s), one per line in alphabetical order. Note
+       that this only includes the alias name and not its expanded email addresses.
        See 'sendemail.aliasesfile' for more information about aliases.
 
 
index 595b002152fda5dbdedbc65d7feda8d0c4f9ec20..b9e73f2e77b1ccd35ac76ce075a59b362fa7f1dd 100644 (file)
@@ -55,7 +55,7 @@ be in a separate packet, and the list must end with a flush packet.
 --force::
        Usually, the command refuses to update a remote ref that
        is not an ancestor of the local ref used to overwrite it.
-       This flag disables the check.  What this means is that
+       This flag disables the check.  This means that
        the remote repository can lose commits; use it with
        care.
 
@@ -106,7 +106,7 @@ SPECIFYING THE REFS
 There are three ways to specify which refs to update on the
 remote end.
 
-With `--all` flag, all refs that exist locally are transferred to
+With the `--all` flag, all refs that exist locally are transferred to
 the remote side.  You cannot specify any '<ref>' if you use
 this flag.
 
@@ -115,9 +115,9 @@ both on the local side and on the remote side are updated.
 
 When one or more '<ref>' are specified explicitly (whether on the
 command line or via `--stdin`), it can be either a
-single pattern, or a pair of such pattern separated by a colon
+single pattern, or a pair of such patterns separated by a colon
 ":" (this means that a ref name cannot have a colon in it).  A
-single pattern '<name>' is just shorthand for '<name>:<name>'.
+single pattern '<name>' is just shorthand for '<name>:<name>'.
 
 Each pattern pair consists of the source side (before the colon)
 and the destination side (after the colon).  The ref to be
@@ -130,7 +130,7 @@ name. See linkgit:git-rev-parse[1].
  - It is an error if <src> does not match exactly one of the
    local refs.
 
- - It is an error if <dst> matches more than one remote refs.
+ - It is an error if <dst> matches more than one remote ref.
 
  - If <dst> does not match any remote ref, either
 
@@ -143,9 +143,9 @@ name. See linkgit:git-rev-parse[1].
 
 Without `--force`, the <src> ref is stored at the remote only if
 <dst> does not exist, or <dst> is a proper subset (i.e. an
-ancestor) of <src>.  This check, known as "fast-forward check",
-is performed in order to avoid accidentally overwriting the
-remote ref and lose other peoples' commits from there.
+ancestor) of <src>.  This check, known as the "fast-forward check",
+is performed to avoid accidentally overwriting the
+remote ref and losing other people's commits from there.
 
 With `--force`, the fast-forward check is disabled for all refs.
 
index 8632612c31d07818659ff4f68ee567c789e5cd48..bdaf6e5fc4fa79f055e7eb1717464716ea420cc8 100644 (file)
@@ -22,7 +22,7 @@ The 'git sh-setup' scriptlet is designed to be sourced (using
 the normal Git directories and a few helper shell functions.
 
 Before sourcing it, your script should set up a few variables;
-`USAGE` (and `LONG_USAGE`, if any) is used to define message
+`USAGE` (and `LONG_USAGE`, if any) is used to define the message
 given by `usage()` shell function.  `SUBDIRECTORY_OK` can be set
 if the script can run from a subdirectory of the working tree
 (some commands do not).
index 71f608b1ff1e1de10708212bcd815b744f9284bf..c771c89770787356193bd4e241b1fae8069f8d48 100644 (file)
@@ -50,7 +50,7 @@ OPTIONS
 
 --current::
        With this option, the command includes the current
-       branch to the list of revs to be shown when it is not
+       branch in the list of revs to be shown when it is not
        given on the command line.
 
 --topo-order::
@@ -74,8 +74,7 @@ OPTIONS
        that is the common ancestor of all the branches.  This
        flag tells the command to go <n> more common commits
        beyond that.  When <n> is negative, display only the
-       <reference>s given, without showing the commit ancestry
-       tree.
+       <ref>s given, without showing the commit ancestry tree.
 
 --list::
        Synonym to `--more=-1`
@@ -88,8 +87,8 @@ OPTIONS
        the case of three or more commits.
 
 --independent::
-       Among the <reference>s given, display only the ones that
-       cannot be reached from any other <reference>.
+       Among the <ref>s given, display only the ones that cannot be
+       reached from any other <ref>.
 
 --no-name::
        Do not show naming strings for each commit.
@@ -126,25 +125,26 @@ OPTIONS
        default to color output.
        Same as `--color=never`.
 
-Note that --more, --list, --independent and --merge-base options
+Note that --more, --list, --independent, and --merge-base options
 are mutually exclusive.
 
 
 OUTPUT
 ------
-Given N <references>, the first N lines are the one-line
-description from their commit message.  The branch head that is
-pointed at by $GIT_DIR/HEAD is prefixed with an asterisk `*`
-character while other heads are prefixed with a `!` character.
 
-Following these N lines, one-line log for each commit is
+Given N <ref>s, the first N lines are the one-line description from
+their commit message. The branch head that is pointed at by
+$GIT_DIR/HEAD is prefixed with an asterisk `*` character while other
+heads are prefixed with a `!` character.
+
+Following these N lines, a one-line log for each commit is
 displayed, indented N places.  If a commit is on the I-th
 branch, the I-th indentation character shows a `+` sign;
 otherwise it shows a space.  Merge commits are denoted by
 a `-` sign.  Each commit shows a short name that
 can be used as an extended SHA-1 to name that commit.
 
-The following example shows three branches, "master", "fixes"
+The following example shows three branches, "master", "fixes",
 and "mhf":
 
 ------------------------------------------------
@@ -154,7 +154,7 @@ $ git show-branch master fixes mhf
   ! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
 ---
   + [mhf] Allow "+remote:local" refspec to cause --force when fetching.
-  + [mhf~1] Use git-octopus when pulling more than one heads.
+  + [mhf~1] Use git-octopus when pulling more than one head.
  +  [fixes] Introduce "reset type" flag to "git reset"
   + [mhf~2] "git fetch --force".
   + [mhf~3] Use .git/remote/origin, not .git/branches/origin.
@@ -197,7 +197,7 @@ $ git show-branch --reflog="10,1 hour ago" --list master
 
 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.
+topologically related to each other.
 
 CONFIGURATION
 -------------
index d1d56f68b4376279534d61ec44db10e9e6efd297..36e81b9dec45c08a19d5ef4d7840037923d02f8d 100644 (file)
@@ -23,7 +23,7 @@ particular ref exists.
 
 By default, shows the tags, heads, and remote refs.
 
-The --exclude-existing form is a filter that does the inverse. It reads
+The `--exclude-existing` form is a filter that does the inverse. It reads
 refs from stdin, one ref per line, and shows those that don't exist in
 the local repository.
 
@@ -47,14 +47,14 @@ OPTIONS
 -d::
 --dereference::
 
-       Dereference tags into object IDs as well. They will be shown with "{caret}{}"
+       Dereference tags into object IDs as well. They will be shown with `^{}`
        appended.
 
 -s::
 --hash[=<n>]::
 
-       Only show the SHA-1 hash, not the reference name. When combined with
-       --dereference the dereferenced tag will still be shown after the SHA-1.
+       Only show the OID, not the reference name. When combined with
+       `--dereference`, the dereferenced tag will still be shown after the OID.
 
 --verify::
 
@@ -70,15 +70,15 @@ OPTIONS
 -q::
 --quiet::
 
-       Do not print any results to stdout. When combined with `--verify` this
+       Do not print any results to stdout. When combined with `--verify`, this
        can be used to silently check if a reference exists.
 
 --exclude-existing[=<pattern>]::
 
-       Make 'git show-ref' act as a filter that reads refs from stdin of the
-       form "`^(?:<anything>\s)?<refname>(?:\^{})?$`"
+       Make `git show-ref` act as a filter that reads refs from stdin of the
+       form `^(?:<anything>\s)?<refname>(?:\^{})?$`
        and performs the following actions on each:
-       (1) strip "{caret}{}" at the end of line if any;
+       (1) strip `^{}` at the end of line if any;
        (2) ignore if pattern is provided and does not head-match refname;
        (3) warn if refname is not a well-formed refname and skip;
        (4) ignore if refname is a ref that exists in the local repository;
@@ -96,7 +96,13 @@ OPTIONS
 OUTPUT
 ------
 
-The output is in the format: '<SHA-1 ID>' '<space>' '<reference name>'.
+The output is in the format:
+
+------------
+<oid> SP <ref> LF
+------------
+
+For example,
 
 -----------------------------------------------------------------------------
 $ git show-ref --head --dereference
@@ -110,7 +116,13 @@ $ git show-ref --head --dereference
 ...
 -----------------------------------------------------------------------------
 
-When using --hash (and not --dereference) the output format is: '<SHA-1 ID>'
+When using `--hash` (and not `--dereference`), the output is in the format:
+
+------------
+<oid> LF
+------------
+
+For example,
 
 -----------------------------------------------------------------------------
 $ git show-ref --heads --hash
@@ -132,7 +144,7 @@ use:
 -----------------------------------------------------------------------------
 
 This will show "refs/heads/master" but also "refs/remote/other-repo/master",
-if such references exists.
+if such references exist.
 
 When using the `--verify` flag, the command requires an exact path:
 
@@ -142,10 +154,10 @@ When using the `--verify` flag, the command requires an exact path:
 
 will only match the exact branch called "master".
 
-If nothing matches, 'git show-ref' will return an error code of 1,
+If nothing matches, `git show-ref` will return an error code of 1,
 and in the case of verification, it will show an error message.
 
-For scripting, you can ask it to be quiet with the "--quiet" flag, which
+For scripting, you can ask it to be quiet with the `--quiet` flag, which
 allows you to do things like
 
 -----------------------------------------------------------------------------
@@ -157,11 +169,11 @@ to check whether a particular branch exists or not (notice how we don't
 actually want to show any results, and we want to use the full refname for it
 in order to not trigger the problem with ambiguous partial matches).
 
-To show only tags, or only proper branch heads, use "--tags" and/or "--heads"
+To show only tags, or only proper branch heads, use `--tags` and/or `--heads`
 respectively (using both means that it shows tags and heads, but not other
 random references under the refs/ subdirectory).
 
-To do automatic tag object dereferencing, use the "-d" or "--dereference"
+To do automatic tag object dereferencing, use the `-d` or `--dereference`
 flag, so you can do
 
 -----------------------------------------------------------------------------
index 2b1bc7288d5f6fd27b92ed8119ef5dfbc89b9d1d..5eb67439affbef1a7fccb6a745220977b6a0a45d 100644 (file)
@@ -26,7 +26,7 @@ with --name-only).
 
 For plain blobs, it shows the plain contents.
 
-The command takes options applicable to the 'git diff-tree' command to
+Some options that 'git log' command understands can be used to
 control how the changes the commit introduces are shown.
 
 This manual page describes only the most frequently used options.
@@ -61,7 +61,7 @@ EXAMPLES
 --------
 
 `git show v1.0.0`::
-       Shows the tag `v1.0.0`, along with the object the tags
+       Shows the tag `v1.0.0`, along with the object the tag
        points at.
 
 `git show v1.0.0^{tree}`::
index 53dc17aa77a2904ecdf977db132bf71506c2fda5..529a8edd9c1ed88c8b0ab9c39ab95dccd97671b3 100644 (file)
@@ -286,7 +286,7 @@ patterns in non-cone mode has a number of shortcomings:
     problem above?  Also, if it suggests paths, what if the user has a
     file or directory that begins with either a '!' or '#' or has a '*',
     '\', '?', '[', or ']' in its name?  And if it suggests paths, will
-    it complete "/pro" to "/proc" (in the root filesytem) rather than to
+    it complete "/pro" to "/proc" (in the root filesystem) rather than to
     "/progress.txt" in the current directory?  (Note that users are
     likely to want to start paths with a leading '/' in non-cone mode,
     for the same reason that .gitignore files often have one.)
index f4bb6114d91f87f803003a6c7d0ac5e59978855d..06fb7f1d18c6bec047b9cbdb2487f72614fa6073 100644 (file)
@@ -366,7 +366,7 @@ only the commit ends-up being in the stash and not on the current branch.
 # ... hack hack hack ...
 $ git add --patch foo           # add unrelated changes to the index
 $ git stash push --staged       # save these changes to the stash
-# ... hack hack hack, finish curent changes ...
+# ... hack hack hack, finish current changes ...
 $ git commit -m 'Massive'       # commit fully tested changes
 $ git switch fixup-branch       # switch to another branch
 $ git stash pop                 # to finish work on the saved changes
index a051b1e8f383abc618397ea7e2ac2f173d30a111..10fecc51a75d4783c68565d25302c50480d626ce 100644 (file)
@@ -245,11 +245,12 @@ U           U    unmerged, both modified
 ....
 
 Submodules have more state and instead report
-               M    the submodule has a different HEAD than
-                    recorded in the index
-               m    the submodule has modified content
-               ?    the submodule has untracked files
-since modified content or untracked files in a submodule cannot be added
+
+* 'M' = the submodule has a different HEAD than recorded in the index
+* 'm' = the submodule has modified content
+* '?' = the submodule has untracked files
+
+This is since modified content or untracked files in a submodule cannot be added
 via `git add` in the superproject to prepare a commit.
 
 'm' and '?' are applied recursively. For example if a nested submodule
index 2438f76da05ebf013103a08962d634c4baa9ea15..a293327581aa54e120d1edc3b72467e42c250af4 100644 (file)
@@ -29,7 +29,7 @@ With no arguments, this will:
 In the case where the input consists entirely of whitespace characters, no
 output will be produced.
 
-*NOTE*: This is intended for cleaning metadata, prefer the `--whitespace=fix`
+*NOTE*: This is intended for cleaning metadata. Prefer the `--whitespace=fix`
 mode of linkgit:git-apply[1] for correcting whitespace of patches or files in
 the repository.
 
@@ -37,11 +37,11 @@ OPTIONS
 -------
 -s::
 --strip-comments::
-       Skip and remove all lines starting with comment character (default '#').
+       Skip and remove all lines starting with comment character (default '#').
 
 -c::
 --comment-lines::
-       Prepend comment character and blank to each line. Lines will automatically
+       Prepend the comment character and a blank space to each line. Lines will automatically
        be terminated with a newline. On empty lines, only the comment character
        will be prepended.
 
index 4d3ab6b9f925cde1ef8835d790fa1fd66108a36d..695730609aa3ab5a18d45cbff6aba5d1499dfdce 100644 (file)
@@ -95,7 +95,7 @@ too (and can also report changes to a submodule's work tree).
 init [--] [<path>...]::
        Initialize the submodules recorded in the index (which were
        added and committed elsewhere) by setting `submodule.$name.url`
-       in .git/config. It uses the same setting from `.gitmodules` as
+       in `.git/config`, using the same setting from `.gitmodules` as
        a template. If the URL is relative, it will be resolved using
        the default remote. If there is no default remote, the current
        repository will be assumed to be upstream.
@@ -105,9 +105,12 @@ If no path is specified and submodule.active has been configured, submodules
 configured to be active will be initialized, otherwise all submodules are
 initialized.
 +
-When present, it will also copy the value of `submodule.$name.update`.
-This command does not alter existing information in .git/config.
-You can then customize the submodule clone URLs in .git/config
+It will also copy the value of `submodule.$name.update`, if present in
+the `.gitmodules` file, to `.git/config`, but (1) this command does not
+alter existing information in `.git/config`, and (2) `submodule.$name.update`
+that is set to a custom command is *not* copied for security reasons.
++
+You can then customize the submodule clone URLs in `.git/config`
 for your local setup and proceed to `git submodule update`;
 you can also just use `git submodule update --init` without
 the explicit 'init' step if you do not intend to customize
@@ -143,6 +146,8 @@ the submodules. The "updating" can be done in several ways depending
 on command line options and the value of `submodule.<name>.update`
 configuration variable. The command line option takes precedence over
 the configuration variable. If neither is given, a 'checkout' is performed.
+(note: what is in `.gitmodules` file is irrelevant at this point;
+see `git submodule init` above for how `.gitmodules` is used).
 The 'update' procedures supported both from the command line as well as
 through the `submodule.<name>.update` configuration are:
 
@@ -160,16 +165,18 @@ checked out in the submodule.
        merge;; the commit recorded in the superproject will be merged
            into the current branch in the submodule.
 
-The following 'update' procedures are only available via the
-`submodule.<name>.update` configuration variable:
+The following update procedures have additional limitations:
 
-       custom command;; arbitrary shell command that takes a single
-           argument (the sha1 of the commit recorded in the
-           superproject) is executed. When `submodule.<name>.update`
-           is set to '!command', the remainder after the exclamation mark
-           is the custom command.
+       custom command;; mechanism for running arbitrary commands with the
+           commit ID as an argument. Specifically, if the
+           `submodule.<name>.update` configuration variable is set to
+           `!custom command`, the object name of the commit recorded in the
+           superproject for the submodule is appended to the `custom command`
+           string and executed. Note that this mechanism is not supported in
+           the `.gitmodules` file or on the command line.
 
-       none;; the submodule is not updated.
+       none;; the submodule is not updated. This update procedure is not
+           allowed on the command line.
 
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in `.gitmodules`, you can automatically initialize the
index 102c83eb19e98a7c14f8de879cca93d610b5fd34..761b154bcbb58b7c27245fb77e10c4f2e6a8a063 100644 (file)
@@ -27,7 +27,7 @@ symbolic ref.
 
 A symbolic ref is a regular file that stores a string that
 begins with `ref: refs/`.  For example, your `.git/HEAD` is
-a regular file whose contents is `ref: refs/heads/master`.
+a regular file whose content is `ref: refs/heads/master`.
 
 OPTIONS
 -------
index 7f61c1edb3e65a3ed06ed0090b66ac855851b554..d42efb3112787f943559723b9b19915df8181d5e 100644 (file)
@@ -381,6 +381,16 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
 
 include::date-formats.txt[]
 
+FILES
+-----
+
+`$GIT_DIR/TAG_EDITMSG`::
+       This file contains the message of an in-progress annotated
+       tag. If `git tag` exits due to an error before creating an
+       annotated tag then the tag message that has been provided by the
+       user in an editor session will be available in this file, but
+       may be overwritten by the next invocation of `git tag`.
+
 NOTES
 -----
 
index f4bb9c5daf95c6669210429d7a560565dadc91d5..8c47890a6a89bd7c0dbb2e3d259961262e4db3f7 100644 (file)
@@ -49,7 +49,7 @@ OPTIONS
 --remove::
        If a specified file is in the index but is missing then it's
        removed.
-       Default behavior is to ignore removed file.
+       Default behavior is to ignore removed files.
 
 --refresh::
        Looks at the current index and checks to see if merges or
@@ -95,7 +95,7 @@ OPTIONS
        the index.  If you want to change the working tree file,
        you need to unset the bit to tell Git.  This is
        sometimes helpful when working with a big project on a
-       filesystem that has very slow lstat(2) system call
+       filesystem that has very slow lstat(2) system call
        (e.g. cifs).
 +
 Git will fail (gracefully) in case it needs to modify this file
@@ -108,7 +108,7 @@ you will need to handle the situation manually.
        without regard to the "assume unchanged" setting.
 
 --[no-]skip-worktree::
-       When one of these flags is specified, the object name recorded
+       When one of these flags is specified, the object names recorded
        for the paths are not updated. Instead, these options
        set and unset the "skip-worktree" bit for the paths. See
        section "Skip-worktree bit" below for more information.
@@ -119,7 +119,7 @@ you will need to handle the situation manually.
        the `--remove` option was specified.
 
 --[no-]fsmonitor-valid::
-       When one of these flags is specified, the object name recorded
+       When one of these flags is specified, the object names recorded
        for the paths are not updated. Instead, these options
        set and unset the "fsmonitor valid" bit for the paths. See
        section "File System Monitor" below for more information.
@@ -127,7 +127,7 @@ you will need to handle the situation manually.
 -g::
 --again::
        Runs 'git update-index' itself on the paths whose index
-       entries are different from those from the `HEAD` commit.
+       entries are different from those of the `HEAD` commit.
 
 --unresolve::
        Restores the 'unmerged' or 'needs updating' state of a
@@ -151,24 +151,30 @@ you will need to handle the situation manually.
        automatically removed with warning messages.
 
 --stdin::
-       Instead of taking list of paths from the command line,
-       read list of paths from the standard input.  Paths are
+       Instead of taking list of paths from the command line,
+       read list of paths from the standard input.  Paths are
        separated by LF (i.e. one path per line) by default.
 
 --verbose::
-        Report what is being added and removed from index.
+       Report what is being added and removed from the index.
 
 --index-version <n>::
        Write the resulting index out in the named on-disk format version.
-       Supported versions are 2, 3 and 4. The current default version is 2
+       Supported versions are 2, 3, and 4. The current default version is 2
        or 3, depending on whether extra features are used, such as
-       `git add -N`.
+       `git add -N`.  With `--verbose`, also report the version the index
+       file uses before and after this command.
 +
 Version 4 performs a simple pathname compression that reduces index
 size by 30%-50% on large repositories, which results in faster load
-time. Version 4 is relatively young (first released in 1.8.0 in
-October 2012). Other Git implementations such as JGit and libgit2
-may not support it yet.
+time.  Git supports it since version 1.8.0, released in October 2012,
+and support for it was added to libgit2 in 2016 and to JGit in 2020.
+Older versions of this manual page called it "relatively young", but
+it should be considered mature technology these days.
+
+--show-index-version::
+       Report the index format version used by the on-disk index file.
+       See `--index-version` above.
 
 -z::
        Only meaningful with `--stdin` or `--index-info`; paths are
index 48b6683071e65be1abf29ece20dc90c5f0579ec3..0561808cca04a6873909ad18a6fd5f6e9af8b8de 100644 (file)
@@ -118,7 +118,7 @@ verify::
        <oldvalue> is zero or missing, the ref must not exist.
 
 option::
-       Modify behavior of the next command naming a <ref>.
+       Modify the behavior of the next command naming a <ref>.
        The only valid option is `no-deref` to avoid dereferencing
        a symbolic ref.
 
index 17e429dbd095605835bdf6b67d96bd8a92559cac..6bc9b50d89f7aac6921e6b9fd9b2659d1d81d3af 100644 (file)
@@ -23,13 +23,13 @@ OPTIONS
 -------
 -f::
 --force::
-       update the info files from scratch.
+       Update the info files from scratch.
 
 OUTPUT
 ------
 
 Currently the command updates the following files.  Please see
-linkgit:gitrepository-layout[5] for description of
+linkgit:gitrepository-layout[5] for description of
 what they are for:
 
 * objects/info/packs
index b656b4756752f6d91098b85d2766a80e86ca092a..7ad60bc3485bc80606fbf38bb13a4ba0e8f0902e 100644 (file)
@@ -26,7 +26,7 @@ OPTIONS
 -------
 
 --[no-]strict::
-       Do not try <directory>/.git/ if <directory> is no Git directory.
+       Do not try <directory>/.git/ if <directory> is not a Git directory.
 
 --timeout=<n>::
        Interrupt transfer after <n> seconds of inactivity.
index f40202b8e3ab521ea22c78986d3bf5bb44a67f09..0680568dfda732e9786011cd7b8088a91fca1662 100644 (file)
@@ -19,7 +19,7 @@ no value.
 OPTIONS
 -------
 -l::
-       Cause the logical variables to be listed. In addition, all the
+       Display the logical variables. In addition, all the
        variables of the Git configuration file .git/config are listed
        as well. (However, the configuration variables listing functionality
        is deprecated in favor of `git config -l`.)
@@ -71,6 +71,29 @@ endif::git-default-pager[]
 GIT_DEFAULT_BRANCH::
     The name of the first branch created in newly initialized repositories.
 
+GIT_SHELL_PATH::
+    The path of the binary providing the POSIX shell for commands which use the shell.
+
+GIT_ATTR_SYSTEM::
+    The path to the system linkgit:gitattributes[5] file, if one is enabled.
+
+GIT_ATTR_GLOBAL::
+    The path to the global (per-user) linkgit:gitattributes[5] file.
+
+GIT_CONFIG_SYSTEM::
+    The path to the system configuration file, if one is enabled.
+
+GIT_CONFIG_GLOBAL::
+    The path to the global (per-user) configuration files, if any.
+
+Most path values contain only one value. However, some can contain multiple
+values, which are separated by newlines, and are listed in order from highest to
+lowest priority.  Callers should be prepared for any such path value to contain
+multiple items.
+
+Note that paths are printed even if they do not exist, but not if they are
+disabled by other environment variables.
+
 SEE ALSO
 --------
 linkgit:git-commit-tree[1]
index b8720dce8abc34fffee6fa1235c48976ad44f1fb..d7e886918aa7af8accc73737e51cacc38118f747 100644 (file)
@@ -15,7 +15,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 Reads given idx file for packed Git archive created with the
-'git pack-objects' command and verifies idx file and the
+'git pack-objects' command and verifies the idx file and the
 corresponding pack file.
 
 OPTIONS
@@ -25,13 +25,13 @@ OPTIONS
 
 -v::
 --verbose::
-       After verifying the pack, show list of objects contained
+       After verifying the pack, show the list of objects contained
        in the pack and a histogram of delta chain length.
 
 -s::
 --stat-only::
        Do not verify the pack contents; only show the histogram of delta
-       chain length.  With `--verbose`, list of objects is also shown.
+       chain length.  With `--verbose`, the list of objects is also shown.
 
 \--::
        Do not interpret any more arguments as options.
index 8b63ceb00e71a5e2f09cf7686b0978dcf71d1e03..8e55e0bb1ec8a6aaeaef5f6b615929850f63c358 100644 (file)
@@ -3,7 +3,7 @@ git-whatchanged(1)
 
 NAME
 ----
-git-whatchanged - Show logs with difference each commit introduces
+git-whatchanged - Show logs with differences each commit introduces
 
 
 SYNOPSIS
@@ -18,11 +18,11 @@ Shows commit logs and diff output each commit introduces.
 
 New users are encouraged to use linkgit:git-log[1] instead.  The
 `whatchanged` command is essentially the same as linkgit:git-log[1]
-but defaults to show the raw format diff output and to skip merges.
+but defaults to showing the raw format diff output and skipping merges.
 
-The command is kept primarily for historical reasons; fingers of
+The command is primarily kept for historical reasons; fingers of
 many people who learned Git long before `git log` was invented by
-reading Linux kernel mailing list are trained to type it.
+reading the Linux kernel mailing list are trained to type it.
 
 
 Examples
index 063d6eeb99dd34c4b08f3c3dde9340146ce48756..93d76f5d665a57a8bdca565add921cbd8b76bc37 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]]
-                  [-b <new-branch>] <path> [<commit-ish>]
+                  [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]
 'git worktree list' [-v | --porcelain [-z]]
 'git worktree lock' [--reason <string>] <worktree>
 'git worktree move' <worktree> <new-path>
@@ -95,6 +95,16 @@ exist, a new branch based on `HEAD` is automatically created as if
 `-b <branch>` was given.  If `<branch>` does exist, it will be checked out
 in the new worktree, if it's not checked out anywhere else, otherwise the
 command will refuse to create the worktree (unless `--force` is used).
++
+If `<commit-ish>` is omitted, neither `--detach`, or `--orphan` is
+used, and there are no valid local branches (or remote branches if
+`--guess-remote` is specified) then, as a convenience, the new worktree is
+associated with a new orphan branch named `<branch>` (after
+`$(basename <path>)` if neither `-b` or `-B` is used) as if `--orphan` was
+passed to the command. In the event the repository has a remote and
+`--guess-remote` is used, but no remote or local branches exist, then the
+command fails with a warning reminding the user to fetch from their remote
+first (or override by using `-f/--force`).
 
 list::
 
@@ -222,6 +232,10 @@ This can also be set up as the default behaviour by using the
        With `prune`, do not remove anything; just report what it would
        remove.
 
+--orphan::
+       With `add`, make the new worktree and index empty, associating
+       the worktree with a new orphan/unborn branch named `<new-branch>`.
+
 --porcelain::
        With `list`, output in an easy-to-parse format for scripts.
        This format will remain stable across Git versions and regardless of user
@@ -272,7 +286,8 @@ rules and how to access refs of one worktree from another.
 In general, all pseudo refs are per-worktree and all refs starting with
 `refs/` are shared. Pseudo refs are ones like `HEAD` which are directly
 under `$GIT_DIR` instead of inside `$GIT_DIR/refs`. There are exceptions,
-however: refs inside `refs/bisect` and `refs/worktree` are not shared.
+however: refs inside `refs/bisect`, `refs/worktree` and `refs/rewritten` are
+not shared.
 
 Refs that are per-worktree can still be accessed from another worktree via
 two special paths, `main-worktree` and `worktrees`. The former gives
@@ -349,8 +364,8 @@ linked worktree `git rev-parse --git-path HEAD` returns
 `/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
 rev-parse --git-path refs/heads/master` uses
 `$GIT_COMMON_DIR` and returns `/path/main/.git/refs/heads/master`,
-since refs are shared across all worktrees, except `refs/bisect` and
-`refs/worktree`.
+since refs are shared across all worktrees, except `refs/bisect`,
+`refs/worktree` and `refs/rewritten`.
 
 See linkgit:gitrepository-layout[5] for more information. The rule of
 thumb is do not make any assumption about whether a path belongs to
index f0cafa22906d60822167c104e2c09a311ce25c30..9aeabde26200e1585d8d5283b6cdbc85ef8a37dc 100644 (file)
@@ -96,9 +96,9 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config
        to avoid ambiguity with `<name>` containing one.
 +
 This is useful for cases where you want to pass transitory
-configuration options to git, but are doing so on OS's where
-other processes might be able to read your cmdline
-(e.g. `/proc/self/cmdline`), but not your environ
+configuration options to git, but are doing so on operating systems
+where other processes might be able to read your command line
+(e.g. `/proc/self/cmdline`), but not your environment
 (e.g. `/proc/self/environ`). That behavior is the default on
 Linux, but may not be on your system.
 +
@@ -553,8 +553,8 @@ double-quotes and respecting backslash escapes. E.g., the value
        If this variable is set, the default hash algorithm for new
        repositories will be set to this value. This value is
        ignored when cloning and the setting of the remote repository
-       is always used. The default is "sha1". THIS VARIABLE IS
-       EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
+       is always used. The default is "sha1".
+       See `--object-format` in linkgit:git-init[1].
 
 Git Commits
 ~~~~~~~~~~~
index 02a3ec83e4d8583ad9c69f9d76ae5dc4d58a2944..8c1793c14880439da7103bc07f0f89a11137fc86 100644 (file)
@@ -1132,7 +1132,10 @@ size (see below).
 The merge driver is expected to leave the result of the merge in
 the file named with `%A` by overwriting it, and exit with zero
 status if it managed to merge them cleanly, or non-zero if there
-were conflicts.
+were conflicts.  When the driver crashes (e.g. killed by SEGV),
+it is expected to exit with non-zero status that are higher than
+128, and in such a case, the merge results in a failure (which is
+different from producing a conflict).
 
 The `merge.*.recursive` variable specifies what other merge
 driver to use when the merge driver is called for an internal
@@ -1148,8 +1151,8 @@ will be stored via placeholder `%P`.
 ^^^^^^^^^^^^^^^^^^^^^^
 
 This attribute controls the length of conflict markers left in
-the work tree file during a conflicted merge.  Only setting to
-the value to a positive integer has any meaningful effect.
+the work tree file during a conflicted merge.  Only a positive
+integer has a meaningful effect.
 
 For example, this line in `.gitattributes` can be used to tell the merge
 machinery to leave much longer (instead of the usual 7-character-long)
index 1819a5a1859c5479064823bd786e98267f7037b5..e5fac943227a23a5bf9214cddb08d48b0ce3c5ca 100644 (file)
@@ -23,10 +23,10 @@ arguments.  Here are the rules:
     A subcommand may take dashed options (which may take their own
     arguments, e.g. "--max-parents 2") and arguments.  You SHOULD
     give dashed options first and then arguments.  Some commands may
-    accept dashed options after you have already gave non-option
+    accept dashed options after you have already given non-option
     arguments (which may make the command ambiguous), but you should
     not rely on it (because eventually we may find a way to fix
-    these ambiguity by enforcing the "options then args" rule).
+    these ambiguities by enforcing the "options then args" rule).
 
  * Revisions come first and then paths.
    E.g. in `git diff v1.0 v2.0 arch/x86 include/asm-x86`,
@@ -37,12 +37,12 @@ arguments.  Here are the rules:
    they can be disambiguated by placing `--` between them.
    E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
    tree.  Please show changes between the version I staged in the index
-   and what I have in the work tree for that file", not "show difference
+   and what I have in the work tree for that file", not "show the difference
    between the HEAD commit and the work tree as a whole".  You can say
    `git diff HEAD --` to ask for the latter.
 
  * Without disambiguating `--`, Git makes a reasonable guess, but errors
-   out and asking you to disambiguate when ambiguous.  E.g. if you have a
+   out and asks you to disambiguate when ambiguous.  E.g. if you have a
    file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
    you have to say either `git diff HEAD --` or `git diff -- HEAD` to
    disambiguate.
index 100f045bb1a0918e51cc3834a015913f9286dbbb..71dd19731af0dfb187ac55b15826e6b4b3e887b6 100644 (file)
@@ -104,6 +104,17 @@ $ git help credential-foo
 $ git config --global credential.helper foo
 -------------------------------------------
 
+=== Available helpers
+
+The community maintains a comprehensive list of Git credential helpers at
+https://git-scm.com/doc/credential-helpers.
+
+=== OAuth
+
+An alternative to inputting passwords or personal access tokens is to use an
+OAuth credential helper. Initial authentication opens a browser window to the
+host. Subsequent authentication happens in the background. Many popular Git
+hosts support OAuth.
 
 CREDENTIAL CONTEXTS
 -------------------
@@ -260,7 +271,7 @@ appended to its command line, which is one of:
 
 `erase`::
 
-       Remove a matching credential, if any, from the helper's storage.
+       Remove matching credentials, if any, from the helper's storage.
 
 The details of the credential will be provided on the helper's stdin
 stream. The exact format is the same as the input/output format of the
index 0d57f86abc4a51c9665f88ff34103bbe94f09009..3cda2e07c24a96af8ff1c08c46780b5fdb490f4f 100644 (file)
@@ -173,7 +173,7 @@ Note that when rename detection is on but both copy and break
 detection are off, rename detection adds a preliminary step that first
 checks if files are moved across directories while keeping their
 filename the same.  If there is a file added to a directory whose
-contents is sufficiently similar to a file with the same name that got
+contents are sufficiently similar to a file with the same name that got
 deleted from a different directory, it will mark them as renames and
 exclude them from the later quadratic step (the one that pairwise
 compares all unmatched files to find the "best" matches, determined by
@@ -213,7 +213,7 @@ from the original, and does not count insertion.  If you removed
 only 10 lines from a 100-line document, even if you added 910
 new lines to make a new 1000-line document, you did not do a
 complete rewrite.  diffcore-break breaks such a case in order to
-help diffcore-rename to consider such filepairs as candidate of
+help diffcore-rename to consider such filepairs as candidate of
 rename/copy detection, but if filepairs broken that way were not
 matched with other filepairs to create rename/copy, then this
 transformation merges them back into the original
@@ -230,13 +230,13 @@ like these:
 
 * -B/60 (the same as above, since diffcore-break defaults to 50%).
 
-Note that earlier implementation left a broken pair as separate
-creation and deletion patches.  This was an unnecessary hack and
+Note that earlier implementation left a broken pair as separate
+creation and deletion patches.  This was an unnecessary hack, and
 the latest implementation always merges all the broken pairs
 back into modifications, but the resulting patch output is
 formatted differently for easier review in case of such
-a complete rewrite by showing the entire contents of old version
-prefixed with '-', followed by the entire contents of new
+a complete rewrite by showing the entire contents of the old version
+prefixed with '-', followed by the entire contents of the new
 version prefixed with '+'.
 
 
@@ -263,7 +263,7 @@ textual diff has an added or a deleted line that matches the given
 regular expression.  This means that it will detect in-file (or what
 rename-detection considers the same file) moves, which is noise.  The
 implementation runs diff twice and greps, and this can be quite
-expensive.  To speed things up binary files without textconv filters
+expensive.  To speed things up, binary files without textconv filters
 will be ignored.
 
 When `-S` or `-G` are used without `--pickaxe-all`, only filepairs
index faba2ef0881c52e8c6c2e5ec0f5702c0b1ba5028..6cfdd0e07b46f269c059e38409dffe45d44a59f9 100644 (file)
@@ -14,7 +14,7 @@ DESCRIPTION
 -----------
 
 Git users can broadly be grouped into four categories for the purposes of
-describing here a small set of useful command for everyday Git.
+describing here a small set of useful commands for everyday Git.
 
 *      <<STANDALONE,Individual Developer (Standalone)>> commands are essential
        for anybody who makes a commit, even for somebody who works alone.
@@ -229,7 +229,7 @@ without a formal "merging". Or longhand +
   git am -3 -k`
 
 An alternate participant submission mechanism is using the
-`git request-pull` or pull-request mechanisms (e.g as used on
+`git request-pull` or pull-request mechanisms (e.g. as used on
 GitHub (www.github.com) to notify your upstream of your
 contribution.
 
index 00e0a20e6571969ebeabca8da5d9815be65d682b..1b75cf71cec103f8a5e36056532f888d1ac58e71 100644 (file)
@@ -67,7 +67,7 @@ A Git bundle consists of several parts.
 * "Capabilities", which are only in the v3 format, indicate functionality that
        the bundle requires to be read properly.
 
-* "Prerequisites" lists the objects that are NOT included in the bundle and the
+* "Prerequisites" list the objects that are NOT included in the bundle and the
   reader of the bundle MUST already have, in order to use the data in the
   bundle. The objects stored in the bundle may refer to prerequisite objects and
   anything reachable from them (e.g. a tree object in the bundle can reference
@@ -86,10 +86,10 @@ 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 shallow clones and Git bundles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Note that the prerequisites does not represent a shallow-clone boundary. The
+Note that the prerequisites do 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.
 
index 57202ede273ad266be910045294fd74853dd193c..3315df6201dc964886652c494b2123260de9f434 100644 (file)
@@ -42,7 +42,7 @@ Each row consists of a 4-byte chunk identifier (ID) and an 8-byte offset.
 Each integer is stored in network-byte order.
 
 The chunk identifier `ID[i]` is a label for the data stored within this
-fill from `OFFSET[i]` (inclusive) to `OFFSET[i+1]` (exclusive). Thus, the
+file from `OFFSET[i]` (inclusive) to `OFFSET[i+1]` (exclusive). Thus, the
 size of the `i`th chunk is equal to the difference between `OFFSET[i+1]`
 and `OFFSET[i]`. This requires that the chunk data appears contiguously
 in the same order as the table of contents.
@@ -67,7 +67,7 @@ caller is responsible for opening the `hashfile` and writing header
 information so the file format is identifiable before the chunk-based
 format begins.
 
-Then, call `add_chunk()` for each chunk that is intended for write. This
+Then, call `add_chunk()` for each chunk that is intended for writing. This
 populates the `chunkfile` with information about the order and size of
 each chunk to write. Provide a `chunk_write_fn` function pointer to
 perform the write of the chunk data upon request.
index 0c1be2dbe85caf3300a314c374dd12d54b7434a7..4a4d87e7dbf5ceedb294833254281bcffb3b9880 100644 (file)
@@ -17,8 +17,8 @@ $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
+The Git pack format is how Git stores most of its primary repository
+data. Over the lifetime of 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].
 
@@ -48,7 +48,7 @@ Similarly, in SHA-256 repositories, these values are computed using SHA-256.
      Observation: we cannot have more than 4G versions ;-) and
      more than 4G objects in a pack.
 
-   - The header is followed by number of object entries, each of
+   - The header is followed by number of object entries, each of
      which looks like this:
 
      (undeltified representation)
@@ -62,7 +62,7 @@ Similarly, in SHA-256 repositories, these values are computed using SHA-256.
         is an OBJ_OFS_DELTA object
      compressed delta data
 
-     Observation: length of each object is encoded in a variable
+     Observation: the length of each object is encoded in a variable
      length format and is not constrained to 32-bit or anything.
 
   - The trailer records a pack checksum of all of the above.
@@ -117,7 +117,7 @@ the delta data is a sequence of instructions to reconstruct the object
 from the base object. If the base object is deltified, it must be
 converted to canonical form first. Each instruction appends more and
 more data to the target object until it's complete. There are two
-supported instructions so far: one for copy a byte range from the
+supported instructions so far: one for copying a byte range from the
 source object and one for inserting new data embedded in the
 instruction itself.
 
@@ -137,7 +137,7 @@ copy. Offset and size are in little-endian order.
 
 All offset and size bytes are optional. This is to reduce the
 instruction size when encoding small offsets or sizes. The first seven
-bits in the first octet determines which of the next seven octets is
+bits in the first octet determine which of the next seven octets is
 present. If bit zero is set, offset1 is present. If bit one is set
 offset2 is present and so on.
 
@@ -161,9 +161,9 @@ converted to 0x10000.
   | 0xxxxxxx |    data    |
   +----------+============+
 
-This is the instruction to construct target object without the base
+This is the instruction to construct the target object without the base
 object. The following data is appended to the target object. The first
-seven bits of the first octet determines the size of data in
+seven bits of the first octet determine the size of data in
 bytes. The size must be non-zero.
 
 ==== Reserved instruction
@@ -294,7 +294,7 @@ Pack file entry: <+
 
   - The same trailer as a v1 pack file:
 
-    A copy of the pack checksum at the end of
+    A copy of the pack checksum at the end of the
     corresponding packfile.
 
     Index checksum of all of the above.
@@ -588,51 +588,17 @@ 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
-setting the `gc.cruftPacks` configuration to "false" 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.
+  - The location of the per-object mtime data.
 
 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
index 86f804720ae71fc3d0db94623663539bd05a06f2..883982e7a0516204ddd2f2f9e14775fa17e2a810 100644 (file)
@@ -80,7 +80,7 @@ If it exits with non-zero status, then the working tree will not be
 committed after applying the patch.
 
 It can be used to inspect the current working tree and refuse to
-make a commit if it does not pass certain test.
+make a commit if it does not pass certain tests.
 
 The default 'pre-applypatch' hook, when enabled, runs the
 'pre-commit' hook, if the latter is enabled.
@@ -157,7 +157,7 @@ If the exit status is non-zero, `git commit` will abort.
 The purpose of the hook is to edit the message file in place, and
 it is not suppressed by the `--no-verify` option.  A non-zero exit
 means a failure of the hook and aborts the commit.  It should not
-be used as replacement for pre-commit hook.
+be used as a replacement for the pre-commit hook.
 
 The sample `prepare-commit-msg` hook that comes with Git removes the
 help message found in the commented portion of the commit template.
@@ -345,7 +345,7 @@ for the user.
 
 The default 'update' hook, when enabled--and with
 `hooks.allowunannotated` config option unset or set to false--prevents
-unannotated tags to be pushed.
+unannotated tags from being pushed.
 
 [[proc-receive]]
 proc-receive
@@ -379,12 +379,12 @@ following example for the protocol, the letter 'S' stands for
     S: ... ...
     S: flush-pkt
 
-    # Receive result from the hook.
+    # Receive results from the hook.
     # OK, run this command successfully.
     H: PKT-LINE(ok <ref>)
     # NO, I reject it.
     H: PKT-LINE(ng <ref> <reason>)
-    # Fall through, let 'receive-pack' to execute it.
+    # Fall through, let 'receive-pack' execute it.
     H: PKT-LINE(ok <ref>)
     H: PKT-LINE(option fall-through)
     # OK, but has an alternate reference.  The alternate reference name
index 4c17f2356c40b2fce2c588db97c3abf4f7f262b0..5e0964ef4191d95acc0965b82fdfa1de295a6bc3 100644 (file)
@@ -88,7 +88,7 @@ PATTERN FORMAT
    Put a backslash ("`\`") in front of the first "`!`" for patterns
    that begin with a literal "`!`", for example, "`\!important!.txt`".
 
- - The slash '/' is used as the directory separator. Separators may
+ - The slash "`/`" is used as the directory separator. Separators may
    occur at the beginning, middle or end of the `.gitignore` search pattern.
 
  - If there is a separator at the beginning or middle (or both) of the
@@ -174,10 +174,10 @@ EXAMPLES
    is not relevant  if there is already a middle slash in
    the pattern.
 
- - The pattern "foo/*", matches "foo/test.json"
-   (a regular file), "foo/bar" (a directory), but it does not match
-   "foo/bar/hello.c" (a regular file), as the asterisk in the
-   pattern does not match "bar/hello.c" which has a slash in it.
+ - The pattern `foo/*`, matches `foo/test.json`
+   (a regular file), `foo/bar` (a directory), but it does not match
+   `foo/bar/hello.c` (a regular file), as the asterisk in the
+   pattern does not match `bar/hello.c` which has a slash in it.
 
 --------------------------------------------------------------
     $ git status
index d50e9ed10e04c688b6ee898b20e24a1cd796cc78..c2213bb77b380a213c1d4a8f6230790b9d8ecb57 100644 (file)
@@ -26,7 +26,7 @@ changes each commit introduces are shown.  Finally, it supports some
 gitk-specific options.
 
 gitk generally only understands options with arguments in the
-'sticked' form (see linkgit:gitcli[7]) due to limitations in the
+'stuck' form (see linkgit:gitcli[7]) due to limitations in the
 command-line parser.
 
 rev-list options and arguments
index dcee09b5001dc8cfb95753c0c02a5b49ba036752..d9bec8b1875502b22934877311d3124a3e5a22df 100644 (file)
@@ -43,9 +43,9 @@ submodule.<name>.update::
        command in the superproject. This is only used by `git
        submodule init` to initialize the configuration variable of
        the same name. Allowed values here are 'checkout', 'rebase',
-       'merge' or 'none'. See description of 'update' command in
-       linkgit:git-submodule[1] for their meaning. For security
-       reasons, the '!command' form is not accepted here.
+       'merge' or 'none', but not '!command' (for security reasons).
+       See the description of the 'update' command in
+       linkgit:git-submodule[1] for more details.
 
 submodule.<name>.branch::
        A remote branch name for tracking updates in the upstream submodule.
index 0fb5ea0c1ca7547679d060f8fe2be7d2edf58c86..d6c6effc2151ffa136f0f2e36a07b659e25c43e4 100644 (file)
@@ -30,7 +30,7 @@ to be in effect. The client MUST NOT ask for capabilities the server
 did not say it supports.
 
 Server MUST diagnose and abort if capabilities it does not understand
-was sent.  Server MUST NOT ignore capabilities that client requested
+were sent.  Server MUST NOT ignore capabilities that client requested
 and server advertised.  As a consequence of these rules, server MUST
 NOT advertise capabilities it does not understand.
 
@@ -61,8 +61,8 @@ complete cut across the DAG, or the client has said "done".
 Without multi_ack, a client sends have lines in --date-order until
 the server has found a common base.  That means the client will send
 have lines that are already known by the server to be common, because
-they overlap in time with another branch that the server hasn't found
-a common base on yet.
+they overlap in time with another branch on which the server hasn't found
+a common base yet.
 
 For example suppose the client has commits in caps that the server
 doesn't and the server has commits in lower case that the client
@@ -88,7 +88,7 @@ interleaved with S-R-Q.
 
 multi_ack_detailed
 ------------------
-This is an extension of multi_ack that permits client to better
+This is an extension of multi_ack that permits the client to better
 understand the server's in-memory state. See linkgit:gitprotocol-pack[5],
 section "Packfile Negotiation" for more information.
 
@@ -135,7 +135,7 @@ to disable the feature in a backwards-compatible manner.
 side-band, side-band-64k
 ------------------------
 
-This capability means that server can send, and client understand multiplexed
+This capability means that the server can send, and the client can understand, multiplexed
 progress reports and error info interleaved with the packfile itself.
 
 These two options are mutually exclusive. A modern client always
@@ -163,14 +163,14 @@ Further, with side-band and its up to 1000-byte messages, it's actually
 same deal, you have up to 65519 bytes of data and 1 byte for the stream
 code.
 
-The client MUST send only maximum of one of "side-band" and "side-
-band-64k".  Server MUST diagnose it as an error if client requests
+The client MUST send only one of "side-band" and "side-
+band-64k".  The server MUST diagnose it as an error if client requests
 both.
 
 ofs-delta
 ---------
 
-Server can send, and client understand PACKv2 with delta referring to
+The server can send, and the client can understand, PACKv2 with delta referring to
 its base by position in pack rather than by an obj-id.  That is, they can
 send/read OBJ_OFS_DELTA (aka type 6) in a packfile.
 
@@ -252,7 +252,7 @@ the current shallow boundary, instead of the depth from remote refs.
 no-progress
 -----------
 
-The client was started with "git clone -q" or something, and doesn't
+The client was started with "git clone -q" or something similar, and doesn't
 want that side band 2.  Basically the client just says "I do not
 wish to receive stream 2 on sideband, so do not send it to me, and if
 you did, I will drop it on the floor anyway".  However, the sideband
@@ -273,7 +273,7 @@ request include-tag only has to do with the client's desires for tag
 data, whether or not a server had advertised objects in the
 refs/tags/* namespace.
 
-Servers MUST pack the tags if their referrant is packed and the client
+Servers MUST pack the tags if their referent is packed and the client
 has requested include-tags.
 
 Clients MUST be prepared for the case where a server has ignored
index 1486651bd1002f3c121c703caae154caa822fedc..cdc9d6e707586cc1f7c23de318957d2e42ef5d88 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-This document sets defines things common to various over-the-wire
+This document defines things common to various over-the-wire
 protocols and file formats used in Git.
 
 ABNF Notation
index ccc13f0a40758ac5f8268472354998d63331bf92..21b73b7a1f5bd0bee369cb56070ea6b684390446 100644 (file)
@@ -42,7 +42,7 @@ both the "smart" and "dumb" HTTP protocols used by Git operate
 by appending additional path components onto the end of the user
 supplied `$GIT_URL` string.
 
-An example of a dumb client requesting for a loose object:
+An example of a dumb client requesting a loose object:
 
   $GIT_URL:     http://example.com:8080/git/repo.git
   URL request:  http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355
@@ -379,7 +379,7 @@ C: Place any object seen into set `advertised`.
 C: Build an empty set, `common`, to hold the objects that are later
    determined to be on both ends.
 
-C: Build a set, `want`, of the objects from `advertised` the client
+C: Build a set, `want`, of the objects from `advertised` that the client
    wants to fetch, based on what it saw during ref discovery.
 
 C: Start a queue, `c_pending`, ordered by commit time (popping newest
@@ -423,7 +423,7 @@ multiple commands. Object names MUST be given using the object format
 negotiated through the `object-format` capability (default SHA-1).
 
 The `have` list is created by popping the first 32 commits
-from `c_pending`.  Less can be supplied if `c_pending` empties.
+from `c_pending`.  Fewer can be supplied if `c_pending` empties.
 
 If the client has sent 256 "have" commits and has not yet
 received one of those back from `s_common`, or the client has
index dd4108b7a3b95456e0887fc41aed4e381261bd41..837b691c892b31e204948c29b986337809683ce1 100644 (file)
@@ -30,7 +30,7 @@ pkt-line Format
 ---------------
 
 The descriptions below build on the pkt-line format described in
-linkgit:gitprotocol-common[5]. When the grammar indicate `PKT-LINE(...)`, unless
+linkgit:gitprotocol-common[5]. When the grammar indicates `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.
 
@@ -137,7 +137,7 @@ an absolute path in the remote filesystem.
                    v
     ssh user@example.com "git-upload-pack '/project.git'"
 
-In a "user@host:path" format URI, its relative to the user's home
+In a "user@host:path" format URI, it's relative to the user's home
 directory, because the Git client will run:
 
      git clone user@example.com:project.git
@@ -325,7 +325,7 @@ a positive depth, this step is skipped.
 
 If the client has requested a positive depth, the server will compute
 the set of commits which are no deeper than the desired depth. The set
-of commits start at the client's wants.
+of commits starts at the client's wants.
 
 The server writes 'shallow' lines for each
 commit whose parents will not be sent as a result. The server writes
index acb97ad0c22440a5039d8cf3da6f00dd60295a24..8c1e7c61eac751d352b9268ff2d57b357ce62ed4 100644 (file)
@@ -29,7 +29,7 @@ protocol.  Protocol v2 will improve upon v1 in the following ways:
     semantics the http remote helper can simply act as a proxy
 
 In protocol v2 communication is command oriented.  When first contacting a
-server a list of capabilities will advertised.  Some of these capabilities
+server a list of capabilities will be advertised.  Some of these capabilities
 will be commands which a client can request be executed.  Once a command
 has completed, a client can reuse the connection and request that other
 commands be executed.
index 941858a6ecce88440975f02c2462f6aa8692b0bc..8400d591da0e8a93035d72a947b07728055eeebd 100644 (file)
@@ -78,7 +78,7 @@ Submodule operations can be configured using the following mechanisms
 
  * The command line for those commands that support taking submodules
    as part of their pathspecs. Most commands have a boolean flag
-   `--recurse-submodules` which specify whether to recurse into submodules.
+   `--recurse-submodules` which specifies whether to recurse into submodules.
    Examples are `grep` and `checkout`.
    Some commands take enums, such as `fetch` and `push`, where you can
    specify how submodules are affected.
@@ -192,7 +192,7 @@ For example:
   [submodule "baz"]
     url = https://example.org/baz
 
-In the above config only the submodule 'bar' and 'baz' are active,
+In the above config only the submodules 'bar' and 'baz' are active,
 'bar' due to (1) and 'baz' due to (3). 'foo' is inactive because
 (1) takes precedence over (3)
 
@@ -274,7 +274,7 @@ will not be checked out by default; you can instruct `clone` to recurse
 into submodules. The `init` and `update` subcommands of `git submodule`
 will maintain submodules checked out and at an appropriate revision in
 your working tree. Alternatively you can set `submodule.recurse` to have
-`checkout` recursing into submodules (note that `submodule.recurse` also
+`checkout` recurse into submodules (note that `submodule.recurse` also
 affects other Git commands, see linkgit:git-config[1] for a complete list).
 
 
index c7cadd8aaf1a0e6606d2b559b674526bc687849a..4759408788070baba26b94e91dde74a9e6c6dda5 100644 (file)
@@ -137,10 +137,10 @@ which will automatically notice any modified (but not new) files, add
 them to the index, and commit, all in one step.
 
 A note on commit messages: Though not required, it's a good idea to
-begin the commit message with a single short (less than 50 character)
-line summarizing the change, followed by a blank line and then a more
-thorough description. The text up to the first blank line in a commit
-message is treated as the commit title, and that title is used
+begin the commit message with a single short (no more than 50
+characters) line summarizing the change, followed by a blank line and
+then a more thorough description. The text up to the first blank line in
+a commit message is treated as the commit title, and that title is used
 throughout Git.  For example, linkgit:git-format-patch[1] turns a
 commit into email, and it uses the title on the Subject line and the
 rest of the commit in the body.
index 34b1d6e224356cd3e9a637d0d5bdbef2f6ee269d..b078fef6f5c6ff09c9db52ee8a3d3945144b6fc1 100644 (file)
@@ -53,7 +53,7 @@ following order:
    `/etc/gitweb-common.conf`),
 
  * either per-instance configuration file (defaults to 'gitweb_config.perl'
-   in the same directory as the installed gitweb), or if it does not exists
+   in the same directory as the installed gitweb), or if it does not exist
    then fallback system-wide configuration file (defaults to `/etc/gitweb.conf`).
 
 Values obtained in later configuration files override values obtained earlier
index 7cee9d36899101b1ea48cebcb875388164b002b8..1030e9667ea8c2a0089cef0a725f57581093aa19 100644 (file)
@@ -8,7 +8,7 @@ gitweb - Git web interface (web frontend to Git repositories)
 SYNOPSIS
 --------
 To get started with gitweb, run linkgit:git-instaweb[1] from a Git repository.
-This would configure and start your web server, and run web browser pointing to
+This will configure and start your web server, and run a web browser pointing to
 gitweb.
 
 
@@ -20,13 +20,13 @@ Gitweb provides a web interface to Git repositories.  Its features include:
 * Browsing every revision of the repository.
 * Viewing the contents of files in the repository at any revision.
 * Viewing the revision log of branches, history of files and directories,
-  see what was changed when, by who.
+  seeing what was changed, when, and by whom.
 * Viewing the blame/annotation details of any file (if enabled).
 * Generating RSS and Atom feeds of commits, for any branch.
   The feeds are auto-discoverable in modern web browsers.
-* Viewing everything that was changed in a revision, and step through
+* Viewing everything that was changed in a revision, and stepping through
   revisions one at a time, viewing the history of the repository.
-* Finding commits which commit messages matches given search term.
+* Finding commits whose commit messages match a given search term.
 
 See http://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
 browsed using gitweb itself.
@@ -41,9 +41,9 @@ for details.
 Repositories
 ~~~~~~~~~~~~
 Gitweb can show information from one or more Git repositories.  These
-repositories have to be all on local filesystem, and have to share common
+repositories have to be all on local filesystem, and have to share common
 repository root, i.e. be all under a single parent repository (but see also
-"Advanced web server setup" section, "Webserver configuration with multiple
+the "Advanced web server setup" section, "Webserver configuration with multiple
 projects' root" subsection).
 
 -----------------------------------------------------------------------
@@ -51,7 +51,7 @@ our $projectroot = '/path/to/parent/directory';
 -----------------------------------------------------------------------
 
 The default value for `$projectroot` is `/pub/git`.  You can change it during
-building gitweb via `GITWEB_PROJECTROOT` build configuration variable.
+building gitweb via the `GITWEB_PROJECTROOT` build configuration variable.
 
 By default all Git repositories under `$projectroot` are visible and available
 to gitweb.  The list of projects is generated by default by scanning the
@@ -66,7 +66,7 @@ found at "$projectroot/$repo".
 
 Projects list file format
 ~~~~~~~~~~~~~~~~~~~~~~~~~
-Instead of having gitweb find repositories by scanning filesystem
+Instead of having gitweb find repositories by scanning the filesystem
 starting from $projectroot, you can provide a pre-generated list of
 visible projects by setting `$projects_list` to point to a plain text
 file with a list of projects (with some additional info).
@@ -503,7 +503,7 @@ repositories, you can configure Apache like this:
 
 The above configuration expects your public repositories to live under
 `/pub/git` and will serve them as `http://git.domain.org/dir-under-pub-git`,
-both as clonable Git URL and as browseable gitweb interface.  If you then
+both as clonable Git URL and as browsable gitweb interface.  If you then
 start your linkgit:git-daemon[1] with `--base-path=/pub/git --export-all`
 then you can even use the `git://` URL with exactly the same path.
 
index 5a537268e275e45142640820942004b5cd731dbb..65c89e7b3eb0178d9167ef714c42d9ad3873f2f5 100644 (file)
@@ -186,7 +186,7 @@ current branch integrates with) obviously do not work, as there is no
        points at the directory that is the real repository.
 
 [[def_grafts]]grafts::
-       Grafts enables two otherwise different lines of development to be joined
+       Grafts enable two otherwise different lines of development to be joined
        together by recording fake ancestry information for commits. This way
        you can make Git pretend the set of <<def_parent,parents>> a <<def_commit,commit>> has
        is different from what was recorded when the commit was
index e653775bab18ddeacb03ec16beaa6d25af5ecf3d..b9cb95e82f0eca994c7a0b9149e028feef83bdec 100644 (file)
@@ -145,7 +145,7 @@ Opening a Security Advisory draft
 
 The first step is to https://github.com/git/git/security/advisories/new[open
 an advisory]. Technically, this is not necessary. However, it is the most
-convenient way to obtain the CVE number and it give us a private repository
+convenient way to obtain the CVE number and it gives us a private repository
 associated with it that can be used to collaborate on a fix.
 
 Notifying the Linux distributions
index d07c6d44e53c3bd0e7805efa036f2cf3eeaf79ac..013014bbef67ac149ea8ebdb3093ed8648b5a469 100644 (file)
@@ -104,7 +104,7 @@ by doing the following:
    files in mbox format).
 
  - Write his own patches to address issues raised on the list but
-   nobody has stepped up solving.  Send it out just like other
+   nobody has stepped up to solve.  Send it out just like other
    contributors do, and pick them up just like patches from other
    contributors (see above).
 
@@ -411,13 +411,13 @@ Preparing a "merge-fix"
 
 A merge of two topics may not textually conflict but still have
 conflict at the semantic level. A classic example is for one topic
-to rename an variable and all its uses, while another topic adds a
+to rename a variable and all its uses, while another topic adds a
 new use of the variable under its old name. When these two topics
 are merged together, the reference to the variable newly added by
 the latter topic will still use the old name in the result.
 
 The Meta/Reintegrate script that is used by redo-jch and redo-seen
-scripts implements a crude but usable way to work this issue around.
+scripts implements a crude but usable way to work around this issue.
 When the script merges branch $X, it checks if "refs/merge-fix/$X"
 exists, and if so, the effect of it is squashed into the result of
 the mechanical merge.  In other words,
index 7af2e52cf312c474d5888855fb86b7456a2d82db..2cad9b3ca5366fd115569e1e8d3b7484fed75bfd 100644 (file)
@@ -4,7 +4,7 @@ How to use git-daemon
 =====================
 
 Git can be run in inetd mode and in stand alone mode. But all you want is
-let a coworker pull from you, and therefore need to set up a Git server
+to let a coworker pull from you, and therefore need to set up a Git server
 real quick, right?
 
 Note that git-daemon is not really chatty at the moment, especially when
index a499a94ac2289ac6664035d339e37914748757d2..3bd581ac3591b6c3bf49a77c60e705539ab8319d 100644 (file)
@@ -11,7 +11,7 @@ Message-ID: <BAYC1-PASMTP12374B54BA370A1E1C6E78AE4E0@CEZ.ICE>
 How to use the subtree merge strategy
 =====================================
 
-There are situations where you want to include contents in your project
+There are situations where you want to include content in your project
 from an independently developed project. You can just pull from the
 other project as long as there are no conflicting paths.
 
index 6c6baeeeb75bd8ff15e7b2ec1f3c394e0c9ef845..3a866af4a4205d0cd101d862c45e7d96bd5718fa 100644 (file)
@@ -34,7 +34,7 @@ project find it more convenient to use legacy encodings, Git
 does not forbid it.  However, there are a few things to keep in
 mind.
 
-. 'git commit' and 'git commit-tree' issues
+. 'git commit' and 'git commit-tree' issue
   a warning if the commit log message given to it does not look
   like a valid UTF-8 string, unless you explicitly say your
   project uses a legacy encoding.  The way to say this is to
@@ -46,7 +46,7 @@ mind.
 ------------
 +
 Commit objects created with the above setting record the value
-of `i18n.commitEncoding` in its `encoding` header.  This is to
+of `i18n.commitEncoding` in their `encoding` header.  This is to
 help other people who look at them later.  Lack of this header
 implies that the commit log message is encoded in UTF-8.
 
index 2d631e9b1f242f334d9751823b5771d8e1d84112..d1a4c468e6354e47f52579d6e44f2387b51ba811 100644 (file)
@@ -32,10 +32,10 @@ have special meaning:
   - `+` is used to "open a new tab"
   - `,` is used to "open a new vertical split"
   - `/` is used to "open a new horizontal split"
-  - `@` is used to indicate which is the file containing the final version after
+  - `@` is used to indicate the file containing the final version after
     solving the conflicts. If not present, `MERGED` will be used by default.
 
-The precedence of the operators is this one (you can use parentheses to change
+The precedence of the operators is as follows (you can use parentheses to change
 it):
 
     `@` > `+` > `/` > `,`
@@ -162,7 +162,7 @@ information as the first tab, with a different layout.
 |       REMOTE        |                     |
 ---------------------------------------------
 ....
-Note how in the third tab definition we need to use parenthesis to make `,`
+Note how in the third tab definition we need to use parentheses to make `,`
 have precedence over `/`.
 --
 
index 4cb106f0d146e754e626e5d22a512ad9ab5524a3..e561e6668c9e59daa705e563068cd8b20aabd038 100644 (file)
@@ -1,6 +1,9 @@
-THIS OPTION IS EXPERIMENTAL! SHA-256 support is experimental and still
-in an early stage.  A SHA-256 repository will in general not be able to
-share work with "regular" SHA-1 repositories.  It should be assumed
-that, e.g., Git internal file formats in relation to SHA-256
-repositories may change in backwards-incompatible ways.  Only use
-`--object-format=sha256` for testing purposes.
+Note: At present, there is no interoperability between SHA-256
+repositories and SHA-1 repositories.
+
+Historically, we warned that SHA-256 repositories may later need
+backward incompatible changes when we introduce such interoperability
+features. Today, we only expect compatible changes. Furthermore, if such
+changes prove to be necessary, it can be expected that SHA-256 repositories
+created with today's Git will be usable by future versions of Git
+without data loss.
index 3b713344597090037bd6cd7bc034aaeed8316656..d38b4ab5666c35e0ae83680abca0e067c7b14792 100644 (file)
@@ -122,7 +122,9 @@ The placeholders are:
 - Placeholders that expand to a single literal character:
 '%n':: newline
 '%%':: a raw '%'
-'%x00':: print a byte from a hex code
+'%x00':: '%x' followed by two hexadecimal digits is replaced with a
+        byte with the hexadecimal digits' value (we will call this
+        "literal formatting code" in the rest of this document).
 
 - Placeholders that affect formatting of later placeholders:
 '%Cred':: switch color to red
@@ -222,13 +224,30 @@ The placeholders are:
        linkgit:git-rev-list[1])
 '%d':: ref names, like the --decorate option of linkgit:git-log[1]
 '%D':: ref names without the " (", ")" wrapping.
-'%(describe[:options])':: human-readable name, like
-                         linkgit:git-describe[1]; empty string for
-                         undescribable commits.  The `describe` string
-                         may be followed by a colon and zero or more
-                         comma-separated options.  Descriptions can be
-                         inconsistent when tags are added or removed at
-                         the same time.
+'%(decorate[:<options>])'::
+ref names with custom decorations. The `decorate` string may be followed by a
+colon and zero or more comma-separated options. Option values may contain
+literal formatting codes. These must be used for commas (`%x2C`) and closing
+parentheses (`%x29`), due to their role in the option syntax.
++
+** 'prefix=<value>': Shown before the list of ref names.  Defaults to "{nbsp}`(`".
+** 'suffix=<value>': Shown after the list of ref names.  Defaults to "`)`".
+** 'separator=<value>': Shown between ref names.  Defaults to "`,`{nbsp}".
+** 'pointer=<value>': Shown between HEAD and the branch it points to, if any.
+                     Defaults to "{nbsp}`->`{nbsp}".
+** 'tag=<value>': Shown before tag names. Defaults to "`tag:`{nbsp}".
+
++
+For example, to produce decorations with no wrapping
+or tag annotations, and spaces as separators:
++
+`%(decorate:prefix=,suffix=,tag=,separator= )`
+
+'%(describe[:<options>])'::
+human-readable name, like linkgit:git-describe[1]; empty string for
+undescribable commits.  The `describe` string may be followed by a colon and
+zero or more comma-separated options.  Descriptions can be inconsistent when
+tags are added or removed at the same time.
 +
 ** 'tags[=<bool-value>]': Instead of only considering annotated tags,
    consider lightweight tags as well.
@@ -281,13 +300,11 @@ endif::git-rev-list[]
 '%gE':: reflog identity email (respecting .mailmap, see
        linkgit:git-shortlog[1] or linkgit:git-blame[1])
 '%gs':: reflog subject
-'%(trailers[:options])':: display the trailers of the body as
-                         interpreted by
-                         linkgit:git-interpret-trailers[1]. The
-                         `trailers` string may be followed by a colon
-                         and zero or more comma-separated options.
-                         If any option is provided multiple times the
-                         last occurrence wins.
+'%(trailers[:<options>])'::
+display the trailers of the body as interpreted by
+linkgit:git-interpret-trailers[1]. The `trailers` string may be followed by
+a colon and zero or more comma-separated options. If any option is provided
+multiple times, the last occurrence wins.
 +
 ** 'key=<key>': only show trailers with specified <key>. Matching is done
    case-insensitively and trailing colon is optional. If option is
index dc685be363a674e754dc62f961558d97d5e65a7d..23888cd612c9fb0c18ac1e24ac56a1a6f2a0a149 100644 (file)
@@ -48,7 +48,7 @@ people using 80-column terminals.
 --expand-tabs::
 --no-expand-tabs::
        Perform a tab expansion (replace each tab with enough spaces
-       to fill to the next display column that is multiple of '<n>')
+       to fill to the next display column that is multiple of '<n>')
        in the log message before showing it in the output.
        `--expand-tabs` is a short-hand for `--expand-tabs=8`, and
        `--no-expand-tabs` is a short-hand for `--expand-tabs=0`,
@@ -73,7 +73,7 @@ environment overrides). See linkgit:git-config[1] for more details.
 With an optional '<ref>' argument, use the ref to find the notes
 to display.  The ref can specify the full refname when it begins
 with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
-`refs/notes/` is prefixed to form a full name of the ref.
+`refs/notes/` is prefixed to form the full name of the ref.
 +
 Multiple --notes options can be combined to control which notes are
 being displayed. Examples: "--notes=foo" will show only notes from
@@ -87,6 +87,10 @@ being displayed. Examples: "--notes=foo" will show only notes from
        "--notes --notes=foo --no-notes --notes=bar" will only show notes
        from "refs/notes/bar".
 
+--show-notes-by-default::
+       Show the default notes unless options for displaying specific
+       notes are given.
+
 --show-notes[=<ref>]::
 --[no-]standard-notes::
        These options are deprecated. Use the above --notes/--no-notes
index 95a7390b2c78bddfc2c094fa6f0ba82e2b6de417..c718f7946f065d425c818c09bfd11fd641b73b4f 100644 (file)
@@ -71,7 +71,7 @@ refspec (or `--force`).
 Unlike when pushing with linkgit:git-push[1], any updates outside of
 `refs/{tags,heads}/*` will be accepted without `+` in the refspec (or
 `--force`), whether that's swapping e.g. a tree object for a blob, or
-a commit for another commit that's doesn't have the previous commit as
+a commit for another commit that doesn't have the previous commit as
 an ancestor etc.
 +
 Unlike when pushing with linkgit:git-push[1], there is no
@@ -80,7 +80,7 @@ configuration which'll amend these rules, and nothing like a
 +
 As with pushing with linkgit:git-push[1], all of the rules described
 above about what's not allowed as an update can be overridden by
-adding an the optional leading `+` to a refspec (or using `--force`
+adding an optional leading `+` to a refspec (or using the `--force`
 command line option). The only exception to this is that no amount of
 forcing will make the `refs/heads/*` namespace accept a non-commit
 object.
@@ -88,7 +88,7 @@ object.
 [NOTE]
 When the remote branch you want to fetch is known to
 be rewound and rebased regularly, it is expected that
-its new tip will not be descendant of its previous tip
+its new tip will not be descendant of its previous tip
 (as stored in your remote-tracking branch the last time
 you fetched).  You would want
 to use the `+` sign to indicate non-fast-forward updates
index 3000888a90852f6bd95eee5b40dc2f184ddd3dc9..2bf239ff0309aa0e45436c06788f49c094bfac8f 100644 (file)
@@ -56,7 +56,7 @@ endif::git-rev-list[]
        error to use this option unless `--walk-reflogs` is in use.
 
 --grep=<pattern>::
-       Limit the commits output to ones with log message that
+       Limit the commits output to ones with log message that
        matches the specified pattern (regular expression).  With
        more than one `--grep=<pattern>`, commits whose message
        matches any of the given patterns are chosen (but see
@@ -72,7 +72,7 @@ endif::git-rev-list[]
        instead of ones that match at least one.
 
 --invert-grep::
-       Limit the commits output to ones with log message that do not
+       Limit the commits output to ones with log message that do not
        match the pattern specified with `--grep=<pattern>`.
 
 -i::
@@ -151,6 +151,10 @@ endif::git-log[]
 --not::
        Reverses the meaning of the '{caret}' prefix (or lack thereof)
        for all following revision specifiers, up to the next `--not`.
+       When used on the command line before --stdin, the revisions passed
+       through stdin will not be affected by it. Conversely, when passed
+       via standard input, the revisions passed on the command line will
+       not be affected by it.
 
 --all::
        Pretend as if all the refs in `refs/`, along with `HEAD`, are
@@ -236,10 +240,13 @@ ifndef::git-rev-list[]
 endif::git-rev-list[]
 
 --stdin::
-       In addition to the '<commit>' listed on the command
-       line, read them from the standard input. If a `--` separator is
-       seen, stop reading commits and start reading paths to limit the
-       result.
+       In addition to getting arguments from the command line, read
+       them from standard input as well. This accepts commits and
+       pseudo-options like `--all` and `--glob=`. When a `--` separator
+       is seen, the following input is treated as paths and used to
+       limit the result. Flags like `--not` which are read via standard input
+       are only respected for arguments passed in the same way and will not
+       influence any subsequent command line arguments.
 
 ifdef::git-rev-list[]
 --quiet::
index 9aa58052bc73dc773844d77819889c66222dc591..6ea6c7cead16476a710629d1aa56c345d07b8538 100644 (file)
@@ -30,10 +30,11 @@ characters and to avoid word splitting.
   explicitly say 'heads/master' to tell Git which one you mean.
   When ambiguous, a '<refname>' is disambiguated by taking the
   first match in the following rules:
-
++
   . If '$GIT_DIR/<refname>' exists, that is what you mean (this is usually
-    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`
-    and `CHERRY_PICK_HEAD`);
+    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`,
+    `REBASE_HEAD`, `REVERT_HEAD`, `CHERRY_PICK_HEAD`, `BISECT_HEAD`
+    and `AUTO_MERGE`);
 
   . otherwise, 'refs/<refname>' if it exists;
 
@@ -44,19 +45,38 @@ characters and to avoid word splitting.
   . otherwise, 'refs/remotes/<refname>' if it exists;
 
   . otherwise, 'refs/remotes/<refname>/HEAD' if it exists.
+
 +
-`HEAD` names the commit on which you based the changes in the working tree.
-`FETCH_HEAD` records the branch which you fetched from a remote repository
-with your last `git fetch` invocation.
-`ORIG_HEAD` is created by commands that move your `HEAD` in a drastic
-way (`git am`, `git merge`, `git rebase`, `git reset`),
-to record the position of the `HEAD` before their operation, so that
-you can easily change the tip of the branch back to the state before you ran
-them.
-`MERGE_HEAD` records the commit(s) which you are merging into your branch
-when you run `git merge`.
-`CHERRY_PICK_HEAD` records the commit which you are cherry-picking
-when you run `git cherry-pick`.
+  `HEAD`:::
+    names the commit on which you based the changes in the working tree.
+  `FETCH_HEAD`:::
+    records the branch which you fetched from a remote repository with
+    your last `git fetch` invocation.
+  `ORIG_HEAD`:::
+    is created by commands that move your `HEAD` in a drastic way (`git
+    am`, `git merge`, `git rebase`, `git reset`), to record the position
+    of the `HEAD` before their operation, so that you can easily change
+    the tip of the branch back to the state before you ran them.
+  `MERGE_HEAD`:::
+    records the commit(s) which you are merging into your branch when you
+    run `git merge`.
+  `REBASE_HEAD`:::
+    during a rebase, records the commit at which the operation is
+    currently stopped, either because of conflicts or an `edit` command in
+    an interactive rebase.
+  `REVERT_HEAD`:::
+    records the commit which you are reverting when you run `git revert`.
+  `CHERRY_PICK_HEAD`:::
+    records the commit which you are cherry-picking when you run `git
+    cherry-pick`.
+  `BISECT_HEAD`:::
+    records the current commit to be tested when you run `git bisect
+    --no-checkout`.
+  `AUTO_MERGE`:::
+    records a tree object corresponding to the state the
+    'ort' merge strategy wrote to the working tree when a merge operation
+    resulted in conflicts.
+
 +
 Note that any of the 'refs/*' cases above may come either from
 the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
index f33436c7f65ff9fd46f7ee4fa10975c833a61096..361f51a64736fab34faa8efaa90071c957d74c3b 100644 (file)
@@ -8,7 +8,8 @@ scalar - A tool for managing large Git repositories
 SYNOPSIS
 --------
 [verse]
-scalar clone [--single-branch] [--branch <main-branch>] [--full-clone] <url> [<enlistment>]
+scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
+       [--[no-]src] <url> [<enlistment>]
 scalar list
 scalar register [<enlistment>]
 scalar unregister [<enlistment>]
@@ -80,6 +81,11 @@ remote-tracking branch for the branch this option was used for the initial
 cloning. If the HEAD at the remote did not point at any branch when
 `--single-branch` clone was made, no remote-tracking branch is created.
 
+--[no-]src::
+       By default, `scalar clone` places the cloned repository within a
+       `<entlistment>/src` directory. Use `--no-src` to place the cloned
+       repository directly in the `<enlistment>` directory.
+
 --[no-]full-clone::
        A sparse-checkout is initialized by default. This behavior can be
        turned off via `--full-clone`.
index eda8c195c19629dfe836b36d9baaa21ec06199d6..7780a76b080e4b7ad2c82dc8eb6616e92fd21c4e 100644 (file)
@@ -1,7 +1,7 @@
 Git API Documents
 =================
 
-Git has grown a set of internal API over time.  This collection
+Git has grown a set of internal APIs over time.  This collection
 documents them.
 
 ////////////////////////////////////////////////////////////////
index 487d4d83fff2a873e762a9fc57a6f392a68caad4..c2ba01828c6b01b258d4d77d46714db3fafb6e0a 100644 (file)
@@ -28,9 +28,9 @@ and `diff.c` for examples.
 
 * `struct ll_merge_options`
 
-Check ll-merge.h for details.
+Check merge-ll.h for details.
 
 Low-level (single file) merge
 -----------------------------
 
-Check ll-merge.h for details.
+Check merge-ll.h for details.
index d44ada98e7db9ccdd7dd622221ee298af5de5000..c4fb152b23291c3978db623b5ebe5eaea1385442 100644 (file)
@@ -2,7 +2,7 @@ Simple-IPC API
 ==============
 
 The Simple-IPC API is a collection of `ipc_` prefixed library routines
-and a basic communication protocol that allow an IPC-client process to
+and a basic communication protocol that allows an IPC-client process to
 send an application-specific IPC-request message to an IPC-server
 process and receive an application-specific IPC-response message.
 
@@ -20,12 +20,12 @@ IPC-client.
 
 The IPC-client routines within a client application process connect
 to the IPC-server and send a request message and wait for a response.
-When received, the response is returned back the caller.
+When received, the response is returned back to the caller.
 
 For example, the `fsmonitor--daemon` feature will be built as a server
 application on top of the IPC-server library routines.  It will have
 threads watching for file system events and a thread pool waiting for
-client connections.  Clients, such as `git status` will request a list
+client connections.  Clients, such as `git status`, will request a list
 of file system events since a point in time and the server will
 respond with a list of changed files and directories.  The formats of
 the request and response are application-specific; the IPC-client and
@@ -37,7 +37,7 @@ Comparison with sub-process model
 
 The Simple-IPC mechanism differs from the existing `sub-process.c`
 model (Documentation/technical/long-running-process-protocol.txt) and
-used by applications like Git-LFS.  In the LFS-style sub-process model
+used by applications like Git-LFS.  In the LFS-style sub-process model,
 the helper is started by the foreground process, communication happens
 via a pair of file descriptors bound to the stdin/stdout of the
 sub-process, the sub-process only serves the current foreground
@@ -102,4 +102,4 @@ stateless request, receive an application-specific
 response, and disconnect.  It is a one round trip facility for
 querying the server.  The Simple-IPC routines hide the socket,
 named pipe, and thread pool details and allow the application
-layer to focus on the application at hand.
+layer to focus on the task at hand.
index c2e652b71a7f698a6843bbf327535b4692538c0f..f5d200939b056076368d4e8a735772fde114599d 100644 (file)
@@ -114,7 +114,7 @@ result in an empty bitmap (no bits set).
 
     * N entries with compressed bitmaps, one for each indexed commit
 +
-Where `N` is the total amount of entries in this bitmap index.
+Where `N` is the total number of entries in this bitmap index.
 Each entry contains the following:
 
        ** {empty}
@@ -126,7 +126,7 @@ Each entry contains the following:
        ** {empty}
        1-byte XOR-offset: ::
            The xor offset used to compress this bitmap. For an entry
-           in position `x`, a XOR offset of `y` means that the actual
+           in position `x`, an XOR offset of `y` means that the actual
            bitmap representing this commit is composed by XORing the
            bitmap for this entry with the bitmap in entry `x-y` (i.e.
            the bitmap `y` entries before this one).
@@ -239,7 +239,7 @@ 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
+(sorted in the ascending order of `commit_pos`). The content of the i'th
 triplet is -
 
        * {empty}
index 86fed0de0f77f97031621ffd4ca94c1cbd2b5ba1..2c26e95e51ab9aacb147fad022c669a2a17e928b 100644 (file)
@@ -136,7 +136,7 @@ Design Details
 
 - Commit grafts and replace objects can change the shape of the commit
   history. The latter can also be enabled/disabled on the fly using
-  `--no-replace-objects`. This leads to difficultly storing both possible
+  `--no-replace-objects`. This leads to difficulty storing both possible
   interpretations of a commit id, especially when computing generation
   numbers. The commit-graph will not be read or written when
   replace-objects or grafts are present.
index 47c9b6183cfad0f3f8e60df2003cd60657a92b0d..b4a144e5f4758d30e523406596b85009336141b0 100644 (file)
@@ -63,7 +63,7 @@ improvements over the sequential code, but there was still too much lock
 contention. A `perf` profiling indicated that around 20% of the runtime
 during a local Linux clone (on an SSD) was spent in locking functions.
 For this reason this approach was rejected in favor of using multiple
-child processes, which led to better performance.
+child processes, which led to better performance.
 
 Multi-Process Solution
 ----------------------
@@ -126,7 +126,7 @@ Then, for each assigned item, each worker:
 
 * W5: Writes the result to the file descriptor opened at W2.
 
-* W6: Calls `fstat()` or lstat()` on the just-written path, and sends
+* W6: Calls `fstat()` or `lstat()` on the just-written path, and sends
   the result back to the main process, together with the end status of
   the operation and the item's identification number.
 
@@ -148,7 +148,7 @@ information, the main process handles the results in two steps:
 
 - First, it updates the in-memory index with the `lstat()` information
   sent by the workers. (This must be done first as this information
-  might me required in the following step.)
+  might be required in the following step.)
 
 - Then it writes the items which collided on disk (i.e. items marked
   with `PC_ITEM_COLLIDED`). More on this below.
@@ -185,7 +185,7 @@ quite straightforward: for each parallel-eligible entry, the main
 process must remove all files that prevent this entry from being written
 (before enqueueing it). This includes any non-directory file in the
 leading path of the entry. Later, when a worker gets assigned the entry,
-it looks again for the non-directories files and for an already existing
+it looks again for the non-directory files and for an already existing
 file at the entry's path. If any of these checks finds something, the
 worker knows that there was a path collision.
 
@@ -232,7 +232,7 @@ conversion and re-encoding, are eligible for parallel checkout.
 Ineligible entries are checked out by the classic sequential codepath
 *before* spawning workers.
 
-Note: submodules's files are also eligible for parallel checkout (as
+Note: submodules' files are also eligible for parallel checkout (as
 long as they don't fall into any of the excluding categories mentioned
 above). But since each submodule is checked out in its own child
 process, we don't mix the superproject's and the submodules' files in
index 92fcee2bfffff8c42a07f0dd4b87421abd94f2bb..cd948b00722cba5ae9f01b31f6a226f8d4497ea8 100644 (file)
@@ -3,7 +3,7 @@ Partial Clone Design Notes
 
 The "Partial Clone" feature is a performance optimization for Git that
 allows Git to function without having a complete copy of the repository.
-The goal of this work is to allow Git better handle extremely large
+The goal of this work is to allow Git to better handle extremely large
 repositories.
 
 During clone and fetch operations, Git downloads the complete contents
@@ -256,7 +256,7 @@ remote in a specific order.
 - Dynamic object fetching currently uses the existing pack protocol V0
   which means that each object is requested via fetch-pack.  The server
   will send a full set of info/refs when the connection is established.
-  If there are large number of refs, this may incur significant overhead.
+  If there are large number of refs, this may incur significant overhead.
 
 
 Future Work
@@ -265,7 +265,7 @@ Future Work
 - Improve the way to specify the order in which promisor remotes are
   tried.
 +
-For example this could allow to specify explicitly something like:
+For example this could allow specifying explicitly something like:
 "When fetching from this remote, I want to use these promisor remotes
 in this order, though, when pushing or fetching to that remote, I want
 to use those promisor remotes in that order."
@@ -322,7 +322,7 @@ Footnotes
 
 [a] expensive-to-modify list of missing objects:  Earlier in the design of
     partial clone we discussed the need for a single list of missing objects.
-    This would essentially be a sorted linear list of OIDs that the were
+    This would essentially be a sorted linear list of OIDs that were
     omitted by the server during a clone or subsequent fetches.
 
 This file would need to be loaded into memory on every object lookup.
index ceda4bbfda4d27c8138c79f207f0d2adadf8bf50..59bea66c0fc6ef704e0ba9e81809a8ad1c2e9058 100644 (file)
@@ -11,7 +11,7 @@ write out the next tree object to be committed.  The state is
 "virtual" in the sense that it does not necessarily have to, and
 often does not, match the files in the working tree.
 
-There are cases Git needs to examine the differences between the
+There are cases where Git needs to examine the differences between the
 virtual working tree state in the index and the files in the
 working tree.  The most obvious case is when the user asks `git
 diff` (or its low level implementation, `git diff-files`) or
@@ -165,9 +165,9 @@ Avoiding runtime penalty
 
 In order to avoid the above runtime penalty, post 1.4.2 Git used
 to have a code that made sure the index file
-got timestamp newer than the youngest files in the index when
-there are many young files with the same timestamp as the
-resulting index file would otherwise would have by waiting
+got timestamp newer than the youngest files in the index when
+there were many young files with the same timestamp as the
+resulting index file otherwise would have by waiting
 before finishing writing the index file out.
 
 I suspected that in practice the situation where many paths in the
@@ -190,7 +190,7 @@ In a large project where raciness avoidance cost really matters,
 however, the initial computation of all object names in the
 index takes more than one second, and the index file is written
 out after all that happens.  Therefore the timestamp of the
-index file will be more than one seconds later than the
+index file will be more than one second later than the
 youngest file in the working tree.  This means that in these
 cases there actually will not be any racily clean entry in
 the resulting index.
index 6a67cc4174f820931a25bbd40c83959237b2983c..dd0b37c4e34738038b0171038dba6b180739d433 100644 (file)
@@ -46,7 +46,7 @@ search lookup, and range scans.
 
 Storage in the file is organized into variable sized blocks. Prefix
 compression is used within a single block to reduce disk space. Block
-size and alignment is tunable by the writer.
+size and alignment are tunable by the writer.
 
 Performance
 ^^^^^^^^^^^
@@ -115,7 +115,7 @@ Varint encoding
 Varint encoding is identical to the ofs-delta encoding method used
 within pack files.
 
-Decoder works such as:
+Decoder works as follows:
 
 ....
 val = buf[ptr] & 0x7f
@@ -175,7 +175,7 @@ log_index*
 footer
 ....
 
-in a log-only file the first log block immediately follows the file
+In a log-only file, the first log block immediately follows the file
 header, without padding to block alignment.
 
 Block size
@@ -247,7 +247,7 @@ uint32( hash_id )
 ....
 
 The header is identical to `version_number=1`, with the 4-byte hash ID
-("sha1" for SHA1 and "s256" for SHA-256) append to the header.
+("sha1" for SHA1 and "s256" for SHA-256) appended to the header.
 
 For maximum backward compatibility, it is recommended to use version 1 when
 writing SHA1 reftables.
@@ -288,7 +288,7 @@ The 2-byte `restart_count` stores the number of entries in the
 `restart_count` to binary search between restarts before starting a
 linear scan.
 
-Exactly `restart_count` 3-byte `restart_offset` values precedes the
+Exactly `restart_count` 3-byte `restart_offset` values precede the
 `restart_count`. Offsets are relative to the start of the block and
 refer to the first byte of any `ref_record` whose name has not been
 prefix compressed. Entries in the `restart_offset` list must be sorted,
index 1e34d913901e5922089da9451042ad2dc496b8f0..73f41761e2090a467dc0cade4888825d4606a7a7 100644 (file)
@@ -664,7 +664,7 @@ skip-irrelevant-renames optimization means we sometimes don't detect
 renames for any files within a directory that was renamed, in which
 case we will not have been able to detect any rename for the directory
 itself.  In such a case, we do not know whether the directory was
-renamed; we want to be careful to avoid cacheing some kind of "this
+renamed; we want to be careful to avoid caching some kind of "this
 directory was not renamed" statement.  If we did, then a subsequent
 commit being rebased could add a file to the old directory, and the
 user would expect it to end up in the correct directory -- something
index 8ef664b0b9537ad3c8fc554e68448a69a3b7f439..045a76756fcf47401dc61cb55f37df1deff480d7 100644 (file)
@@ -96,7 +96,7 @@ The value of this key is the name of the promisor remote.
 ==== `worktreeConfig`
 
 If set, by default "git config" reads from both "config" and
-"config.worktree" file from GIT_DIR in that order. In
+"config.worktree" files from GIT_DIR in that order. In
 multiple working directory mode, "config" file is shared while
 "config.worktree" is per-working directory (i.e., it's in
 GIT_COMMON_DIR/worktrees/<id>/config.worktree)
index be58f1bee368941cd7f8050fdfc23c55e48e48fa..580f23360a27bf71581ce6d570a041eba62d075a 100644 (file)
@@ -60,7 +60,7 @@ By resolving this conflict, to leave line D, the user declares:
     what AB and AC wanted to do.
 
 As branch AC2 refers to the same commit as AC, the above implies that
-this is also compatible what AB and AC2 wanted to do.
+this is also compatible with what AB and AC2 wanted to do.
 
 By extension, this means that rerere should recognize that the above
 conflicts are the same.  To do this, the labels on the conflict
@@ -76,7 +76,7 @@ examples would both result in the following normalized conflict:
 Sorting hunks
 ~~~~~~~~~~~~~
 
-As before, lets imagine that a common ancestor had a file with line A
+As before, let's imagine that a common ancestor had a file with line A
 its early part, and line X in its late part.  And then four branches
 are forked that do these things:
 
@@ -145,7 +145,7 @@ Nested conflicts
 Nested conflicts are handled very similarly to "simple" conflicts.
 Similar to simple conflicts, the conflict is first normalized by
 stripping the labels from conflict markers, stripping the common ancestor
-version, and the sorting the conflict hunks, both for the outer and the
+version, and sorting the conflict hunks, both for the outer and the
 inner conflict.  This is done recursively, so any number of nested
 conflicts can be handled.
 
index e410912fe52b9defd6de1601174cd214998ab336..bf17012241536ceb1c407fea04b7b1a84441923f 100644 (file)
@@ -33,9 +33,9 @@ config file would appear like this:
 ------------
 
 The `<pushurl>` is used for pushes only. It is optional and defaults
-to `<URL>`. Pushing to a remote affects all defined pushurls or to all
+to `<URL>`. Pushing to a remote affects all defined pushurls or all
 defined urls if no pushurls are defined. Fetch, however, will only
-fetch from the first defined url if muliple urls are defined.
+fetch from the first defined url if multiple urls are defined.
 
 Named file in `$GIT_DIR/remotes`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -48,7 +48,7 @@ provide a refspec on the command line.  This file should have the
 following format:
 
 ------------
-       URL: one of the above URL format
+       URL: one of the above URL formats
        Push: <refspec>
        Pull: <refspec>
 
index 1c229d758152b6377e23125967e2041a5fd5be5a..4e79c1589ece05ff21a144e5b48829a5dc39b50f 100644 (file)
@@ -6,9 +6,9 @@ address of the remote server, and the path to the repository.
 Depending on the transport protocol, some of this information may be
 absent.
 
-Git supports ssh, git, http, and https protocols (in addition, ftp,
+Git supports ssh, git, http, and https protocols (in addition, ftp
 and ftps can be used for fetching, but this is inefficient and
-deprecated; do not use it).
+deprecated; do not use them).
 
 The native transport (i.e. git:// URL) does no authentication and
 should be used with caution on unsecured networks.
index dc9c6a663a97e644d865e7d01957bfa2ac77bb5d..d8dbe6b56d42a693461d7deae9ac76e214f3d1e4 100644 (file)
@@ -1122,7 +1122,7 @@ choosing "Stage Hunk For Commit").
 === Creating good commit messages
 
 Though not required, it's a good idea to begin the commit message
-with a single short (less than 50 character) line summarizing the
+with a single short (no more than 50 characters) line summarizing the
 change, followed by a blank line and then a more thorough
 description.  The text up to the first blank line in a commit
 message is treated as the commit title, and that title is used
@@ -1343,6 +1343,33 @@ $ git diff -3 file.txt           # diff against stage 3
 $ git diff --theirs file.txt   # same as the above.
 -------------------------------------------------
 
+When using the 'ort' merge strategy (the default), before updating the working
+tree with the result of the merge, Git writes a special ref named AUTO_MERGE
+reflecting the state of the tree it is about to write. Conflicted paths with
+textual conflicts that could not be automatically merged are written to this
+tree with conflict markers, just as in the working tree. AUTO_MERGE can thus be
+used with linkgit:git-diff[1] to show the changes you've made so far to resolve
+conflicts. Using the same example as above, after resolving the conflict we
+get:
+
+-------------------------------------------------
+$ git diff AUTO_MERGE
+diff --git a/file.txt b/file.txt
+index cd10406..8bf5ae7 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,5 +1 @@
+-<<<<<<< HEAD:file.txt
+-Hello world
+-=======
+-Goodbye
+->>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
++Goodbye world
+-------------------------------------------------
+
+Notice that the diff shows we deleted the conflict markers and both versions of
+the content line, and wrote "Goodbye world" instead.
+
 The linkgit:git-log[1] and linkgit:gitk[1] commands also provide special help
 for merges:
 
@@ -4102,13 +4129,11 @@ Note that terminology has changed since that revision.  For example, the
 README in that revision uses the word "changeset" to describe what we
 now call a <<def_commit_object,commit>>.
 
-Also, we do not call it "cache" any more, but rather "index"; however, the
-file is still called `cache.h`.  Remark: Not much reason to change it now,
-especially since there is no good single name for it anyway, because it is
-basically _the_ header file which is included by _all_ of Git's C sources.
+Also, we do not call it "cache" any more, but rather "index"; however,
+the file is still called `read-cache.h`.
 
 If you grasp the ideas in that initial commit, you should check out a
-more recent version and skim `cache.h`, `object.h` and `commit.h`.
+more recent version and skim `read-cache-ll.h`, `object.h` and `commit.h`.
 
 In the early days, Git (in the tradition of UNIX) was a bunch of programs
 which were extremely simple, and which you used in scripts, piping the
@@ -4119,11 +4144,11 @@ many of these parts have become builtins, and some of the core has been
 and to avoid code duplication.
 
 By now, you know what the index is (and find the corresponding data
-structures in `cache.h`), and that there are just a couple of object types
-(blobs, trees, commits and tags) which inherit their common structure from
-`struct object`, which is their first member (and thus, you can cast e.g.
-`(struct object *)commit` to achieve the _same_ as `&commit->object`, i.e.
-get at the object name and flags).
+structures in `read-cache-ll.h`), and that there are just a couple of
+object types (blobs, trees, commits and tags) which inherit their
+common structure from `struct object`, which is their first member
+(and thus, you can cast e.g.  `(struct object *)commit` to achieve the
+_same_ as `&commit->object`, i.e.  get at the object name and flags).
 
 Now is a good point to take a break to let this information sink in.
 
index b37f72a5527080e551c38090e2ab9e28c739d10a..7e71bb38003a314845f6ae90c62273068865f6d1 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.41.0
+DEF_VER=v2.43.0-rc0
 
 LF='
 '
index e440728c2461b9367e01db5a817ae48479afcf65..03adcb5a48072e2c7edd006ca9b249812f9a39c5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -800,6 +800,7 @@ TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
 TEST_BUILTINS_OBJS += test-env-helper.o
 TEST_BUILTINS_OBJS += test-example-decorate.o
 TEST_BUILTINS_OBJS += test-fast-rebase.o
+TEST_BUILTINS_OBJS += test-find-pack.o
 TEST_BUILTINS_OBJS += test-fsmonitor-client.o
 TEST_BUILTINS_OBJS += test-genrandom.o
 TEST_BUILTINS_OBJS += test-genzeros.o
@@ -808,7 +809,6 @@ TEST_BUILTINS_OBJS += test-hash-speed.o
 TEST_BUILTINS_OBJS += test-hash.o
 TEST_BUILTINS_OBJS += test-hashmap.o
 TEST_BUILTINS_OBJS += test-hexdump.o
-TEST_BUILTINS_OBJS += test-index-version.o
 TEST_BUILTINS_OBJS += test-json-writer.o
 TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
 TEST_BUILTINS_OBJS += test-match-trees.o
@@ -852,6 +852,7 @@ 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-truncate.o
 TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
 TEST_BUILTINS_OBJS += test-userdiff.o
 TEST_BUILTINS_OBJS += test-wildmatch.o
@@ -1040,6 +1041,7 @@ LIB_OBJS += hash-lookup.o
 LIB_OBJS += hashmap.o
 LIB_OBJS += help.o
 LIB_OBJS += hex.o
+LIB_OBJS += hex-ll.o
 LIB_OBJS += hook.o
 LIB_OBJS += ident.o
 LIB_OBJS += json-writer.o
@@ -1051,7 +1053,6 @@ LIB_OBJS += linear-assignment.o
 LIB_OBJS += list-objects-filter-options.o
 LIB_OBJS += list-objects-filter.o
 LIB_OBJS += list-objects.o
-LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
 LIB_OBJS += ls-refs.o
@@ -1060,6 +1061,7 @@ LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += mem-pool.o
 LIB_OBJS += merge-blobs.o
+LIB_OBJS += merge-ll.o
 LIB_OBJS += merge-ort.o
 LIB_OBJS += merge-ort-wrappers.o
 LIB_OBJS += merge-recursive.o
@@ -1090,6 +1092,7 @@ LIB_OBJS += pack-write.o
 LIB_OBJS += packfile.o
 LIB_OBJS += pager.o
 LIB_OBJS += parallel-checkout.o
+LIB_OBJS += parse.o
 LIB_OBJS += parse-options-cb.o
 LIB_OBJS += parse-options.o
 LIB_OBJS += patch-delta.o
@@ -1142,6 +1145,7 @@ LIB_OBJS += sigchain.o
 LIB_OBJS += sparse-index.o
 LIB_OBJS += split-index.o
 LIB_OBJS += stable-qsort.o
+LIB_OBJS += statinfo.o
 LIB_OBJS += strbuf.o
 LIB_OBJS += streaming.o
 LIB_OBJS += string-list.o
@@ -1951,7 +1955,7 @@ endif
        BASIC_CFLAGS += \
                -DSHA1DC_NO_STANDARD_INCLUDES \
                -DSHA1DC_INIT_SAFE_HASH_DEFAULT=0 \
-               -DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"cache.h\"" \
+               -DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"git-compat-util.h\"" \
                -DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="\"git-compat-util.h\""
 endif
 endif
@@ -2742,8 +2746,8 @@ exec-cmd.sp exec-cmd.s exec-cmd.o: EXTRA_CPPFLAGS = \
        '-DBINDIR="$(bindir_relative_SQ)"' \
        '-DFALLBACK_RUNTIME_PREFIX="$(prefix_SQ)"'
 
-builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX
-builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
+setup.sp setup.s setup.o: GIT-PREFIX
+setup.sp setup.s setup.o: EXTRA_CPPFLAGS = \
        -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
 
 config.sp config.s config.o: GIT-PREFIX
@@ -2778,6 +2782,13 @@ compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
 compat/nedmalloc/nedmalloc.sp: SP_EXTRA_FLAGS += -Wno-non-pointer-null
 endif
 
+headless-git.o: compat/win32/headless.c GIT-CFLAGS
+       $(QUIET_CC)$(CC) $(ALL_CFLAGS) $(COMPAT_CFLAGS) \
+               -fno-stack-protector -o $@ -c -Wall -Wwrite-strings $<
+
+headless-git$X: headless-git.o git.res GIT-LDFLAGS
+       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -mwindows -o $@ $< git.res
+
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
@@ -3215,6 +3226,12 @@ $(SP_OBJ): %.sp: %.c %.o
 sparse: $(SP_OBJ)
 
 EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
+ifndef OPENSSL_SHA1
+       EXCEPT_HDRS += sha1/openssl.h
+endif
+ifndef OPENSSL_SHA256
+       EXCEPT_HDRS += sha256/openssl.h
+endif
 ifndef NETTLE_SHA256
        EXCEPT_HDRS += sha256/nettle.h
 endif
@@ -3651,6 +3668,7 @@ clean: profile-clean coverage-clean cocciclean
        $(RM) po/git.pot po/git-core.pot
        $(RM) git.res
        $(RM) $(OBJECTS)
+       $(RM) headless-git.o
        $(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
        $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
        $(RM) $(TEST_PROGRAMS)
@@ -3679,6 +3697,7 @@ endif
        $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
 ifdef MSVC
        $(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
+       $(RM) headless-git.o.pdb
        $(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
        $(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
        $(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
index 4da73c9a6d376789944260138a56c6d8d79fd5fb..278cea33c4cc4cfaf34427ee340c163755d935df 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.41.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.43.0.txt
\ No newline at end of file
index d032f5dce517cbeb11ce703c5d9709bc35c8435b..1202cde23dbc9b27e3bee5d3198a9cec3236a288 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)
                return xstrdup(arg);
        return prefix_filename(pfx, arg);
 }
+
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
+{
+       if (!*path)
+               die("The empty string is not a valid path");
+       if (!is_absolute_path(path)) {
+               struct stat cwd_stat, pwd_stat;
+               size_t orig_len = sb->len;
+               char *cwd = xgetcwd();
+               char *pwd = getenv("PWD");
+               if (pwd && strcmp(pwd, cwd) &&
+                   !stat(cwd, &cwd_stat) &&
+                   (cwd_stat.st_dev || cwd_stat.st_ino) &&
+                   !stat(pwd, &pwd_stat) &&
+                   pwd_stat.st_dev == cwd_stat.st_dev &&
+                   pwd_stat.st_ino == cwd_stat.st_ino)
+                       strbuf_addstr(sb, pwd);
+               else
+                       strbuf_addstr(sb, cwd);
+               if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
+                       strbuf_addch(sb, '/');
+               free(cwd);
+       }
+       strbuf_addstr(sb, path);
+}
+
+void strbuf_add_real_path(struct strbuf *sb, const char *path)
+{
+       if (sb->len) {
+               struct strbuf resolved = STRBUF_INIT;
+               strbuf_realpath(&resolved, path, 1);
+               strbuf_addbuf(sb, &resolved);
+               strbuf_release(&resolved);
+       } else
+               strbuf_realpath(sb, path, 1);
+}
index 7cd3de5e9de5391381dfa6a28a43bb709e4b04c4..4653080d5e4b7aee7c5bc2a239c709012d6f6474 100644 (file)
--- a/abspath.h
+++ b/abspath.h
@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)
        return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
 }
 
+/**
+ * Add a path to a buffer, converting a relative path to an
+ * absolute one in the process.  Symbolic links are not
+ * resolved.
+ */
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
+/**
+ * Canonize `path` (make it absolute, resolve symlinks, remove extra
+ * slashes) and append it to `sb`.  Die with an informative error
+ * message if there is a problem.
+ *
+ * The directory part of `path` (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.
+ *
+ * Callers that don't mind links should use the more lightweight
+ * strbuf_add_absolute_path() instead.
+ */
+void strbuf_add_real_path(struct strbuf *sb, const char *path);
+
 #endif /* ABSPATH_H */
index de877ca0525482c9a5a2a6ad9d86e02e5fc79e53..6bf87e7ae71b06ea59d42d238c6242a66fdec0b5 100644 (file)
@@ -1,10 +1,14 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "add-interactive.h"
 #include "color.h"
 #include "config.h"
 #include "diffcore.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
+#include "repository.h"
 #include "revision.h"
 #include "refs.h"
 #include "string-list.h"
@@ -565,7 +569,7 @@ static int get_modified_files(struct repository *r,
                        copy_pathspec(&rev.prune_data, ps);
 
                if (s.mode == FROM_INDEX)
-                       run_diff_index(&rev, 1);
+                       run_diff_index(&rev, DIFF_INDEX_CACHED);
                else {
                        rev.diffopt.flags.ignore_dirty_submodules = 1;
                        run_diff_files(&rev, 0);
@@ -1017,9 +1021,9 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
        return res;
 }
 
-static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
-                   struct prefix_item_list *unused_files,
-                   struct list_and_choose_options *unused_opts)
+static int run_help(struct add_i_state *s, const struct pathspec *ps UNUSED,
+                   struct prefix_item_list *files UNUSED,
+                   struct list_and_choose_options *opts UNUSED)
 {
        color_fprintf_ln(stdout, s->help_color, "status        - %s",
                         _("show paths with changes"));
@@ -1070,7 +1074,7 @@ struct print_command_item_data {
        const char *color, *reset;
 };
 
-static void print_command_item(int i, int selected,
+static void print_command_item(int i, int selected UNUSED,
                               struct string_list_item *item,
                               void *print_command_item_data)
 {
index 8d770d203ff78f487b9497cf0603436cb56d4e74..bfe19876cd50c5aca2e465d9334c49e65a1972fc 100644 (file)
@@ -1,11 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "add-interactive.h"
 #include "advice.h"
-#include "alloc.h"
 #include "editor.h"
 #include "environment.h"
 #include "gettext.h"
 #include "object-name.h"
+#include "read-cache-ll.h"
+#include "repository.h"
 #include "strbuf.h"
 #include "run-command.h"
 #include "strvec.h"
@@ -1105,10 +1106,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
        size_t i;
 
        strbuf_reset(&s->buf);
-       strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
-                                     "a quick guide.\n"));
+       strbuf_commented_addf(&s->buf, comment_line_char,
+                             _("Manual hunk edit mode -- see bottom for "
+                               "a quick guide.\n"));
        render_hunk(s, hunk, 0, 0, &s->buf);
-       strbuf_commented_addf(&s->buf,
+       strbuf_commented_addf(&s->buf, comment_line_char,
                              _("---\n"
                                "To remove '%c' lines, make them ' ' lines "
                                "(context).\n"
@@ -1117,12 +1119,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
                              s->mode->is_reverse ? '+' : '-',
                              s->mode->is_reverse ? '-' : '+',
                              comment_line_char);
-       strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
+       strbuf_commented_addf(&s->buf, comment_line_char, "%s",
+                             _(s->mode->edit_hunk_hint));
        /*
         * TRANSLATORS: 'it' refers to the patch mentioned in the previous
         * messages.
         */
-       strbuf_commented_addf(&s->buf,
+       strbuf_commented_addf(&s->buf, comment_line_char,
                              _("If it does not apply cleanly, you will be "
                                "given an opportunity to\n"
                                "edit again.  If all lines of the hunk are "
index d6232439c3863b4c6136adfd12465b0aa714e81f..50c79443ba749fc56437806c21a20755c1988714 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -78,6 +78,7 @@ static struct {
        [ADVICE_SUBMODULES_NOT_UPDATED]                 = { "submodulesNotUpdated", 1 },
        [ADVICE_UPDATE_SPARSE_PATH]                     = { "updateSparsePath", 1 },
        [ADVICE_WAITING_FOR_EDITOR]                     = { "waitingForEditor", 1 },
+       [ADVICE_WORKTREE_ADD_ORPHAN]                    = { "worktreeAddOrphan", 1 },
 };
 
 static const char turn_off_instructions[] =
@@ -190,9 +191,10 @@ int error_resolve_conflict(const char *me)
                error(_("Pulling is not possible because you have unmerged files."));
        else if (!strcmp(me, "revert"))
                error(_("Reverting is not possible because you have unmerged files."));
+       else if (!strcmp(me, "rebase"))
+               error(_("Rebasing is not possible because you have unmerged files."));
        else
-               error(_("It is not possible to %s because you have unmerged files."),
-                       me);
+               BUG("Unhandled conflict reason '%s'", me);
 
        if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
                /*
index 0f584163f5808ce536ff5d1a5294eed2437ba23b..2affbe142616de0d329c9aaaaee9ca355fb73adf 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -49,6 +49,7 @@ struct string_list;
        ADVICE_UPDATE_SPARSE_PATH,
        ADVICE_WAITING_FOR_EDITOR,
        ADVICE_SKIPPED_CHERRY_PICKS,
+       ADVICE_WORKTREE_ADD_ORPHAN,
 };
 
 int git_default_advice_config(const char *var, const char *value);
diff --git a/alias.c b/alias.c
index 54a1a23d2cf1a5983e47f4369fe08ef935616508..5a238f2e3012d2fb12443b27ed02831e9edee476 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "alias.h"
-#include "alloc.h"
 #include "config.h"
 #include "gettext.h"
 #include "strbuf.h"
@@ -12,7 +11,8 @@ struct config_alias_data {
        struct string_list *list;
 };
 
-static int config_alias_cb(const char *key, const char *value, void *d)
+static int config_alias_cb(const char *key, const char *value,
+                          const struct config_context *ctx UNUSED, void *d)
 {
        struct config_alias_data *data = d;
        const char *p;
diff --git a/alloc.h b/alloc.h
index 4312db4bd087bde3632c547bb72d0b5cc77be713..3f4a0ad310a94bd026f48f48491985e3e2053ee2 100644 (file)
--- a/alloc.h
+++ b/alloc.h
@@ -17,79 +17,4 @@ void *alloc_object_node(struct repository *r);
 struct alloc_state *allocate_alloc_state(void);
 void clear_alloc_state(struct alloc_state *s);
 
-#define alloc_nr(x) (((x)+16)*3/2)
-
-/**
- * Dynamically growing an array using realloc() is error prone and boring.
- *
- * Define your array with:
- *
- * - a pointer (`item`) that points at the array, initialized to `NULL`
- *   (although please name the variable based on its contents, not on its
- *   type);
- *
- * - an integer variable (`alloc`) that keeps track of how big the current
- *   allocation is, initialized to `0`;
- *
- * - another integer variable (`nr`) to keep track of how many elements the
- *   array currently has, initialized to `0`.
- *
- * Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
- * alloc)`.  This ensures that the array can hold at least `n` elements by
- * calling `realloc(3)` and adjusting `alloc` variable.
- *
- * ------------
- * sometype *item;
- * size_t nr;
- * size_t alloc
- *
- * for (i = 0; i < nr; i++)
- *     if (we like item[i] already)
- *             return;
- *
- * // we did not like any existing one, so add one
- * ALLOC_GROW(item, nr + 1, alloc);
- * item[nr++] = value you like;
- * ------------
- *
- * You are responsible for updating the `nr` variable.
- *
- * If you need to specify the number of elements to allocate explicitly
- * then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
- *
- * Consider using ALLOC_GROW_BY instead of ALLOC_GROW as it has some
- * added niceties.
- *
- * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
- */
-#define ALLOC_GROW(x, nr, alloc) \
-       do { \
-               if ((nr) > alloc) { \
-                       if (alloc_nr(alloc) < (nr)) \
-                               alloc = (nr); \
-                       else \
-                               alloc = alloc_nr(alloc); \
-                       REALLOC_ARRAY(x, alloc); \
-               } \
-       } while (0)
-
-/*
- * Similar to ALLOC_GROW but handles updating of the nr value and
- * zeroing the bytes of the newly-grown array elements.
- *
- * DO NOT USE any expression with side-effect for any of the
- * arguments.
- */
-#define ALLOC_GROW_BY(x, nr, increase, alloc) \
-       do { \
-               if (increase) { \
-                       size_t new_nr = nr + (increase); \
-                       if (new_nr < nr) \
-                               BUG("negative growth in ALLOC_GROW_BY"); \
-                       ALLOC_GROW(x, new_nr, alloc); \
-                       memset((x) + nr, 0, sizeof(*(x)) * (increase)); \
-                       nr = new_nr; \
-               } \
-       } while (0)
-
 #endif
diff --git a/apply.c b/apply.c
index 6212ab3a1b3958cd56c8c3e199a3f0ed35de1488..3d69fec836d41fbae10988606ac20ce96dad562d 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -7,12 +7,11 @@
  *
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "base85.h"
 #include "config.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "delta.h"
 #include "diff.h"
 #include "gettext.h"
 #include "hex.h"
 #include "xdiff-interface.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "lockfile.h"
+#include "name-hash.h"
 #include "object-name.h"
 #include "object-file.h"
 #include "parse-options.h"
+#include "path.h"
 #include "quote.h"
+#include "read-cache.h"
 #include "rerere.h"
 #include "apply.h"
 #include "entry.h"
 #include "setup.h"
 #include "symlinks.h"
+#include "wildmatch.h"
 #include "ws.h"
-#include "wrapper.h"
 
 struct gitdiff_data {
        struct strbuf *root;
@@ -410,9 +412,10 @@ static void say_patch_name(FILE *output, const char *fmt, struct patch *patch)
 
 static int read_patch_file(struct strbuf *sb, int fd)
 {
-       if (strbuf_read(sb, fd, 0) < 0 || sb->len >= MAX_APPLY_SIZE)
-               return error_errno("git apply: failed to read");
-
+       if (strbuf_read(sb, fd, 0) < 0)
+               return error_errno(_("failed to read patch"));
+       else if (sb->len >= MAX_APPLY_SIZE)
+               return error(_("patch too large"));
        /*
         * Make sure that we have some slop in the buffer
         * so that we can do speculative "memcmp" etc, and
index 4cd81d8161e738c582d47709a90bc2f55d838f50..07269968399a5e1b1731fb458d48f4188ed25577 100644 (file)
@@ -2,14 +2,13 @@
  * Copyright (c) 2005, 2006 Rene Scharfe
  */
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "gettext.h"
 #include "git-zlib.h"
 #include "hex.h"
 #include "tar.h"
 #include "archive.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "streaming.h"
 #include "run-command.h"
 #include "write-or-die.h"
@@ -411,14 +410,15 @@ static int tar_filter_config(const char *var, const char *value,
        return 0;
 }
 
-static int git_tar_config(const char *var, const char *value, void *cb)
+static int git_tar_config(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "tar.umask")) {
                if (value && !strcmp(value, "user")) {
                        tar_umask = umask(0);
                        umask(tar_umask);
                } else {
-                       tar_umask = git_config_int(var, value);
+                       tar_umask = git_config_int(var, value, ctx->kvi);
                }
                return 0;
        }
index d0d065a312eeca3b1e9399f6d4adad46a05d8f60..7229e3e454feb080509d1587a974925ff1318f31 100644 (file)
@@ -9,7 +9,7 @@
 #include "hex.h"
 #include "streaming.h"
 #include "utf8.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "userdiff.h"
 #include "write-or-die.h"
 #include "xdiff-interface.h"
@@ -617,6 +617,7 @@ static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)
 }
 
 static int archive_zip_config(const char *var, const char *value,
+                             const struct config_context *ctx UNUSED,
                              void *data UNUSED)
 {
        return userdiff_config(var, value);
index 2ea9cbef92affafe6edf7d7f69dc7cd2235a5e4f..ca11db185b15a73dd31b239d91a609071faa9a2a 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -1,15 +1,15 @@
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "convert.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
+#include "path.h"
 #include "pretty.h"
 #include "setup.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "tree.h"
 #include "tree-walk.h"
diff --git a/attr.c b/attr.c
index d45d34058df639c9a6c3fc80f51fa864611e5b21..e62876dfd3e9beae50d18da63f15285d5974b8ec 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -6,23 +6,26 @@
  * an insanely large number of attributes.
  */
 
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "environment.h"
 #include "exec-cmd.h"
 #include "attr.h"
 #include "dir.h"
 #include "gettext.h"
+#include "path.h"
 #include "utf8.h"
 #include "quote.h"
+#include "read-cache-ll.h"
 #include "revision.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "setup.h"
 #include "thread-utils.h"
 #include "tree-walk.h"
 #include "object-name.h"
 
+const char *git_attr_tree;
+
 const char git_attr__true[] = "(builtin)true";
 const char git_attr__false[] = "\0(builtin)false";
 static const char git_attr__unknown[] = "(builtin)unknown";
@@ -806,35 +809,56 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,
 static struct attr_stack *read_attr_from_index(struct index_state *istate,
                                               const char *path, unsigned flags)
 {
+       struct attr_stack *stack = NULL;
        char *buf;
        unsigned long size;
+       int sparse_dir_pos = -1;
 
        if (!istate)
                return NULL;
 
        /*
-        * The .gitattributes file only applies to files within its
-        * parent directory. In the case of cone-mode sparse-checkout,
-        * the .gitattributes file is sparse if and only if all paths
-        * within that directory are also sparse. Thus, don't load the
-        * .gitattributes file since it will not matter.
-        *
-        * In the case of a sparse index, it is critical that we don't go
-        * looking for a .gitattributes file, as doing so would cause the
-        * index to expand.
+        * When handling sparse-checkouts, .gitattributes files
+        * may reside within a sparse directory. We distinguish
+        * whether a path exists directly in the index or not by
+        * evaluating if 'pos' is negative.
+        * If 'pos' is negative, the path is not directly present
+        * in the index and is likely within a sparse directory.
+        * For paths not in the index, The absolute value of 'pos'
+        * minus 1 gives us the position where the path would be
+        * inserted in lexicographic order within the index.
+        * We then subtract another 1 from this value
+        * (sparse_dir_pos = -pos - 2) to find the position of the
+        * last index entry which is lexicographically smaller than
+        * the path. This would be the sparse directory containing
+        * the path. By identifying the sparse directory containing
+        * the path, we can correctly read the attributes specified
+        * in the .gitattributes file from the tree object of the
+        * sparse directory.
         */
-       if (!path_in_cone_mode_sparse_checkout(path, istate))
-               return NULL;
+       if (!path_in_cone_mode_sparse_checkout(path, istate)) {
+               int pos = index_name_pos_sparse(istate, path, strlen(path));
 
-       buf = read_blob_data_from_index(istate, path, &size);
-       if (!buf)
-               return NULL;
-       if (size >= ATTR_MAX_FILE_SIZE) {
-               warning(_("ignoring overly large gitattributes blob '%s'"), path);
-               return NULL;
+               if (pos < 0)
+                       sparse_dir_pos = -pos - 2;
        }
 
-       return read_attr_from_buf(buf, path, flags);
+       if (sparse_dir_pos >= 0 &&
+           S_ISSPARSEDIR(istate->cache[sparse_dir_pos]->ce_mode) &&
+           !strncmp(istate->cache[sparse_dir_pos]->name, path, ce_namelen(istate->cache[sparse_dir_pos]))) {
+               const char *relative_path = path + ce_namelen(istate->cache[sparse_dir_pos]);
+               stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags);
+       } else {
+               buf = read_blob_data_from_index(istate, path, &size);
+               if (!buf)
+                       return NULL;
+               if (size >= ATTR_MAX_FILE_SIZE) {
+                       warning(_("ignoring overly large gitattributes blob '%s'"), path);
+                       return NULL;
+               }
+               stack = read_attr_from_buf(buf, path, flags);
+       }
+       return stack;
 }
 
 static struct attr_stack *read_attr(struct index_state *istate,
@@ -870,7 +894,7 @@ static struct attr_stack *read_attr(struct index_state *istate,
        return res;
 }
 
-static const char *git_etc_gitattributes(void)
+const char *git_attr_system_file(void)
 {
        static const char *system_wide;
        if (!system_wide)
@@ -878,7 +902,7 @@ static const char *git_etc_gitattributes(void)
        return system_wide;
 }
 
-static const char *get_home_gitattributes(void)
+const char *git_attr_global_file(void)
 {
        if (!git_attributes_file)
                git_attributes_file = xdg_config_home("attributes");
@@ -886,7 +910,7 @@ static const char *get_home_gitattributes(void)
        return git_attributes_file;
 }
 
-static int git_attr_system(void)
+int git_attr_system_is_enabled(void)
 {
        return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
 }
@@ -920,14 +944,14 @@ static void bootstrap_attr_stack(struct index_state *istate,
        push_stack(stack, e, NULL, 0);
 
        /* system-wide frame */
-       if (git_attr_system()) {
-               e = read_attr_from_file(git_etc_gitattributes(), flags);
+       if (git_attr_system_is_enabled()) {
+               e = read_attr_from_file(git_attr_system_file(), flags);
                push_stack(stack, e, NULL, 0);
        }
 
        /* home directory */
-       if (get_home_gitattributes()) {
-               e = read_attr_from_file(get_home_gitattributes(), flags);
+       if (git_attr_global_file()) {
+               e = read_attr_from_file(git_attr_global_file(), flags);
                push_stack(stack, e, NULL, 0);
        }
 
@@ -1172,6 +1196,7 @@ static void collect_some_attrs(struct index_state *istate,
 }
 
 static const char *default_attr_source_tree_object_name;
+static int ignore_bad_attr_tree;
 
 void set_git_attr_source(const char *tree_object_name)
 {
@@ -1183,10 +1208,24 @@ static void compute_default_attr_source(struct object_id *attr_source)
        if (!default_attr_source_tree_object_name)
                default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
 
+       if (!default_attr_source_tree_object_name && git_attr_tree) {
+               default_attr_source_tree_object_name = git_attr_tree;
+               ignore_bad_attr_tree = 1;
+       }
+
+       if (!default_attr_source_tree_object_name &&
+           startup_info->have_repository &&
+           is_bare_repository()) {
+               default_attr_source_tree_object_name = "HEAD";
+               ignore_bad_attr_tree = 1;
+       }
+
        if (!default_attr_source_tree_object_name || !is_null_oid(attr_source))
                return;
 
-       if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source))
+       if (repo_get_oid_treeish(the_repository,
+                                default_attr_source_tree_object_name,
+                                attr_source) && !ignore_bad_attr_tree)
                die(_("bad --attr-source or GIT_ATTR_SOURCE"));
 }
 
diff --git a/attr.h b/attr.h
index 676bd17ce27766784b45f8f8b15f6b01c184e2e7..127998ae013c9de221b700144ad2082a78bfcaba 100644 (file)
--- a/attr.h
+++ b/attr.h
@@ -227,4 +227,15 @@ void git_attr_set_direction(enum git_attr_direction new_direction);
 
 void attr_start(void);
 
+/* Return the system gitattributes file. */
+const char *git_attr_system_file(void);
+
+/* Return the global gitattributes file, if any. */
+const char *git_attr_global_file(void);
+
+/* Return whether the system gitattributes file is enabled and should be used. */
+int git_attr_system_is_enabled(void);
+
+extern const char *git_attr_tree;
+
 #endif /* ATTR_H */
index 8d5f8e58851ea650224c8de043891ea0de4a77cd..1be8e0a2711df9d29c1ba903fd4e8901379ea406 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -18,7 +18,8 @@
 #include "commit-slab.h"
 #include "commit-reach.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "dir.h"
 
 static struct oid_array good_revs;
diff --git a/blame.c b/blame.c
index b8306540627faef3ae82525a815b5870f8ab37d7..141756975bf5a58a1744eda78c1750d9d949272f 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -1,6 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "cache-tree.h"
 #include "mergesort.h"
 #include "convert.h"
@@ -8,6 +8,8 @@
 #include "diffcore.h"
 #include "gettext.h"
 #include "hex.h"
+#include "path.h"
+#include "read-cache.h"
 #include "setup.h"
 #include "tag.h"
 #include "trace2.h"
@@ -2804,7 +2806,9 @@ void setup_scoreboard(struct blame_scoreboard *sb,
                        parent_oid = &head_oid;
                }
 
-               setup_work_tree();
+               if (!sb->contents_from)
+                       setup_work_tree();
+
                sb->final = fake_working_tree_commit(sb->repo,
                                                     &sb->revs->diffopt,
                                                     sb->path, sb->contents_from,
diff --git a/blame.h b/blame.h
index b60d1d81e3032acc5df2191321202b13eecc81fe..31ddc85f19e359908710162ad4aa144784dec16b 100644 (file)
--- a/blame.h
+++ b/blame.h
@@ -2,6 +2,7 @@
 #define BLAME_H
 
 #include "commit.h"
+#include "oidset.h"
 #include "xdiff-interface.h"
 #include "revision.h"
 #include "prio-queue.h"
diff --git a/bloom.c b/bloom.c
index aef6b5fea2d18f521b4812bd017fe685f635be47..1474aa19fa524ff1695c2b518259f61b1c2023b7 100644 (file)
--- a/bloom.c
+++ b/bloom.c
@@ -29,6 +29,26 @@ static inline unsigned char get_bitmask(uint32_t pos)
        return ((unsigned char)1) << (pos & (BITS_PER_WORD - 1));
 }
 
+static int check_bloom_offset(struct commit_graph *g, uint32_t pos,
+                             uint32_t offset)
+{
+       /*
+        * Note that we allow offsets equal to the data size, which would set
+        * our pointers at one past the end of the chunk memory. This is
+        * necessary because the on-disk index points to the end of the
+        * entries (so we can compute size by comparing adjacent ones). And
+        * naturally the final entry's end is one-past-the-end of the chunk.
+        */
+       if (offset <= g->chunk_bloom_data_size - BLOOMDATA_CHUNK_HEADER_SIZE)
+               return 0;
+
+       warning("ignoring out-of-range offset (%"PRIuMAX") for changed-path"
+               " filter at pos %"PRIuMAX" of %s (chunk size: %"PRIuMAX")",
+               (uintmax_t)offset, (uintmax_t)pos,
+               g->filename, (uintmax_t)g->chunk_bloom_data_size);
+       return -1;
+}
+
 static int load_bloom_filter_from_graph(struct commit_graph *g,
                                        struct bloom_filter *filter,
                                        uint32_t graph_pos)
@@ -51,6 +71,20 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
        else
                start_index = 0;
 
+       if (check_bloom_offset(g, lex_pos, end_index) < 0 ||
+           check_bloom_offset(g, lex_pos - 1, start_index) < 0)
+               return 0;
+
+       if (end_index < start_index) {
+               warning("ignoring decreasing changed-path index offsets"
+                       " (%"PRIuMAX" > %"PRIuMAX") for positions"
+                       " %"PRIuMAX" and %"PRIuMAX" of %s",
+                       (uintmax_t)start_index, (uintmax_t)end_index,
+                       (uintmax_t)(lex_pos-1), (uintmax_t)lex_pos,
+                       g->filename);
+               return 0;
+       }
+
        filter->len = end_index - start_index;
        filter->data = (unsigned char *)(g->chunk_bloom_data +
                                        sizeof(unsigned char) * start_index +
index ba3914adf5b7bfdccd5b76774e1287bf52d1e749..06f7af9dd47260d87158ba672f90d2b5c37e558e 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -6,6 +6,7 @@
 #include "gettext.h"
 #include "hex.h"
 #include "object-name.h"
+#include "path.h"
 #include "refs.h"
 #include "refspec.h"
 #include "remote.h"
@@ -37,7 +38,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)
        if (!remote_find_tracking(remote, &tracking->spec)) {
                switch (++tracking->matches) {
                case 1:
-                       string_list_append(tracking->srcs, tracking->spec.src);
+                       string_list_append_nodup(tracking->srcs, tracking->spec.src);
                        tracking->remote = remote->name;
                        break;
                case 2:
@@ -233,7 +234,7 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
                return -1;
        }
 
-       tracking->remote = xstrdup(branch->remote_name);
+       tracking->remote = branch->remote_name;
        for (i = 0; i < branch->merge_nr; i++)
                string_list_append(tracking->srcs, branch->merge_name[i]);
        return 0;
@@ -333,7 +334,7 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
                if (!skip_prefix(tracking.srcs->items[0].string,
                                 "refs/heads/", &tracked_branch) ||
                    strcmp(tracked_branch, new_ref))
-                       return;
+                       goto cleanup;
        }
 
        if (tracking.srcs->nr < 1)
@@ -470,7 +471,7 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)
 
        if ((path = branch_checked_out(ref->buf)))
                die(_("cannot force update the branch '%s' "
-                     "checked out at '%s'"),
+                     "used by worktree at '%s'"),
                    ref->buf + strlen("refs/heads/"), path);
 
        return 1;
@@ -480,9 +481,12 @@ static int check_tracking_branch(struct remote *remote, void *cb_data)
 {
        char *tracking_branch = cb_data;
        struct refspec_item query;
+       int res;
        memset(&query, 0, sizeof(struct refspec_item));
        query.dst = tracking_branch;
-       return !remote_find_tracking(remote, &query);
+       res = !remote_find_tracking(remote, &query);
+       free(query.src);
+       return res;
 }
 
 static int validate_remote_tracking_branch(char *ref)
@@ -638,9 +642,10 @@ void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
                             const char *orig_ref, enum branch_track track,
                             int quiet)
 {
-       char *real_orig_ref;
+       char *real_orig_ref = NULL;
        dwim_branch_start(r, orig_ref, track, &real_orig_ref, NULL);
        setup_tracking(new_ref, real_orig_ref, track, quiet);
+       free(real_orig_ref);
 }
 
 /**
@@ -833,7 +838,7 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree)
 
                if (is_shared_symref(worktrees[i], "HEAD", branch)) {
                        skip_prefix(branch, "refs/heads/", &branch);
-                       die(_("'%s' is already checked out at '%s'"),
+                       die(_("'%s' is already used by worktree at '%s'"),
                                branch, worktrees[i]->path);
                }
        }
index cb0db676814d8a43dd3e5cb3a7a729676f5a429d..d560baa6618ac9e021dc7f957b942466ac6e35b3 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -2,9 +2,6 @@
 #define BUILTIN_H
 
 #include "git-compat-util.h"
-#include "strbuf.h"
-#include "cache.h"
-#include "commit.h"
 
 /*
  * builtin API
index 76cc026a68a992a750b24a9ac23d05f4899dacc2..5126d2ede3d7614f764c0cb7cab4b694a792074e 100644 (file)
@@ -4,10 +4,9 @@
  * Copyright (C) 2006 Linus Torvalds
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "advice.h"
 #include "config.h"
-#include "builtin.h"
 #include "lockfile.h"
 #include "editor.h"
 #include "dir.h"
 #include "cache-tree.h"
 #include "run-command.h"
 #include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "read-cache.h"
+#include "repository.h"
 #include "revision.h"
 #include "bulk-checkin.h"
 #include "strvec.h"
@@ -36,11 +39,6 @@ static int pathspec_file_nul;
 static int include_sparse;
 static const char *pathspec_from_file;
 
-struct update_callback_data {
-       int flags;
-       int add_errors;
-};
-
 static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
 {
        int i, ret = 0;
@@ -69,95 +67,6 @@ static int chmod_pathspec(struct pathspec *pathspec, char flip, int show_only)
        return ret;
 }
 
-static int fix_unmerged_status(struct diff_filepair *p,
-                              struct update_callback_data *data)
-{
-       if (p->status != DIFF_STATUS_UNMERGED)
-               return p->status;
-       if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
-               /*
-                * This is not an explicit add request, and the
-                * path is missing from the working tree (deleted)
-                */
-               return DIFF_STATUS_DELETED;
-       else
-               /*
-                * Either an explicit add request, or path exists
-                * in the working tree.  An attempt to explicitly
-                * add a path that does not exist in the working tree
-                * will be caught as an error by the caller immediately.
-                */
-               return DIFF_STATUS_MODIFIED;
-}
-
-static void update_callback(struct diff_queue_struct *q,
-                           struct diff_options *opt UNUSED, void *cbdata)
-{
-       int i;
-       struct update_callback_data *data = cbdata;
-
-       for (i = 0; i < q->nr; i++) {
-               struct diff_filepair *p = q->queue[i];
-               const char *path = p->one->path;
-
-               if (!include_sparse && !path_in_sparse_checkout(path, &the_index))
-                       continue;
-
-               switch (fix_unmerged_status(p, data)) {
-               default:
-                       die(_("unexpected diff status %c"), p->status);
-               case DIFF_STATUS_MODIFIED:
-               case DIFF_STATUS_TYPE_CHANGED:
-                       if (add_file_to_index(&the_index, path, data->flags)) {
-                               if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
-                                       die(_("updating files failed"));
-                               data->add_errors++;
-                       }
-                       break;
-               case DIFF_STATUS_DELETED:
-                       if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
-                               break;
-                       if (!(data->flags & ADD_CACHE_PRETEND))
-                               remove_file_from_index(&the_index, path);
-                       if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
-                               printf(_("remove '%s'\n"), path);
-                       break;
-               }
-       }
-}
-
-int add_files_to_cache(const char *prefix,
-                      const struct pathspec *pathspec, int flags)
-{
-       struct update_callback_data data;
-       struct rev_info rev;
-
-       memset(&data, 0, sizeof(data));
-       data.flags = flags;
-
-       repo_init_revisions(the_repository, &rev, prefix);
-       setup_revisions(0, NULL, &rev, NULL);
-       if (pathspec)
-               copy_pathspec(&rev.prune_data, pathspec);
-       rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
-       rev.diffopt.format_callback = update_callback;
-       rev.diffopt.format_callback_data = &data;
-       rev.diffopt.flags.override_submodule_config = 1;
-       rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
-
-       /*
-        * Use an ODB transaction to optimize adding multiple objects.
-        * This function is invoked from commands other than 'add', which
-        * may not have their own transaction active.
-        */
-       begin_odb_transaction();
-       run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
-       end_odb_transaction();
-
-       release_revisions(&rev);
-       return !!data.add_errors;
-}
-
 static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
 {
        int i, retval = 0;
@@ -273,7 +182,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 
        if (repo_read_index(the_repository) < 0)
-               die(_("Could not read the index"));
+               die(_("could not read the index"));
 
        repo_init_revisions(the_repository, &rev, prefix);
        rev.diffopt.context = 7;
@@ -285,22 +194,21 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
        rev.diffopt.file = xfdopen(out, "w");
        rev.diffopt.close_file = 1;
-       if (run_diff_files(&rev, 0))
-               die(_("Could not write patch"));
+       run_diff_files(&rev, 0);
 
        if (launch_editor(file, NULL, NULL))
                die(_("editing patch failed"));
 
        if (stat(file, &st))
-               die_errno(_("Could not stat '%s'"), file);
+               die_errno(_("could not stat '%s'"), file);
        if (!st.st_size)
-               die(_("Empty patch. Aborted."));
+               die(_("empty patch. aborted"));
 
        child.git_cmd = 1;
        strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
                     NULL);
        if (run_command(&child))
-               die(_("Could not apply '%s'"), file);
+               die(_("could not apply '%s'"), file);
 
        unlink(file);
        free(file);
@@ -323,6 +231,8 @@ static char *chmod_arg;
 
 static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
 {
+       BUG_ON_OPT_ARG(arg);
+
        /* if we are told to ignore, we are not adding removals */
        *(int *)opt->value = !unset ? 0 : 1;
        return 0;
@@ -357,7 +267,8 @@ static struct option builtin_add_options[] = {
        OPT_END(),
 };
 
-static int add_config(const char *var, const char *value, void *cb)
+static int add_config(const char *var, const char *value,
+                     const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "add.ignoreerrors") ||
            !strcmp(var, "add.ignore-errors")) {
@@ -365,7 +276,10 @@ static int add_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       if (git_color_config(var, value, cb) < 0)
+               return -1;
+
+       return git_default_config(var, value, ctx, cb);
 }
 
 static const char embedded_advice[] = N_(
@@ -640,7 +554,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (add_renormalize)
                exit_status |= renormalize_tracked_files(&pathspec, flags);
        else
-               exit_status |= add_files_to_cache(prefix, &pathspec, flags);
+               exit_status |= add_files_to_cache(the_repository, prefix,
+                                                 &pathspec, include_sparse,
+                                                 flags);
 
        if (add_new_files)
                exit_status |= add_files(&dir, flags);
@@ -652,7 +568,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 finish:
        if (write_locked_index(&the_index, &lock_file,
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
-               die(_("Unable to write new index file"));
+               die(_("unable to write new index file"));
 
        dir_clear(&dir);
        clear_pathspec(&pathspec);
index 5c83f2e003fb01ab6409a23e3a79ab15e4aed6f2..9f084d58bc705c74d6986541fe81161dcd37df8c 100644 (file)
@@ -4,11 +4,10 @@
  * Based on git-am.sh by Junio C Hamano.
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "abspath.h"
 #include "advice.h"
 #include "config.h"
-#include "builtin.h"
 #include "editor.h"
 #include "environment.h"
 #include "exec-cmd.h"
@@ -29,6 +28,7 @@
 #include "unpack-trees.h"
 #include "branch.h"
 #include "object-name.h"
+#include "preload-index.h"
 #include "sequencer.h"
 #include "revision.h"
 #include "merge-recursive.h"
@@ -41,9 +41,9 @@
 #include "string-list.h"
 #include "packfile.h"
 #include "pager.h"
+#include "path.h"
 #include "repository.h"
 #include "pretty.h"
-#include "wrapper.h"
 
 /**
  * Returns the length of the first line of msg.
@@ -92,9 +92,16 @@ enum signoff_type {
        SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
 };
 
-enum show_patch_type {
-       SHOW_PATCH_RAW = 0,
-       SHOW_PATCH_DIFF = 1,
+enum resume_type {
+       RESUME_FALSE = 0,
+       RESUME_APPLY,
+       RESUME_RESOLVED,
+       RESUME_SKIP,
+       RESUME_ABORT,
+       RESUME_QUIT,
+       RESUME_SHOW_PATCH_RAW,
+       RESUME_SHOW_PATCH_DIFF,
+       RESUME_ALLOW_EMPTY,
 };
 
 enum empty_action {
@@ -786,7 +793,7 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
  * A split_mail_conv() callback that converts an StGit patch to an RFC2822
  * message suitable for parsing with git-mailinfo.
  */
-static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr)
+static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr UNUSED)
 {
        struct strbuf sb = STRBUF_INIT;
        int subject_printed = 0;
@@ -869,7 +876,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,
  * A split_patches_conv() callback that converts a mercurial patch to a RFC2822
  * message suitable for parsing with git-mailinfo.
  */
-static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
+static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr UNUSED)
 {
        struct strbuf sb = STRBUF_INIT;
        int rc = 0;
@@ -1283,7 +1290,7 @@ static int parse_mail(struct am_state *state, const char *mail)
 
        strbuf_addstr(&msg, "\n\n");
        strbuf_addbuf(&msg, &mi.log_message);
-       strbuf_stripspace(&msg, 0);
+       strbuf_stripspace(&msg, '\0');
 
        assert(!state->author_name);
        state->author_name = strbuf_detach(&author_name, NULL);
@@ -1430,7 +1437,7 @@ static void write_index_patch(const struct am_state *state)
        rev_info.diffopt.close_file = 1;
        add_pending_object(&rev_info, &tree->object, "");
        diff_setup_done(&rev_info.diffopt);
-       run_diff_index(&rev_info, 1);
+       run_diff_index(&rev_info, DIFF_INDEX_CACHED);
        release_revisions(&rev_info);
 }
 
@@ -1593,7 +1600,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
                rev_info.diffopt.filter |= diff_filter_bit('M');
                add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
                diff_setup_done(&rev_info.diffopt);
-               run_diff_index(&rev_info, 1);
+               run_diff_index(&rev_info, DIFF_INDEX_CACHED);
                release_revisions(&rev_info);
        }
 
@@ -2191,7 +2198,7 @@ static void am_abort(struct am_state *state)
        am_destroy(state);
 }
 
-static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
+static int show_patch(struct am_state *state, enum resume_type resume_mode)
 {
        struct strbuf sb = STRBUF_INIT;
        const char *patch_path;
@@ -2206,11 +2213,11 @@ static int show_patch(struct am_state *state, enum show_patch_type sub_mode)
                return run_command(&cmd);
        }
 
-       switch (sub_mode) {
-       case SHOW_PATCH_RAW:
+       switch (resume_mode) {
+       case RESUME_SHOW_PATCH_RAW:
                patch_path = am_path(state, msgnum(state));
                break;
-       case SHOW_PATCH_DIFF:
+       case RESUME_SHOW_PATCH_DIFF:
                patch_path = am_path(state, "patch");
                break;
        default:
@@ -2257,56 +2264,25 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
        return 0;
 }
 
-enum resume_type {
-       RESUME_FALSE = 0,
-       RESUME_APPLY,
-       RESUME_RESOLVED,
-       RESUME_SKIP,
-       RESUME_ABORT,
-       RESUME_QUIT,
-       RESUME_SHOW_PATCH,
-       RESUME_ALLOW_EMPTY,
-};
-
-struct resume_mode {
-       enum resume_type mode;
-       enum show_patch_type sub_mode;
-};
-
 static int parse_opt_show_current_patch(const struct option *opt, const char *arg, int unset)
 {
        int *opt_value = opt->value;
-       struct resume_mode *resume = container_of(opt_value, struct resume_mode, mode);
 
+       BUG_ON_OPT_NEG(unset);
+
+       if (!arg)
+               *opt_value = opt->defval;
+       else if (!strcmp(arg, "raw"))
+               *opt_value = RESUME_SHOW_PATCH_RAW;
+       else if (!strcmp(arg, "diff"))
+               *opt_value = RESUME_SHOW_PATCH_DIFF;
        /*
         * Please update $__git_showcurrentpatch in git-completion.bash
         * when you add new options
         */
-       const char *valid_modes[] = {
-               [SHOW_PATCH_DIFF] = "diff",
-               [SHOW_PATCH_RAW] = "raw"
-       };
-       int new_value = SHOW_PATCH_RAW;
-
-       BUG_ON_OPT_NEG(unset);
-
-       if (arg) {
-               for (new_value = 0; new_value < ARRAY_SIZE(valid_modes); new_value++) {
-                       if (!strcmp(arg, valid_modes[new_value]))
-                               break;
-               }
-               if (new_value >= ARRAY_SIZE(valid_modes))
-                       return error(_("invalid value for '%s': '%s'"),
-                                    "--show-current-patch", arg);
-       }
-
-       if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
-               return error(_("options '%s=%s' and '%s=%s' "
-                                          "cannot be used together"),
-                                        "--show-current-patch", "--show-current-patch", arg, valid_modes[resume->sub_mode]);
-
-       resume->mode = RESUME_SHOW_PATCH;
-       resume->sub_mode = new_value;
+       else
+               return error(_("invalid value for '%s': '%s'"),
+                            "--show-current-patch", arg);
        return 0;
 }
 
@@ -2316,7 +2292,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
        int binary = -1;
        int keep_cr = -1;
        int patch_format = PATCH_FORMAT_UNKNOWN;
-       struct resume_mode resume = { .mode = RESUME_FALSE };
+       enum resume_type resume_mode = RESUME_FALSE;
        int in_progress;
        int ret = 0;
 
@@ -2347,12 +2323,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                        N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),
                OPT_BOOL('m', "message-id", &state.message_id,
                        N_("pass -m flag to git-mailinfo")),
-               OPT_SET_INT_F(0, "keep-cr", &keep_cr,
-                       N_("pass --keep-cr flag to git-mailsplit for mbox format"),
-                       1, PARSE_OPT_NONEG),
-               OPT_SET_INT_F(0, "no-keep-cr", &keep_cr,
-                       N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),
-                       0, PARSE_OPT_NONEG),
+               OPT_SET_INT(0, "keep-cr", &keep_cr,
+                           N_("pass --keep-cr flag to git-mailsplit for mbox format"),
+                           1),
                OPT_BOOL('c', "scissors", &state.scissors,
                        N_("strip everything before a scissors line")),
                OPT_CALLBACK_F(0, "quoted-cr", &state.quoted_cr, N_("action"),
@@ -2390,27 +2363,27 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                        PARSE_OPT_NOARG),
                OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL,
                        N_("override error message when patch failure occurs")),
-               OPT_CMDMODE(0, "continue", &resume.mode,
+               OPT_CMDMODE(0, "continue", &resume_mode,
                        N_("continue applying patches after resolving a conflict"),
                        RESUME_RESOLVED),
-               OPT_CMDMODE('r', "resolved", &resume.mode,
+               OPT_CMDMODE('r', "resolved", &resume_mode,
                        N_("synonyms for --continue"),
                        RESUME_RESOLVED),
-               OPT_CMDMODE(0, "skip", &resume.mode,
+               OPT_CMDMODE(0, "skip", &resume_mode,
                        N_("skip the current patch"),
                        RESUME_SKIP),
-               OPT_CMDMODE(0, "abort", &resume.mode,
+               OPT_CMDMODE(0, "abort", &resume_mode,
                        N_("restore the original branch and abort the patching operation"),
                        RESUME_ABORT),
-               OPT_CMDMODE(0, "quit", &resume.mode,
+               OPT_CMDMODE(0, "quit", &resume_mode,
                        N_("abort the patching operation but keep HEAD where it is"),
                        RESUME_QUIT),
-               { OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
+               { OPTION_CALLBACK, 0, "show-current-patch", &resume_mode,
                  "(diff|raw)",
                  N_("show the patch being applied"),
                  PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
-                 parse_opt_show_current_patch, RESUME_SHOW_PATCH },
-               OPT_CMDMODE(0, "allow-empty", &resume.mode,
+                 parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW },
+               OPT_CMDMODE(0, "allow-empty", &resume_mode,
                        N_("record the empty patch as an empty commit"),
                        RESUME_ALLOW_EMPTY),
                OPT_BOOL(0, "committer-date-is-author-date",
@@ -2422,7 +2395,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                { OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"),
                  N_("GPG-sign commits"),
                  PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
-               OPT_CALLBACK_F(STOP_ON_EMPTY_COMMIT, "empty", &state.empty_type, "{stop,drop,keep}",
+               OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)",
                  N_("how to handle empty patches"),
                  PARSE_OPT_NONEG, am_option_parse_empty),
                OPT_HIDDEN_BOOL(0, "rebasing", &state.rebasing,
@@ -2465,12 +2438,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                 *    intend to feed us a patch but wanted to continue
                 *    unattended.
                 */
-               if (argc || (resume.mode == RESUME_FALSE && !isatty(0)))
+               if (argc || (resume_mode == RESUME_FALSE && !isatty(0)))
                        die(_("previous rebase directory %s still exists but mbox given."),
                                state.dir);
 
-               if (resume.mode == RESUME_FALSE)
-                       resume.mode = RESUME_APPLY;
+               if (resume_mode == RESUME_FALSE)
+                       resume_mode = RESUME_APPLY;
 
                if (state.signoff == SIGNOFF_EXPLICIT)
                        am_append_signoff(&state);
@@ -2484,7 +2457,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                 * stray directories.
                 */
                if (file_exists(state.dir) && !state.rebasing) {
-                       if (resume.mode == RESUME_ABORT || resume.mode == RESUME_QUIT) {
+                       if (resume_mode == RESUME_ABORT || resume_mode == RESUME_QUIT) {
                                am_destroy(&state);
                                am_state_release(&state);
                                return 0;
@@ -2495,7 +2468,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                                state.dir);
                }
 
-               if (resume.mode)
+               if (resume_mode)
                        die(_("Resolve operation not in progress, we are not resuming."));
 
                for (i = 0; i < argc; i++) {
@@ -2513,7 +2486,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                strvec_clear(&paths);
        }
 
-       switch (resume.mode) {
+       switch (resume_mode) {
        case RESUME_FALSE:
                am_run(&state, 0);
                break;
@@ -2522,7 +2495,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                break;
        case RESUME_RESOLVED:
        case RESUME_ALLOW_EMPTY:
-               am_resolve(&state, resume.mode == RESUME_ALLOW_EMPTY ? 1 : 0);
+               am_resolve(&state, resume_mode == RESUME_ALLOW_EMPTY ? 1 : 0);
                break;
        case RESUME_SKIP:
                am_skip(&state);
@@ -2534,8 +2507,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                am_rerere_clear();
                am_destroy(&state);
                break;
-       case RESUME_SHOW_PATCH:
-               ret = show_patch(&state, resume.sub_mode);
+       case RESUME_SHOW_PATCH_RAW:
+       case RESUME_SHOW_PATCH_DIFF:
+               ret = show_patch(&state, resume_mode);
                break;
        default:
                BUG("invalid resume value");
index e3ff02a09e3e8031712d1979a9b5dbfd2b8ccbf4..c18b7ea5d3da4aa66d82c9fa0e911274308ad598 100644 (file)
@@ -1,4 +1,3 @@
-#include "cache.h"
 #include "builtin.h"
 #include "gettext.h"
 #include "parse-options.h"
index b0eaa3c14a3236990e188b82b020415ce698b7de..90761fdfee0f58f0d2d8cca9c7b0bcd6e0ee7fe9 100644 (file)
@@ -2,7 +2,6 @@
  * Copyright (c) 2006 Franck Bui-Huu
  * Copyright (c) 2006 Rene Scharfe
  */
-#include "cache.h"
 #include "builtin.h"
 #include "archive.h"
 #include "gettext.h"
index 4812450c393da3e2df36521c5f0295ad48e65fe2..35938b05fd1c0b51e64a01e58294f267afc4d758 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "copy.h"
 #include "environment.h"
 #include "gettext.h"
 #include "strvec.h"
 #include "run-command.h"
 #include "oid-array.h"
+#include "path.h"
 #include "prompt.h"
 #include "quote.h"
 #include "revision.h"
-#include "wrapper.h"
 
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
@@ -27,7 +26,7 @@ static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 
 #define BUILTIN_GIT_BISECT_START_USAGE \
-       N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+       N_("git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]" \
           "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
           "    [<pathspec>...]")
 #define BUILTIN_GIT_BISECT_STATE_USAGE \
@@ -47,7 +46,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 #define BUILTIN_GIT_BISECT_LOG_USAGE \
        "git bisect log"
 #define BUILTIN_GIT_BISECT_RUN_USAGE \
-       N_("git bisect run <cmd>...")
+       N_("git bisect run <cmd> [<arg>...]")
 
 static const char * const git_bisect_usage[] = {
        BUILTIN_GIT_BISECT_START_USAGE,
index 2df6039a6e0e139227c937023b8d8565e5ceb611..9c987d656756e8f436e3b1cb818306097e402e4c 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "color.h"
 #include "builtin.h"
@@ -29,7 +28,7 @@
 #include "dir.h"
 #include "progress.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pager.h"
 #include "blame.h"
 #include "refs.h"
@@ -694,7 +693,8 @@ static const char *add_prefix(const char *prefix, const char *path)
        return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
 }
 
-static int git_blame_config(const char *var, const char *value, void *cb)
+static int git_blame_config(const char *var, const char *value,
+                           const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "blame.showroot")) {
                show_root = git_config_bool(var, value);
@@ -767,7 +767,7 @@ static int git_blame_config(const char *var, const char *value, void *cb)
        if (userdiff_config(var, value) < 0)
                return -1;
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static int blame_copy_callback(const struct option *option, const char *arg, int unset)
index e6c2655af68b339a7aa863cedd6d75e5176dd443..e7ee9bd0f15028532087132cdc6062e8632568c2 100644 (file)
@@ -5,20 +5,20 @@
  * Based on git-branch.sh by Junio C Hamano.
  */
 
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "color.h"
 #include "editor.h"
 #include "environment.h"
 #include "refs.h"
 #include "commit.h"
-#include "builtin.h"
 #include "gettext.h"
 #include "object-name.h"
 #include "remote.h"
 #include "parse-options.h"
 #include "branch.h"
 #include "diff.h"
+#include "path.h"
 #include "revision.h"
 #include "string-list.h"
 #include "column.h"
@@ -28,7 +28,6 @@
 #include "worktree.h"
 #include "help.h"
 #include "commit-reach.h"
-#include "wrapper.h"
 
 static const char * const builtin_branch_usage[] = {
        N_("git branch [<options>] [-r | -a] [--merged] [--no-merged]"),
@@ -83,7 +82,8 @@ static unsigned int colopts;
 
 define_list_config_array(color_branch_slots);
 
-static int git_branch_config(const char *var, const char *value, void *cb)
+static int git_branch_config(const char *var, const char *value,
+                            const struct config_context *ctx, void *cb)
 {
        const char *slot_name;
 
@@ -117,7 +117,10 @@ static int git_branch_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_color_default_config(var, value, cb);
+       if (git_color_config(var, value, cb) < 0)
+               return -1;
+
+       return git_default_config(var, value, ctx, cb);
 }
 
 static const char *branch_get_color(enum color_branch ix)
@@ -170,11 +173,11 @@ static int branch_merged(int kind, const char *name,
            (head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0) != merged) {
                if (merged)
                        warning(_("deleting branch '%s' that has been merged to\n"
-                               "         '%s', but not yet merged to HEAD."),
+                               "         '%s', but not yet merged to HEAD"),
                                name, reference_name);
                else
                        warning(_("not deleting branch '%s' that is not yet merged to\n"
-                               "         '%s', even though it is merged to HEAD."),
+                               "         '%s', even though it is merged to HEAD"),
                                name, reference_name);
        }
        free(reference_name_to_free);
@@ -187,13 +190,13 @@ static int check_branch_commit(const char *branchname, const char *refname,
 {
        struct commit *rev = lookup_commit_reference(the_repository, oid);
        if (!force && !rev) {
-               error(_("Couldn't look up commit object for '%s'"), refname);
+               error(_("couldn't look up commit object for '%s'"), refname);
                return -1;
        }
        if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
-               error(_("The branch '%s' is not fully merged.\n"
+               error(_("the branch '%s' is not fully merged.\n"
                      "If you are sure you want to delete it, "
-                     "run 'git branch -D %s'."), branchname, branchname);
+                     "run 'git branch -D %s'"), branchname, branchname);
                return -1;
        }
        return 0;
@@ -204,7 +207,7 @@ static void delete_branch_config(const char *branchname)
        struct strbuf buf = STRBUF_INIT;
        strbuf_addf(&buf, "branch.%s", branchname);
        if (git_config_rename_section(buf.buf, NULL) < 0)
-               warning(_("Update of config-file failed"));
+               warning(_("update of config-file failed"));
        strbuf_release(&buf);
 }
 
@@ -257,8 +260,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                if (kinds == FILTER_REFS_BRANCHES) {
                        const char *path;
                        if ((path = branch_checked_out(name))) {
-                               error(_("Cannot delete branch '%s' "
-                                       "checked out at '%s'"),
+                               error(_("cannot delete branch '%s' "
+                                       "used by worktree at '%s'"),
                                      bname.buf, path);
                                ret = 1;
                                continue;
@@ -272,7 +275,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                                        &oid, &flags);
                if (!target) {
                        if (remote_branch) {
-                               error(_("remote-tracking branch '%s' not found."), bname.buf);
+                               error(_("remote-tracking branch '%s' not found"), bname.buf);
                        } else {
                                char *virtual_name = mkpathdup(fmt_remotes, bname.buf);
                                char *virtual_target = resolve_refdup(virtual_name,
@@ -287,7 +290,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                                                "Did you forget --remote?"),
                                                bname.buf);
                                else
-                                       error(_("branch '%s' not found."), bname.buf);
+                                       error(_("branch '%s' not found"), bname.buf);
                                FREE_AND_NULL(virtual_target);
                        }
                        ret = 1;
@@ -366,17 +369,8 @@ static const char *quote_literal_for_format(const char *s)
        static struct strbuf buf = STRBUF_INIT;
 
        strbuf_reset(&buf);
-       while (*s) {
-               const char *ep = strchrnul(s, '%');
-               if (s < ep)
-                       strbuf_add(&buf, s, ep - s);
-               if (*ep == '%') {
-                       strbuf_addstr(&buf, "%%");
-                       s = ep + 1;
-               } else {
-                       s = ep;
-               }
-       }
+       while (strbuf_expand_step(&buf, &s))
+               strbuf_addstr(&buf, "%%");
        return buf.buf;
 }
 
@@ -524,11 +518,11 @@ static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
                        continue;
 
                if (is_worktree_being_rebased(wt, target))
-                       die(_("Branch %s is being rebased at %s"),
+                       die(_("branch %s is being rebased at %s"),
                            target, wt->path);
 
                if (is_worktree_being_bisected(wt, target))
-                       die(_("Branch %s is being bisected at %s"),
+                       die(_("branch %s is being bisected at %s"),
                            target, wt->path);
        }
 }
@@ -584,7 +578,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
                if (ref_exists(oldref.buf))
                        recovery = 1;
                else
-                       die(_("Invalid branch name: '%s'"), oldname);
+                       die(_("invalid branch name: '%s'"), oldname);
        }
 
        for (int i = 0; worktrees[i]; i++) {
@@ -600,9 +594,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 
        if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
                if (oldref_usage & IS_HEAD)
-                       die(_("No commit on branch '%s' yet."), oldname);
+                       die(_("no commit on branch '%s' yet"), oldname);
                else
-                       die(_("No branch named '%s'."), oldname);
+                       die(_("no branch named '%s'"), oldname);
        }
 
        /*
@@ -630,32 +624,32 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
 
        if (!copy && !(oldref_usage & IS_ORPHAN) &&
            rename_ref(oldref.buf, newref.buf, logmsg.buf))
-               die(_("Branch rename failed"));
+               die(_("branch rename failed"));
        if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
-               die(_("Branch copy failed"));
+               die(_("branch copy failed"));
 
        if (recovery) {
                if (copy)
-                       warning(_("Created a copy of a misnamed branch '%s'"),
+                       warning(_("created a copy of a misnamed branch '%s'"),
                                interpreted_oldname);
                else
-                       warning(_("Renamed a misnamed branch '%s' away"),
+                       warning(_("renamed a misnamed branch '%s' away"),
                                interpreted_oldname);
        }
 
        if (!copy && (oldref_usage & IS_HEAD) &&
            replace_each_worktree_head_symref(worktrees, oldref.buf, newref.buf,
                                              logmsg.buf))
-               die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
+               die(_("branch renamed to %s, but HEAD is not updated"), newname);
 
        strbuf_release(&logmsg);
 
        strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
        strbuf_addf(&newsection, "branch.%s", interpreted_newname);
        if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
-               die(_("Branch is renamed, but update of config-file failed"));
+               die(_("branch is renamed, but update of config-file failed"));
        if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
-               die(_("Branch is copied, but update of config-file failed"));
+               die(_("branch is copied, but update of config-file failed"));
        strbuf_release(&oldref);
        strbuf_release(&newref);
        strbuf_release(&oldsection);
@@ -674,7 +668,7 @@ static int edit_branch_description(const char *branch_name)
        exists = !read_branch_desc(&buf, branch_name);
        if (!buf.len || buf.buf[buf.len-1] != '\n')
                strbuf_addch(&buf, '\n');
-       strbuf_commented_addf(&buf,
+       strbuf_commented_addf(&buf, comment_line_char,
                    _("Please edit the description for the branch\n"
                      "  %s\n"
                      "Lines starting with '%c' will be stripped.\n"),
@@ -685,7 +679,7 @@ static int edit_branch_description(const char *branch_name)
                strbuf_release(&buf);
                return -1;
        }
-       strbuf_stripspace(&buf, 1);
+       strbuf_stripspace(&buf, comment_line_char);
 
        strbuf_addf(&name, "branch.%s.description", branch_name);
        if (buf.len || exists)
@@ -707,7 +701,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        int reflog = 0, quiet = 0, icase = 0, force = 0,
            recurse_submodules_explicit = 0;
        enum branch_track track;
-       struct ref_filter filter;
+       struct ref_filter filter = REF_FILTER_INIT;
        static struct ref_sorting *sorting;
        struct string_list sorting_options = STRING_LIST_INIT_DUP;
        struct ref_format format = REF_FORMAT_INIT;
@@ -726,8 +720,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
                OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("unset the upstream info")),
                OPT__COLOR(&branch_use_color, N_("use colored output")),
-               OPT_SET_INT('r', "remotes",     &filter.kind, N_("act on remote-tracking branches"),
-                       FILTER_REFS_REMOTES),
+               OPT_SET_INT_F('r', "remotes",     &filter.kind, N_("act on remote-tracking branches"),
+                             FILTER_REFS_REMOTES,
+                             PARSE_OPT_NONEG),
                OPT_CONTAINS(&filter.with_commit, N_("print only branches that contain the commit")),
                OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches that don't contain the commit")),
                OPT_WITH(&filter.with_commit, N_("print only branches that contain the commit")),
@@ -735,8 +730,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                OPT__ABBREV(&filter.abbrev),
 
                OPT_GROUP(N_("Specific git-branch actions:")),
-               OPT_SET_INT('a', "all", &filter.kind, N_("list both remote-tracking and local branches"),
-                       FILTER_REFS_REMOTES | FILTER_REFS_BRANCHES),
+               OPT_SET_INT_F('a', "all", &filter.kind, N_("list both remote-tracking and local branches"),
+                             FILTER_REFS_REMOTES | FILTER_REFS_BRANCHES,
+                             PARSE_OPT_NONEG),
                OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
                OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
                OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
@@ -765,7 +761,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
        setup_ref_filter_porcelain_msg();
 
-       memset(&filter, 0, sizeof(filter));
        filter.kind = FILTER_REFS_BRANCHES;
        filter.abbrev = -1;
 
@@ -778,7 +773,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
        head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
-               die(_("Failed to resolve HEAD as a valid ref."));
+               die(_("failed to resolve HEAD as a valid ref"));
        if (!strcmp(head, "HEAD"))
                filter.detached = 1;
        else if (!skip_prefix(head, "refs/heads/", &head))
@@ -832,6 +827,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        if (list)
                setup_auto_pager("branch", 1);
 
+       UNLEAK(sorting_options);
+
        if (delete) {
                if (!argc)
                        die(_("branch name required"));
@@ -859,6 +856,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                print_columns(&output, colopts, NULL);
                string_list_clear(&output, 0);
                ref_sorting_release(sorting);
+               ref_filter_clear(&filter);
                return 0;
        } else if (edit_description) {
                const char *branch_name;
@@ -868,7 +866,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
                if (!argc) {
                        if (filter.detached)
-                               die(_("Cannot give description to detached HEAD"));
+                               die(_("cannot give description to detached HEAD"));
                        branch_name = head;
                } else if (argc == 1) {
                        strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
@@ -880,8 +878,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
                if (!ref_exists(branch_ref.buf))
                        error((!argc || branch_checked_out(branch_ref.buf))
-                             ? _("No commit on branch '%s' yet.")
-                             : _("No branch named '%s'."),
+                             ? _("no commit on branch '%s' yet")
+                             : _("no branch named '%s'"),
                              branch_name);
                else if (!edit_branch_description(branch_name))
                        ret = 0; /* happy */
@@ -894,8 +892,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (!argc)
                        die(_("branch name required"));
                else if ((argc == 1) && filter.detached)
-                       die(copy? _("cannot copy the current branch while not on any.")
-                               : _("cannot rename the current branch while not on any."));
+                       die(copy? _("cannot copy the current branch while not on any")
+                               : _("cannot rename the current branch while not on any"));
                else if (argc == 1)
                        copy_or_rename_branch(head, argv[0], copy, copy + rename > 1);
                else if (argc == 2)
@@ -918,14 +916,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (!branch) {
                        if (!argc || !strcmp(argv[0], "HEAD"))
                                die(_("could not set upstream of HEAD to %s when "
-                                     "it does not point to any branch."),
+                                     "it does not point to any branch"),
                                    new_upstream);
                        die(_("no such branch '%s'"), argv[0]);
                }
 
                if (!ref_exists(branch->refname)) {
                        if (!argc || branch_checked_out(branch->refname))
-                               die(_("No commit on branch '%s' yet."), branch->name);
+                               die(_("no commit on branch '%s' yet"), branch->name);
                        die(_("branch '%s' does not exist"), branch->name);
                }
 
@@ -948,12 +946,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (!branch) {
                        if (!argc || !strcmp(argv[0], "HEAD"))
                                die(_("could not unset upstream of HEAD when "
-                                     "it does not point to any branch."));
+                                     "it does not point to any branch"));
                        die(_("no such branch '%s'"), argv[0]);
                }
 
                if (!branch_has_merge_config(branch))
-                       die(_("Branch '%s' has no upstream information"), branch->name);
+                       die(_("branch '%s' has no upstream information"), branch->name);
 
                strbuf_reset(&buf);
                strbuf_addf(&buf, "branch.%s.remote", branch->name);
@@ -967,11 +965,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                const char *start_name = argc == 2 ? argv[1] : head;
 
                if (filter.kind != FILTER_REFS_BRANCHES)
-                       die(_("The -a, and -r, options to 'git branch' do not take a branch name.\n"
+                       die(_("the -a, and -r, options to 'git branch' do not take a branch name.\n"
                                  "Did you mean to use: -a|-r --list <pattern>?"));
 
                if (track == BRANCH_TRACK_OVERRIDE)
-                       die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
+                       die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead"));
 
                if (recurse_submodules) {
                        create_branches_recursively(the_repository, branch_name,
index daf6c236577626fffd8dd61c63489d9e6e706635..d2ae5c305db82cda78851196411f6437f4abbda9 100644 (file)
@@ -11,7 +11,6 @@
 #include "diagnose.h"
 #include "object-file.h"
 #include "setup.h"
-#include "wrapper.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
index 44113389d7a34a7cf3fde15a52c3387d851f44db..3ad11dc5d0548727da0f27e04563a8d947207f74 100644 (file)
@@ -6,7 +6,6 @@
 #include "parse-options.h"
 #include "pkt-line.h"
 #include "repository.h"
-#include "cache.h"
 #include "bundle.h"
 
 /*
@@ -69,42 +68,36 @@ static int parse_options_cmd_bundle(int argc,
 }
 
 static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
-       int all_progress_implied = 1;
-       int progress = isatty(STDERR_FILENO);
-       struct strvec pack_opts;
+       struct strvec pack_opts = STRVEC_INIT;
        int version = -1;
        int ret;
        struct option options[] = {
-               OPT_SET_INT('q', "quiet", &progress,
-                           N_("do not show progress meter"), 0),
-               OPT_SET_INT(0, "progress", &progress,
-                           N_("show progress meter"), 1),
-               OPT_SET_INT_F(0, "all-progress", &progress,
-                             N_("historical; same as --progress"), 2,
-                             PARSE_OPT_HIDDEN),
-               OPT_HIDDEN_BOOL(0, "all-progress-implied",
-                               &all_progress_implied,
-                               N_("historical; does nothing")),
+               OPT_PASSTHRU_ARGV('q', "quiet", &pack_opts, NULL,
+                                 N_("do not show progress meter"),
+                                 PARSE_OPT_NOARG),
+               OPT_PASSTHRU_ARGV(0, "progress", &pack_opts, NULL,
+                                 N_("show progress meter"),
+                                 PARSE_OPT_NOARG),
+               OPT_PASSTHRU_ARGV(0, "all-progress", &pack_opts, NULL,
+                                 N_("historical; same as --progress"),
+                                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+               OPT_PASSTHRU_ARGV(0, "all-progress-implied", &pack_opts, NULL,
+                                 N_("historical; does nothing"),
+                                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
                OPT_INTEGER(0, "version", &version,
                            N_("specify bundle format version")),
                OPT_END()
        };
        char *bundle_file;
 
+       if (isatty(STDERR_FILENO))
+               strvec_push(&pack_opts, "--progress");
+       strvec_push(&pack_opts, "--all-progress-implied");
+
        argc = parse_options_cmd_bundle(argc, argv, prefix,
                        builtin_bundle_create_usage, options, &bundle_file);
        /* bundle internals use argv[1] as further parameters */
 
-       strvec_init(&pack_opts);
-       if (progress == 0)
-               strvec_push(&pack_opts, "--quiet");
-       else if (progress == 1)
-               strvec_push(&pack_opts, "--progress");
-       else if (progress == 2)
-               strvec_push(&pack_opts, "--all-progress");
-       if (progress && all_progress_implied)
-               strvec_push(&pack_opts, "--all-progress-implied");
-
        if (!startup_info->have_repository)
                die(_("Need a repository to create a bundle."));
        ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
index 0bafc14e6c03ac1c034e64878b884ebcb15128af..ea8ad601ecc0b7ee2d7eb9c3da2bb70bcfc55cf8 100644 (file)
@@ -4,11 +4,9 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
-#include "alloc.h"
+#include "builtin.h"
 #include "config.h"
 #include "convert.h"
-#include "builtin.h"
 #include "diff.h"
 #include "environment.h"
 #include "gettext.h"
@@ -22,7 +20,7 @@
 #include "packfile.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "replace-object.h"
 #include "promisor-remote.h"
 #include "mailmap.h"
@@ -42,7 +40,8 @@ struct batch_options {
        int all_objects;
        int unordered;
        int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
-       int nul_terminated;
+       char input_delim;
+       char output_delim;
        const char *format;
 };
 
@@ -309,10 +308,8 @@ static int is_atom(const char *atom, const char *s, int slen)
 }
 
 static void expand_atom(struct strbuf *sb, const char *atom, int len,
-                       void *vdata)
+                       struct expand_data *data)
 {
-       struct expand_data *data = vdata;
-
        if (is_atom("objectname", atom, len)) {
                if (!data->mark_query)
                        strbuf_addstr(sb, oid_to_hex(&data->oid));
@@ -346,19 +343,21 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
                die("unknown format element: %.*s", len, atom);
 }
 
-static size_t expand_format(struct strbuf *sb, const char *start, void *data)
+static void expand_format(struct strbuf *sb, const char *start,
+                         struct expand_data *data)
 {
-       const char *end;
-
-       if (*start != '(')
-               return 0;
-       end = strchr(start + 1, ')');
-       if (!end)
-               die("format element '%s' does not end in ')'", start);
-
-       expand_atom(sb, start + 1, end - start - 1, data);
-
-       return end - start + 1;
+       while (strbuf_expand_step(sb, &start)) {
+               const char *end;
+
+               if (skip_prefix(start, "%", &start) || *start != '(')
+                       strbuf_addch(sb, '%');
+               else if (!(end = strchr(start + 1, ')')))
+                       die("format element '%s' does not end in ')'", start);
+               else {
+                       expand_atom(sb, start + 1, end - start - 1, data);
+                       start = end + 1;
+               }
+       }
 }
 
 static void batch_write(struct batch_options *opt, const void *data, int len)
@@ -437,11 +436,12 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
        }
 }
 
-static void print_default_format(struct strbuf *scratch, struct expand_data *data)
+static void print_default_format(struct strbuf *scratch, struct expand_data *data,
+                                struct batch_options *opt)
 {
-       strbuf_addf(scratch, "%s %s %"PRIuMAX"\n", oid_to_hex(&data->oid),
+       strbuf_addf(scratch, "%s %s %"PRIuMAX"%c", oid_to_hex(&data->oid),
                    type_name(data->type),
-                   (uintmax_t)data->size);
+                   (uintmax_t)data->size, opt->output_delim);
 }
 
 /*
@@ -470,8 +470,8 @@ static void batch_object_write(const char *obj_name,
                                                       &data->oid, &data->info,
                                                       OBJECT_INFO_LOOKUP_REPLACE);
                if (ret < 0) {
-                       printf("%s missing\n",
-                              obj_name ? obj_name : oid_to_hex(&data->oid));
+                       printf("%s missing%c",
+                              obj_name ? obj_name : oid_to_hex(&data->oid), opt->output_delim);
                        fflush(stdout);
                        return;
                }
@@ -492,17 +492,17 @@ static void batch_object_write(const char *obj_name,
        strbuf_reset(scratch);
 
        if (!opt->format) {
-               print_default_format(scratch, data);
+               print_default_format(scratch, data, opt);
        } else {
-               strbuf_expand(scratch, opt->format, expand_format, data);
-               strbuf_addch(scratch, '\n');
+               expand_format(scratch, opt->format, data);
+               strbuf_addch(scratch, opt->output_delim);
        }
 
        batch_write(opt, scratch->buf, scratch->len);
 
        if (opt->batch_mode == BATCH_MODE_CONTENTS) {
                print_object_or_die(opt, data);
-               batch_write(opt, "\n", 1);
+               batch_write(opt, &opt->output_delim, 1);
        }
 }
 
@@ -520,22 +520,25 @@ static void batch_one_object(const char *obj_name,
        if (result != FOUND) {
                switch (result) {
                case MISSING_OBJECT:
-                       printf("%s missing\n", obj_name);
+                       printf("%s missing%c", obj_name, opt->output_delim);
                        break;
                case SHORT_NAME_AMBIGUOUS:
-                       printf("%s ambiguous\n", obj_name);
+                       printf("%s ambiguous%c", obj_name, opt->output_delim);
                        break;
                case DANGLING_SYMLINK:
-                       printf("dangling %"PRIuMAX"\n%s\n",
-                              (uintmax_t)strlen(obj_name), obj_name);
+                       printf("dangling %"PRIuMAX"%c%s%c",
+                              (uintmax_t)strlen(obj_name),
+                              opt->output_delim, obj_name, opt->output_delim);
                        break;
                case SYMLINK_LOOP:
-                       printf("loop %"PRIuMAX"\n%s\n",
-                              (uintmax_t)strlen(obj_name), obj_name);
+                       printf("loop %"PRIuMAX"%c%s%c",
+                              (uintmax_t)strlen(obj_name),
+                              opt->output_delim, obj_name, opt->output_delim);
                        break;
                case NOT_DIR:
-                       printf("notdir %"PRIuMAX"\n%s\n",
-                              (uintmax_t)strlen(obj_name), obj_name);
+                       printf("notdir %"PRIuMAX"%c%s%c",
+                              (uintmax_t)strlen(obj_name),
+                              opt->output_delim, obj_name, opt->output_delim);
                        break;
                default:
                        BUG("unknown get_sha1_with_context result %d\n",
@@ -547,9 +550,9 @@ static void batch_one_object(const char *obj_name,
        }
 
        if (ctx.mode == 0) {
-               printf("symlink %"PRIuMAX"\n%s\n",
+               printf("symlink %"PRIuMAX"%c%s%c",
                       (uintmax_t)ctx.symlink_path.len,
-                      ctx.symlink_path.buf);
+                      opt->output_delim, ctx.symlink_path.buf, opt->output_delim);
                fflush(stdout);
                return;
        }
@@ -694,20 +697,12 @@ static void batch_objects_command(struct batch_options *opt,
        struct queued_cmd *queued_cmd = NULL;
        size_t alloc = 0, nr = 0;
 
-       while (1) {
-               int i, ret;
+       while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
+               int i;
                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))
@@ -777,9 +772,8 @@ static int batch_objects(struct batch_options *opt)
         */
        memset(&data, 0, sizeof(data));
        data.mark_query = 1;
-       strbuf_expand(&output,
+       expand_format(&output,
                      opt->format ? opt->format : DEFAULT_FORMAT,
-                     expand_format,
                      &data);
        data.mark_query = 0;
        strbuf_release(&output);
@@ -805,7 +799,7 @@ static int batch_objects(struct batch_options *opt)
                if (repo_has_promisor_remote(the_repository))
                        warning("This repository uses promisor remotes. Some objects may not be loaded.");
 
-               read_replace_refs = 0;
+               disable_replace_refs();
 
                cb.opt = opt;
                cb.expand = &data;
@@ -851,16 +845,7 @@ static int batch_objects(struct batch_options *opt)
                goto cleanup;
        }
 
-       while (1) {
-               int ret;
-               if (opt->nul_terminated)
-                       ret = strbuf_getline_nul(&input, stdin);
-               else
-                       ret = strbuf_getline(&input, stdin);
-
-               if (ret == EOF)
-                       break;
-
+       while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
                if (data.split_on_whitespace) {
                        /*
                         * Split at first whitespace, tying off the beginning
@@ -885,12 +870,13 @@ static int batch_objects(struct batch_options *opt)
        return retval;
 }
 
-static int git_cat_file_config(const char *var, const char *value, void *cb)
+static int git_cat_file_config(const char *var, const char *value,
+                              const struct config_context *ctx, void *cb)
 {
        if (userdiff_config(var, value) < 0)
                return -1;
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static int batch_option_callback(const struct option *opt,
@@ -929,16 +915,18 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        const char *exp_type = NULL, *obj_name = NULL;
        struct batch_options batch = {0};
        int unknown_type = 0;
+       int input_nul_terminated = 0;
+       int nul_terminated = 0;
 
        const char * const usage[] = {
                N_("git cat-file <type> <object>"),
                N_("git cat-file (-e | -p) <object>"),
                N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
-               N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
-                  "             [--buffer] [--follow-symlinks] [--unordered]\n"
-                  "             [--textconv | --filters] [-z]"),
                N_("git cat-file (--textconv | --filters)\n"
                   "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
+               N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
+                  "             [--buffer] [--follow-symlinks] [--unordered]\n"
+                  "             [--textconv | --filters] [-Z]"),
                NULL
        };
        const struct option options[] = {
@@ -965,7 +953,9 @@ 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_BOOL_F('z', NULL, &input_nul_terminated, N_("stdin is NUL-terminated"),
+                       PARSE_OPT_HIDDEN),
+               OPT_BOOL('Z', NULL, &nul_terminated, N_("stdin and stdout is NUL-terminated")),
                OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
                        N_("read commands from stdin"),
                        PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
@@ -1024,9 +1014,18 @@ 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)
+       else if (input_nul_terminated)
                usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
                               "-z");
+       else if (nul_terminated)
+               usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+                              "-Z");
+
+       batch.input_delim = batch.output_delim = '\n';
+       if (input_nul_terminated)
+               batch.input_delim = '\0';
+       if (nul_terminated)
+               batch.input_delim = batch.output_delim = '\0';
 
        /* Batch defaults */
        if (batch.buffer_output < 0)
index e27b86d150588b15b1884d456aba2ac17bd3e2be..c1da1d184e9f6e24687f751bc67f88641f7083b0 100644 (file)
@@ -1,6 +1,5 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "attr.h"
 #include "environment.h"
@@ -123,6 +122,9 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, check_attr_options,
                             check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
 
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
+
        if (repo_read_index(the_repository) < 0) {
                die("invalid cache");
        }
index e4b78782a321920bab57404a63d35019a26c90ac..906cd967536c6f3a90c0a57cb4f3649e7b0da804 100644 (file)
@@ -1,6 +1,5 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
 #include "gettext.h"
index 002d2941e931034f9426c8e3dbda28310fc2776a..b8a05b8e07b523953dfe9e8d6e572346a27d7791 100644 (file)
@@ -4,6 +4,7 @@
 #include "ident.h"
 #include "mailmap.h"
 #include "parse-options.h"
+#include "strbuf.h"
 #include "string-list.h"
 #include "write-or-die.h"
 
index 57f0505070f6293460803ad670e491d98240c1ca..5eb6bdc3f691e8a71e07fc2be80ee94e3599f522 100644 (file)
@@ -2,9 +2,8 @@
  * GIT - The information manager from hell
  */
 
-#include "cache.h"
-#include "refs.h"
 #include "builtin.h"
+#include "refs.h"
 #include "setup.h"
 #include "strbuf.h"
 
index 2120dd1d300788b1833e0c1619652586f7366508..6b62b5375bd2bf0d998f74ba2c63c071a5e76e73 100644 (file)
@@ -1,11 +1,11 @@
 #include "builtin.h"
-#include "alloc.h"
 #include "config.h"
 #include "entry.h"
 #include "gettext.h"
 #include "parallel-checkout.h"
 #include "parse-options.h"
 #include "pkt-line.h"
+#include "read-cache-ll.h"
 
 static void packet_to_pc_item(const char *buffer, int len,
                              struct parallel_checkout_item *pc_item)
index 9375a05539f3613efc354abf007d63cdce09ecd8..3b68b47615302473cf3e2c5c70f9ebf1c707c3af 100644 (file)
 #include "parse-options.h"
 #include "entry.h"
 #include "parallel-checkout.h"
+#include "read-cache-ll.h"
 #include "setup.h"
+#include "sparse-index.h"
 
 #define CHECKOUT_ALL 4
 static int nul_term_line;
 static int checkout_stage; /* default to checkout stage0 */
 static int ignore_skip_worktree; /* default to 0 */
-static int to_tempfile;
+static int to_tempfile = -1;
 static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
 
 static struct checkout state = CHECKOUT_INIT;
@@ -191,15 +193,16 @@ static const char * const builtin_checkout_index_usage[] = {
 static int option_parse_stage(const struct option *opt,
                              const char *arg, int unset)
 {
+       int *stage = opt->value;
+
        BUG_ON_OPT_NEG(unset);
 
        if (!strcmp(arg, "all")) {
-               to_tempfile = 1;
-               checkout_stage = CHECKOUT_ALL;
+               *stage = CHECKOUT_ALL;
        } else {
                int ch = arg[0];
                if ('1' <= ch && ch <= '3')
-                       checkout_stage = arg[0] - '0';
+                       *stage = arg[0] - '0';
                else
                        die(_("stage should be between 1 and 3 or all"));
        }
@@ -237,7 +240,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                        N_("write the content to temporary files")),
                OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
                        N_("when creating files, prepend <string>")),
-               OPT_CALLBACK_F(0, "stage", NULL, "(1|2|3|all)",
+               OPT_CALLBACK_F(0, "stage", &checkout_stage, "(1|2|3|all)",
                        N_("copy out the files from named stage"),
                        PARSE_OPT_NONEG, option_parse_stage),
                OPT_END()
@@ -267,6 +270,12 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                state.base_dir = "";
        state.base_dir_len = strlen(state.base_dir);
 
+       if (to_tempfile < 0)
+               to_tempfile = (checkout_stage == CHECKOUT_ALL);
+       if (!to_tempfile && checkout_stage == CHECKOUT_ALL)
+               die(_("options '%s' and '%s' cannot be used together"),
+                   "--stage=all", "--no-temp");
+
        /*
         * when --prefix is specified we do not want to update cache.
         */
index 715eeb5048f99a1b27cd859596b03bc4f073081a..f02434bc155ba1769a248350afa686322e6110bb 100644 (file)
 #include "gettext.h"
 #include "hex.h"
 #include "hook.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "lockfile.h"
 #include "mem-pool.h"
 #include "merge-recursive.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
 #include "refs.h"
 #include "remote.h"
 #include "resolve-undo.h"
@@ -520,6 +523,15 @@ static int checkout_paths(const struct checkout_opts *opts,
                            "--merge", "--conflict", "--staged");
        }
 
+       /*
+        * recreating unmerged index entries and writing out data from
+        * unmerged index entries would make no sense when checking out
+        * of a tree-ish.
+        */
+       if ((opts->merge || opts->writeout_stage) && opts->source_tree)
+               die(_("'%s', '%s', or '%s' cannot be used when checking out of a tree"),
+                   "--merge", "--ours", "--theirs");
+
        if (opts->patch_mode) {
                enum add_p_mode patch_mode;
                const char *rev = new_branch_info->name;
@@ -557,6 +569,8 @@ static int checkout_paths(const struct checkout_opts *opts,
 
        if (opts->source_tree)
                read_tree_some(opts->source_tree, &opts->pathspec);
+       if (opts->merge)
+               unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
 
        ps_matched = xcalloc(opts->pathspec.nr, 1);
 
@@ -580,10 +594,6 @@ static int checkout_paths(const struct checkout_opts *opts,
        }
        free(ps_matched);
 
-       /* "checkout -m path" to recreate conflicted state */
-       if (opts->merge)
-               unmerge_marked_index(&the_index);
-
        /* Any unmerged paths? */
        for (pos = 0; pos < the_index.cache_nr; pos++) {
                const struct cache_entry *ce = the_index.cache[pos];
@@ -861,7 +871,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                         * entries in the index.
                         */
 
-                       add_files_to_cache(NULL, NULL, 0);
+                       add_files_to_cache(the_repository, NULL, NULL, 0, 0);
                        init_merge_options(&o, the_repository);
                        o.verbosity = 0;
                        work = write_in_core_index_as_tree(the_repository);
@@ -913,7 +923,7 @@ static void report_tracking(struct branch_info *new_branch_info)
        struct strbuf sb = STRBUF_INIT;
        struct branch *branch = branch_get(new_branch_info->name);
 
-       if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL))
+       if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL, 1))
                return;
        fputs(sb.buf, stdout);
        strbuf_release(&sb);
@@ -1186,7 +1196,8 @@ static int switch_branches(const struct checkout_opts *opts,
        return ret || writeout_error;
 }
 
-static int git_checkout_config(const char *var, const char *value, void *cb)
+static int git_checkout_config(const char *var, const char *value,
+                              const struct config_context *ctx, void *cb)
 {
        struct checkout_opts *opts = cb;
 
@@ -1202,7 +1213,7 @@ static int git_checkout_config(const char *var, const char *value, void *cb)
        if (starts_with(var, "submodule."))
                return git_default_submodule_config(var, value, NULL);
 
-       return git_xmerge_config(var, value, NULL);
+       return git_xmerge_config(var, value, ctx, NULL);
 }
 
 static void setup_new_branch_info_and_source_tree(
@@ -1689,8 +1700,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
        }
 
        if (opts->conflict_style) {
+               struct key_value_info kvi = KVI_INIT;
+               struct config_context ctx = {
+                       .kvi = &kvi,
+               };
                opts->merge = 1; /* implied */
-               git_xmerge_config("merge.conflictstyle", opts->conflict_style, NULL);
+               git_xmerge_config("merge.conflictstyle", opts->conflict_style,
+                                 &ctx, NULL);
        }
        if (opts->force) {
                opts->discard_changes = 1;
index 78852d28cecb579e824cec08aa56633f411bdcac..49c224e626d61819a633252572d3e7f3b32ffd62 100644 (file)
@@ -9,11 +9,12 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
 #include "gettext.h"
 #include "parse-options.h"
+#include "path.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 #include "string-list.h"
@@ -103,7 +104,8 @@ struct menu_stuff {
 
 define_list_config_array(color_interactive_slots);
 
-static int git_clean_config(const char *var, const char *value, void *cb)
+static int git_clean_config(const char *var, const char *value,
+                           const struct config_context *ctx, void *cb)
 {
        const char *slot_name;
 
@@ -130,8 +132,10 @@ static int git_clean_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       /* inspect the color.ui config variable and others */
-       return git_color_default_config(var, value, cb);
+       if (git_color_config(var, value, cb) < 0)
+               return -1;
+
+       return git_default_config(var, value, ctx, cb);
 }
 
 static const char *clean_get_color(enum color_clean ix)
index 15f9912b4cae0583ac62d387120fcaa24a58ff23..c6357af949895a688639c83984598931906b2690 100644 (file)
@@ -23,7 +23,7 @@
 #include "refs.h"
 #include "refspec.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
 #include "setup.h"
 #include "connected.h"
 #include "packfile.h"
+#include "path.h"
 #include "pkt-line.h"
 #include "list-objects-filter-options.h"
 #include "hook.h"
 #include "bundle.h"
 #include "bundle-uri.h"
-#include "wrapper.h"
 
 /*
  * Overall FIXMEs:
@@ -161,10 +161,7 @@ static struct option builtin_clone_options[] = {
                        N_("set config inside the new repository")),
        OPT_STRING_LIST(0, "server-option", &server_options,
                        N_("server-specific"), N_("option to transmit")),
-       OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
-                       TRANSPORT_FAMILY_IPV4),
-       OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
-                       TRANSPORT_FAMILY_IPV6),
+       OPT_IPVERSION(&family),
        OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
        OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
                    N_("apply partial clone filters to submodules")),
@@ -790,7 +787,8 @@ static int checkout(int submodule_progress, int filter_submodules)
        return err;
 }
 
-static int git_clone_config(const char *k, const char *v, void *cb)
+static int git_clone_config(const char *k, const char *v,
+                           const struct config_context *ctx, void *cb)
 {
        if (!strcmp(k, "clone.defaultremotename")) {
                free(remote_name);
@@ -801,17 +799,19 @@ static int git_clone_config(const char *k, const char *v, void *cb)
        if (!strcmp(k, "clone.filtersubmodules"))
                config_filter_submodules = git_config_bool(k, v);
 
-       return git_default_config(k, v, cb);
+       return git_default_config(k, v, ctx, cb);
 }
 
-static int write_one_config(const char *key, const char *value, void *data)
+static int write_one_config(const char *key, const char *value,
+                           const struct config_context *ctx,
+                           void *data)
 {
        /*
         * give git_clone_config a chance to write config values back to the
         * environment, since git_config_set_multivar_gently only deals with
         * config-file writes
         */
-       int apply_failed = git_clone_config(key, value, data);
+       int apply_failed = git_clone_config(key, value, ctx, data);
        if (apply_failed)
                return apply_failed;
 
@@ -930,6 +930,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        int submodule_progress;
        int filter_submodules = 0;
        int hash_algo;
+       const int do_not_override_repo_unix_permissions = -1;
 
        struct transport_ls_refs_options transport_ls_refs_options =
                TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -1097,7 +1098,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
 
        init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
-               INIT_DB_QUIET);
+               do_not_override_repo_unix_permissions, INIT_DB_QUIET);
 
        if (real_git_dir) {
                free((char *)git_dir);
index de623a16c2d2f5bd4e206f9c84721be1b454281b..a83be8bc991a8c9dfca5b64f886d33f952890236 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "gettext.h"
 #include "strbuf.h"
@@ -13,7 +12,8 @@ static const char * const builtin_column_usage[] = {
 };
 static unsigned int colopts;
 
-static int column_config(const char *var, const char *value, void *cb)
+static int column_config(const char *var, const char *value,
+                        const struct config_context *ctx UNUSED, void *cb)
 {
        return git_column_config(var, value, cb, &colopts);
 }
index a3d00fa232b51a0ed6581a2638ca65bf50db3023..45d035af6007a2a64833015dbe58300493a55f80 100644 (file)
@@ -1,4 +1,5 @@
 #include "builtin.h"
+#include "commit.h"
 #include "config.h"
 #include "dir.h"
 #include "environment.h"
@@ -8,7 +9,7 @@
 #include "parse-options.h"
 #include "repository.h"
 #include "commit-graph.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "progress.h"
 #include "replace-object.h"
 #include "tag.h"
@@ -68,10 +69,12 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
        struct commit_graph *graph = NULL;
        struct object_directory *odb = NULL;
        char *graph_name;
-       int open_ok;
+       char *chain_name;
+       enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
        int fd;
        struct stat st;
        int flags = 0;
+       int incomplete_chain = 0;
        int ret;
 
        static struct option builtin_commit_graph_verify_options[] = {
@@ -101,24 +104,39 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
 
        odb = find_odb(the_repository, opts.obj_dir);
        graph_name = get_commit_graph_filename(odb);
-       open_ok = open_commit_graph(graph_name, &fd, &st);
-       if (!open_ok && errno != ENOENT)
+       chain_name = get_commit_graph_chain_filename(odb);
+       if (open_commit_graph(graph_name, &fd, &st))
+               opened = OPENED_GRAPH;
+       else if (errno != ENOENT)
                die_errno(_("Could not open commit-graph '%s'"), graph_name);
+       else if (open_commit_graph_chain(chain_name, &fd, &st))
+               opened = OPENED_CHAIN;
+       else if (errno != ENOENT)
+               die_errno(_("could not open commit-graph chain '%s'"), chain_name);
 
        FREE_AND_NULL(graph_name);
+       FREE_AND_NULL(chain_name);
        FREE_AND_NULL(options);
 
-       if (open_ok)
+       if (opened == OPENED_NONE)
+               return 0;
+       else if (opened == OPENED_GRAPH)
                graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
        else
-               graph = read_commit_graph_one(the_repository, odb);
+               graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
+                                                     &incomplete_chain);
 
-       /* Return failure if open_ok predicted success */
        if (!graph)
-               return !!open_ok;
+               return 1;
 
        ret = verify_commit_graph(the_repository, graph, flags);
        free_commit_graph(graph);
+
+       if (incomplete_chain) {
+               error("one or more commit-graph chain files could not be loaded");
+               ret |= 1;
+       }
+
        return ret;
 }
 
@@ -186,10 +204,11 @@ static int write_option_max_new_filters(const struct option *opt,
 }
 
 static int git_commit_graph_write_config(const char *var, const char *value,
+                                        const struct config_context *ctx,
                                         void *cb UNUSED)
 {
        if (!strcmp(var, "commitgraph.maxnewfilters"))
-               write_opts.max_new_filters = git_config_int(var, value);
+               write_opts.max_new_filters = git_config_int(var, value, ctx->kvi);
        /*
         * No need to fall-back to 'git_default_config', since this was already
         * called in 'cmd_commit_graph()'.
@@ -309,6 +328,7 @@ cleanup:
        FREE_AND_NULL(options);
        string_list_clear(&pack_indexes, 0);
        strbuf_release(&buf);
+       oidset_clear(&commits);
        return result;
 }
 
@@ -324,7 +344,7 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
 
        git_config(git_default_config, NULL);
 
-       read_replace_refs = 0;
+       disable_replace_refs();
        save_commit_buffer = 0;
 
        argc = parse_options(argc, argv, prefix, options,
index d1d251c3ded2798ecb6667034bb7e21477be847d..02625e71761dbf8d25f063b5ff4835e5eb4bf477 100644 (file)
@@ -3,16 +3,15 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "commit.h"
 #include "tree.h"
-#include "builtin.h"
 #include "utf8.h"
 #include "gpg-interface.h"
 #include "parse-options.h"
index e67c4be2211eed8f6c8d61f510adc2fc87d9b007..781af2e206c1060213f16dd7cacb5ca68884f6b8 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "advice.h"
 #include "config.h"
 #include "lockfile.h"
@@ -15,7 +15,6 @@
 #include "dir.h"
 #include "editor.h"
 #include "environment.h"
-#include "builtin.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "commit.h"
@@ -30,6 +29,9 @@
 #include "utf8.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
 #include "string-list.h"
 #include "rerere.h"
 #include "unpack-trees.h"
@@ -38,6 +40,7 @@
 #include "gpg-interface.h"
 #include "column.h"
 #include "sequencer.h"
+#include "sparse-index.h"
 #include "mailmap.h"
 #include "help.h"
 #include "commit-reach.h"
@@ -447,11 +450,12 @@ static const char *prepare_index(const char **argv, const char *prefix,
        if (all || (also && pathspec.nr)) {
                repo_hold_locked_index(the_repository, &index_lock,
                                       LOCK_DIE_ON_ERROR);
-               add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
+               add_files_to_cache(the_repository, also ? prefix : NULL,
+                                  &pathspec, 0, 0);
                refresh_cache_or_die(refresh_flags);
                cache_tree_update(&the_index, WRITE_TREE_SILENT);
                if (write_locked_index(&the_index, &index_lock, 0))
-                       die(_("unable to write new_index file"));
+                       die(_("unable to write new index file"));
                commit_style = COMMIT_NORMAL;
                ret = get_lock_file_path(&index_lock);
                goto out;
@@ -475,7 +479,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
                        cache_tree_update(&the_index, WRITE_TREE_SILENT);
                if (write_locked_index(&the_index, &index_lock,
                                       COMMIT_LOCK | SKIP_IF_UNCHANGED))
-                       die(_("unable to write new_index file"));
+                       die(_("unable to write new index file"));
                commit_style = COMMIT_AS_IS;
                ret = get_index_file();
                goto out;
@@ -523,7 +527,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
        refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
        cache_tree_update(&the_index, WRITE_TREE_SILENT);
        if (write_locked_index(&the_index, &index_lock, 0))
-               die(_("unable to write new_index file"));
+               die(_("unable to write new index file"));
 
        hold_lock_file_for_update(&false_lock,
                                  git_path("next-index-%"PRIuMAX,
@@ -763,7 +767,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                        struct commit *c;
                        c = lookup_commit_reference_by_name(squash_message);
                        if (!c)
-                               die(_("could not lookup commit %s"), squash_message);
+                               die(_("could not lookup commit '%s'"), squash_message);
                        ctx.output_encoding = get_commit_output_encoding();
                        repo_format_commit_message(the_repository, c,
                                                   "squash! %s\n\n", &sb,
@@ -798,7 +802,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                char *fmt;
                commit = lookup_commit_reference_by_name(fixup_commit);
                if (!commit)
-                       die(_("could not lookup commit %s"), fixup_commit);
+                       die(_("could not lookup commit '%s'"), fixup_commit);
                ctx.output_encoding = get_commit_output_encoding();
                fmt = xstrfmt("%s! %%s\n\n", fixup_prefix);
                repo_format_commit_message(the_repository, commit, fmt, &sb,
@@ -893,7 +897,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        s->hints = 0;
 
        if (clean_message_contents)
-               strbuf_stripspace(&sb, 0);
+               strbuf_stripspace(&sb, '\0');
 
        if (signoff)
                append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
@@ -998,11 +1002,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                struct object_id oid;
                const char *parent = "HEAD";
 
-               if (!the_index.cache_nr) {
-                       discard_index(&the_index);
-                       if (repo_read_index(the_repository) < 0)
-                               die(_("Cannot read index"));
-               }
+               if (!the_index.initialized && repo_read_index(the_repository) < 0)
+                       die(_("Cannot read index"));
 
                if (amend)
                        parent = "HEAD^1";
@@ -1043,7 +1044,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                struct child_process run_trailer = CHILD_PROCESS_INIT;
 
                strvec_pushl(&run_trailer.args, "interpret-trailers",
-                            "--in-place", git_path_commit_editmsg(), NULL);
+                            "--in-place", "--no-divider",
+                            git_path_commit_editmsg(), NULL);
                strvec_pushv(&run_trailer.args, trailer_args.v);
                run_trailer.git_cmd = 1;
                if (run_command(&run_trailer))
@@ -1189,7 +1191,7 @@ static const char *read_commit_message(const char *name)
 
        commit = lookup_commit_reference_by_name(name);
        if (!commit)
-               die(_("could not lookup commit %s"), name);
+               die(_("could not lookup commit '%s'"), name);
        out_enc = get_commit_output_encoding();
        return repo_logmsg_reencode(the_repository, commit, NULL, out_enc);
 }
@@ -1405,7 +1407,8 @@ static int parse_status_slot(const char *slot)
        return LOOKUP_CONFIG(color_status_slots, slot);
 }
 
-static int git_status_config(const char *k, const char *v, void *cb)
+static int git_status_config(const char *k, const char *v,
+                            const struct config_context *ctx, void *cb)
 {
        struct wt_status *s = cb;
        const char *slot_name;
@@ -1414,7 +1417,8 @@ static int git_status_config(const char *k, const char *v, void *cb)
                return git_column_config(k, v, "status", &s->colopts);
        if (!strcmp(k, "status.submodulesummary")) {
                int is_bool;
-               s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
+               s->submodule_summary = git_config_bool_or_int(k, v, ctx->kvi,
+                                                             &is_bool);
                if (is_bool && s->submodule_summary)
                        s->submodule_summary = -1;
                return 0;
@@ -1474,11 +1478,11 @@ static int git_status_config(const char *k, const char *v, void *cb)
        }
        if (!strcmp(k, "diff.renamelimit")) {
                if (s->rename_limit == -1)
-                       s->rename_limit = git_config_int(k, v);
+                       s->rename_limit = git_config_int(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "status.renamelimit")) {
-               s->rename_limit = git_config_int(k, v);
+               s->rename_limit = git_config_int(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "diff.renames")) {
@@ -1490,7 +1494,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
                s->detect_rename = git_config_rename(k, v);
                return 0;
        }
-       return git_diff_ui_config(k, v, NULL);
+       return git_diff_ui_config(k, v, ctx, NULL);
 }
 
 int cmd_status(int argc, const char **argv, const char *prefix)
@@ -1605,7 +1609,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
-static int git_commit_config(const char *k, const char *v, void *cb)
+static int git_commit_config(const char *k, const char *v,
+                            const struct config_context *ctx, void *cb)
 {
        struct wt_status *s = cb;
 
@@ -1623,11 +1628,12 @@ static int git_commit_config(const char *k, const char *v, void *cb)
        }
        if (!strcmp(k, "commit.verbose")) {
                int is_bool;
-               config_commit_verbose = git_config_bool_or_int(k, v, &is_bool);
+               config_commit_verbose = git_config_bool_or_int(k, v, ctx->kvi,
+                                                              &is_bool);
                return 0;
        }
 
-       return git_status_config(k, v, s);
+       return git_status_config(k, v, ctx, s);
 }
 
 int cmd_commit(int argc, const char **argv, const char *prefix)
@@ -1856,7 +1862,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        if (commit_index_files())
                die(_("repository has been updated, but unable to write\n"
-                     "new_index file. Check that disk is not full and quota is\n"
+                     "new index file. Check that disk is not full and quota is\n"
                      "not exceeded, and then \"git restore --staged :/\" to recover."));
 
        git_test_write_commit_graph_or_die();
index ff2fe8ef1257f71dd1ae777cb75b8ea308fae97a..11a4d4ef1411222f3750c760b68efd10180148c0 100644 (file)
@@ -1,10 +1,10 @@
 #include "builtin.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "color.h"
 #include "editor.h"
 #include "environment.h"
+#include "repository.h"
 #include "gettext.h"
 #include "ident.h"
 #include "parse-options.h"
@@ -12,8 +12,8 @@
 #include "path.h"
 #include "quote.h"
 #include "setup.h"
+#include "strbuf.h"
 #include "worktree.h"
-#include "wrapper.h"
 
 static const char *const builtin_config_usage[] = {
        N_("git config [<options>]"),
@@ -193,37 +193,42 @@ static void check_argc(int argc, int min, int max)
        usage_builtin_config();
 }
 
-static void show_config_origin(struct strbuf *buf)
+static void show_config_origin(const struct key_value_info *kvi,
+                              struct strbuf *buf)
 {
        const char term = end_nul ? '\0' : '\t';
 
-       strbuf_addstr(buf, current_config_origin_type());
+       strbuf_addstr(buf, config_origin_type_name(kvi->origin_type));
        strbuf_addch(buf, ':');
        if (end_nul)
-               strbuf_addstr(buf, current_config_name());
+               strbuf_addstr(buf, kvi->filename ? kvi->filename : "");
        else
-               quote_c_style(current_config_name(), buf, NULL, 0);
+               quote_c_style(kvi->filename ? kvi->filename : "", buf, NULL, 0);
        strbuf_addch(buf, term);
 }
 
-static void show_config_scope(struct strbuf *buf)
+static void show_config_scope(const struct key_value_info *kvi,
+                             struct strbuf *buf)
 {
        const char term = end_nul ? '\0' : '\t';
-       const char *scope = config_scope_name(current_config_scope());
+       const char *scope = config_scope_name(kvi->scope);
 
        strbuf_addstr(buf, N_(scope));
        strbuf_addch(buf, term);
 }
 
 static int show_all_config(const char *key_, const char *value_,
+                          const struct config_context *ctx,
                           void *cb UNUSED)
 {
+       const struct key_value_info *kvi = ctx->kvi;
+
        if (show_origin || show_scope) {
                struct strbuf buf = STRBUF_INIT;
                if (show_scope)
-                       show_config_scope(&buf);
+                       show_config_scope(kvi, &buf);
                if (show_origin)
-                       show_config_origin(&buf);
+                       show_config_origin(kvi, &buf);
                /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
                fwrite(buf.buf, 1, buf.len, stdout);
                strbuf_release(&buf);
@@ -241,12 +246,13 @@ struct strbuf_list {
        int alloc;
 };
 
-static int format_config(struct strbuf *buf, const char *key_, const char *value_)
+static int format_config(struct strbuf *buf, const char *key_,
+                        const char *value_, const struct key_value_info *kvi)
 {
        if (show_scope)
-               show_config_scope(buf);
+               show_config_scope(kvi, buf);
        if (show_origin)
-               show_config_origin(buf);
+               show_config_origin(kvi, buf);
        if (show_keys)
                strbuf_addstr(buf, key_);
        if (!omit_values) {
@@ -255,13 +261,14 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
 
                if (type == TYPE_INT)
                        strbuf_addf(buf, "%"PRId64,
-                                   git_config_int64(key_, value_ ? value_ : ""));
+                                   git_config_int64(key_, value_ ? value_ : "", kvi));
                else if (type == TYPE_BOOL)
                        strbuf_addstr(buf, git_config_bool(key_, value_) ?
                                      "true" : "false");
                else if (type == TYPE_BOOL_OR_INT) {
                        int is_bool, v;
-                       v = git_config_bool_or_int(key_, value_, &is_bool);
+                       v = git_config_bool_or_int(key_, value_, kvi,
+                                                  &is_bool);
                        if (is_bool)
                                strbuf_addstr(buf, v ? "true" : "false");
                        else
@@ -300,9 +307,11 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
        return 0;
 }
 
-static int collect_config(const char *key_, const char *value_, void *cb)
+static int collect_config(const char *key_, const char *value_,
+                         const struct config_context *ctx, void *cb)
 {
        struct strbuf_list *values = cb;
+       const struct key_value_info *kvi = ctx->kvi;
 
        if (!use_key_regexp && strcmp(key_, key))
                return 0;
@@ -317,7 +326,7 @@ static int collect_config(const char *key_, const char *value_, void *cb)
        ALLOC_GROW(values->items, values->nr + 1, values->alloc);
        strbuf_init(&values->items[values->nr], 0);
 
-       return format_config(&values->items[values->nr++], key_, value_);
+       return format_config(&values->items[values->nr++], key_, value_, kvi);
 }
 
 static int get_value(const char *key_, const char *regex_, unsigned flags)
@@ -375,14 +384,18 @@ static int get_value(const char *key_, const char *regex_, unsigned flags)
        }
 
        config_with_options(collect_config, &values,
-                           &given_config_source, &config_options);
+                           &given_config_source, the_repository,
+                           &config_options);
 
        if (!values.nr && default_value) {
+               struct key_value_info kvi = KVI_INIT;
                struct strbuf *item;
+
+               kvi_from_param(&kvi);
                ALLOC_GROW(values.items, values.nr + 1, values.alloc);
                item = &values.items[values.nr++];
                strbuf_init(item, 0);
-               if (format_config(item, key_, default_value) < 0)
+               if (format_config(item, key_, default_value, &kvi) < 0)
                        die(_("failed to format default config value: %s"),
                                default_value);
        }
@@ -411,7 +424,8 @@ free_strings:
        return ret;
 }
 
-static char *normalize_value(const char *key, const char *value)
+static char *normalize_value(const char *key, const char *value,
+                            struct key_value_info *kvi)
 {
        if (!value)
                return NULL;
@@ -426,12 +440,12 @@ static char *normalize_value(const char *key, const char *value)
                 */
                return xstrdup(value);
        if (type == TYPE_INT)
-               return xstrfmt("%"PRId64, git_config_int64(key, value));
+               return xstrfmt("%"PRId64, git_config_int64(key, value, kvi));
        if (type == TYPE_BOOL)
                return xstrdup(git_config_bool(key, value) ?  "true" : "false");
        if (type == TYPE_BOOL_OR_INT) {
                int is_bool, v;
-               v = git_config_bool_or_int(key, value, &is_bool);
+               v = git_config_bool_or_int(key, value, kvi, &is_bool);
                if (!is_bool)
                        return xstrfmt("%d", v);
                else
@@ -468,6 +482,7 @@ static const char *get_colorbool_slot;
 static char parsed_color[COLOR_MAXLEN];
 
 static int git_get_color_config(const char *var, const char *value,
+                               const struct config_context *ctx UNUSED,
                                void *cb UNUSED)
 {
        if (!strcmp(var, get_color_slot)) {
@@ -486,7 +501,8 @@ static void get_color(const char *var, const char *def_color)
        get_color_found = 0;
        parsed_color[0] = '\0';
        config_with_options(git_get_color_config, NULL,
-                           &given_config_source, &config_options);
+                           &given_config_source, the_repository,
+                           &config_options);
 
        if (!get_color_found && def_color) {
                if (color_parse(def_color, parsed_color) < 0)
@@ -500,6 +516,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,
+                                   const struct config_context *ctx UNUSED,
                                    void *data UNUSED)
 {
        if (!strcmp(var, get_colorbool_slot))
@@ -518,7 +535,8 @@ static int get_colorbool(const char *var, int print)
        get_diff_color_found = -1;
        get_color_ui_found = -1;
        config_with_options(git_get_colorbool_config, NULL,
-                           &given_config_source, &config_options);
+                           &given_config_source, the_repository,
+                           &config_options);
 
        if (get_colorbool_found < 0) {
                if (!strcmp(get_colorbool_slot, "color.diff"))
@@ -555,13 +573,17 @@ static void check_write(void)
 struct urlmatch_current_candidate_value {
        char value_is_null;
        struct strbuf value;
+       struct key_value_info kvi;
 };
 
-static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
+static int urlmatch_collect_fn(const char *var, const char *value,
+                              const struct config_context *ctx,
+                              void *cb)
 {
        struct string_list *values = cb;
        struct string_list_item *item = string_list_insert(values, var);
        struct urlmatch_current_candidate_value *matched = item->util;
+       const struct key_value_info *kvi = ctx->kvi;
 
        if (!matched) {
                matched = xmalloc(sizeof(*matched));
@@ -570,6 +592,7 @@ static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
        } else {
                strbuf_reset(&matched->value);
        }
+       matched->kvi = *kvi;
 
        if (value) {
                strbuf_addstr(&matched->value, value);
@@ -607,7 +630,8 @@ static int get_urlmatch(const char *var, const char *url)
        }
 
        config_with_options(urlmatch_config_entry, &config,
-                           &given_config_source, &config_options);
+                           &given_config_source, the_repository,
+                           &config_options);
 
        ret = !values.nr;
 
@@ -616,7 +640,8 @@ static int get_urlmatch(const char *var, const char *url)
                struct strbuf buf = STRBUF_INIT;
 
                format_config(&buf, item->string,
-                             matched->value_is_null ? NULL : matched->value.buf);
+                             matched->value_is_null ? NULL : matched->value.buf,
+                             &matched->kvi);
                fwrite(buf.buf, 1, buf.len, stdout);
                strbuf_release(&buf);
 
@@ -650,6 +675,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        char *value = NULL;
        int flags = 0;
        int ret = 0;
+       struct key_value_info default_kvi = KVI_INIT;
 
        given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
 
@@ -713,7 +739,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                given_config_source.scope = CONFIG_SCOPE_LOCAL;
        } else if (use_worktree_config) {
                struct worktree **worktrees = get_worktrees();
-               if (repository_format_worktree_config)
+               if (the_repository->repository_format_worktree_config)
                        given_config_source.file = git_pathdup("config.worktree");
                else if (worktrees[0] && worktrees[1])
                        die(_("--worktree cannot be used with multiple "
@@ -827,7 +853,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        if (actions == ACTION_LIST) {
                check_argc(argc, 0, 0);
                if (config_with_options(show_all_config, NULL,
-                                       &given_config_source,
+                                       &given_config_source, the_repository,
                                        &config_options) < 0) {
                        if (given_config_source.file)
                                die_errno(_("unable to read config file '%s'"),
@@ -867,7 +893,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        else if (actions == ACTION_SET) {
                check_write();
                check_argc(argc, 2, 2);
-               value = normalize_value(argv[0], argv[1]);
+               value = normalize_value(argv[0], argv[1], &default_kvi);
                ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
                if (ret == CONFIG_NOTHING_SET)
                        error(_("cannot overwrite multiple values with a single value\n"
@@ -876,7 +902,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        else if (actions == ACTION_SET_ALL) {
                check_write();
                check_argc(argc, 2, 3);
-               value = normalize_value(argv[0], argv[1]);
+               value = normalize_value(argv[0], argv[1], &default_kvi);
                ret = git_config_set_multivar_in_file_gently(given_config_source.file,
                                                             argv[0], value, argv[2],
                                                             flags);
@@ -884,7 +910,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        else if (actions == ACTION_ADD) {
                check_write();
                check_argc(argc, 2, 2);
-               value = normalize_value(argv[0], argv[1]);
+               value = normalize_value(argv[0], argv[1], &default_kvi);
                ret = git_config_set_multivar_in_file_gently(given_config_source.file,
                                                             argv[0], value,
                                                             CONFIG_REGEX_NONE,
@@ -893,7 +919,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        else if (actions == ACTION_REPLACE_ALL) {
                check_write();
                check_argc(argc, 2, 3);
-               value = normalize_value(argv[0], argv[1]);
+               value = normalize_value(argv[0], argv[1], &default_kvi);
                ret = git_config_set_multivar_in_file_gently(given_config_source.file,
                                                             argv[0], value, argv[2],
                                                             flags | CONFIG_FLAGS_MULTI_REPLACE);
index f3d8f1bcbb00902356d0bb5f0637b04672af7fe9..2d4bb5e8d0a8dfce1290760f7cd99dac7ba39a3e 100644 (file)
@@ -4,17 +4,17 @@
  * Copyright (c) 2006 Junio C Hamano
  */
 
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
+#include "path.h"
 #include "repository.h"
-#include "builtin.h"
 #include "parse-options.h"
 #include "quote.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 static unsigned long garbage;
 static off_t size_garbage;
@@ -82,7 +82,7 @@ static int count_cruft(const char *basename UNUSED, const char *path,
        return 0;
 }
 
-static int print_alternate(struct object_directory *odb, void *data)
+static int print_alternate(struct object_directory *odb, void *data UNUSED)
 {
        printf("alternate: ");
        quote_c_style(odb->path, NULL, stdout, 0);
index 756c5f02aef56ef4f6601729154c16dddc358810..3a6a750a8eb320bb3622184843ede3d2b9884385 100644 (file)
@@ -1,6 +1,5 @@
 #include "builtin.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "gettext.h"
 #include "object-file.h"
 #include "parse-options.h"
@@ -38,19 +37,22 @@ static struct credential_cache_entry *lookup_credential(const struct credential
        int i;
        for (i = 0; i < entries_nr; i++) {
                struct credential *e = &entries[i].item;
-               if (credential_match(c, e))
+               if (credential_match(c, e, 0))
                        return &entries[i];
        }
        return NULL;
 }
 
-static void remove_credential(const struct credential *c)
+static void remove_credential(const struct credential *c, int match_password)
 {
        struct credential_cache_entry *e;
 
-       e = lookup_credential(c);
-       if (e)
-               e->expiration = 0;
+       int i;
+       for (i = 0; i < entries_nr; i++) {
+               e = &entries[i];
+               if (credential_match(c, &e->item, match_password))
+                       e->expiration = 0;
+       }
 }
 
 static timestamp_t check_expirations(void)
@@ -151,14 +153,14 @@ static void serve_one_client(FILE *in, FILE *out)
                exit(0);
        }
        else if (!strcmp(action.buf, "erase"))
-               remove_credential(&c);
+               remove_credential(&c, 1);
        else if (!strcmp(action.buf, "store")) {
                if (timeout < 0)
                        warning("cache client didn't specify a timeout");
                else if (!c.username || !c.password)
                        warning("cache client gave us a partial credential");
                else {
-                       remove_credential(&c);
+                       remove_credential(&c, 0);
                        cache_credential(&c, timeout);
                }
        }
index 0ffacfdd83c94f31910980c45f206c5963965894..43b9d0e5b16ba5da555a3b16ce53b88dff5dbb4c 100644 (file)
@@ -2,7 +2,7 @@
 #include "gettext.h"
 #include "parse-options.h"
 #include "path.h"
-#include "wrapper.h"
+#include "strbuf.h"
 #include "write-or-die.h"
 
 #ifndef NO_UNIX_SOCKETS
index 30c6ccf56c05df3ae6e14497a5c6b719f933fecb..4a492411bbf3d2a7f0a34ada0bd127ae97cf5552 100644 (file)
@@ -13,7 +13,8 @@ static struct lock_file credential_lock;
 static int parse_credential_file(const char *fn,
                                  struct credential *c,
                                  void (*match_cb)(struct credential *),
-                                 void (*other_cb)(struct strbuf *))
+                                 void (*other_cb)(struct strbuf *),
+                                 int match_password)
 {
        FILE *fh;
        struct strbuf line = STRBUF_INIT;
@@ -30,7 +31,7 @@ static int parse_credential_file(const char *fn,
        while (strbuf_getline_lf(&line, fh) != EOF) {
                if (!credential_from_url_gently(&entry, line.buf, 1) &&
                    entry.username && entry.password &&
-                   credential_match(c, &entry)) {
+                   credential_match(c, &entry, match_password)) {
                        found_credential = 1;
                        if (match_cb) {
                                match_cb(&entry);
@@ -60,7 +61,7 @@ static void print_line(struct strbuf *buf)
 }
 
 static void rewrite_credential_file(const char *fn, struct credential *c,
-                                   struct strbuf *extra)
+                                   struct strbuf *extra, int match_password)
 {
        int timeout_ms = 1000;
 
@@ -69,11 +70,30 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
                die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms);
        if (extra)
                print_line(extra);
-       parse_credential_file(fn, c, NULL, print_line);
+       parse_credential_file(fn, c, NULL, print_line, match_password);
        if (commit_lock_file(&credential_lock) < 0)
                die_errno("unable to write credential store");
 }
 
+static int is_rfc3986_unreserved(char ch)
+{
+       return isalnum(ch) ||
+               ch == '-' || ch == '_' || ch == '.' || ch == '~';
+}
+
+static int is_rfc3986_reserved_or_unreserved(char ch)
+{
+       if (is_rfc3986_unreserved(ch))
+               return 1;
+       switch (ch) {
+               case '!': case '*': case '\'': case '(': case ')': case ';':
+               case ':': case '@': case '&': case '=': case '+': case '$':
+               case ',': case '/': case '?': case '#': case '[': case ']':
+                       return 1;
+       }
+       return 0;
+}
+
 static void store_credential_file(const char *fn, struct credential *c)
 {
        struct strbuf buf = STRBUF_INIT;
@@ -91,7 +111,7 @@ static void store_credential_file(const char *fn, struct credential *c)
                                        is_rfc3986_reserved_or_unreserved);
        }
 
-       rewrite_credential_file(fn, c, &buf);
+       rewrite_credential_file(fn, c, &buf, 0);
        strbuf_release(&buf);
 }
 
@@ -138,7 +158,7 @@ static void remove_credential(const struct string_list *fns, struct credential *
                return;
        for_each_string_list_item(fn, fns)
                if (!access(fn->string, F_OK))
-                       rewrite_credential_file(fn->string, c, NULL);
+                       rewrite_credential_file(fn->string, c, NULL, 1);
 }
 
 static void lookup_credential(const struct string_list *fns, struct credential *c)
@@ -146,7 +166,7 @@ static void lookup_credential(const struct string_list *fns, struct credential *
        struct string_list_item *fn;
 
        for_each_string_list_item(fn, fns)
-               if (parse_credential_file(fn->string, c, print_entry, NULL))
+               if (parse_credential_file(fn->string, c, print_entry, NULL, 0))
                        return; /* Found credential */
 }
 
index 55b4baaa223d9aa2ba32ee61539d39f28445a839..fb6b0508f3212db5d41bc33cfe76de441534ca7c 100644 (file)
@@ -1,5 +1,5 @@
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -9,21 +9,23 @@
 #include "tag.h"
 #include "blob.h"
 #include "refs.h"
-#include "builtin.h"
 #include "exec-cmd.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "read-cache-ll.h"
 #include "revision.h"
 #include "diff.h"
 #include "hashmap.h"
 #include "setup.h"
 #include "strvec.h"
 #include "run-command.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "list-objects.h"
 #include "commit-slab.h"
+#include "wildmatch.h"
 
 #define MAX_TAGS       (FLAG_BITS - 1)
+#define DEFAULT_CANDIDATES 10
 
 define_commit_slab(commit_names, struct commit_name *);
 
@@ -40,7 +42,7 @@ static int tags;      /* Allow lightweight tags */
 static int longformat;
 static int first_parent;
 static int abbrev = -1; /* unspecified */
-static int max_candidates = 10;
+static int max_candidates = DEFAULT_CANDIDATES;
 static struct hashmap names;
 static int have_util;
 static struct string_list patterns = STRING_LIST_INIT_NODUP;
@@ -556,6 +558,17 @@ static void describe(const char *arg, int last_one)
        strbuf_release(&sb);
 }
 
+static int option_parse_exact_match(const struct option *opt, const char *arg,
+                                   int unset)
+{
+       int *val = opt->value;
+
+       BUG_ON_OPT_ARG(arg);
+
+       *val = unset ? DEFAULT_CANDIDATES : 0;
+       return 0;
+}
+
 int cmd_describe(int argc, const char **argv, const char *prefix)
 {
        int contains = 0;
@@ -567,8 +580,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "long",       &longformat, N_("always use long format")),
                OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
                OPT__ABBREV(&abbrev),
-               OPT_SET_INT(0, "exact-match", &max_candidates,
-                           N_("only output exact matches"), 0),
+               OPT_CALLBACK_F(0, "exact-match", &max_candidates, NULL,
+                              N_("only output exact matches"),
+                              PARSE_OPT_NOARG, option_parse_exact_match),
                OPT_INTEGER(0, "candidates", &max_candidates,
                            N_("consider <n> most recent tags (default: 10)")),
                OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
@@ -656,7 +670,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        struct lock_file index_lock = LOCK_INIT;
                        struct rev_info revs;
                        struct strvec args = STRVEC_INIT;
-                       int fd, result;
+                       int fd;
 
                        setup_work_tree();
                        prepare_repo_settings(the_repository);
@@ -673,9 +687,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        strvec_pushv(&args, diff_index_args);
                        if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
                                BUG("malformed internal diff-index command line");
-                       result = run_diff_index(&revs, 0);
+                       run_diff_index(&revs, 0);
 
-                       if (!diff_result_code(&revs.diffopt, result))
+                       if (!diff_result_code(&revs.diffopt))
                                suffix = NULL;
                        else
                                suffix = dirty;
index 360464e6ef2dc4a2a613c4e8f8a59e2237a7d327..f38912cd407bf4e5098d84a928affd849f4123d8 100644 (file)
@@ -3,13 +3,14 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "diff.h"
 #include "diff-merges.h"
 #include "commit.h"
+#include "preload-index.h"
+#include "repository.h"
 #include "revision.h"
-#include "builtin.h"
 #include "submodule.h"
 
 static const char diff_files_usage[] =
@@ -79,14 +80,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
            (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
                diff_merges_set_dense_combined_if_unset(&rev);
 
-       if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
-               perror("repo_read_index_preload");
-               result = -1;
-               goto cleanup;
-       }
-       result = run_diff_files(&rev, options);
-       result = diff_result_code(&rev.diffopt, result);
-cleanup:
+       if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0)
+               die_errno("repo_read_index_preload");
+       run_diff_files(&rev, options);
+       result = diff_result_code(&rev.diffopt);
        release_revisions(&rev);
        return result;
 }
index b9a19bb7d38074a907369c74b9cd72c98ac208c7..220f341ffa2a138f70d6aa0d343594e6e60d2ebb 100644 (file)
@@ -1,11 +1,13 @@
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "diff.h"
 #include "diff-merges.h"
 #include "commit.h"
+#include "preload-index.h"
+#include "repository.h"
 #include "revision.h"
-#include "builtin.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule.h"
 
 static const char diff_cache_usage[] =
@@ -70,8 +72,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
                perror("repo_read_index");
                return -1;
        }
-       result = run_diff_index(&rev, option);
-       result = diff_result_code(&rev.diffopt, result);
+       run_diff_index(&rev, option);
+       result = diff_result_code(&rev.diffopt);
        release_revisions(&rev);
        return result;
 }
index 0b02c62b85e5b64b4371b3604f467a9aa2d5f512..86be6342861be40da9edbf2f1a2002fa4abc0cda 100644 (file)
@@ -1,14 +1,15 @@
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "diff.h"
 #include "commit.h"
 #include "gettext.h"
 #include "hex.h"
 #include "log-tree.h"
-#include "builtin.h"
 #include "submodule.h"
+#include "read-cache-ll.h"
 #include "repository.h"
+#include "revision.h"
 #include "tree.h"
 
 static struct rev_info log_tree_opt;
@@ -98,7 +99,7 @@ static const char diff_tree_usage[] =
 "  --root        include the initial commit as diff against /dev/null\n"
 COMMON_DIFF_OPTIONS_HELP;
 
-static void diff_tree_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt)
+static void diff_tree_tweak_rev(struct rev_info *rev)
 {
        if (!rev->diffopt.output_format) {
                if (rev->dense_combined_merges)
@@ -122,6 +123,10 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
                usage(diff_tree_usage);
 
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
+
        repo_init_revisions(the_repository, opt, prefix);
        if (repo_read_index(the_repository) < 0)
                die(_("index file corrupt"));
@@ -227,5 +232,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
                diff_free(&opt->diffopt);
        }
 
-       return diff_result_code(&opt->diffopt, 0);
+       return diff_result_code(&opt->diffopt);
 }
index 7b64659fe79301fcf5d6c34e12e09cc8b6089f1c..55e7d21755a09c9754d45fea8689cbcbd32939dd 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2006 Junio C Hamano
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "ewah/ewok.h"
 #include "lockfile.h"
 #include "diff.h"
 #include "diff-merges.h"
 #include "diffcore.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
 #include "revision.h"
 #include "log-tree.h"
-#include "builtin.h"
 #include "setup.h"
 #include "submodule.h"
 #include "oid-array.h"
@@ -76,9 +77,9 @@ static void stuff_change(struct diff_options *opt,
        diff_queue(&diff_queued_diff, one, two);
 }
 
-static int builtin_diff_b_f(struct rev_info *revs,
-                           int argc, const char **argv UNUSED,
-                           struct object_array_entry **blob)
+static void builtin_diff_b_f(struct rev_info *revs,
+                            int argc, const char **argv UNUSED,
+                            struct object_array_entry **blob)
 {
        /* Blob vs file in the working tree*/
        struct stat st;
@@ -108,12 +109,11 @@ static int builtin_diff_b_f(struct rev_info *revs,
                     path);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
-       return 0;
 }
 
-static int builtin_diff_blobs(struct rev_info *revs,
-                             int argc, const char **argv UNUSED,
-                             struct object_array_entry **blob)
+static void builtin_diff_blobs(struct rev_info *revs,
+                              int argc, const char **argv UNUSED,
+                              struct object_array_entry **blob)
 {
        const unsigned mode = canon_mode(S_IFREG | 0644);
 
@@ -133,11 +133,10 @@ static int builtin_diff_blobs(struct rev_info *revs,
                     blob_path(blob[0]), blob_path(blob[1]));
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
-       return 0;
 }
 
-static int builtin_diff_index(struct rev_info *revs,
-                             int argc, const char **argv)
+static void builtin_diff_index(struct rev_info *revs,
+                              int argc, const char **argv)
 {
        unsigned int option = 0;
        while (1 < argc) {
@@ -162,20 +161,18 @@ static int builtin_diff_index(struct rev_info *revs,
                setup_work_tree();
                if (repo_read_index_preload(the_repository,
                                            &revs->diffopt.pathspec, 0) < 0) {
-                       perror("repo_read_index_preload");
-                       return -1;
+                       die_errno("repo_read_index_preload");
                }
        } else if (repo_read_index(the_repository) < 0) {
-               perror("repo_read_cache");
-               return -1;
+               die_errno("repo_read_cache");
        }
-       return run_diff_index(revs, option);
+       run_diff_index(revs, option);
 }
 
-static int builtin_diff_tree(struct rev_info *revs,
-                            int argc, const char **argv,
-                            struct object_array_entry *ent0,
-                            struct object_array_entry *ent1)
+static void builtin_diff_tree(struct rev_info *revs,
+                             int argc, const char **argv,
+                             struct object_array_entry *ent0,
+                             struct object_array_entry *ent1)
 {
        const struct object_id *(oid[2]);
        struct object_id mb_oid;
@@ -208,13 +205,12 @@ static int builtin_diff_tree(struct rev_info *revs,
        }
        diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
        log_tree_diff_flush(revs);
-       return 0;
 }
 
-static int builtin_diff_combined(struct rev_info *revs,
-                                int argc, const char **argv UNUSED,
-                                struct object_array_entry *ent,
-                                int ents, int first_non_parent)
+static void builtin_diff_combined(struct rev_info *revs,
+                                 int argc, const char **argv UNUSED,
+                                 struct object_array_entry *ent,
+                                 int ents, int first_non_parent)
 {
        struct oid_array parents = OID_ARRAY_INIT;
        int i;
@@ -235,7 +231,6 @@ static int builtin_diff_combined(struct rev_info *revs,
        }
        diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
        oid_array_clear(&parents);
-       return 0;
 }
 
 static void refresh_index_quietly(void)
@@ -253,7 +248,7 @@ static void refresh_index_quietly(void)
        repo_update_index_if_able(the_repository, &lock_file);
 }
 
-static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+static void builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
 {
        unsigned int options = 0;
 
@@ -268,8 +263,10 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
                        options |= DIFF_SILENT_ON_REMOVED;
                else if (!strcmp(argv[1], "-h"))
                        usage(builtin_diff_usage);
-               else
-                       return error(_("invalid option: %s"), argv[1]);
+               else {
+                       error(_("invalid option: %s"), argv[1]);
+                       usage(builtin_diff_usage);
+               }
                argv++; argc--;
        }
 
@@ -286,10 +283,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
        setup_work_tree();
        if (repo_read_index_preload(the_repository, &revs->diffopt.pathspec,
                                    0) < 0) {
-               perror("repo_read_index_preload");
-               return -1;
+               die_errno("repo_read_index_preload");
        }
-       return run_diff_files(revs, options);
+       run_diff_files(revs, options);
 }
 
 struct symdiff {
@@ -403,7 +399,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        int blobs = 0, paths = 0;
        struct object_array_entry *blob[2];
        int nongit = 0, no_index = 0;
-       int result = 0;
+       int result;
        struct symdiff sdiff;
 
        /*
@@ -478,8 +474,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        repo_init_revisions(the_repository, &rev, prefix);
 
        /* Set up defaults that will apply to both no-index and regular diffs. */
-       rev.diffopt.stat_width = -1;
-       rev.diffopt.stat_graph_width = -1;
+       init_diffstat_widths(&rev.diffopt);
        rev.diffopt.flags.allow_external = 1;
        rev.diffopt.flags.allow_textconv = 1;
 
@@ -582,17 +577,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        if (!ent.nr) {
                switch (blobs) {
                case 0:
-                       result = builtin_diff_files(&rev, argc, argv);
+                       builtin_diff_files(&rev, argc, argv);
                        break;
                case 1:
                        if (paths != 1)
                                usage(builtin_diff_usage);
-                       result = builtin_diff_b_f(&rev, argc, argv, blob);
+                       builtin_diff_b_f(&rev, argc, argv, blob);
                        break;
                case 2:
                        if (paths)
                                usage(builtin_diff_usage);
-                       result = builtin_diff_blobs(&rev, argc, argv, blob);
+                       builtin_diff_blobs(&rev, argc, argv, blob);
                        break;
                default:
                        usage(builtin_diff_usage);
@@ -601,18 +596,18 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        else if (blobs)
                usage(builtin_diff_usage);
        else if (ent.nr == 1)
-               result = builtin_diff_index(&rev, argc, argv);
+               builtin_diff_index(&rev, argc, argv);
        else if (ent.nr == 2) {
                if (sdiff.warn)
                        warning(_("%s...%s: multiple merge bases, using %s"),
                                sdiff.left, sdiff.right, sdiff.base);
-               result = builtin_diff_tree(&rev, argc, argv,
-                                          &ent.objects[0], &ent.objects[1]);
+               builtin_diff_tree(&rev, argc, argv,
+                                 &ent.objects[0], &ent.objects[1]);
        } else
-               result = builtin_diff_combined(&rev, argc, argv,
-                                              ent.objects, ent.nr,
-                                              first_non_parent);
-       result = diff_result_code(&rev.diffopt, result);
+               builtin_diff_combined(&rev, argc, argv,
+                                     ent.objects, ent.nr,
+                                     first_non_parent);
+       result = diff_result_code(&rev.diffopt);
        if (1 < rev.diffopt.skip_stat_unmatch)
                refresh_index_quietly();
        release_revisions(&rev);
index 0049342f5c0daf79f6818ac6dea89a8ea7692d8a..0f5eae9cd41b3219b06964011089bb8d389975b4 100644 (file)
  * Copyright (C) 2016 Johannes Schindelin
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "abspath.h"
 #include "config.h"
 #include "copy.h"
-#include "builtin.h"
 #include "run-command.h"
 #include "environment.h"
 #include "exec-cmd.h"
 #include "gettext.h"
 #include "hex.h"
 #include "parse-options.h"
+#include "read-cache-ll.h"
+#include "sparse-index.h"
 #include "strvec.h"
 #include "strbuf.h"
 #include "lockfile.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "dir.h"
 #include "entry.h"
 #include "setup.h"
-#include "wrapper.h"
 
 static int trust_exit_code;
 
@@ -40,14 +40,15 @@ static const char *const builtin_difftool_usage[] = {
        NULL
 };
 
-static int difftool_config(const char *var, const char *value, void *cb)
+static int difftool_config(const char *var, const char *value,
+                          const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "difftool.trustexitcode")) {
                trust_exit_code = git_config_bool(var, value);
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static int print_tool_help(void)
index 9a95f6a1a82affafc02895cce56ed9a790c6666c..70aff515acbe97b20db80cc8b746e28f0149b56f 100644 (file)
@@ -4,14 +4,13 @@
  * Copyright (C) 2007 Johannes E. Schindelin
  */
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
 #include "refs.h"
 #include "refspec.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "object.h"
 #include "tag.h"
@@ -34,9 +33,9 @@ static const char *fast_export_usage[] = {
 };
 
 static int progress;
-static enum { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
-static enum { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
-static enum { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
+static enum signed_tag_mode { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
+static enum tag_of_filtered_mode { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
+static enum reencode_mode { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
 static int fake_missing_tagger;
 static int use_done_feature;
 static int no_data;
@@ -54,16 +53,18 @@ static struct revision_sources revision_sources;
 static int parse_opt_signed_tag_mode(const struct option *opt,
                                     const char *arg, int unset)
 {
+       enum signed_tag_mode *val = opt->value;
+
        if (unset || !strcmp(arg, "abort"))
-               signed_tag_mode = SIGNED_TAG_ABORT;
+               *val = SIGNED_TAG_ABORT;
        else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
-               signed_tag_mode = VERBATIM;
+               *val = VERBATIM;
        else if (!strcmp(arg, "warn"))
-               signed_tag_mode = WARN;
+               *val = WARN;
        else if (!strcmp(arg, "warn-strip"))
-               signed_tag_mode = WARN_STRIP;
+               *val = WARN_STRIP;
        else if (!strcmp(arg, "strip"))
-               signed_tag_mode = STRIP;
+               *val = STRIP;
        else
                return error("Unknown signed-tags mode: %s", arg);
        return 0;
@@ -72,12 +73,14 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
 static int parse_opt_tag_of_filtered_mode(const struct option *opt,
                                          const char *arg, int unset)
 {
+       enum tag_of_filtered_mode *val = opt->value;
+
        if (unset || !strcmp(arg, "abort"))
-               tag_of_filtered_mode = TAG_FILTERING_ABORT;
+               *val = TAG_FILTERING_ABORT;
        else if (!strcmp(arg, "drop"))
-               tag_of_filtered_mode = DROP;
+               *val = DROP;
        else if (!strcmp(arg, "rewrite"))
-               tag_of_filtered_mode = REWRITE;
+               *val = REWRITE;
        else
                return error("Unknown tag-of-filtered mode: %s", arg);
        return 0;
@@ -86,21 +89,23 @@ static int parse_opt_tag_of_filtered_mode(const struct option *opt,
 static int parse_opt_reencode_mode(const struct option *opt,
                                   const char *arg, int unset)
 {
+       enum reencode_mode *val = opt->value;
+
        if (unset) {
-               reencode_mode = REENCODE_ABORT;
+               *val = REENCODE_ABORT;
                return 0;
        }
 
        switch (git_parse_maybe_bool(arg)) {
        case 0:
-               reencode_mode = REENCODE_NO;
+               *val = REENCODE_NO;
                break;
        case 1:
-               reencode_mode = REENCODE_YES;
+               *val = REENCODE_YES;
                break;
        default:
                if (!strcasecmp(arg, "abort"))
-                       reencode_mode = REENCODE_ABORT;
+                       *val = REENCODE_ABORT;
                else
                        return error("Unknown reencoding mode: %s", arg);
        }
index bbd9b2b3e715db7e84011cc41542e2fe6dd4d4f0..444f41cf8ca8e6ba523f54169a3534d384094196 100644 (file)
@@ -1,6 +1,5 @@
 #include "builtin.h"
 #include "abspath.h"
-#include "cache.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
@@ -13,6 +12,7 @@
 #include "commit.h"
 #include "delta.h"
 #include "pack.h"
+#include "path.h"
 #include "refs.h"
 #include "csum-file.h"
 #include "quote.h"
 #include "packfile.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "mem-pool.h"
 #include "commit-reach.h"
 #include "khash.h"
 #include "date.h"
-#include "wrapper.h"
 
 #define PACK_ID_BITS 16
 #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@ -1103,6 +1102,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
                || (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
                cycle_packfile();
 
+       the_hash_algo->init_fn(&checkpoint.ctx);
        hashfile_checkpoint(pack_file, &checkpoint);
        offset = checkpoint.offset;
 
index 3ba0fe5a39614b3785f80ad75cd0f3a494547f37..44c05ee86cc7048e72e455f4c2a28a1d42a1f7fa 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "alloc.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object-file.h"
index 849a9be421d0487a32e78fe9d941cc42714c4886..fd134ba74d9086cfa44ba1c1b5a5a2597d182bee 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "git fetch"
  */
-#include "cache.h"
+#include "builtin.h"
 #include "advice.h"
 #include "config.h"
 #include "gettext.h"
 #include "refs.h"
 #include "refspec.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oidset.h"
 #include "oid-array.h"
 #include "commit.h"
-#include "builtin.h"
 #include "string-list.h"
 #include "remote.h"
 #include "transport.h"
@@ -29,6 +28,7 @@
 #include "utf8.h"
 #include "packfile.h"
 #include "pager.h"
+#include "path.h"
 #include "pkt-line.h"
 #include "list-objects-filter-options.h"
 #include "commit-reach.h"
@@ -58,7 +58,6 @@ enum {
 };
 
 enum display_format {
-       DISPLAY_FORMAT_UNKNOWN = 0,
        DISPLAY_FORMAT_FULL,
        DISPLAY_FORMAT_COMPACT,
        DISPLAY_FORMAT_PORCELAIN,
@@ -74,14 +73,11 @@ struct display_state {
        int url_len, shown_url;
 };
 
-static int fetch_prune_config = -1; /* unspecified */
-static int fetch_show_forced_updates = 1;
 static uint64_t forced_updates_ms = 0;
 static int prefetch = 0;
 static int prune = -1; /* unspecified */
 #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
 
-static int fetch_prune_tags_config = -1; /* unspecified */
 static int prune_tags = -1; /* unspecified */
 #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
 
@@ -90,8 +86,6 @@ static int write_fetch_head = 1;
 static int verbosity, deepen_relative, set_upstream, refetch;
 static int progress = -1;
 static int tags = TAGS_DEFAULT, update_shallow, deepen;
-static int submodule_fetch_jobs_config = -1;
-static int fetch_parallel_config = 1;
 static int atomic_fetch;
 static enum transport_family family;
 static const char *depth;
@@ -101,7 +95,6 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *gtransport;
 static struct transport *gsecondary;
-static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static struct refspec refmap = REFSPEC_INIT_FETCH;
 static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
 static struct string_list server_options = STRING_LIST_INIT_DUP;
@@ -109,47 +102,54 @@ static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
 
 struct fetch_config {
        enum display_format display_format;
+       int prune;
+       int prune_tags;
+       int show_forced_updates;
+       int recurse_submodules;
+       int parallel;
+       int submodule_fetch_jobs;
 };
 
-static int git_fetch_config(const char *k, const char *v, void *cb)
+static int git_fetch_config(const char *k, const char *v,
+                           const struct config_context *ctx, void *cb)
 {
        struct fetch_config *fetch_config = cb;
 
        if (!strcmp(k, "fetch.prune")) {
-               fetch_prune_config = git_config_bool(k, v);
+               fetch_config->prune = git_config_bool(k, v);
                return 0;
        }
 
        if (!strcmp(k, "fetch.prunetags")) {
-               fetch_prune_tags_config = git_config_bool(k, v);
+               fetch_config->prune_tags = git_config_bool(k, v);
                return 0;
        }
 
        if (!strcmp(k, "fetch.showforcedupdates")) {
-               fetch_show_forced_updates = git_config_bool(k, v);
+               fetch_config->show_forced_updates = git_config_bool(k, v);
                return 0;
        }
 
        if (!strcmp(k, "submodule.recurse")) {
                int r = git_config_bool(k, v) ?
                        RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
-               recurse_submodules = r;
+               fetch_config->recurse_submodules = r;
        }
 
        if (!strcmp(k, "submodule.fetchjobs")) {
-               submodule_fetch_jobs_config = parse_submodule_fetchjobs(k, v);
+               fetch_config->submodule_fetch_jobs = parse_submodule_fetchjobs(k, v, ctx->kvi);
                return 0;
        } else if (!strcmp(k, "fetch.recursesubmodules")) {
-               recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
+               fetch_config->recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
                return 0;
        }
 
        if (!strcmp(k, "fetch.parallel")) {
-               fetch_parallel_config = git_config_int(k, v);
-               if (fetch_parallel_config < 0)
+               fetch_config->parallel = git_config_int(k, v, ctx->kvi);
+               if (fetch_config->parallel < 0)
                        die(_("fetch.parallel cannot be negative"));
-               if (!fetch_parallel_config)
-                       fetch_parallel_config = online_cpus();
+               if (!fetch_config->parallel)
+                       fetch_config->parallel = online_cpus();
                return 0;
        }
 
@@ -165,7 +165,7 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
                            "fetch.output", v);
        }
 
-       return git_default_config(k, v, cb);
+       return git_default_config(k, v, ctx, cb);
 }
 
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
@@ -176,7 +176,7 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
         * "git fetch --refmap='' origin foo"
         * can be used to tell the command not to store anywhere
         */
-       refspec_append(&refmap, arg);
+       refspec_append(opt->value, arg);
 
        return 0;
 }
@@ -308,7 +308,7 @@ static void clear_item(struct refname_hash_entry *item)
 
 
 static void add_already_queued_tags(const char *refname,
-                                   const struct object_id *old_oid,
+                                   const struct object_id *old_oid UNUSED,
                                    const struct object_id *new_oid,
                                    void *cb_data)
 {
@@ -892,7 +892,8 @@ static int update_local_ref(struct ref *ref,
                            struct ref_transaction *transaction,
                            struct display_state *display_state,
                            const struct ref *remote_ref,
-                           int summary_width)
+                           int summary_width,
+                           const struct fetch_config *config)
 {
        struct commit *current = NULL, *updated;
        int fast_forward = 0;
@@ -954,11 +955,10 @@ static int update_local_ref(struct ref *ref,
                 * Base this on the remote's ref name, as it's
                 * more likely to follow a standard layout.
                 */
-               const char *name = remote_ref ? remote_ref->name : "";
-               if (starts_with(name, "refs/tags/")) {
+               if (starts_with(remote_ref->name, "refs/tags/")) {
                        msg = "storing tag";
                        what = _("[new tag]");
-               } else if (starts_with(name, "refs/heads/")) {
+               } else if (starts_with(remote_ref->name, "refs/heads/")) {
                        msg = "storing head";
                        what = _("[new branch]");
                } else {
@@ -974,7 +974,7 @@ static int update_local_ref(struct ref *ref,
                return r;
        }
 
-       if (fetch_show_forced_updates) {
+       if (config->show_forced_updates) {
                uint64_t t_before = getnanotime();
                fast_forward = repo_in_merge_bases(the_repository, current,
                                                   updated);
@@ -1127,7 +1127,8 @@ static int store_updated_refs(struct display_state *display_state,
                              const char *remote_name,
                              int connectivity_checked,
                              struct ref_transaction *transaction, struct ref *ref_map,
-                             struct fetch_head *fetch_head)
+                             struct fetch_head *fetch_head,
+                             const struct fetch_config *config)
 {
        int rc = 0;
        struct strbuf note = STRBUF_INIT;
@@ -1210,7 +1211,7 @@ static int store_updated_refs(struct display_state *display_state,
                                ref->force = rm->peer_ref->force;
                        }
 
-                       if (recurse_submodules != RECURSE_SUBMODULES_OFF &&
+                       if (config->recurse_submodules != RECURSE_SUBMODULES_OFF &&
                            (!rm->peer_ref || !oideq(&ref->old_oid, &ref->new_oid))) {
                                check_for_new_submodule_commits(&rm->old_oid);
                        }
@@ -1243,7 +1244,7 @@ static int store_updated_refs(struct display_state *display_state,
 
                        if (ref) {
                                rc |= update_local_ref(ref, transaction, display_state,
-                                                      rm, summary_width);
+                                                      rm, summary_width, config);
                                free(ref);
                        } else if (write_fetch_head || dry_run) {
                                /*
@@ -1267,7 +1268,7 @@ static int store_updated_refs(struct display_state *display_state,
                      "branches"), remote_name);
 
        if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) {
-               if (!fetch_show_forced_updates) {
+               if (!config->show_forced_updates) {
                        warning(_(warn_show_forced_updates));
                } else if (forced_updates_ms > FORCED_UPDATES_DELAY_WARNING_IN_MS) {
                        warning(_(warn_time_show_forced_updates),
@@ -1328,7 +1329,8 @@ static int fetch_and_consume_refs(struct display_state *display_state,
                                  struct transport *transport,
                                  struct ref_transaction *transaction,
                                  struct ref *ref_map,
-                                 struct fetch_head *fetch_head)
+                                 struct fetch_head *fetch_head,
+                                 const struct fetch_config *config)
 {
        int connectivity_checked = 1;
        int ret;
@@ -1351,7 +1353,7 @@ static int fetch_and_consume_refs(struct display_state *display_state,
        trace2_region_enter("fetch", "consume_refs", the_repository);
        ret = store_updated_refs(display_state, transport->remote->name,
                                 connectivity_checked, transaction, ref_map,
-                                fetch_head);
+                                fetch_head, config);
        trace2_region_leave("fetch", "consume_refs", the_repository);
 
 out:
@@ -1522,7 +1524,8 @@ static int backfill_tags(struct display_state *display_state,
                         struct transport *transport,
                         struct ref_transaction *transaction,
                         struct ref *ref_map,
-                        struct fetch_head *fetch_head)
+                        struct fetch_head *fetch_head,
+                        const struct fetch_config *config)
 {
        int retcode, cannot_reuse;
 
@@ -1543,7 +1546,8 @@ static int backfill_tags(struct display_state *display_state,
        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(display_state, transport, transaction, ref_map, fetch_head);
+       retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map,
+                                        fetch_head, config);
 
        if (gsecondary) {
                transport_disconnect(gsecondary);
@@ -1555,7 +1559,7 @@ static int backfill_tags(struct display_state *display_state,
 
 static int do_fetch(struct transport *transport,
                    struct refspec *rs,
-                   enum display_format display_format)
+                   const struct fetch_config *config)
 {
        struct ref_transaction *transaction = NULL;
        struct ref *ref_map = NULL;
@@ -1641,7 +1645,8 @@ static int do_fetch(struct transport *transport,
        if (retcode)
                goto cleanup;
 
-       display_state_init(&display_state, ref_map, transport->url, display_format);
+       display_state_init(&display_state, ref_map, transport->url,
+                          config->display_format);
 
        if (atomic_fetch) {
                transaction = ref_transaction_begin(&err);
@@ -1669,7 +1674,8 @@ static int do_fetch(struct transport *transport,
                        retcode = 1;
        }
 
-       if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map, &fetch_head)) {
+       if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
+                                  &fetch_head, config)) {
                retcode = 1;
                goto cleanup;
        }
@@ -1692,7 +1698,7 @@ static int do_fetch(struct transport *transport,
                         * the transaction and don't commit anything.
                         */
                        if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
-                                         &fetch_head))
+                                         &fetch_head, config))
                                retcode = 1;
                }
 
@@ -1794,7 +1800,9 @@ struct remote_group_data {
        struct string_list *list;
 };
 
-static int get_remote_group(const char *key, const char *value, void *priv)
+static int get_remote_group(const char *key, const char *value,
+                           const struct config_context *ctx UNUSED,
+                           void *priv)
 {
        struct remote_group_data *g = priv;
 
@@ -1830,7 +1838,7 @@ static int add_remote_or_group(const char *name, struct string_list *list)
 }
 
 static void add_options_to_argv(struct strvec *argv,
-                               enum display_format format)
+                               const struct fetch_config *config)
 {
        if (dry_run)
                strvec_push(argv, "--dry-run");
@@ -1844,11 +1852,11 @@ static void add_options_to_argv(struct strvec *argv,
                strvec_push(argv, "--force");
        if (keep)
                strvec_push(argv, "--keep");
-       if (recurse_submodules == RECURSE_SUBMODULES_ON)
+       if (config->recurse_submodules == RECURSE_SUBMODULES_ON)
                strvec_push(argv, "--recurse-submodules");
-       else if (recurse_submodules == RECURSE_SUBMODULES_OFF)
+       else if (config->recurse_submodules == RECURSE_SUBMODULES_OFF)
                strvec_push(argv, "--no-recurse-submodules");
-       else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+       else if (config->recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
                strvec_push(argv, "--recurse-submodules=on-demand");
        if (tags == TAGS_SET)
                strvec_push(argv, "--tags");
@@ -1866,7 +1874,7 @@ static void add_options_to_argv(struct strvec *argv,
                strvec_push(argv, "--ipv6");
        if (!write_fetch_head)
                strvec_push(argv, "--no-write-fetch-head");
-       if (format == DISPLAY_FORMAT_PORCELAIN)
+       if (config->display_format == DISPLAY_FORMAT_PORCELAIN)
                strvec_pushf(argv, "--porcelain");
 }
 
@@ -1876,7 +1884,7 @@ struct parallel_fetch_state {
        const char **argv;
        struct string_list *remotes;
        int next, result;
-       enum display_format format;
+       const struct fetch_config *config;
 };
 
 static int fetch_next_remote(struct child_process *cp,
@@ -1896,7 +1904,7 @@ static int fetch_next_remote(struct child_process *cp,
        strvec_push(&cp->args, remote);
        cp->git_cmd = 1;
 
-       if (verbosity >= 0 && state->format != DISPLAY_FORMAT_PORCELAIN)
+       if (verbosity >= 0 && state->config->display_format != DISPLAY_FORMAT_PORCELAIN)
                printf(_("Fetching %s\n"), remote);
 
        return 1;
@@ -1929,7 +1937,7 @@ static int fetch_finished(int result, struct strbuf *out,
 }
 
 static int fetch_multiple(struct string_list *list, int max_children,
-                         enum display_format format)
+                         const struct fetch_config *config)
 {
        int i, result = 0;
        struct strvec argv = STRVEC_INIT;
@@ -1947,10 +1955,10 @@ static int fetch_multiple(struct string_list *list, int max_children,
        strvec_pushl(&argv, "-c", "fetch.bundleURI=",
                     "fetch", "--append", "--no-auto-gc",
                     "--no-write-commit-graph", NULL);
-       add_options_to_argv(&argv, format);
+       add_options_to_argv(&argv, config);
 
        if (max_children != 1 && list->nr != 1) {
-               struct parallel_fetch_state state = { argv.v, list, 0, 0, format };
+               struct parallel_fetch_state state = { argv.v, list, 0, 0, config };
                const struct run_process_parallel_opts opts = {
                        .tr2_category = "fetch",
                        .tr2_label = "parallel/fetch",
@@ -1974,7 +1982,7 @@ static int fetch_multiple(struct string_list *list, int max_children,
 
                        strvec_pushv(&cmd.args, argv.v);
                        strvec_push(&cmd.args, name);
-                       if (verbosity >= 0 && format != DISPLAY_FORMAT_PORCELAIN)
+                       if (verbosity >= 0 && config->display_format != DISPLAY_FORMAT_PORCELAIN)
                                printf(_("Fetching %s\n"), name);
                        cmd.git_cmd = 1;
                        if (run_command(&cmd)) {
@@ -2030,7 +2038,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
 
 static int fetch_one(struct remote *remote, int argc, const char **argv,
                     int prune_tags_ok, int use_stdin_refspecs,
-                    enum display_format display_format)
+                    const struct fetch_config *config)
 {
        struct refspec rs = REFSPEC_INIT_FETCH;
        int i;
@@ -2048,8 +2056,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
                /* no command line request */
                if (0 <= remote->prune)
                        prune = remote->prune;
-               else if (0 <= fetch_prune_config)
-                       prune = fetch_prune_config;
+               else if (0 <= config->prune)
+                       prune = config->prune;
                else
                        prune = PRUNE_BY_DEFAULT;
        }
@@ -2058,8 +2066,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
                /* no command line request */
                if (0 <= remote->prune_tags)
                        prune_tags = remote->prune_tags;
-               else if (0 <= fetch_prune_tags_config)
-                       prune_tags = fetch_prune_tags_config;
+               else if (0 <= config->prune_tags)
+                       prune_tags = config->prune_tags;
                else
                        prune_tags = PRUNE_TAGS_BY_DEFAULT;
        }
@@ -2097,7 +2105,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
        sigchain_push_common(unlock_pack_on_signal);
        atexit(unlock_pack_atexit);
        sigchain_push(SIGPIPE, SIG_IGN);
-       exit_code = do_fetch(gtransport, &rs, display_format);
+       exit_code = do_fetch(gtransport, &rs, config);
        sigchain_pop(SIGPIPE);
        refspec_clear(&rs);
        transport_disconnect(gtransport);
@@ -2109,6 +2117,12 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 {
        struct fetch_config config = {
                .display_format = DISPLAY_FORMAT_FULL,
+               .prune = -1,
+               .prune_tags = -1,
+               .show_forced_updates = 1,
+               .recurse_submodules = RECURSE_SUBMODULES_DEFAULT,
+               .parallel = 1,
+               .submodule_fetch_jobs = -1,
        };
        const char *submodule_prefix = "";
        const char *bundle_uri;
@@ -2190,13 +2204,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                           PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
                OPT_BOOL(0, "update-shallow", &update_shallow,
                         N_("accept refs that update .git/shallow")),
-               OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
+               OPT_CALLBACK_F(0, "refmap", &refmap, N_("refmap"),
                               N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
                OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
-               OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
-                               TRANSPORT_FAMILY_IPV4),
-               OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
-                               TRANSPORT_FAMILY_IPV6),
+               OPT_IPVERSION(&family),
                OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
                                N_("report that we have only objects reachable from this object")),
                OPT_BOOL(0, "negotiate-only", &negotiate_only,
@@ -2206,7 +2217,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                         N_("run 'maintenance --auto' after fetching")),
                OPT_BOOL(0, "auto-gc", &enable_auto_gc,
                         N_("run 'maintenance --auto' after fetching")),
-               OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
+               OPT_BOOL(0, "show-forced-updates", &config.show_forced_updates,
                         N_("check for forced-updates on all updated branches")),
                OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
                         N_("write the commit-graph after fetching")),
@@ -2237,7 +2248,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                             builtin_fetch_options, builtin_fetch_usage, 0);
 
        if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
-               recurse_submodules = recurse_submodules_cli;
+               config.recurse_submodules = recurse_submodules_cli;
 
        if (negotiate_only) {
                switch (recurse_submodules_cli) {
@@ -2248,7 +2259,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                         * submodules. Skip it by setting recurse_submodules to
                         * RECURSE_SUBMODULES_OFF.
                         */
-                       recurse_submodules = RECURSE_SUBMODULES_OFF;
+                       config.recurse_submodules = RECURSE_SUBMODULES_OFF;
                        break;
 
                default:
@@ -2257,11 +2268,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                }
        }
 
-       if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
-               int *sfjc = submodule_fetch_jobs_config == -1
-                           ? &submodule_fetch_jobs_config : NULL;
-               int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
-                         ? &recurse_submodules : NULL;
+       if (config.recurse_submodules != RECURSE_SUBMODULES_OFF) {
+               int *sfjc = config.submodule_fetch_jobs == -1
+                           ? &config.submodule_fetch_jobs : NULL;
+               int *rs = config.recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+                         ? &config.recurse_submodules : NULL;
 
                fetch_config_from_gitmodules(sfjc, rs);
        }
@@ -2275,7 +2286,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                         * Reference updates in submodules would be ambiguous
                         * in porcelain mode, so we reject this combination.
                         */
-                       recurse_submodules = RECURSE_SUBMODULES_OFF;
+                       config.recurse_submodules = RECURSE_SUBMODULES_OFF;
                        break;
 
                default:
@@ -2385,7 +2396,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                if (filter_options.choice || repo_has_promisor_remote(the_repository))
                        fetch_one_setup_partial(remote);
                result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
-                                  config.display_format);
+                                  &config);
        } else {
                int max_children = max_jobs;
 
@@ -2402,10 +2413,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                              "from one remote"));
 
                if (max_children < 0)
-                       max_children = fetch_parallel_config;
+                       max_children = config.parallel;
 
                /* TODO should this also die if we have a previous partial-clone? */
-               result = fetch_multiple(&list, max_children, config.display_format);
+               result = fetch_multiple(&list, max_children, &config);
        }
 
        /*
@@ -2417,20 +2428,20 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
         * the fetched history from each remote, so there is no need
         * to fetch submodules from here.
         */
-       if (!result && remote && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+       if (!result && remote && (config.recurse_submodules != RECURSE_SUBMODULES_OFF)) {
                struct strvec options = STRVEC_INIT;
                int max_children = max_jobs;
 
                if (max_children < 0)
-                       max_children = submodule_fetch_jobs_config;
+                       max_children = config.submodule_fetch_jobs;
                if (max_children < 0)
-                       max_children = fetch_parallel_config;
+                       max_children = config.parallel;
 
-               add_options_to_argv(&options, config.display_format);
+               add_options_to_argv(&options, &config);
                result = fetch_submodules(the_repository,
                                          &options,
                                          submodule_prefix,
-                                         recurse_submodules,
+                                         config.recurse_submodules,
                                          recurse_submodules_default,
                                          verbosity < 0,
                                          max_children);
index cc812416420d7c3ac876b95affbb3ebab7caf040..0f9855b680eb7bf4e534af40847e32af835cfa13 100644 (file)
@@ -3,7 +3,6 @@
 #include "fmt-merge-msg.h"
 #include "gettext.h"
 #include "parse-options.h"
-#include "wrapper.h"
 
 static const char * const fmt_merge_msg_usage[] = {
        N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
index 695fc8f4a5e5622b15de4167f892559aaa8aafd4..350bfa6e811b8c53d94ba33083a03bf9d93437dc 100644 (file)
@@ -1,11 +1,11 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "gettext.h"
 #include "refs.h"
 #include "object.h"
 #include "parse-options.h"
 #include "ref-filter.h"
+#include "strbuf.h"
 #include "strvec.h"
 #include "commit-reach.h"
 
@@ -24,7 +24,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        struct string_list sorting_options = STRING_LIST_INIT_DUP;
        int maxcount = 0, icase = 0, omit_empty = 0;
        struct ref_array array;
-       struct ref_filter filter;
+       struct ref_filter filter = REF_FILTER_INIT;
        struct ref_format format = REF_FORMAT_INIT;
        struct strbuf output = STRBUF_INIT;
        struct strbuf err = STRBUF_INIT;
@@ -47,6 +47,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
                OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT__COLOR(&format.use_color, N_("respect format colors")),
+               OPT_REF_FILTER_EXCLUDE(&filter),
                OPT_REF_SORT(&sorting_options),
                OPT_CALLBACK(0, "points-at", &filter.points_at,
                             N_("object"), N_("print only refs which points at the given object"),
@@ -61,7 +62,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        };
 
        memset(&array, 0, sizeof(array));
-       memset(&filter, 0, sizeof(filter));
 
        format.format = "%(objectname) %(objecttype)\t%(refname)";
 
@@ -121,8 +121,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        strbuf_release(&err);
        strbuf_release(&output);
        ref_array_clear(&array);
-       free_commit_list(filter.with_commit);
-       free_commit_list(filter.no_commit);
+       ref_filter_clear(&filter);
        ref_sorting_release(sorting);
        strvec_clear(&vec);
        return 0;
index 37daf7bec143e8e72f1a6b91fd2c8d9381840c1c..28186b30f54818cdbb42a4876358b7ceb20d20e2 100644 (file)
@@ -1,6 +1,5 @@
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "path.h"
index dcc165bf0c508da9b0ebe238a83fc5861def40c7..611925905e4fd1d972565806156059016d2eb1a6 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "gettext.h"
 #include "hex.h"
 #include "repository.h"
 #include "packfile.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "read-cache-ll.h"
 #include "replace-object.h"
 #include "resolve-undo.h"
 #include "run-command.h"
+#include "sparse-index.h"
 #include "worktree.h"
 #include "pack-revindex.h"
 #include "pack-bitmap.h"
@@ -90,11 +92,11 @@ static int objerror(struct object *obj, const char *err)
        return -1;
 }
 
-static int fsck_error_func(struct fsck_options *o,
+static int fsck_error_func(struct fsck_options *o UNUSED,
                           const struct object_id *oid,
                           enum object_type object_type,
                           enum fsck_msg_type msg_type,
-                          enum fsck_msg_id msg_id,
+                          enum fsck_msg_id msg_id UNUSED,
                           const char *message)
 {
        switch (msg_type) {
@@ -119,7 +121,7 @@ static int fsck_error_func(struct fsck_options *o,
 static struct object_array pending;
 
 static int mark_object(struct object *obj, enum object_type type,
-                      void *data, struct fsck_options *options)
+                      void *data, struct fsck_options *options UNUSED)
 {
        struct object *parent = data;
 
@@ -204,8 +206,8 @@ static int traverse_reachable(void)
        return !!result;
 }
 
-static int mark_used(struct object *obj, enum object_type object_type,
-                    void *data, struct fsck_options *options)
+static int mark_used(struct object *obj, enum object_type type UNUSED,
+                    void *data UNUSED, struct fsck_options *options UNUSED)
 {
        if (!obj)
                return 1;
@@ -808,7 +810,7 @@ static int fsck_resolve_undo(struct index_state *istate,
 }
 
 static void fsck_index(struct index_state *istate, const char *index_path,
-                      int is_main_index)
+                      int is_current_worktree)
 {
        unsigned int i;
 
@@ -830,7 +832,7 @@ static void fsck_index(struct index_state *istate, const char *index_path,
                obj->flags |= USED;
                fsck_put_object_name(&fsck_walk_options, &obj->oid,
                                     "%s:%s",
-                                    is_main_index ? "" : index_path,
+                                    is_current_worktree ? "" : index_path,
                                     istate->cache[i]->name);
                mark_object_reachable(obj);
        }
@@ -929,7 +931,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        fetch_if_missing = 0;
 
        errors_found = 0;
-       read_replace_refs = 0;
+       disable_replace_refs();
        save_commit_buffer = 0;
 
        argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
@@ -1072,6 +1074,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        commit_graph_verify.git_cmd = 1;
                        strvec_pushl(&commit_graph_verify.args, "commit-graph",
                                     "verify", "--object-dir", odb->path, NULL);
+                       if (show_progress)
+                               strvec_push(&commit_graph_verify.args, "--progress");
+                       else
+                               strvec_push(&commit_graph_verify.args, "--no-progress");
                        if (run_command(&commit_graph_verify))
                                errors_found |= ERROR_COMMIT_GRAPH;
                }
@@ -1086,6 +1092,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        midx_verify.git_cmd = 1;
                        strvec_pushl(&midx_verify.args, "multi-pack-index",
                                     "verify", "--object-dir", odb->path, NULL);
+                       if (show_progress)
+                               strvec_push(&midx_verify.args, "--progress");
+                       else
+                               strvec_push(&midx_verify.args, "--no-progress");
                        if (run_command(&midx_verify))
                                errors_found |= ERROR_MULTI_PACK_INDEX;
                }
index f6dd9a784c195e6ff5368b1b86c1eaa0c6c4b4c0..5d01db5c029e2bf967ab96795bf0b3aef5b6102e 100644 (file)
@@ -1,19 +1,20 @@
 #include "builtin.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
 #include "parse-options.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsmonitor-ipc.h"
 #include "fsmonitor-path-utils.h"
+#include "fsmonitor-settings.h"
 #include "compat/fsmonitor/fsm-health.h"
 #include "compat/fsmonitor/fsm-listen.h"
 #include "fsmonitor--daemon.h"
 #include "simple-ipc.h"
 #include "khash.h"
 #include "pkt-line.h"
+#include "trace.h"
 #include "trace2.h"
 
 static const char * const builtin_fsmonitor__daemon_usage[] = {
@@ -37,10 +38,11 @@ static int fsmonitor__start_timeout_sec = 60;
 #define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
 static int fsmonitor__announce_startup = 0;
 
-static int fsmonitor_config(const char *var, const char *value, void *cb)
+static int fsmonitor_config(const char *var, const char *value,
+                           const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, FSMONITOR__IPC_THREADS)) {
-               int i = git_config_int(var, value);
+               int i = git_config_int(var, value, ctx->kvi);
                if (i < 1)
                        return error(_("value of '%s' out of range: %d"),
                                     FSMONITOR__IPC_THREADS, i);
@@ -49,7 +51,7 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp(var, FSMONITOR__START_TIMEOUT)) {
-               int i = git_config_int(var, value);
+               int i = git_config_int(var, value, ctx->kvi);
                if (i < 0)
                        return error(_("value of '%s' out of range: %d"),
                                     FSMONITOR__START_TIMEOUT, i);
@@ -59,7 +61,7 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
 
        if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) {
                int is_bool;
-               int i = git_config_bool_or_int(var, value, &is_bool);
+               int i = git_config_bool_or_int(var, value, ctx->kvi, &is_bool);
                if (i < 0)
                        return error(_("value of '%s' not bool or int: %d"),
                                     var, i);
@@ -67,7 +69,7 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 /*
@@ -127,8 +129,9 @@ struct fsmonitor_cookie_item {
        enum fsmonitor_cookie_item_result result;
 };
 
-static int cookies_cmp(const void *data, const struct hashmap_entry *he1,
-                    const struct hashmap_entry *he2, const void *keydata)
+static int cookies_cmp(const void *data UNUSED,
+                      const struct hashmap_entry *he1,
+                      const struct hashmap_entry *he2, const void *keydata)
 {
        const struct fsmonitor_cookie_item *a =
                container_of(he1, const struct fsmonitor_cookie_item, entry);
@@ -1410,7 +1413,7 @@ done:
        return err;
 }
 
-static int try_to_run_foreground_daemon(int detach_console)
+static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
 {
        /*
         * Technically, we don't need to probe for an existing daemon
@@ -1440,7 +1443,8 @@ static int try_to_run_foreground_daemon(int detach_console)
 
 static start_bg_wait_cb bg_wait_cb;
 
-static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+                     void *cb_data UNUSED)
 {
        enum ipc_active_state s = fsmonitor_ipc__get_state();
 
index f3942188a614c9aaff25e76293675000dded7228..7c11d5ebef052a46cd06b411960fb1c2b3d6ac08 100644 (file)
 #include "commit-graph.h"
 #include "packfile.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pack.h"
 #include "pack-objects.h"
+#include "path.h"
 #include "blob.h"
 #include "tree.h"
 #include "promisor-remote.h"
@@ -40,7 +41,6 @@
 #include "hook.h"
 #include "setup.h"
 #include "trace2.h"
-#include "wrapper.h"
 
 #define FAILED_RUN "failed to run %s"
 
@@ -52,6 +52,7 @@ static const char * const builtin_gc_usage[] = {
 static int pack_refs = 1;
 static int prune_reflogs = 1;
 static int cruft_packs = 1;
+static unsigned long max_cruft_size;
 static int aggressive_depth = 50;
 static int aggressive_window = 250;
 static int gc_auto_threshold = 6700;
@@ -61,6 +62,8 @@ static timestamp_t gc_log_expire_time;
 static const char *gc_log_expire = "1.day.ago";
 static const char *prune_expire = "2.weeks.ago";
 static const char *prune_worktrees_expire = "3.months.ago";
+static char *repack_filter;
+static char *repack_filter_to;
 static unsigned long big_pack_threshold;
 static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
 
@@ -163,6 +166,7 @@ static void gc_config(void)
        git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
        git_config_get_bool("gc.autodetach", &detach_auto);
        git_config_get_bool("gc.cruftpacks", &cruft_packs);
+       git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
        git_config_get_expiry("gc.pruneexpire", &prune_expire);
        git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
        git_config_get_expiry("gc.logexpiry", &gc_log_expire);
@@ -170,6 +174,9 @@ static void gc_config(void)
        git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
        git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
 
+       git_config_get_string("gc.repackfilter", &repack_filter);
+       git_config_get_string("gc.repackfilterto", &repack_filter_to);
+
        git_config(git_default_config, NULL);
 }
 
@@ -347,6 +354,9 @@ static void add_repack_all_option(struct string_list *keep_pack)
                strvec_push(&repack, "--cruft");
                if (prune_expire)
                        strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
+               if (max_cruft_size)
+                       strvec_pushf(&repack, "--max-cruft-size=%lu",
+                                    max_cruft_size);
        } else {
                strvec_push(&repack, "-A");
                if (prune_expire)
@@ -355,6 +365,11 @@ static void add_repack_all_option(struct string_list *keep_pack)
 
        if (keep_pack)
                for_each_string_list(keep_pack, keep_one_pack, NULL);
+
+       if (repack_filter && *repack_filter)
+               strvec_pushf(&repack, "--filter=%s", repack_filter);
+       if (repack_filter_to && *repack_filter_to)
+               strvec_pushf(&repack, "--filter-to=%s", repack_filter_to);
 }
 
 static void add_repack_incremental_option(void)
@@ -575,6 +590,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                        N_("prune unreferenced objects"),
                        PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
                OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
+               OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
+                             N_("with --cruft, limit the size of new cruft packs")),
                OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
                OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
                           PARSE_OPT_NOCOMPLETE),
@@ -1403,7 +1420,7 @@ static void initialize_task_config(int schedule)
        strbuf_release(&config_name);
 }
 
-static int task_option_parse(const struct option *opt,
+static int task_option_parse(const struct option *opt UNUSED,
                             const char *arg, int unset)
 {
        int i, num_selected = 0;
@@ -1708,6 +1725,15 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
        return 1;
 }
 
+static int get_random_minute(void)
+{
+       /* Use a static value when under tests. */
+       if (getenv("GIT_TEST_MAINT_SCHEDULER"))
+               return 13;
+
+       return git_rand() % 60;
+}
+
 static int is_launchctl_available(void)
 {
        const char *cmd = "launchctl";
@@ -1820,6 +1846,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
        struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
        struct stat st;
        const char *cmd = "launchctl";
+       int minute = get_random_minute();
 
        get_schedule_cmd(&cmd, NULL);
        preamble = "<?xml version=\"1.0\"?>\n"
@@ -1845,29 +1872,30 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
        case SCHEDULE_HOURLY:
                repeat = "<dict>\n"
                         "<key>Hour</key><integer>%d</integer>\n"
-                        "<key>Minute</key><integer>0</integer>\n"
+                        "<key>Minute</key><integer>%d</integer>\n"
                         "</dict>\n";
                for (i = 1; i <= 23; i++)
-                       strbuf_addf(&plist, repeat, i);
+                       strbuf_addf(&plist, repeat, i, minute);
                break;
 
        case SCHEDULE_DAILY:
                repeat = "<dict>\n"
                         "<key>Day</key><integer>%d</integer>\n"
                         "<key>Hour</key><integer>0</integer>\n"
-                        "<key>Minute</key><integer>0</integer>\n"
+                        "<key>Minute</key><integer>%d</integer>\n"
                         "</dict>\n";
                for (i = 1; i <= 6; i++)
-                       strbuf_addf(&plist, repeat, i);
+                       strbuf_addf(&plist, repeat, i, minute);
                break;
 
        case SCHEDULE_WEEKLY:
-               strbuf_addstr(&plist,
-                             "<dict>\n"
-                             "<key>Day</key><integer>0</integer>\n"
-                             "<key>Hour</key><integer>0</integer>\n"
-                             "<key>Minute</key><integer>0</integer>\n"
-                             "</dict>\n");
+               strbuf_addf(&plist,
+                           "<dict>\n"
+                           "<key>Day</key><integer>0</integer>\n"
+                           "<key>Hour</key><integer>0</integer>\n"
+                           "<key>Minute</key><integer>%d</integer>\n"
+                           "</dict>\n",
+                           minute);
                break;
 
        default:
@@ -1923,7 +1951,7 @@ static int launchctl_add_plists(void)
               launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY);
 }
 
-static int launchctl_update_schedule(int run_maintenance, int fd)
+static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
 {
        if (run_maintenance)
                return launchctl_add_plists();
@@ -1984,6 +2012,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
        const char *frequency = get_frequency(schedule);
        char *name = schtasks_task_name(frequency);
        struct strbuf tfilename = STRBUF_INIT;
+       int minute = get_random_minute();
 
        get_schedule_cmd(&cmd, NULL);
 
@@ -2004,7 +2033,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
        switch (schedule) {
        case SCHEDULE_HOURLY:
                fprintf(tfile->fp,
-                       "<StartBoundary>2020-01-01T01:00:00</StartBoundary>\n"
+                       "<StartBoundary>2020-01-01T01:%02d:00</StartBoundary>\n"
                        "<Enabled>true</Enabled>\n"
                        "<ScheduleByDay>\n"
                        "<DaysInterval>1</DaysInterval>\n"
@@ -2013,12 +2042,13 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
                        "<Interval>PT1H</Interval>\n"
                        "<Duration>PT23H</Duration>\n"
                        "<StopAtDurationEnd>false</StopAtDurationEnd>\n"
-                       "</Repetition>\n");
+                       "</Repetition>\n",
+                       minute);
                break;
 
        case SCHEDULE_DAILY:
                fprintf(tfile->fp,
-                       "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+                       "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
                        "<Enabled>true</Enabled>\n"
                        "<ScheduleByWeek>\n"
                        "<DaysOfWeek>\n"
@@ -2030,19 +2060,21 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
                        "<Saturday />\n"
                        "</DaysOfWeek>\n"
                        "<WeeksInterval>1</WeeksInterval>\n"
-                       "</ScheduleByWeek>\n");
+                       "</ScheduleByWeek>\n",
+                       minute);
                break;
 
        case SCHEDULE_WEEKLY:
                fprintf(tfile->fp,
-                       "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+                       "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
                        "<Enabled>true</Enabled>\n"
                        "<ScheduleByWeek>\n"
                        "<DaysOfWeek>\n"
                        "<Sunday />\n"
                        "</DaysOfWeek>\n"
                        "<WeeksInterval>1</WeeksInterval>\n"
-                       "</ScheduleByWeek>\n");
+                       "</ScheduleByWeek>\n",
+                       minute);
                break;
 
        default:
@@ -2068,7 +2100,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
              "</Settings>\n"
              "<Actions Context=\"Author\">\n"
              "<Exec>\n"
-             "<Command>\"%s\\git.exe\"</Command>\n"
+             "<Command>\"%s\\headless-git.exe\"</Command>\n"
              "<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
              "</Exec>\n"
              "</Actions>\n"
@@ -2100,7 +2132,7 @@ static int schtasks_schedule_tasks(void)
               schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY);
 }
 
-static int schtasks_update_schedule(int run_maintenance, int fd)
+static int schtasks_update_schedule(int run_maintenance, int fd UNUSED)
 {
        if (run_maintenance)
                return schtasks_schedule_tasks();
@@ -2159,6 +2191,7 @@ static int crontab_update_schedule(int run_maintenance, int fd)
        FILE *cron_list, *cron_in;
        struct strbuf line = STRBUF_INIT;
        struct tempfile *tmpedit = NULL;
+       int minute = get_random_minute();
 
        get_schedule_cmd(&cmd, NULL);
        strvec_split(&crontab_list.args, cmd);
@@ -2213,11 +2246,11 @@ static int crontab_update_schedule(int run_maintenance, int fd)
                        "# replaced in the future by a Git command.\n\n");
 
                strbuf_addf(&line_format,
-                           "%%s %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
+                           "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
                            exec_path, exec_path);
-               fprintf(cron_in, line_format.buf, "0", "1-23", "*", "hourly");
-               fprintf(cron_in, line_format.buf, "0", "0", "1-6", "daily");
-               fprintf(cron_in, line_format.buf, "0", "0", "0", "weekly");
+               fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
+               fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
+               fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
                strbuf_release(&line_format);
 
                fprintf(cron_in, "\n%s\n", END_LINE);
@@ -2276,77 +2309,54 @@ static char *xdg_config_home_systemd(const char *filename)
        return xdg_config_home_for("systemd/user", filename);
 }
 
-static int systemd_timer_enable_unit(int enable,
-                                    enum schedule_priority schedule)
-{
-       const char *cmd = "systemctl";
-       struct child_process child = CHILD_PROCESS_INIT;
-       const char *frequency = get_frequency(schedule);
+#define SYSTEMD_UNIT_FORMAT "git-maintenance@%s.%s"
 
-       /*
-        * Disabling the systemd unit while it is already disabled makes
-        * systemctl print an error.
-        * Let's ignore it since it means we already are in the expected state:
-        * the unit is disabled.
-        *
-        * On the other hand, enabling a systemd unit which is already enabled
-        * produces no error.
-        */
-       if (!enable)
-               child.no_stderr = 1;
-
-       get_schedule_cmd(&cmd, NULL);
-       strvec_split(&child.args, cmd);
-       strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
-                    "--now", NULL);
-       strvec_pushf(&child.args, "git-maintenance@%s.timer", frequency);
-
-       if (start_command(&child))
-               return error(_("failed to start systemctl"));
-       if (finish_command(&child))
-               /*
-                * Disabling an already disabled systemd unit makes
-                * systemctl fail.
-                * Let's ignore this failure.
-                *
-                * Enabling an enabled systemd unit doesn't fail.
-                */
-               if (enable)
-                       return error(_("failed to run systemctl"));
-       return 0;
-}
-
-static int systemd_timer_delete_unit_templates(void)
+static int systemd_timer_delete_timer_file(enum schedule_priority priority)
 {
        int ret = 0;
-       char *filename = xdg_config_home_systemd("git-maintenance@.timer");
-       if (unlink(filename) && !is_missing_file_error(errno))
-               ret = error_errno(_("failed to delete '%s'"), filename);
-       FREE_AND_NULL(filename);
+       const char *frequency = get_frequency(priority);
+       char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+       char *filename = xdg_config_home_systemd(local_timer_name);
 
-       filename = xdg_config_home_systemd("git-maintenance@.service");
        if (unlink(filename) && !is_missing_file_error(errno))
                ret = error_errno(_("failed to delete '%s'"), filename);
 
        free(filename);
+       free(local_timer_name);
        return ret;
 }
 
-static int systemd_timer_delete_units(void)
+static int systemd_timer_delete_service_template(void)
 {
-       return systemd_timer_enable_unit(0, SCHEDULE_HOURLY) ||
-              systemd_timer_enable_unit(0, SCHEDULE_DAILY) ||
-              systemd_timer_enable_unit(0, SCHEDULE_WEEKLY) ||
-              systemd_timer_delete_unit_templates();
+       int ret = 0;
+       char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+       char *filename = xdg_config_home_systemd(local_service_name);
+       if (unlink(filename) && !is_missing_file_error(errno))
+               ret = error_errno(_("failed to delete '%s'"), filename);
+
+       free(filename);
+       free(local_service_name);
+       return ret;
 }
 
-static int systemd_timer_write_unit_templates(const char *exec_path)
+/*
+ * Write the schedule information into a git-maintenance@<schedule>.timer
+ * file using a custom minute. This timer file cannot use the templating
+ * system, so we generate a specific file for each.
+ */
+static int systemd_timer_write_timer_file(enum schedule_priority schedule,
+                                         int minute)
 {
+       int res = -1;
        char *filename;
        FILE *file;
        const char *unit;
+       char *schedule_pattern = NULL;
+       const char *frequency = get_frequency(schedule);
+       char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+       filename = xdg_config_home_systemd(local_timer_name);
 
-       filename = xdg_config_home_systemd("git-maintenance@.timer");
        if (safe_create_leading_directories(filename)) {
                error(_("failed to create directories for '%s'"), filename);
                goto error;
@@ -2355,6 +2365,23 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
        if (!file)
                goto error;
 
+       switch (schedule) {
+       case SCHEDULE_HOURLY:
+               schedule_pattern = xstrfmt("*-*-* 1..23:%02d:00", minute);
+               break;
+
+       case SCHEDULE_DAILY:
+               schedule_pattern = xstrfmt("Tue..Sun *-*-* 0:%02d:00", minute);
+               break;
+
+       case SCHEDULE_WEEKLY:
+               schedule_pattern = xstrfmt("Mon 0:%02d:00", minute);
+               break;
+
+       default:
+               BUG("Unhandled schedule_priority");
+       }
+
        unit = "# This file was created and is maintained by Git.\n"
               "# Any edits made in this file might be replaced in the future\n"
               "# by a Git command.\n"
@@ -2363,12 +2390,12 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
               "Description=Optimize Git repositories data\n"
               "\n"
               "[Timer]\n"
-              "OnCalendar=%i\n"
+              "OnCalendar=%s\n"
               "Persistent=true\n"
               "\n"
               "[Install]\n"
               "WantedBy=timers.target\n";
-       if (fputs(unit, file) == EOF) {
+       if (fprintf(file, unit, schedule_pattern) < 0) {
                error(_("failed to write to '%s'"), filename);
                fclose(file);
                goto error;
@@ -2377,9 +2404,36 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
                error_errno(_("failed to flush '%s'"), filename);
                goto error;
        }
+
+       res = 0;
+
+error:
+       free(schedule_pattern);
+       free(local_timer_name);
        free(filename);
+       return res;
+}
 
-       filename = xdg_config_home_systemd("git-maintenance@.service");
+/*
+ * No matter the schedule, we use the same service and can make use of the
+ * templating system. When installing git-maintenance@<schedule>.timer,
+ * systemd will notice that git-maintenance@.service exists as a template
+ * and will use this file and insert the <schedule> into the template at
+ * the position of "%i".
+ */
+static int systemd_timer_write_service_template(const char *exec_path)
+{
+       int res = -1;
+       char *filename;
+       FILE *file;
+       const char *unit;
+       char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+
+       filename = xdg_config_home_systemd(local_service_name);
+       if (safe_create_leading_directories(filename)) {
+               error(_("failed to create directories for '%s'"), filename);
+               goto error;
+       }
        file = fopen_or_warn(filename, "w");
        if (!file)
                goto error;
@@ -2397,7 +2451,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
               "LockPersonality=yes\n"
               "MemoryDenyWriteExecute=yes\n"
               "NoNewPrivileges=yes\n"
-              "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\n"
+              "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_VSOCK\n"
               "RestrictNamespaces=yes\n"
               "RestrictRealtime=yes\n"
               "RestrictSUIDSGID=yes\n"
@@ -2412,29 +2466,114 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
                error_errno(_("failed to flush '%s'"), filename);
                goto error;
        }
+
+       res = 0;
+
+error:
+       free(local_service_name);
        free(filename);
+       return res;
+}
+
+static int systemd_timer_enable_unit(int enable,
+                                    enum schedule_priority schedule,
+                                    int minute)
+{
+       const char *cmd = "systemctl";
+       struct child_process child = CHILD_PROCESS_INIT;
+       const char *frequency = get_frequency(schedule);
+
+       /*
+        * Disabling the systemd unit while it is already disabled makes
+        * systemctl print an error.
+        * Let's ignore it since it means we already are in the expected state:
+        * the unit is disabled.
+        *
+        * On the other hand, enabling a systemd unit which is already enabled
+        * produces no error.
+        */
+       if (!enable)
+               child.no_stderr = 1;
+       else if (systemd_timer_write_timer_file(schedule, minute))
+               return -1;
+
+       get_schedule_cmd(&cmd, NULL);
+       strvec_split(&child.args, cmd);
+       strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
+                    "--now", NULL);
+       strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+       if (start_command(&child))
+               return error(_("failed to start systemctl"));
+       if (finish_command(&child))
+               /*
+                * Disabling an already disabled systemd unit makes
+                * systemctl fail.
+                * Let's ignore this failure.
+                *
+                * Enabling an enabled systemd unit doesn't fail.
+                */
+               if (enable)
+                       return error(_("failed to run systemctl"));
        return 0;
+}
+
+/*
+ * A previous version of Git wrote the timer units as template files.
+ * Clean these up, if they exist.
+ */
+static void systemd_timer_delete_stale_timer_templates(void)
+{
+       char *timer_template_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "timer");
+       char *filename = xdg_config_home_systemd(timer_template_name);
+
+       if (unlink(filename) && !is_missing_file_error(errno))
+               warning(_("failed to delete '%s'"), filename);
 
-error:
        free(filename);
-       systemd_timer_delete_unit_templates();
-       return -1;
+       free(timer_template_name);
+}
+
+static int systemd_timer_delete_unit_files(void)
+{
+       systemd_timer_delete_stale_timer_templates();
+
+       /* Purposefully not short-circuited to make sure all are called. */
+       return systemd_timer_delete_timer_file(SCHEDULE_HOURLY) |
+              systemd_timer_delete_timer_file(SCHEDULE_DAILY) |
+              systemd_timer_delete_timer_file(SCHEDULE_WEEKLY) |
+              systemd_timer_delete_service_template();
+}
+
+static int systemd_timer_delete_units(void)
+{
+       int minute = get_random_minute();
+       /* Purposefully not short-circuited to make sure all are called. */
+       return systemd_timer_enable_unit(0, SCHEDULE_HOURLY, minute) |
+              systemd_timer_enable_unit(0, SCHEDULE_DAILY, minute) |
+              systemd_timer_enable_unit(0, SCHEDULE_WEEKLY, minute) |
+              systemd_timer_delete_unit_files();
 }
 
 static int systemd_timer_setup_units(void)
 {
+       int minute = get_random_minute();
        const char *exec_path = git_exec_path();
 
-       int ret = systemd_timer_write_unit_templates(exec_path) ||
-                 systemd_timer_enable_unit(1, SCHEDULE_HOURLY) ||
-                 systemd_timer_enable_unit(1, SCHEDULE_DAILY) ||
-                 systemd_timer_enable_unit(1, SCHEDULE_WEEKLY);
+       int ret = systemd_timer_write_service_template(exec_path) ||
+                 systemd_timer_enable_unit(1, SCHEDULE_HOURLY, minute) ||
+                 systemd_timer_enable_unit(1, SCHEDULE_DAILY, minute) ||
+                 systemd_timer_enable_unit(1, SCHEDULE_WEEKLY, minute);
+
        if (ret)
                systemd_timer_delete_units();
+       else
+               systemd_timer_delete_stale_timer_templates();
+
        return ret;
 }
 
-static int systemd_timer_update_schedule(int run_maintenance, int fd)
+static int systemd_timer_update_schedule(int run_maintenance, int fd UNUSED)
 {
        if (run_maintenance)
                return systemd_timer_setup_units();
@@ -2606,9 +2745,12 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
        opts.scheduler = resolve_scheduler(opts.scheduler);
        validate_scheduler(opts.scheduler);
 
+       if (update_background_schedule(&opts, 1))
+               die(_("failed to set up maintenance schedule"));
+
        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);
+       return 0;
 }
 
 static const char *const builtin_maintenance_stop_usage[] = {
index 564cfcac4fb0ac4c9de1748b816f395d45665cbb..20d0dfe9cf1dfefe6ffacb23bd500701cca71a09 100644 (file)
@@ -1,12 +1,10 @@
 /*
  * Copyright (c) 2005, 2006 Rene Scharfe
  */
-#include "cache.h"
+#include "builtin.h"
 #include "commit.h"
 #include "tar.h"
-#include "builtin.h"
 #include "quote.h"
-#include "wrapper.h"
 
 static const char builtin_get_tar_commit_id_usage[] =
 "git get-tar-commit-id";
index b86c754defbc59654a6e455b2115487ba01f084f..fe78d4c98b13b578a09de344d6a56d2316a8cb00 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
-#include "cache.h"
-#include "alloc.h"
+#include "builtin.h"
+#include "abspath.h"
 #include "gettext.h"
 #include "hex.h"
 #include "repository.h"
@@ -14,7 +14,6 @@
 #include "commit.h"
 #include "tag.h"
 #include "tree-walk.h"
-#include "builtin.h"
 #include "parse-options.h"
 #include "string-list.h"
 #include "run-command.h"
 #include "submodule-config.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
 #include "pager.h"
+#include "path.h"
+#include "read-cache-ll.h"
 #include "write-or-die.h"
 
 static const char *grep_prefix;
@@ -290,14 +291,18 @@ static int wait_all(void)
        return hit;
 }
 
-static int grep_cmd_config(const char *var, const char *value, void *cb)
+static int grep_cmd_config(const char *var, const char *value,
+                          const struct config_context *ctx, void *cb)
 {
-       int st = grep_config(var, value, cb);
-       if (git_color_default_config(var, value, NULL) < 0)
+       int st = grep_config(var, value, ctx, cb);
+
+       if (git_color_config(var, value, cb) < 0)
+               st = -1;
+       else if (git_default_config(var, value, ctx, cb) < 0)
                st = -1;
 
        if (!strcmp(var, "grep.threads")) {
-               num_threads = git_config_int(var, value);
+               num_threads = git_config_int(var, value, ctx->kvi);
                if (num_threads < 0)
                        die(_("invalid number of threads specified (%d) for %s"),
                            num_threads, var);
@@ -639,7 +644,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                        strbuf_addstr(&name, base->buf + tn_len);
                        match = tree_entry_interesting(repo->index,
                                                       &entry, &name,
-                                                      0, pathspec);
+                                                      pathspec);
                        strbuf_setlen(&name, name_base_len);
 
                        if (match == all_entries_not_interesting)
@@ -808,14 +813,20 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
 {
        struct grep_opt *grep_opt = opt->value;
        int from_stdin;
+       const char *filename = arg;
        FILE *patterns;
        int lno = 0;
        struct strbuf sb = STRBUF_INIT;
 
        BUG_ON_OPT_NEG(unset);
 
-       from_stdin = !strcmp(arg, "-");
-       patterns = from_stdin ? stdin : fopen(arg, "r");
+       if (!*filename)
+               ; /* leave it as-is */
+       else
+               filename = prefix_filename_except_for_dash(grep_prefix, filename);
+
+       from_stdin = !strcmp(filename, "-");
+       patterns = from_stdin ? stdin : fopen(filename, "r");
        if (!patterns)
                die_errno(_("cannot open '%s'"), arg);
        while (strbuf_getline(&sb, patterns) == 0) {
@@ -829,6 +840,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
        if (!from_stdin)
                fclose(patterns);
        strbuf_release(&sb);
+       if (filename != arg)
+               free((void *)filename);
        return 0;
 }
 
@@ -920,9 +933,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                         N_("process binary files with textconv filters")),
                OPT_SET_INT('r', "recursive", &opt.max_depth,
                            N_("search in subdirectories (default)"), -1),
-               { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
-                       N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
-                       NULL, 1 },
+               OPT_INTEGER_F(0, "max-depth", &opt.max_depth,
+                       N_("descend at most <n> levels"), PARSE_OPT_NONEG),
                OPT_GROUP(""),
                OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
                            N_("use extended POSIX regular expressions"),
@@ -986,7 +998,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_CALLBACK_F(0, "and", &opt, NULL,
                        N_("combine patterns specified with -e"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback),
-               OPT_BOOL(0, "or", &dummy, ""),
+               OPT_BOOL_F(0, "or", &dummy, "", PARSE_OPT_NONEG),
                OPT_CALLBACK_F(0, "not", &opt, NULL, "",
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback),
                OPT_CALLBACK_F('(', NULL, &opt, NULL, "",
index a3801211666410eb703fa11bd24a4ba03ff3e6ea..5ffec99dceaf5c95d9b57c1f0c6c90358b80507d 100644 (file)
 #include "gettext.h"
 #include "hex.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "quote.h"
 #include "parse-options.h"
 #include "exec-cmd.h"
 #include "setup.h"
+#include "strbuf.h"
 #include "write-or-die.h"
 
 /*
index d3cf4af3f6ebee4893bb754530a3c7b5c375c9aa..dc1fbe2b9862df507dc1e077258d3c44048eebef 100644 (file)
@@ -1,9 +1,8 @@
 /*
  * Builtin help command
  */
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
 #include "exec-cmd.h"
 #include "gettext.h"
 #include "pager.h"
@@ -398,7 +397,8 @@ static int add_man_viewer_info(const char *var, const char *value)
        return 0;
 }
 
-static int git_help_config(const char *var, const char *value, void *cb)
+static int git_help_config(const char *var, const char *value,
+                          const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "help.format")) {
                if (!value)
@@ -421,7 +421,7 @@ static int git_help_config(const char *var, const char *value, void *cb)
        if (starts_with(var, "man."))
                return add_man_viewer_info(var, value);
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static struct cmdnames main_cmds, other_cmds;
index 88051795c7f5bf016fc5856167c5d350827dff2e..09b51a6487c3928bc099567109193c32fe82fe30 100644 (file)
@@ -1,4 +1,3 @@
-#include "cache.h"
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
index bb67e16655994ceee8116a6325ead1daf1d8e860..dda94a9f46d9a9401c298ee304f57e55db25f217 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "alloc.h"
 #include "config.h"
 #include "delta.h"
 #include "environment.h"
 #include "progress.h"
 #include "fsck.h"
 #include "exec-cmd.h"
+#include "strbuf.h"
 #include "streaming.h"
 #include "thread-utils.h"
 #include "packfile.h"
 #include "pack-revindex.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oid-array.h"
 #include "replace-object.h"
 #include "promisor-remote.h"
 #include "setup.h"
-#include "wrapper.h"
 
 static const char index_pack_usage[] =
 "git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -222,7 +221,8 @@ static void cleanup_thread(void)
 }
 
 static int mark_link(struct object *obj, enum object_type type,
-                    void *data, struct fsck_options *options)
+                    void *data UNUSED,
+                    struct fsck_options *options UNUSED)
 {
        if (!obj)
                return -1;
@@ -1166,6 +1166,7 @@ static void parse_pack_objects(unsigned char *hash)
        struct ofs_delta_entry *ofs_delta = ofs_deltas;
        struct object_id ref_delta_oid;
        struct stat st;
+       git_hash_ctx tmp_ctx;
 
        if (verbose)
                progress = start_progress(
@@ -1202,7 +1203,9 @@ static void parse_pack_objects(unsigned char *hash)
 
        /* Check pack integrity */
        flush();
-       the_hash_algo->final_fn(hash, &input_ctx);
+       the_hash_algo->init_fn(&tmp_ctx);
+       the_hash_algo->clone_fn(&tmp_ctx, &input_ctx);
+       the_hash_algo->final_fn(hash, &tmp_ctx);
        if (!hasheq(fill(the_hash_algo->rawsz), hash))
                die(_("pack is corrupted (SHA1 mismatch)"));
        use(the_hash_algo->rawsz);
@@ -1581,18 +1584,19 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
        strbuf_release(&pack_name);
 }
 
-static int git_index_pack_config(const char *k, const char *v, void *cb)
+static int git_index_pack_config(const char *k, const char *v,
+                                const struct config_context *ctx, void *cb)
 {
        struct pack_idx_option *opts = cb;
 
        if (!strcmp(k, "pack.indexversion")) {
-               opts->version = git_config_int(k, v);
+               opts->version = git_config_int(k, v, ctx->kvi);
                if (opts->version > 2)
                        die(_("bad pack.indexVersion=%"PRIu32), opts->version);
                return 0;
        }
        if (!strcmp(k, "pack.threads")) {
-               nr_threads = git_config_int(k, v);
+               nr_threads = git_config_int(k, v, ctx->kvi);
                if (nr_threads < 0)
                        die(_("invalid number of threads specified (%d)"),
                            nr_threads);
@@ -1608,7 +1612,7 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
                else
                        opts->flags &= ~WRITE_REV;
        }
-       return git_default_config(k, v, cb);
+       return git_default_config(k, v, ctx, cb);
 }
 
 static int cmp_uint32(const void *a_, const void *b_)
@@ -1752,7 +1756,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
 
-       read_replace_refs = 0;
+       disable_replace_refs();
        fsck_options.walk = mark_link;
 
        reset_pack_idx_option(&opts);
index aef40361052ed9ff363661f19533dc466f300d34..cb727c826f5653ab2827ccfbd575e6d305fad75a 100644 (file)
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "abspath.h"
 #include "config.h"
-#include "copy.h"
 #include "environment.h"
 #include "gettext.h"
-#include "refs.h"
-#include "builtin.h"
-#include "exec-cmd.h"
 #include "object-file.h"
 #include "parse-options.h"
 #include "path.h"
 #include "setup.h"
-#include "worktree.h"
-#include "wrapper.h"
-
-#ifndef DEFAULT_GIT_TEMPLATE_DIR
-#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
-#endif
-
-#ifdef NO_TRUSTABLE_FILEMODE
-#define TEST_FILEMODE 0
-#else
-#define TEST_FILEMODE 1
-#endif
-
-#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
-
-static int init_is_bare_repository = 0;
-static int init_shared_repository = -1;
-
-static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
-                            DIR *dir)
-{
-       size_t path_baselen = path->len;
-       size_t template_baselen = template_path->len;
-       struct dirent *de;
-
-       /* Note: if ".git/hooks" file exists in the repository being
-        * re-initialized, /etc/core-git/templates/hooks/update would
-        * cause "git init" to fail here.  I think this is sane but
-        * it means that the set of templates we ship by default, along
-        * with the way the namespace under .git/ is organized, should
-        * be really carefully chosen.
-        */
-       safe_create_dir(path->buf, 1);
-       while ((de = readdir(dir)) != NULL) {
-               struct stat st_git, st_template;
-               int exists = 0;
-
-               strbuf_setlen(path, path_baselen);
-               strbuf_setlen(template_path, template_baselen);
-
-               if (de->d_name[0] == '.')
-                       continue;
-               strbuf_addstr(path, de->d_name);
-               strbuf_addstr(template_path, de->d_name);
-               if (lstat(path->buf, &st_git)) {
-                       if (errno != ENOENT)
-                               die_errno(_("cannot stat '%s'"), path->buf);
-               }
-               else
-                       exists = 1;
-
-               if (lstat(template_path->buf, &st_template))
-                       die_errno(_("cannot stat template '%s'"), template_path->buf);
-
-               if (S_ISDIR(st_template.st_mode)) {
-                       DIR *subdir = opendir(template_path->buf);
-                       if (!subdir)
-                               die_errno(_("cannot opendir '%s'"), template_path->buf);
-                       strbuf_addch(path, '/');
-                       strbuf_addch(template_path, '/');
-                       copy_templates_1(path, template_path, subdir);
-                       closedir(subdir);
-               }
-               else if (exists)
-                       continue;
-               else if (S_ISLNK(st_template.st_mode)) {
-                       struct strbuf lnk = STRBUF_INIT;
-                       if (strbuf_readlink(&lnk, template_path->buf,
-                                           st_template.st_size) < 0)
-                               die_errno(_("cannot readlink '%s'"), template_path->buf);
-                       if (symlink(lnk.buf, path->buf))
-                               die_errno(_("cannot symlink '%s' '%s'"),
-                                         lnk.buf, path->buf);
-                       strbuf_release(&lnk);
-               }
-               else if (S_ISREG(st_template.st_mode)) {
-                       if (copy_file(path->buf, template_path->buf, st_template.st_mode))
-                               die_errno(_("cannot copy '%s' to '%s'"),
-                                         template_path->buf, path->buf);
-               }
-               else
-                       error(_("ignoring template %s"), template_path->buf);
-       }
-}
-
-static void copy_templates(const char *template_dir, const char *init_template_dir)
-{
-       struct strbuf path = STRBUF_INIT;
-       struct strbuf template_path = STRBUF_INIT;
-       size_t template_len;
-       struct repository_format template_format = REPOSITORY_FORMAT_INIT;
-       struct strbuf err = STRBUF_INIT;
-       DIR *dir;
-       char *to_free = NULL;
-
-       if (!template_dir)
-               template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
-       if (!template_dir)
-               template_dir = init_template_dir;
-       if (!template_dir)
-               template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
-       if (!template_dir[0]) {
-               free(to_free);
-               return;
-       }
-
-       strbuf_addstr(&template_path, template_dir);
-       strbuf_complete(&template_path, '/');
-       template_len = template_path.len;
-
-       dir = opendir(template_path.buf);
-       if (!dir) {
-               warning(_("templates not found in %s"), template_dir);
-               goto free_return;
-       }
-
-       /* Make sure that template is from the correct vintage */
-       strbuf_addstr(&template_path, "config");
-       read_repository_format(&template_format, template_path.buf);
-       strbuf_setlen(&template_path, template_len);
-
-       /*
-        * No mention of version at all is OK, but anything else should be
-        * verified.
-        */
-       if (template_format.version >= 0 &&
-           verify_repository_format(&template_format, &err) < 0) {
-               warning(_("not copying templates from '%s': %s"),
-                         template_dir, err.buf);
-               strbuf_release(&err);
-               goto close_free_return;
-       }
-
-       strbuf_addstr(&path, get_git_common_dir());
-       strbuf_complete(&path, '/');
-       copy_templates_1(&path, &template_path, dir);
-close_free_return:
-       closedir(dir);
-free_return:
-       free(to_free);
-       strbuf_release(&path);
-       strbuf_release(&template_path);
-       clear_repository_format(&template_format);
-}
-
-/*
- * If the git_dir is not directly inside the working tree, then git will not
- * find it by default, and we need to set the worktree explicitly.
- */
-static int needs_work_tree_config(const char *git_dir, const char *work_tree)
-{
-       if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
-               return 0;
-       if (skip_prefix(git_dir, work_tree, &git_dir) &&
-           !strcmp(git_dir, "/.git"))
-               return 0;
-       return 1;
-}
-
-void initialize_repository_version(int hash_algo, int reinit)
-{
-       char repo_version_string[10];
-       int repo_version = GIT_REPO_VERSION;
-
-       if (hash_algo != GIT_HASH_SHA1)
-               repo_version = GIT_REPO_VERSION_READ;
-
-       /* This forces creation of new config file */
-       xsnprintf(repo_version_string, sizeof(repo_version_string),
-                 "%d", repo_version);
-       git_config_set("core.repositoryformatversion", repo_version_string);
-
-       if (hash_algo != GIT_HASH_SHA1)
-               git_config_set("extensions.objectformat",
-                              hash_algos[hash_algo].name);
-       else if (reinit)
-               git_config_set_gently("extensions.objectformat", NULL);
-}
-
-static int create_default_files(const char *template_path,
-                               const char *original_git_dir,
-                               const char *initial_branch,
-                               const struct repository_format *fmt,
-                               int quiet)
-{
-       struct stat st1;
-       struct strbuf buf = STRBUF_INIT;
-       char *path;
-       char junk[2];
-       int reinit;
-       int filemode;
-       struct strbuf err = STRBUF_INIT;
-       const char *init_template_dir = NULL;
-       const char *work_tree = get_git_work_tree();
-
-       /*
-        * First copy the templates -- we might have the default
-        * config file there, in which case we would want to read
-        * from it after installing.
-        *
-        * Before reading that config, we also need to clear out any cached
-        * values (since we've just potentially changed what's available on
-        * disk).
-        */
-       git_config_get_pathname("init.templatedir", &init_template_dir);
-       copy_templates(template_path, init_template_dir);
-       free((char *)init_template_dir);
-       git_config_clear();
-       reset_shared_repository();
-       git_config(git_default_config, NULL);
-
-       /*
-        * We must make sure command-line options continue to override any
-        * values we might have just re-read from the config.
-        */
-       is_bare_repository_cfg = init_is_bare_repository || !work_tree;
-       if (init_shared_repository != -1)
-               set_shared_repository(init_shared_repository);
-
-       /*
-        * We would have created the above under user's umask -- under
-        * shared-repository settings, we would need to fix them up.
-        */
-       if (get_shared_repository()) {
-               adjust_shared_perm(get_git_dir());
-       }
-
-       /*
-        * We need to create a "refs" dir in any case so that older
-        * versions of git can tell that this is a repository.
-        */
-       safe_create_dir(git_path("refs"), 1);
-       adjust_shared_perm(git_path("refs"));
-
-       if (refs_init_db(&err))
-               die("failed to set up refs db: %s", err.buf);
-
-       /*
-        * Point the HEAD symref to the initial branch with if HEAD does
-        * not yet exist.
-        */
-       path = git_path_buf(&buf, "HEAD");
-       reinit = (!access(path, R_OK)
-                 || readlink(path, junk, sizeof(junk)-1) != -1);
-       if (!reinit) {
-               char *ref;
-
-               if (!initial_branch)
-                       initial_branch = git_default_branch_name(quiet);
-
-               ref = xstrfmt("refs/heads/%s", initial_branch);
-               if (check_refname_format(ref, 0) < 0)
-                       die(_("invalid initial branch name: '%s'"),
-                           initial_branch);
-
-               if (create_symref("HEAD", ref, NULL) < 0)
-                       exit(1);
-               free(ref);
-       }
-
-       initialize_repository_version(fmt->hash_algo, 0);
-
-       /* Check filemode trustability */
-       path = git_path_buf(&buf, "config");
-       filemode = TEST_FILEMODE;
-       if (TEST_FILEMODE && !lstat(path, &st1)) {
-               struct stat st2;
-               filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
-                               !lstat(path, &st2) &&
-                               st1.st_mode != st2.st_mode &&
-                               !chmod(path, st1.st_mode));
-               if (filemode && !reinit && (st1.st_mode & S_IXUSR))
-                       filemode = 0;
-       }
-       git_config_set("core.filemode", filemode ? "true" : "false");
-
-       if (is_bare_repository())
-               git_config_set("core.bare", "true");
-       else {
-               git_config_set("core.bare", "false");
-               /* allow template config file to override the default */
-               if (log_all_ref_updates == LOG_REFS_UNSET)
-                       git_config_set("core.logallrefupdates", "true");
-               if (needs_work_tree_config(original_git_dir, work_tree))
-                       git_config_set("core.worktree", work_tree);
-       }
-
-       if (!reinit) {
-               /* Check if symlink is supported in the work tree */
-               path = git_path_buf(&buf, "tXXXXXX");
-               if (!close(xmkstemp(path)) &&
-                   !unlink(path) &&
-                   !symlink("testing", path) &&
-                   !lstat(path, &st1) &&
-                   S_ISLNK(st1.st_mode))
-                       unlink(path); /* good */
-               else
-                       git_config_set("core.symlinks", "false");
-
-               /* Check if the filesystem is case-insensitive */
-               path = git_path_buf(&buf, "CoNfIg");
-               if (!access(path, F_OK))
-                       git_config_set("core.ignorecase", "true");
-               probe_utf8_pathname_composition();
-       }
-
-       strbuf_release(&buf);
-       return reinit;
-}
-
-static void create_object_directory(void)
-{
-       struct strbuf path = STRBUF_INIT;
-       size_t baselen;
-
-       strbuf_addstr(&path, get_object_directory());
-       baselen = path.len;
-
-       safe_create_dir(path.buf, 1);
-
-       strbuf_setlen(&path, baselen);
-       strbuf_addstr(&path, "/pack");
-       safe_create_dir(path.buf, 1);
-
-       strbuf_setlen(&path, baselen);
-       strbuf_addstr(&path, "/info");
-       safe_create_dir(path.buf, 1);
-
-       strbuf_release(&path);
-}
-
-static void separate_git_dir(const char *git_dir, const char *git_link)
-{
-       struct stat st;
-
-       if (!stat(git_link, &st)) {
-               const char *src;
-
-               if (S_ISREG(st.st_mode))
-                       src = read_gitfile(git_link);
-               else if (S_ISDIR(st.st_mode))
-                       src = git_link;
-               else
-                       die(_("unable to handle file type %d"), (int)st.st_mode);
-
-               if (rename(src, git_dir))
-                       die_errno(_("unable to move %s to %s"), src, git_dir);
-               repair_worktrees(NULL, NULL);
-       }
-
-       write_file(git_link, "gitdir: %s", git_dir);
-}
-
-static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
-{
-       const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
-       /*
-        * If we already have an initialized repo, don't allow the user to
-        * specify a different algorithm, as that could cause corruption.
-        * Otherwise, if the user has specified one on the command line, use it.
-        */
-       if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
-               die(_("attempt to reinitialize repository with different hash"));
-       else if (hash != GIT_HASH_UNKNOWN)
-               repo_fmt->hash_algo = hash;
-       else if (env) {
-               int env_algo = hash_algo_by_name(env);
-               if (env_algo == GIT_HASH_UNKNOWN)
-                       die(_("unknown hash algorithm '%s'"), env);
-               repo_fmt->hash_algo = env_algo;
-       }
-}
-
-int init_db(const char *git_dir, const char *real_git_dir,
-           const char *template_dir, int hash, const char *initial_branch,
-           unsigned int flags)
-{
-       int reinit;
-       int exist_ok = flags & INIT_DB_EXIST_OK;
-       char *original_git_dir = real_pathdup(git_dir, 1);
-       struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
-
-       if (real_git_dir) {
-               struct stat st;
-
-               if (!exist_ok && !stat(git_dir, &st))
-                       die(_("%s already exists"), git_dir);
-
-               if (!exist_ok && !stat(real_git_dir, &st))
-                       die(_("%s already exists"), real_git_dir);
-
-               set_git_dir(real_git_dir, 1);
-               git_dir = get_git_dir();
-               separate_git_dir(git_dir, original_git_dir);
-       }
-       else {
-               set_git_dir(git_dir, 1);
-               git_dir = get_git_dir();
-       }
-       startup_info->have_repository = 1;
-
-       /* Ensure `core.hidedotfiles` is processed */
-       git_config(platform_core_config, NULL);
-
-       safe_create_dir(git_dir, 0);
-
-       init_is_bare_repository = is_bare_repository();
-
-       /* Check to see if the repository version is right.
-        * Note that a newly created repository does not have
-        * config file, so this will not fail.  What we are catching
-        * is an attempt to reinitialize new repository with an old tool.
-        */
-       check_repository_format(&repo_fmt);
-
-       validate_hash_algorithm(&repo_fmt, hash);
-
-       reinit = create_default_files(template_dir, original_git_dir,
-                                     initial_branch, &repo_fmt,
-                                     flags & INIT_DB_QUIET);
-       if (reinit && initial_branch)
-               warning(_("re-init: ignored --initial-branch=%s"),
-                       initial_branch);
-
-       create_object_directory();
-
-       if (get_shared_repository()) {
-               char buf[10];
-               /* We do not spell "group" and such, so that
-                * the configuration can be read by older version
-                * of git. Note, we use octal numbers for new share modes,
-                * and compatibility values for PERM_GROUP and
-                * PERM_EVERYBODY.
-                */
-               if (get_shared_repository() < 0)
-                       /* force to the mode value */
-                       xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
-               else if (get_shared_repository() == PERM_GROUP)
-                       xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
-               else if (get_shared_repository() == PERM_EVERYBODY)
-                       xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
-               else
-                       BUG("invalid value for shared_repository");
-               git_config_set("core.sharedrepository", buf);
-               git_config_set("receive.denyNonFastforwards", "true");
-       }
-
-       if (!(flags & INIT_DB_QUIET)) {
-               int len = strlen(git_dir);
-
-               if (reinit)
-                       printf(get_shared_repository()
-                              ? _("Reinitialized existing shared Git repository in %s%s\n")
-                              : _("Reinitialized existing Git repository in %s%s\n"),
-                              git_dir, len && git_dir[len-1] != '/' ? "/" : "");
-               else
-                       printf(get_shared_repository()
-                              ? _("Initialized empty shared Git repository in %s%s\n")
-                              : _("Initialized empty Git repository in %s%s\n"),
-                              git_dir, len && git_dir[len-1] != '/' ? "/" : "");
-       }
-
-       free(original_git_dir);
-       return 0;
-}
+#include "strbuf.h"
 
 static int guess_repository_type(const char *git_dir)
 {
@@ -546,6 +78,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        const char *object_format = NULL;
        const char *initial_branch = NULL;
        int hash_algo = GIT_HASH_UNKNOWN;
+       int init_shared_repository = -1;
        const struct option init_db_options[] = {
                OPT_STRING(0, "template", &template_dir, N_("template-directory"),
                                N_("directory from which templates will be used")),
@@ -703,5 +236,5 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 
        flags |= INIT_DB_EXIST_OK;
        return init_db(git_dir, real_git_dir, template_dir, hash_algo,
-                      initial_branch, flags);
+                      initial_branch, init_shared_repository, flags);
 }
index 107ac28f0e8cb0cb6d6f0ac31102a165a4850b20..033bd1556cf9f8d6e56c2730a3e868500388144e 100644 (file)
@@ -5,7 +5,6 @@
  *
  */
 
-#include "cache.h"
 #include "builtin.h"
 #include "gettext.h"
 #include "parse-options.h"
@@ -15,7 +14,7 @@
 
 static const char * const git_interpret_trailers_usage[] = {
        N_("git interpret-trailers [--in-place] [--trim-empty]\n"
-          "                       [(--trailer <token>[(=|:)<value>])...]\n"
+          "                       [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
           "                       [--parse] [<file>...]"),
        NULL
 };
@@ -25,21 +24,24 @@ static enum trailer_if_exists if_exists;
 static enum trailer_if_missing if_missing;
 
 static int option_parse_where(const struct option *opt,
-                             const char *arg, int unset)
+                             const char *arg, int unset UNUSED)
 {
-       return trailer_set_where(&where, arg);
+       /* unset implies NULL arg, which is handled in our helper */
+       return trailer_set_where(opt->value, arg);
 }
 
 static int option_parse_if_exists(const struct option *opt,
-                                 const char *arg, int unset)
+                                 const char *arg, int unset UNUSED)
 {
-       return trailer_set_if_exists(&if_exists, arg);
+       /* unset implies NULL arg, which is handled in our helper */
+       return trailer_set_if_exists(opt->value, arg);
 }
 
 static int option_parse_if_missing(const struct option *opt,
-                                  const char *arg, int unset)
+                                  const char *arg, int unset UNUSED)
 {
-       return trailer_set_if_missing(&if_missing, arg);
+       /* unset implies NULL arg, which is handled in our helper */
+       return trailer_set_if_missing(opt->value, arg);
 }
 
 static void new_trailers_clear(struct list_head *trailers)
@@ -98,19 +100,19 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
                OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
 
-               OPT_CALLBACK(0, "where", NULL, N_("action"),
+               OPT_CALLBACK(0, "where", &where, N_("placement"),
                             N_("where to place the new trailer"), option_parse_where),
-               OPT_CALLBACK(0, "if-exists", NULL, N_("action"),
+               OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
                             N_("action if trailer already exists"), option_parse_if_exists),
-               OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
+               OPT_CALLBACK(0, "if-missing", &if_missing, N_("action"),
                             N_("action if trailer is missing"), option_parse_if_missing),
 
                OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
-               OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")),
-               OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
-               OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("set parsing options"),
+               OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
+               OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
+               OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
-               OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")),
+               OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
                OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
                                N_("trailer(s) to add"), option_parse_trailer),
                OPT_END()
index 676de107d61470360276e8c6439d919213ba3635..ba775d7b5cf886374bd94c9f2e54d5695a3dbaff 100644 (file)
@@ -6,7 +6,6 @@
  */
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -14,7 +13,7 @@
 #include "refs.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pager.h"
 #include "color.h"
 #include "commit.h"
@@ -119,16 +118,19 @@ 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)
+static int clear_decorations_callback(const struct option *opt UNUSED,
+                                     const char *arg, int unset)
 {
+       BUG_ON_OPT_NEG(unset);
+       BUG_ON_OPT_ARG(arg);
        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)
+static int decorate_callback(const struct option *opt UNUSED, const char *arg,
+                            int unset)
 {
        if (unset)
                decoration_style = 0;
@@ -174,16 +176,15 @@ static void cmd_log_init_defaults(struct rev_info *rev)
        if (default_follow)
                rev->diffopt.flags.default_follow_renames = 1;
        rev->verbose_header = 1;
+       init_diffstat_widths(&rev->diffopt);
        rev->diffopt.flags.recursive = 1;
-       rev->diffopt.stat_width = -1; /* use full terminal width */
-       rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
+       rev->diffopt.flags.allow_textconv = 1;
        rev->abbrev_commit = default_abbrev_commit;
        rev->show_root_diff = default_show_root;
        rev->subject_prefix = fmt_patch_subject_prefix;
        rev->patch_name_max = fmt_patch_name_max;
        rev->show_signature = default_show_signature;
        rev->encode_email_headers = default_encode_email_headers;
-       rev->diffopt.flags.allow_textconv = 1;
 
        if (default_date_mode)
                parse_date_format(default_date_mode, &rev->date_mode);
@@ -550,7 +551,7 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
            rev->diffopt.flags.check_failed) {
                return 02;
        }
-       return diff_result_code(&rev->diffopt, 0);
+       return diff_result_code(&rev->diffopt);
 }
 
 static int cmd_log_walk(struct rev_info *rev)
@@ -564,7 +565,8 @@ static int cmd_log_walk(struct rev_info *rev)
        return retval;
 }
 
-static int git_log_config(const char *var, const char *value, void *cb)
+static int git_log_config(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb)
 {
        const char *slot_name;
 
@@ -573,7 +575,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "format.subjectprefix"))
                return git_config_string(&fmt_patch_subject_prefix, var, value);
        if (!strcmp(var, "format.filenamemaxlength")) {
-               fmt_patch_name_max = git_config_int(var, value);
+               fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
                return 0;
        }
        if (!strcmp(var, "format.encodeemailheaders")) {
@@ -613,7 +615,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_diff_ui_config(var, value, cb);
+       return git_diff_ui_config(var, value, ctx, cb);
 }
 
 int cmd_whatchanged(int argc, const char **argv, const char *prefix)
@@ -718,8 +720,7 @@ static int show_tree_object(const struct object_id *oid UNUSED,
        return 0;
 }
 
-static void show_setup_revisions_tweak(struct rev_info *rev,
-                                      struct setup_revision_opt *opt)
+static void show_setup_revisions_tweak(struct rev_info *rev)
 {
        if (rev->first_parent_only)
                diff_merges_default_to_first_parent(rev);
@@ -862,11 +863,10 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
        return cmd_log_deinit(cmd_log_walk(&rev), &rev);
 }
 
-static void log_setup_revisions_tweak(struct rev_info *rev,
-                                     struct setup_revision_opt *opt)
+static void log_setup_revisions_tweak(struct rev_info *rev)
 {
        if (rev->diffopt.flags.default_follow_renames &&
-           rev->prune_data.nr == 1)
+           diff_check_follow_pathspec(&rev->prune_data, 0))
                rev->diffopt.flags.follow_renames = 1;
 
        if (rev->first_parent_only)
@@ -979,7 +979,8 @@ static enum cover_from_description parse_cover_from_description(const char *arg)
                die(_("%s: invalid cover from description mode"), arg);
 }
 
-static int git_format_config(const char *var, const char *value, void *cb)
+static int git_format_config(const char *var, const char *value,
+                            const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "format.headers")) {
                if (!value)
@@ -1108,7 +1109,7 @@ static int git_format_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "diff.noprefix"))
                return 0;
 
-       return git_log_config(var, value, cb);
+       return git_log_config(var, value, ctx, cb);
 }
 
 static const char *output_directory = NULL;
@@ -1254,7 +1255,15 @@ static void show_diffstat(struct rev_info *rev,
        fprintf(rev->diffopt.file, "\n");
 }
 
+static void read_desc_file(struct strbuf *buf, const char *desc_file)
+{
+       if (strbuf_read_file(buf, desc_file, 0) < 0)
+               die_errno(_("unable to read branch description file '%s'"),
+                         desc_file);
+}
+
 static void prepare_cover_text(struct pretty_print_context *pp,
+                              const char *description_file,
                               const char *branch_name,
                               struct strbuf *sb,
                               const char *encoding,
@@ -1268,7 +1277,9 @@ static void prepare_cover_text(struct pretty_print_context *pp,
        if (cover_from_description_mode == COVER_FROM_NONE)
                goto do_pp;
 
-       if (branch_name && *branch_name)
+       if (description_file && *description_file)
+               read_desc_file(&description_sb, description_file);
+       else if (branch_name && *branch_name)
                read_branch_desc(&description_sb, branch_name);
        if (!description_sb.len)
                goto do_pp;
@@ -1314,6 +1325,7 @@ static void get_notes_args(struct strvec *arg, struct rev_info *rev)
 static void make_cover_letter(struct rev_info *rev, int use_separate_file,
                              struct commit *origin,
                              int nr, struct commit **list,
+                             const char *description_file,
                              const char *branch_name,
                              int quiet)
 {
@@ -1353,7 +1365,8 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
        pp.rev = rev;
        pp.print_email_subject = 1;
        pp_user_info(&pp, NULL, &sb, committer, encoding);
-       prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
+       prepare_cover_text(&pp, description_file, branch_name, &sb,
+                          encoding, need_8bit_cte);
        fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
        strbuf_release(&sb);
@@ -1406,7 +1419,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
        }
 }
 
-static const char *clean_message_id(const char *msg_id)
+static char *clean_message_id(const char *msg_id)
 {
        char ch;
        const char *a, *z, *m;
@@ -1424,7 +1437,7 @@ static const char *clean_message_id(const char *msg_id)
        if (!z)
                die(_("insane in-reply-to: %s"), msg_id);
        if (++z == m)
-               return a;
+               return xstrdup(a);
        return xmemdupz(a, z - a);
 }
 
@@ -1469,19 +1482,16 @@ static int subject_prefix = 0;
 static int subject_prefix_callback(const struct option *opt, const char *arg,
                            int unset)
 {
+       struct strbuf *sprefix;
+
        BUG_ON_OPT_NEG(unset);
+       sprefix = opt->value;
        subject_prefix = 1;
-       ((struct rev_info *)opt->value)->subject_prefix = arg;
+       strbuf_reset(sprefix);
+       strbuf_addstr(sprefix, arg);
        return 0;
 }
 
-static int rfc_callback(const struct option *opt, const char *arg, int unset)
-{
-       BUG_ON_OPT_NEG(unset);
-       BUG_ON_OPT_ARG(arg);
-       return subject_prefix_callback(opt, "RFC PATCH", unset);
-}
-
 static int numbered_cmdline_opt = 0;
 
 static int numbered_callback(const struct option *opt, const char *arg,
@@ -1556,7 +1566,8 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
-static int header_callback(const struct option *opt, const char *arg, int unset)
+static int header_callback(const struct option *opt UNUSED, const char *arg,
+                          int unset)
 {
        if (unset) {
                string_list_clear(&extra_hdr, 0);
@@ -1568,24 +1579,6 @@ static int header_callback(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
-static int to_callback(const struct option *opt, const char *arg, int unset)
-{
-       if (unset)
-               string_list_clear(&extra_to, 0);
-       else
-               string_list_append(&extra_to, arg);
-       return 0;
-}
-
-static int cc_callback(const struct option *opt, const char *arg, int unset)
-{
-       if (unset)
-               string_list_clear(&extra_cc, 0);
-       else
-               string_list_append(&extra_cc, arg);
-       return 0;
-}
-
 static int from_callback(const struct option *opt, const char *arg, int unset)
 {
        char **from = opt->value;
@@ -1894,6 +1887,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int quiet = 0;
        const char *reroll_count = NULL;
        char *cover_from_description_arg = NULL;
+       char *description_file = NULL;
        char *branch_name = NULL;
        char *base_commit = NULL;
        struct base_tree_info bases;
@@ -1908,6 +1902,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        struct strbuf rdiff_title = STRBUF_INIT;
        struct strbuf sprefix = STRBUF_INIT;
        int creation_factor = -1;
+       int rfc = 0;
 
        const struct option builtin_format_patch_options[] = {
                OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
@@ -1931,13 +1926,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                            N_("mark the series as Nth re-roll")),
                OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
                            N_("max length of output filename")),
-               OPT_CALLBACK_F(0, "rfc", &rev, NULL,
-                           N_("use [RFC PATCH] instead of [PATCH]"),
-                           PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
+               OPT_BOOL(0, "rfc", &rfc, N_("use [RFC PATCH] instead of [PATCH]")),
                OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
                            N_("cover-from-description-mode"),
                            N_("generate parts of a cover letter based on a branch's description")),
-               OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
+               OPT_FILENAME(0, "description-file", &description_file,
+                            N_("use branch description from file")),
+               OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
                            N_("use [<prefix>] instead of [PATCH]"),
                            PARSE_OPT_NONEG, subject_prefix_callback),
                OPT_CALLBACK_F('o', "output-directory", &output_directory,
@@ -1958,8 +1953,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                OPT_GROUP(N_("Messaging")),
                OPT_CALLBACK(0, "add-header", NULL, N_("header"),
                            N_("add email header"), header_callback),
-               OPT_CALLBACK(0, "to", NULL, N_("email"), N_("add To: header"), to_callback),
-               OPT_CALLBACK(0, "cc", NULL, N_("email"), N_("add Cc: header"), cc_callback),
+               OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")),
+               OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")),
                OPT_CALLBACK_F(0, "from", &from, N_("ident"),
                            N_("set From address to <ident> (or committer ident if absent)"),
                            PARSE_OPT_OPTARG, from_callback),
@@ -2017,11 +2012,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.max_parents = 1;
        rev.diffopt.flags.recursive = 1;
        rev.diffopt.no_free = 1;
-       rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
        s_r_opt.def = "HEAD";
        s_r_opt.revarg_opt = REVARG_COMMITTISH;
 
+       strbuf_addstr(&sprefix, fmt_patch_subject_prefix);
        if (format_no_prefix)
                diff_set_noprefix(&rev.diffopt);
 
@@ -2049,13 +2044,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        if (cover_from_description_arg)
                cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
 
+       if (rfc)
+               strbuf_insertstr(&sprefix, 0, "RFC ");
+
        if (reroll_count) {
-               strbuf_addf(&sprefix, "%s v%s",
-                           rev.subject_prefix, reroll_count);
+               strbuf_addf(&sprefix, " v%s", reroll_count);
                rev.reroll_count = reroll_count;
-               rev.subject_prefix = sprefix.buf;
        }
 
+       rev.subject_prefix = sprefix.buf;
+
        for (i = 0; i < extra_hdr.nr; i++) {
                strbuf_addstr(&buf, extra_hdr.items[i].string);
                strbuf_addch(&buf, '\n');
@@ -2310,11 +2308,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
        if (in_reply_to || thread || cover_letter) {
                rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
-               string_list_init_nodup(rev.ref_message_ids);
+               string_list_init_dup(rev.ref_message_ids);
        }
        if (in_reply_to) {
-               const char *msgid = clean_message_id(in_reply_to);
-               string_list_append(rev.ref_message_ids, msgid);
+               char *msgid = clean_message_id(in_reply_to);
+               string_list_append_nodup(rev.ref_message_ids, msgid);
        }
        rev.numbered_files = just_numbers;
        rev.patch_suffix = fmt_patch_suffix;
@@ -2322,7 +2320,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, !!output_directory,
-                                 origin, nr, list, branch_name, quiet);
+                                 origin, nr, list, description_file, branch_name, quiet);
                print_bases(&bases, rev.diffopt.file);
                print_signature(rev.diffopt.file);
                total++;
@@ -2370,8 +2368,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                                    && (!cover_letter || rev.nr > 1))
                                        free(rev.message_id);
                                else
-                                       string_list_append(rev.ref_message_ids,
-                                                          rev.message_id);
+                                       string_list_append_nodup(rev.ref_message_ids,
+                                                                rev.message_id);
                        }
                        gen_message_id(&rev, oid_to_hex(&commit->object.oid));
                }
@@ -2420,6 +2418,7 @@ done:
        strbuf_release(&rdiff_title);
        strbuf_release(&sprefix);
        free(to_free);
+       free(rev.message_id);
        if (rev.ref_message_ids)
                string_list_clear(rev.ref_message_ids, 0);
        free(rev.ref_message_ids);
index 625f48f0d6178f9078f887a2941e4d8c2a9efe30..a0229c3277874accc9edf0a4a5ac4e8186217903 100644 (file)
@@ -5,13 +5,12 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "repository.h"
 #include "config.h"
 #include "convert.h"
 #include "quote.h"
 #include "dir.h"
-#include "builtin.h"
 #include "gettext.h"
 #include "object-name.h"
 #include "strbuf.h"
 #include "parse-options.h"
 #include "resolve-undo.h"
 #include "string-list.h"
+#include "path.h"
 #include "pathspec.h"
+#include "read-cache.h"
 #include "run-command.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule.h"
 #include "submodule-config.h"
+#include "object-store.h"
+#include "hex.h"
+
 
 static int abbrev;
 static int show_deleted;
@@ -241,68 +246,75 @@ 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)
+static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
+                             const enum object_type type, unsigned int padded)
 {
-       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;
+       if (type == OBJ_BLOB) {
+               unsigned long size;
+               if (oid_object_info(the_repository, oid, &size) < 0)
+                       die(_("could not get object info about '%s'"),
+                           oid_to_hex(oid));
+               if (padded)
+                       strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
+               else
+                       strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
+       } else if (padded) {
+               strbuf_addf(line, "%7s", "-");
+       } else {
+               strbuf_addstr(line, "-");
+       }
 }
 
 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);
+       while (strbuf_expand_step(&sb, &format)) {
+               const char *end;
+               size_t len;
+               struct stat st;
+
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(&sb, '%');
+               else if ((len = strbuf_expand_literal(&sb, format)))
+                       format += len;
+               else if (*format != '(')
+                       die(_("bad ls-files format: element '%s' "
+                             "does not start with '('"), format);
+               else if (!(end = strchr(format + 1, ')')))
+                       die(_("bad ls-files format: element '%s' "
+                             "does not end in ')'"), format);
+               else if (skip_prefix(format, "(objectmode)", &format))
+                       strbuf_addf(&sb, "%06o", ce->ce_mode);
+               else if (skip_prefix(format, "(objectname)", &format))
+                       strbuf_add_unique_abbrev(&sb, &ce->oid, abbrev);
+               else if (skip_prefix(format, "(objecttype)", &format))
+                       strbuf_addstr(&sb, type_name(object_type(ce->ce_mode)));
+               else if (skip_prefix(format, "(objectsize:padded)", &format))
+                       expand_objectsize(&sb, &ce->oid,
+                                         object_type(ce->ce_mode), 1);
+               else if (skip_prefix(format, "(objectsize)", &format))
+                       expand_objectsize(&sb, &ce->oid,
+                                         object_type(ce->ce_mode), 0);
+               else if (skip_prefix(format, "(stage)", &format))
+                       strbuf_addf(&sb, "%d", ce_stage(ce));
+               else if (skip_prefix(format, "(eolinfo:index)", &format))
+                       strbuf_addstr(&sb, S_ISREG(ce->ce_mode) ?
+                                     get_cached_convert_stats_ascii(repo->index,
+                                     ce->name) : "");
+               else if (skip_prefix(format, "(eolinfo:worktree)", &format))
+                       strbuf_addstr(&sb, !lstat(fullname, &st) &&
+                                     S_ISREG(st.st_mode) ?
+                                     get_wt_convert_stats_ascii(fullname) : "");
+               else if (skip_prefix(format, "(eolattr)", &format))
+                       strbuf_addstr(&sb, get_convert_attr_ascii(repo->index,
+                                                                fullname));
+               else if (skip_prefix(format, "(path)", &format))
+                       write_name_to_buf(&sb, fullname);
+               else
+                       die(_("bad ls-files format: %%%.*s"),
+                           (int)(end - format + 1), format);
+       }
        strbuf_addch(&sb, line_terminator);
        fwrite(sb.buf, sb.len, 1, stdout);
        strbuf_release(&sb);
@@ -516,143 +528,6 @@ static int get_common_prefix_len(const char *common_prefix)
        return common_prefix_len;
 }
 
-static int read_one_entry_opt(struct index_state *istate,
-                             const struct object_id *oid,
-                             struct strbuf *base,
-                             const char *pathname,
-                             unsigned mode, int opt)
-{
-       int len;
-       struct cache_entry *ce;
-
-       if (S_ISDIR(mode))
-               return READ_TREE_RECURSIVE;
-
-       len = strlen(pathname);
-       ce = make_empty_cache_entry(istate, base->len + len);
-
-       ce->ce_mode = create_ce_mode(mode);
-       ce->ce_flags = create_ce_flags(1);
-       ce->ce_namelen = base->len + len;
-       memcpy(ce->name, base->buf, base->len);
-       memcpy(ce->name + base->len, pathname, len+1);
-       oidcpy(&ce->oid, oid);
-       return add_index_entry(istate, ce, opt);
-}
-
-static int read_one_entry(const struct object_id *oid, struct strbuf *base,
-                         const char *pathname, unsigned mode,
-                         void *context)
-{
-       struct index_state *istate = context;
-       return read_one_entry_opt(istate, oid, base, pathname,
-                                 mode,
-                                 ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
-}
-
-/*
- * This is used when the caller knows there is no existing entries at
- * the stage that will conflict with the entry being added.
- */
-static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
-                               const char *pathname, unsigned mode,
-                               void *context)
-{
-       struct index_state *istate = context;
-       return read_one_entry_opt(istate, oid, base, pathname,
-                                 mode, ADD_CACHE_JUST_APPEND);
-}
-
-/*
- * Read the tree specified with --with-tree option
- * (typically, HEAD) into stage #1 and then
- * squash them down to stage #0.  This is used for
- * --error-unmatch to list and check the path patterns
- * that were given from the command line.  We are not
- * going to write this index out.
- */
-void overlay_tree_on_index(struct index_state *istate,
-                          const char *tree_name, const char *prefix)
-{
-       struct tree *tree;
-       struct object_id oid;
-       struct pathspec pathspec;
-       struct cache_entry *last_stage0 = NULL;
-       int i;
-       read_tree_fn_t fn = NULL;
-       int err;
-
-       if (repo_get_oid(the_repository, tree_name, &oid))
-               die("tree-ish %s not found.", tree_name);
-       tree = parse_tree_indirect(&oid);
-       if (!tree)
-               die("bad tree-ish %s", tree_name);
-
-       /* Hoist the unmerged entries up to stage #3 to make room */
-       /* TODO: audit for interaction with sparse-index. */
-       ensure_full_index(istate);
-       for (i = 0; i < istate->cache_nr; i++) {
-               struct cache_entry *ce = istate->cache[i];
-               if (!ce_stage(ce))
-                       continue;
-               ce->ce_flags |= CE_STAGEMASK;
-       }
-
-       if (prefix) {
-               static const char *(matchbuf[1]);
-               matchbuf[0] = NULL;
-               parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
-                              PATHSPEC_PREFER_CWD, prefix, matchbuf);
-       } else
-               memset(&pathspec, 0, sizeof(pathspec));
-
-       /*
-        * See if we have cache entry at the stage.  If so,
-        * do it the original slow way, otherwise, append and then
-        * sort at the end.
-        */
-       for (i = 0; !fn && i < istate->cache_nr; i++) {
-               const struct cache_entry *ce = istate->cache[i];
-               if (ce_stage(ce) == 1)
-                       fn = read_one_entry;
-       }
-
-       if (!fn)
-               fn = read_one_entry_quick;
-       err = read_tree(the_repository, tree, &pathspec, fn, istate);
-       clear_pathspec(&pathspec);
-       if (err)
-               die("unable to read tree entries %s", tree_name);
-
-       /*
-        * Sort the cache entry -- we need to nuke the cache tree, though.
-        */
-       if (fn == read_one_entry_quick) {
-               cache_tree_free(&istate->cache_tree);
-               QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
-       }
-
-       for (i = 0; i < istate->cache_nr; i++) {
-               struct cache_entry *ce = istate->cache[i];
-               switch (ce_stage(ce)) {
-               case 0:
-                       last_stage0 = ce;
-                       /* fallthru */
-               default:
-                       continue;
-               case 1:
-                       /*
-                        * If there is stage #0 entry for this, we do not
-                        * need to show it.  We use CE_UPDATE bit to mark
-                        * such an entry.
-                        */
-                       if (last_stage0 &&
-                           !strcmp(last_stage0->name, ce->name))
-                               ce->ce_flags |= CE_UPDATE;
-               }
-       }
-}
-
 static const char * const ls_files_usage[] = {
        N_("git ls-files [<options>] [<file>...]"),
        NULL
index cb6cb77e086bab630ec05924c5ebf173c1946ad8..fc765754305ed7a3f8a2efdcd604dd29c8b3b502 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "gettext.h"
 #include "hex.h"
 #include "transport.h"
@@ -8,6 +7,7 @@
 #include "remote.h"
 #include "refs.h"
 #include "parse-options.h"
+#include "wildmatch.h"
 
 static const char * const ls_remote_usage[] = {
        N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
index 077977a46100327e9d611e8badb9d0c9190de33f..209d2dc0d59af3d0c8860ef4eb397edb34e8b429 100644 (file)
@@ -3,17 +3,17 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "tree.h"
 #include "commit.h"
+#include "path.h"
 #include "quote.h"
-#include "builtin.h"
 #include "parse-options.h"
 #include "pathspec.h"
 
@@ -50,68 +50,10 @@ struct ls_tree_options {
                LS_SHOW_TREES = 1 << 2,
        } ls_options;
        struct pathspec pathspec;
-       int chomp_prefix;
-       const char *ls_tree_prefix;
+       const char *prefix;
        const char *format;
 };
 
-struct show_tree_data {
-       struct ls_tree_options *options;
-       unsigned mode;
-       enum object_type type;
-       const struct object_id *oid;
-       const char *pathname;
-       struct strbuf *base;
-};
-
-static size_t expand_show_tree(struct strbuf *sb, const char *start,
-                              void *context)
-{
-       struct show_tree_data *data = context;
-       struct ls_tree_options *options = data->options;
-       const char *end;
-       const char *p;
-       unsigned int errlen;
-       size_t len = strbuf_expand_literal_cb(sb, start, NULL);
-
-       if (len)
-               return len;
-       if (*start != '(')
-               die(_("bad ls-tree format: element '%s' does not start with '('"), start);
-
-       end = strchr(start + 1, ')');
-       if (!end)
-               die(_("bad ls-tree format: element '%s' does not end in ')'"), start);
-
-       len = end - start + 1;
-       if (skip_prefix(start, "(objectmode)", &p)) {
-               strbuf_addf(sb, "%06o", data->mode);
-       } else if (skip_prefix(start, "(objecttype)", &p)) {
-               strbuf_addstr(sb, type_name(data->type));
-       } else if (skip_prefix(start, "(objectsize:padded)", &p)) {
-               expand_objectsize(sb, data->oid, data->type, 1);
-       } else if (skip_prefix(start, "(objectsize)", &p)) {
-               expand_objectsize(sb, data->oid, data->type, 0);
-       } else if (skip_prefix(start, "(objectname)", &p)) {
-               strbuf_add_unique_abbrev(sb, data->oid, options->abbrev);
-       } else if (skip_prefix(start, "(path)", &p)) {
-               const char *name = data->base->buf;
-               const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
-               struct strbuf sbuf = STRBUF_INIT;
-               size_t baselen = data->base->len;
-
-               strbuf_addstr(data->base, data->pathname);
-               name = relative_path(data->base->buf, prefix, &sbuf);
-               quote_c_style(name, sb, NULL, 0);
-               strbuf_setlen(data->base, baselen);
-               strbuf_release(&sbuf);
-       } else {
-               errlen = (unsigned long)len;
-               die(_("bad ls-tree format: %%%.*s"), errlen, start);
-       }
-       return len;
-}
-
 static int show_recursive(struct ls_tree_options *options, const char *base,
                          size_t baselen, const char *pathname)
 {
@@ -150,14 +92,7 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
        int recurse = 0;
        struct strbuf sb = STRBUF_INIT;
        enum object_type type = object_type(mode);
-       struct show_tree_data cb_data = {
-               .options = options,
-               .mode = mode,
-               .type = type,
-               .oid = oid,
-               .pathname = pathname,
-               .base = base,
-       };
+       const char *format = options->format;
 
        if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
                recurse = READ_TREE_RECURSIVE;
@@ -166,7 +101,45 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
        if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
                return 0;
 
-       strbuf_expand(&sb, options->format, expand_show_tree, &cb_data);
+       while (strbuf_expand_step(&sb, &format)) {
+               const char *end;
+               size_t len;
+
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(&sb, '%');
+               else if ((len = strbuf_expand_literal(&sb, format)))
+                       format += len;
+               else if (*format != '(')
+                       die(_("bad ls-tree format: element '%s' "
+                             "does not start with '('"), format);
+               else if (!(end = strchr(format + 1, ')')))
+                       die(_("bad ls-tree format: element '%s' "
+                             "does not end in ')'"), format);
+               else if (skip_prefix(format, "(objectmode)", &format))
+                       strbuf_addf(&sb, "%06o", mode);
+               else if (skip_prefix(format, "(objecttype)", &format))
+                       strbuf_addstr(&sb, type_name(type));
+               else if (skip_prefix(format, "(objectsize:padded)", &format))
+                       expand_objectsize(&sb, oid, type, 1);
+               else if (skip_prefix(format, "(objectsize)", &format))
+                       expand_objectsize(&sb, oid, type, 0);
+               else if (skip_prefix(format, "(objectname)", &format))
+                       strbuf_add_unique_abbrev(&sb, oid, options->abbrev);
+               else if (skip_prefix(format, "(path)", &format)) {
+                       const char *name;
+                       const char *prefix = options->prefix;
+                       struct strbuf sbuf = STRBUF_INIT;
+                       size_t baselen = base->len;
+
+                       strbuf_addstr(base, pathname);
+                       name = relative_path(base->buf, prefix, &sbuf);
+                       quote_c_style(name, &sb, NULL, 0);
+                       strbuf_setlen(base, baselen);
+                       strbuf_release(&sbuf);
+               } else
+                       die(_("bad ls-tree format: %%%.*s"),
+                           (int)(end - format + 1), format);
+       }
        strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
        fwrite(sb.buf, sb.len, 1, stdout);
        strbuf_release(&sb);
@@ -198,7 +171,7 @@ static void show_tree_common_default_long(struct ls_tree_options *options,
                                          const char *pathname,
                                          const size_t baselen)
 {
-       const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
+       const char *prefix = options->prefix;
 
        strbuf_addstr(base, pathname);
 
@@ -268,7 +241,8 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
        return recurse;
 }
 
-static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+static int show_tree_name_only(const struct object_id *oid UNUSED,
+                              struct strbuf *base,
                               const char *pathname, unsigned mode,
                               void *context)
 {
@@ -283,7 +257,7 @@ static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
        if (early >= 0)
                return early;
 
-       prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
+       prefix = options->prefix;
        strbuf_addstr(base, pathname);
        if (options->null_termination) {
                struct strbuf sb = STRBUF_INIT;
@@ -370,6 +344,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
        struct object_id oid;
        struct tree *tree;
        int i, full_tree = 0;
+       int full_name = !prefix || !*prefix;
        read_tree_fn_t fn = NULL;
        enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
        int null_termination = 0;
@@ -391,8 +366,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                            MODE_NAME_STATUS),
                OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
                            MODE_OBJECT_ONLY),
-               OPT_SET_INT(0, "full-name", &options.chomp_prefix,
-                           N_("use full path names"), 0),
+               OPT_BOOL(0, "full-name", &full_name, N_("use full path names")),
                OPT_BOOL(0, "full-tree", &full_tree,
                         N_("list entire tree; not just current directory "
                            "(implies --full-name)")),
@@ -406,18 +380,15 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
        int ret;
 
        git_config(git_default_config, NULL);
-       options.ls_tree_prefix = prefix;
-       if (prefix)
-               options.chomp_prefix = strlen(prefix);
 
        argc = parse_options(argc, argv, prefix, ls_tree_options,
                             ls_tree_usage, 0);
        options.null_termination = null_termination;
 
-       if (full_tree) {
-               options.ls_tree_prefix = prefix = NULL;
-               options.chomp_prefix = 0;
-       }
+       if (full_tree)
+               prefix = NULL;
+       options.prefix = full_name ? NULL : prefix;
+
        /*
         * We wanted to detect conflicts between --name-only and
         * --name-status, but once we're done with that subsequent
index a032a1c3881cf4d35f72e8b714204647a3e06400..53b55dd71c0537b149860c4b9c0d505ea305fe57 100644 (file)
@@ -2,9 +2,8 @@
  * Another stupid program, this one parsing the headers of an
  * email to figure out authorship and subject
  */
-#include "cache.h"
-#include "abspath.h"
 #include "builtin.h"
+#include "abspath.h"
 #include "environment.h"
 #include "gettext.h"
 #include "utf8.h"
index 0b6193a0915a1fef572bb8a1148ae02f53ecf51c..3af9ddb8ae5c7e902937ada927590d908c193e0f 100644 (file)
@@ -4,7 +4,6 @@
  * It just splits a mbox into a list of files: "0001" "0002" ..
  * so you can process them further from there.
  */
-#include "cache.h"
 #include "builtin.h"
 #include "gettext.h"
 #include "string-list.h"
index 854019a32dcc63c9e2504f7aa9e96e7cd7a86762..e68b7fe45d77a9b032dd6031864b876eeeca5e5c 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "commit.h"
 #include "gettext.h"
index 781818d08f560714303889ff9eb002408307e244..d7eb4c654018e2bf8270ba90f1a3d945a261d025 100644 (file)
@@ -1,6 +1,5 @@
 #include "builtin.h"
 #include "abspath.h"
-#include "cache.h"
 #include "config.h"
 #include "gettext.h"
 #include "setup.h"
index ab16e70f23d532d769f074312352d15ead4ae893..270d5f644ac22e1a8a1b43b282b9ebf0f5cb12b0 100644 (file)
@@ -1,8 +1,10 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "hex.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "run-command.h"
+#include "sparse-index.h"
 
 static const char *pgm;
 static int one_shot, quiet;
index c2e519301e91cef4ac3204a37aa9e792c518c0f3..932924e5d0e573959e2d8c70168f77224de45bc8 100644 (file)
@@ -10,6 +10,7 @@
 #include "git-compat-util.h"
 #include "builtin.h"
 #include "diff.h"
+#include "repository.h"
 
 static const char builtin_merge_ours_usage[] =
        "git merge-ours <base>... -- HEAD <remote>...";
index b9e980384a4d72c228ddf9db84bfa76304f3ec2a..3366699657c9c390f850dfcba11be08327834f50 100644 (file)
@@ -1,4 +1,3 @@
-#include "cache.h"
 #include "builtin.h"
 #include "advice.h"
 #include "commit.h"
index b8f8a8b5d9fb15e9f1225b3650faa7124c869877..a35e0452d6672594da29623e8934256f37784549 100644 (file)
@@ -9,7 +9,7 @@
 #include "commit-reach.h"
 #include "merge-ort.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "parse-options.h"
 #include "repository.h"
 #include "blob.h"
@@ -18,6 +18,7 @@
 #include "quote.h"
 #include "tree.h"
 #include "config.h"
+#include "strvec.h"
 
 static int line_termination = '\n';
 
@@ -324,7 +325,9 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
  * The successful merge rules are the same as for the three-way merge
  * in git-read-tree.
  */
-static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *info)
+static int threeway_callback(int n UNUSED, unsigned long mask,
+                            unsigned long dirmask UNUSED,
+                            struct name_entry *entry, struct traverse_info *info)
 {
        /* Same in both? */
        if (same_entry(entry+1, entry+2) || both_empty(entry+1, entry+2)) {
@@ -412,6 +415,7 @@ struct merge_tree_options {
        int show_messages;
        int name_only;
        int use_stdin;
+       struct merge_options merge_options;
 };
 
 static int real_merge(struct merge_tree_options *o,
@@ -421,10 +425,11 @@ static int real_merge(struct merge_tree_options *o,
 {
        struct commit *parent1, *parent2;
        struct commit_list *merge_bases = NULL;
-       struct merge_options opt;
        struct merge_result result = { 0 };
        int show_messages = o->show_messages;
+       struct merge_options opt;
 
+       copy_merge_options(&opt, &o->merge_options);
        parent1 = get_merge_parent(branch1);
        if (!parent1)
                help_unknown_ref(branch1, "merge-tree",
@@ -435,8 +440,6 @@ static int real_merge(struct merge_tree_options *o,
                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;
@@ -448,7 +451,7 @@ static int real_merge(struct merge_tree_options *o,
 
                base_commit = lookup_commit_reference_by_name(merge_base);
                if (!base_commit)
-                       die(_("could not lookup commit %s"), merge_base);
+                       die(_("could not lookup commit '%s'"), merge_base);
 
                opt.ancestor = merge_base;
                base_tree = repo_get_commit_tree(the_repository, base_commit);
@@ -505,12 +508,14 @@ static int real_merge(struct merge_tree_options *o,
        if (o->use_stdin)
                putchar(line_termination);
        merge_finalize(&opt, &result);
+       clear_merge_options(&opt);
        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 };
+       struct strvec xopts = STRVEC_INIT;
        int expected_remaining_argc;
        int original_argc;
        const char *merge_base = NULL;
@@ -546,14 +551,25 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
                           &merge_base,
                           N_("commit"),
                           N_("specify a merge-base for the merge")),
+               OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+                       N_("option for selected merge strategy")),
                OPT_END()
        };
 
+       /* Init merge options */
+       init_merge_options(&o.merge_options, the_repository);
+
        /* 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);
 
+       if (xopts.nr && o.mode == MODE_TRIVIAL)
+               die(_("--trivial-merge is incompatible with all other options"));
+       for (int x = 0; x < xopts.nr; x++)
+               if (parse_merge_opt(&o.merge_options, xopts.v[x]))
+                       die(_("unknown strategy option: -X%s"), xopts.v[x]);
+
        /* Handle --stdin */
        if (o.use_stdin) {
                struct strbuf buf = STRBUF_INIT;
index 8da3e46abb0fdc692faac47e0b0deb9e13fe4194..d748d46e13517afd6908b1f7297bf448557b1a86 100644 (file)
@@ -7,10 +7,9 @@
  */
 
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "abspath.h"
 #include "advice.h"
-#include "alloc.h"
 #include "config.h"
 #include "editor.h"
 #include "environment.h"
@@ -18,7 +17,6 @@
 #include "hex.h"
 #include "object-name.h"
 #include "parse-options.h"
-#include "builtin.h"
 #include "lockfile.h"
 #include "run-command.h"
 #include "hook.h"
@@ -28,6 +26,7 @@
 #include "refspec.h"
 #include "commit.h"
 #include "diffcore.h"
+#include "path.h"
 #include "revision.h"
 #include "unpack-trees.h"
 #include "cache-tree.h"
@@ -37,6 +36,7 @@
 #include "color.h"
 #include "rerere.h"
 #include "help.h"
+#include "merge.h"
 #include "merge-recursive.h"
 #include "merge-ort-wrappers.h"
 #include "resolve-undo.h"
@@ -52,7 +52,6 @@
 #include "commit-reach.h"
 #include "wt-status.h"
 #include "commit-graph.h"
-#include "wrapper.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -80,8 +79,7 @@ static int overwrite_ignore = 1;
 static struct strbuf merge_msg = STRBUF_INIT;
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
-static const char **xopts;
-static size_t xopts_nr, xopts_alloc;
+static struct strvec xopts = STRVEC_INIT;
 static const char *branch;
 static char *branch_mergeoptions;
 static int verbosity;
@@ -233,7 +231,7 @@ static void append_strategy(struct strategy *s)
        use_strategies[use_strategies_nr++] = s;
 }
 
-static int option_parse_strategy(const struct option *opt,
+static int option_parse_strategy(const struct option *opt UNUSED,
                                 const char *name, int unset)
 {
        if (unset)
@@ -243,29 +241,9 @@ static int option_parse_strategy(const struct option *opt,
        return 0;
 }
 
-static int option_parse_x(const struct option *opt,
-                         const char *arg, int unset)
-{
-       if (unset)
-               return 0;
-
-       ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
-       xopts[xopts_nr++] = xstrdup(arg);
-       return 0;
-}
-
-static int option_parse_n(const struct option *opt,
-                         const char *arg, int unset)
-{
-       BUG_ON_OPT_ARG(arg);
-       show_diffstat = unset;
-       return 0;
-}
-
 static struct option builtin_merge_options[] = {
-       OPT_CALLBACK_F('n', NULL, NULL, NULL,
-               N_("do not show a diffstat at the end of the merge"),
-               PARSE_OPT_NOARG, option_parse_n),
+       OPT_SET_INT('n', NULL, &show_diffstat,
+               N_("do not show a diffstat at the end of the merge"), 0),
        OPT_BOOL(0, "stat", &show_diffstat,
                N_("show a diffstat at the end of the merge")),
        OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
@@ -286,10 +264,10 @@ static struct option builtin_merge_options[] = {
        OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
        OPT_BOOL(0, "verify-signatures", &verify_signatures,
                N_("verify that the named commit has a valid GPG signature")),
-       OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+       OPT_CALLBACK('s', "strategy", NULL, N_("strategy"),
                N_("merge strategy to use"), option_parse_strategy),
-       OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
-               N_("option for selected merge strategy"), option_parse_x),
+       OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+               N_("option for selected merge strategy")),
        OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
                N_("merge commit message (for a non-fast-forward merge)"),
                option_parse_message),
@@ -488,8 +466,7 @@ static void finish(struct commit *head_commit,
        if (new_head && show_diffstat) {
                struct diff_options opts;
                repo_diff_setup(the_repository, &opts);
-               opts.stat_width = -1; /* use full terminal width */
-               opts.stat_graph_width = -1; /* respect statGraphWidth config */
+               init_diffstat_widths(&opts);
                opts.output_format |=
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
@@ -623,7 +600,8 @@ static void parse_branch_merge_options(char *bmo)
        free(argv);
 }
 
-static int git_merge_config(const char *k, const char *v, void *cb)
+static int git_merge_config(const char *k, const char *v,
+                           const struct config_context *ctx, void *cb)
 {
        int status;
        const char *str;
@@ -668,10 +646,10 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return 0;
        }
 
-       status = fmt_merge_msg_config(k, v, cb);
+       status = fmt_merge_msg_config(k, v, ctx, cb);
        if (status)
                return status;
-       return git_diff_ui_config(k, v, cb);
+       return git_diff_ui_config(k, v, ctx, cb);
 }
 
 static int read_tree_trivial(struct object_id *common, struct object_id *head,
@@ -749,9 +727,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                o.show_rename_progress =
                        show_progress == -1 ? isatty(2) : show_progress;
 
-               for (x = 0; x < xopts_nr; x++)
-                       if (parse_merge_opt(&o, xopts[x]))
-                               die(_("unknown strategy option: -X%s"), xopts[x]);
+               for (x = 0; x < xopts.nr; x++)
+                       if (parse_merge_opt(&o, xopts.v[x]))
+                               die(_("unknown strategy option: -X%s"), xopts.v[x]);
 
                o.branch1 = head_arg;
                o.branch2 = merge_remote_util(remoteheads->item)->name;
@@ -777,7 +755,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                return clean ? 0 : 1;
        } else {
                return try_merge_command(the_repository,
-                                        strategy, xopts_nr, xopts,
+                                        strategy, xopts.nr, xopts.v,
                                         common, head_arg, remoteheads);
        }
 }
@@ -879,13 +857,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)
                strbuf_addch(&msg, '\n');
                if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
                        wt_status_append_cut_line(&msg);
-                       strbuf_commented_addf(&msg, "\n");
+                       strbuf_commented_addf(&msg, comment_line_char, "\n");
                }
-               strbuf_commented_addf(&msg, _(merge_editor_comment));
+               strbuf_commented_addf(&msg, comment_line_char,
+                                     _(merge_editor_comment));
                if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
-                       strbuf_commented_addf(&msg, _(scissors_editor_comment));
+                       strbuf_commented_addf(&msg, comment_line_char,
+                                             _(scissors_editor_comment));
                else
-                       strbuf_commented_addf(&msg,
+                       strbuf_commented_addf(&msg, comment_line_char,
                                _(no_scissors_editor_comment), comment_line_char);
        }
        if (signoff)
@@ -1652,6 +1632,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
                for (j = remoteheads; j; j = j->next) {
                        struct commit_list *common_one;
+                       struct commit *common_item;
 
                        /*
                         * Here we *have* to calculate the individual
@@ -1661,7 +1642,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        common_one = repo_get_merge_bases(the_repository,
                                                          head_commit,
                                                          j->item);
-                       if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
+                       common_item = common_one->item;
+                       free_commit_list(common_one);
+                       if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
                                up_to_date = 0;
                                break;
                        }
index 44fa56eff38c298f5444ff1c7dc5fdfdbd1adc7d..d8e0b5afc079d2f71383eed6881b733fea251312 100644 (file)
@@ -2,10 +2,11 @@
 #include "gettext.h"
 #include "hex.h"
 #include "parse-options.h"
+#include "strbuf.h"
 #include "tag.h"
 #include "replace-object.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "fsck.h"
 #include "config.h"
 
@@ -17,11 +18,11 @@ static int option_strict = 1;
 
 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
 
-static int mktag_fsck_error_func(struct fsck_options *o,
-                                const struct object_id *oid,
-                                enum object_type object_type,
+static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
+                                const struct object_id *oid UNUSED,
+                                enum object_type object_type UNUSED,
                                 enum fsck_msg_type msg_type,
-                                enum fsck_msg_id msg_id,
+                                enum fsck_msg_id msg_id UNUSED,
                                 const char *message)
 {
        switch (msg_type) {
index 09a7bd5c5c250fb22ca204932c6e00c50de62690..9a22d4e27735d55265fbf1a16cec8aeb66c27883 100644 (file)
@@ -4,13 +4,13 @@
  * Copyright (c) Junio C Hamano, 2006, 2009
  */
 #include "builtin.h"
-#include "alloc.h"
 #include "gettext.h"
 #include "hex.h"
 #include "quote.h"
+#include "strbuf.h"
 #include "tree.h"
 #include "parse-options.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 static struct treeent {
        unsigned mode;
index 1b5083f8b26cd8f15bf8e0ee0cadd38cc35fc5c6..a72aebecaa2f3aa96f802b635b4d55c5f122d56c 100644 (file)
@@ -1,13 +1,13 @@
 #include "builtin.h"
 #include "abspath.h"
-#include "cache.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "midx.h"
+#include "strbuf.h"
 #include "trace2.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 #define BUILTIN_MIDX_WRITE_USAGE \
        N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
@@ -82,6 +82,7 @@ static struct option *add_common_options(struct option *prev)
 }
 
 static int git_multi_pack_index_write_config(const char *var, const char *value,
+                                            const struct config_context *ctx UNUSED,
                                             void *cb UNUSED)
 {
        if (!strcmp(var, "pack.writebitmaphashcache")) {
index 665bd274485f6c76403e9230539e2650073a47f3..c596515ad0536f4b13ce2fdc2a797f6aaa9df70a 100644 (file)
@@ -7,10 +7,10 @@
 #include "builtin.h"
 #include "abspath.h"
 #include "advice.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
+#include "name-hash.h"
 #include "object-file.h"
 #include "pathspec.h"
 #include "lockfile.h"
@@ -18,6 +18,7 @@
 #include "cache-tree.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 #include "submodule.h"
@@ -183,7 +184,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        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 stat st, dest_st;
        struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
        struct lock_file lock_file = LOCK_INIT;
        struct cache_entry *ce;
@@ -303,8 +304,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                        goto act_on_entry;
                }
                if (S_ISDIR(st.st_mode)
-                   && lstat(dst, &st) == 0) {
-                       bad = _("cannot move directory over file");
+                   && lstat(dst, &dest_st) == 0) {
+                       bad = _("destination already exists");
                        goto act_on_entry;
                }
 
index 4d15a23fc4d52f6360708b07a7d55fa3e206d158..2dd1807c4e09f8dc7ff557c628fdd850dc653361 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
@@ -15,6 +14,7 @@
 #include "hash-lookup.h"
 #include "commit-slab.h"
 #include "commit-graph.h"
+#include "wildmatch.h"
 
 /*
  * One day.  See the 'name a rev shortly after epoch' test in t6120 when
@@ -582,12 +582,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
                OPT_BOOL(0, "always",     &always,
                           N_("show abbreviated commit object as fallback")),
-               {
-                       /* A Hidden OPT_BOOL */
-                       OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL,
-                       N_("dereference tags in the input (internal use)"),
-                       PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1,
-               },
+               OPT_HIDDEN_BOOL(0, "peel-tag", &peel_tag,
+                          N_("dereference tags in the input (internal use)")),
                OPT_END(),
        };
 
index d5788352b6ee7c69663ddf822134b55a36bf95b0..9f38863dd507ff680cf8a006b81a413d75550b1b 100644 (file)
@@ -7,15 +7,17 @@
  * and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
  */
 
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
+#include "alloc.h"
 #include "editor.h"
+#include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "notes.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
 #include "blob.h"
 #include "pretty.h"
 #include "worktree.h"
 #include "write-or-die.h"
 
+static const char *separator = "\n";
 static const char * const git_notes_usage[] = {
        N_("git notes [--ref <notes-ref>] [list [<object>]]"),
-       N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
        N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
-       N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
        N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
        N_("git notes [--ref <notes-ref>] show [<object>]"),
        N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
@@ -101,11 +104,26 @@ static const char * const git_notes_get_ref_usage[] = {
 static const char note_template[] =
        N_("Write/edit the notes for the following object:");
 
+enum notes_stripspace {
+       UNSPECIFIED = -1,
+       NO_STRIPSPACE = 0,
+       STRIPSPACE = 1,
+};
+
+struct note_msg {
+       enum notes_stripspace stripspace;
+       struct strbuf buf;
+};
+
 struct note_data {
        int given;
        int use_editor;
+       int stripspace;
        char *edit_path;
        struct strbuf buf;
+       struct note_msg **messages;
+       size_t msg_nr;
+       size_t msg_alloc;
 };
 
 static void free_note_data(struct note_data *d)
@@ -115,6 +133,12 @@ static void free_note_data(struct note_data *d)
                free(d->edit_path);
        }
        strbuf_release(&d->buf);
+
+       while (d->msg_nr--) {
+               strbuf_release(&d->messages[d->msg_nr]->buf);
+               free(d->messages[d->msg_nr]);
+       }
+       free(d->messages);
 }
 
 static int list_each_note(const struct object_id *object_oid,
@@ -157,7 +181,7 @@ static void write_commented_object(int fd, const struct object_id *object)
 
        if (strbuf_read(&buf, show.out, 0) < 0)
                die_errno(_("could not read 'show' output"));
-       strbuf_add_commented_lines(&cbuf, buf.buf, buf.len);
+       strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);
        write_or_die(fd, cbuf.buf, cbuf.len);
 
        strbuf_release(&cbuf);
@@ -185,9 +209,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
                        copy_obj_to_fd(fd, old_note);
 
                strbuf_addch(&buf, '\n');
-               strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
-               strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));
-               strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
+               strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+               strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
+                                          comment_line_char);
+               strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
                write_or_die(fd, buf.buf, buf.len);
 
                write_commented_object(fd, object);
@@ -199,7 +224,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
                if (launch_editor(d->edit_path, &d->buf, NULL)) {
                        die(_("please supply the note contents using either -m or -F option"));
                }
-               strbuf_stripspace(&d->buf, 1);
+               if (d->stripspace)
+                       strbuf_stripspace(&d->buf, comment_line_char);
        }
 }
 
@@ -215,66 +241,102 @@ static void write_note_data(struct note_data *d, struct object_id *oid)
        }
 }
 
+static void append_separator(struct strbuf *message)
+{
+       size_t sep_len = 0;
+
+       if (!separator)
+               return;
+       else if ((sep_len = strlen(separator)) && separator[sep_len - 1] == '\n')
+               strbuf_addstr(message, separator);
+       else
+               strbuf_addf(message, "%s%s", separator, "\n");
+}
+
+static void concat_messages(struct note_data *d)
+{
+       struct strbuf msg = STRBUF_INIT;
+       size_t i;
+
+       for (i = 0; i < d->msg_nr ; i++) {
+               if (d->buf.len)
+                       append_separator(&d->buf);
+               strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
+               strbuf_addbuf(&d->buf, &msg);
+               if ((d->stripspace == UNSPECIFIED &&
+                    d->messages[i]->stripspace == STRIPSPACE) ||
+                   d->stripspace == STRIPSPACE)
+                       strbuf_stripspace(&d->buf, 0);
+               strbuf_reset(&msg);
+       }
+       strbuf_release(&msg);
+}
+
 static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
 {
        struct note_data *d = opt->value;
+       struct note_msg *msg = xmalloc(sizeof(*msg));
 
        BUG_ON_OPT_NEG(unset);
 
-       strbuf_grow(&d->buf, strlen(arg) + 2);
-       if (d->buf.len)
-               strbuf_addch(&d->buf, '\n');
-       strbuf_addstr(&d->buf, arg);
-       strbuf_stripspace(&d->buf, 0);
-
-       d->given = 1;
+       strbuf_init(&msg->buf, strlen(arg));
+       strbuf_addstr(&msg->buf, arg);
+       ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+       d->messages[d->msg_nr - 1] = msg;
+       msg->stripspace = STRIPSPACE;
        return 0;
 }
 
 static int parse_file_arg(const struct option *opt, const char *arg, int unset)
 {
        struct note_data *d = opt->value;
+       struct note_msg *msg = xmalloc(sizeof(*msg));
 
        BUG_ON_OPT_NEG(unset);
 
-       if (d->buf.len)
-               strbuf_addch(&d->buf, '\n');
+       strbuf_init(&msg->buf , 0);
        if (!strcmp(arg, "-")) {
-               if (strbuf_read(&d->buf, 0, 1024) < 0)
+               if (strbuf_read(&msg->buf, 0, 1024) < 0)
                        die_errno(_("cannot read '%s'"), arg);
-       } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
+       } else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
                die_errno(_("could not open or read '%s'"), arg);
-       strbuf_stripspace(&d->buf, 0);
 
-       d->given = 1;
+       ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+       d->messages[d->msg_nr - 1] = msg;
+       msg->stripspace = STRIPSPACE;
        return 0;
 }
 
 static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
 {
        struct note_data *d = opt->value;
-       char *buf;
+       struct note_msg *msg = xmalloc(sizeof(*msg));
+       char *value;
        struct object_id object;
        enum object_type type;
        unsigned long len;
 
        BUG_ON_OPT_NEG(unset);
 
-       if (d->buf.len)
-               strbuf_addch(&d->buf, '\n');
-
+       strbuf_init(&msg->buf, 0);
        if (repo_get_oid(the_repository, arg, &object))
                die(_("failed to resolve '%s' as a valid ref."), arg);
-       if (!(buf = repo_read_object_file(the_repository, &object, &type, &len)))
+       if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
                die(_("failed to read object '%s'."), arg);
        if (type != OBJ_BLOB) {
-               free(buf);
+               strbuf_release(&msg->buf);
+               free(value);
+               free(msg);
                die(_("cannot read note data from non-blob object '%s'."), arg);
        }
-       strbuf_add(&d->buf, buf, len);
-       free(buf);
 
-       d->given = 1;
+       strbuf_add(&msg->buf, value, len);
+       free(value);
+
+       msg->buf.len = len;
+       ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+       d->messages[d->msg_nr - 1] = msg;
+       msg->stripspace = NO_STRIPSPACE;
        return 0;
 }
 
@@ -286,6 +348,16 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset
        return parse_reuse_arg(opt, arg, unset);
 }
 
+static int parse_separator_arg(const struct option *opt, const char *arg,
+                              int unset)
+{
+       if (unset)
+               *(const char **)opt->value = NULL;
+       else
+               *(const char **)opt->value = arg ? arg : "\n";
+       return 0;
+}
+
 static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
 {
        struct strbuf buf = STRBUF_INIT;
@@ -408,7 +480,8 @@ static int add(int argc, const char **argv, const char *prefix)
        struct notes_tree *t;
        struct object_id object, new_note;
        const struct object_id *note;
-       struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+       struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
+
        struct option options[] = {
                OPT_CALLBACK_F('m', "message", &d, N_("message"),
                        N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -425,6 +498,12 @@ static int add(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "allow-empty", &allow_empty,
                        N_("allow storing empty note")),
                OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
+               OPT_CALLBACK_F(0, "separator", &separator,
+                       N_("<paragraph-break>"),
+                       N_("insert <paragraph-break> between paragraphs"),
+                       PARSE_OPT_OPTARG, parse_separator_arg),
+               OPT_BOOL(0, "stripspace", &d.stripspace,
+                       N_("remove unnecessary whitespace")),
                OPT_END()
        };
 
@@ -436,6 +515,10 @@ static int add(int argc, const char **argv, const char *prefix)
                usage_with_options(git_notes_add_usage, options);
        }
 
+       if (d.msg_nr)
+               concat_messages(&d);
+       d.given = !!d.buf.len;
+
        object_ref = argc > 1 ? argv[1] : "HEAD";
 
        if (repo_get_oid(the_repository, object_ref, &object))
@@ -574,7 +657,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        const struct object_id *note;
        char *logmsg;
        const char * const *usage;
-       struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+       struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
        struct option options[] = {
                OPT_CALLBACK_F('m', "message", &d, N_("message"),
                        N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -590,6 +673,12 @@ static int append_edit(int argc, const char **argv, const char *prefix)
                        parse_reuse_arg),
                OPT_BOOL(0, "allow-empty", &allow_empty,
                        N_("allow storing empty note")),
+               OPT_CALLBACK_F(0, "separator", &separator,
+                       N_("<paragraph-break>"),
+                       N_("insert <paragraph-break> between paragraphs"),
+                       PARSE_OPT_OPTARG, parse_separator_arg),
+               OPT_BOOL(0, "stripspace", &d.stripspace,
+                       N_("remove unnecessary whitespace")),
                OPT_END()
        };
        int edit = !strcmp(argv[0], "edit");
@@ -603,6 +692,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
                usage_with_options(usage, options);
        }
 
+       if (d.msg_nr)
+               concat_messages(&d);
+       d.given = !!d.buf.len;
+
        if (d.given && edit)
                fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
                        "for the 'edit' subcommand.\n"
@@ -622,15 +715,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
                /* Append buf to previous note contents */
                unsigned long size;
                enum object_type type;
-               char *prev_buf = repo_read_object_file(the_repository, note,
-                                                      &type, &size);
+               struct strbuf buf = STRBUF_INIT;
+               char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
 
-               strbuf_grow(&d.buf, size + 1);
-               if (d.buf.len && prev_buf && size)
-                       strbuf_insertstr(&d.buf, 0, "\n");
                if (prev_buf && size)
-                       strbuf_insert(&d.buf, 0, prev_buf, size);
+                       strbuf_add(&buf, prev_buf, size);
+               if (d.buf.len && prev_buf && size)
+                       append_separator(&buf);
+               strbuf_insert(&d.buf, 0, buf.buf, buf.len);
+
                free(prev_buf);
+               strbuf_release(&buf);
        }
 
        if (d.buf.len || allow_empty) {
index 9cfc8801f9bb9aea42aa2031a0bc3f6a8963d89b..89a8b5a9768e42da3edaaddb63a663936ef70576 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
@@ -34,7 +33,7 @@
 #include "list.h"
 #include "packfile.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "replace-object.h"
 #include "dir.h"
 #include "midx.h"
@@ -43,7 +42,6 @@
 #include "promisor-remote.h"
 #include "pack-mtimes.h"
 #include "parse-options.h"
-#include "wrapper.h"
 
 /*
  * Objects we are going to pack are collected in the `to_pack` structure.
@@ -3135,26 +3133,27 @@ static void prepare_pack(int window, int depth)
        free(delta_list);
 }
 
-static int git_pack_config(const char *k, const char *v, void *cb)
+static int git_pack_config(const char *k, const char *v,
+                          const struct config_context *ctx, void *cb)
 {
        if (!strcmp(k, "pack.window")) {
-               window = git_config_int(k, v);
+               window = git_config_int(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "pack.windowmemory")) {
-               window_memory_limit = git_config_ulong(k, v);
+               window_memory_limit = git_config_ulong(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "pack.depth")) {
-               depth = git_config_int(k, v);
+               depth = git_config_int(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "pack.deltacachesize")) {
-               max_delta_cache_size = git_config_int(k, v);
+               max_delta_cache_size = git_config_int(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "pack.deltacachelimit")) {
-               cache_max_small_delta_size = git_config_int(k, v);
+               cache_max_small_delta_size = git_config_int(k, v, ctx->kvi);
                return 0;
        }
        if (!strcmp(k, "pack.writebitmaphashcache")) {
@@ -3180,7 +3179,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                return 0;
        }
        if (!strcmp(k, "pack.threads")) {
-               delta_search_threads = git_config_int(k, v);
+               delta_search_threads = git_config_int(k, v, ctx->kvi);
                if (delta_search_threads < 0)
                        die(_("invalid number of threads specified (%d)"),
                            delta_search_threads);
@@ -3191,7 +3190,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                return 0;
        }
        if (!strcmp(k, "pack.indexversion")) {
-               pack_idx_opts.version = git_config_int(k, v);
+               pack_idx_opts.version = git_config_int(k, v, ctx->kvi);
                if (pack_idx_opts.version > 2)
                        die(_("bad pack.indexVersion=%"PRIu32),
                            pack_idx_opts.version);
@@ -3227,7 +3226,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                ex->uri = xstrdup(pack_end + 1);
                oidmap_put(&configured_exclusions, ex);
        }
-       return git_default_config(k, v, cb);
+       return git_default_config(k, v, ctx, cb);
 }
 
 /* Counters for trace2 output when in --stdin-packs mode. */
@@ -3604,7 +3603,6 @@ static void read_cruft_objects(void)
                        string_list_append(&discard_packs, buf.buf + 1);
                else
                        string_list_append(&fresh_packs, buf.buf);
-               strbuf_reset(&buf);
        }
 
        string_list_sort(&discard_packs);
@@ -3740,7 +3738,7 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
        show_object(obj, name, data);
 }
 
-static int option_parse_missing_action(const struct option *opt,
+static int option_parse_missing_action(const struct option *opt UNUSED,
                                       const char *arg, int unset)
 {
        assert(arg);
@@ -4118,25 +4116,40 @@ static void add_extra_kept_packs(const struct string_list *names)
        }
 }
 
+static int option_parse_quiet(const struct option *opt, const char *arg,
+                             int unset)
+{
+       int *val = opt->value;
+
+       BUG_ON_OPT_ARG(arg);
+
+       if (!unset)
+               *val = 0;
+       else if (!*val)
+               *val = 1;
+       return 0;
+}
+
 static int option_parse_index_version(const struct option *opt,
                                      const char *arg, int unset)
 {
+       struct pack_idx_option *popts = opt->value;
        char *c;
        const char *val = arg;
 
        BUG_ON_OPT_NEG(unset);
 
-       pack_idx_opts.version = strtoul(val, &c, 10);
-       if (pack_idx_opts.version > 2)
+       popts->version = strtoul(val, &c, 10);
+       if (popts->version > 2)
                die(_("unsupported index version %s"), val);
        if (*c == ',' && c[1])
-               pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
-       if (*c || pack_idx_opts.off32_limit & 0x80000000)
+               popts->off32_limit = strtoul(c+1, &c, 0);
+       if (*c || popts->off32_limit & 0x80000000)
                die(_("bad index version '%s'"), val);
        return 0;
 }
 
-static int option_parse_unpack_unreachable(const struct option *opt,
+static int option_parse_unpack_unreachable(const struct option *opt UNUSED,
                                           const char *arg, int unset)
 {
        if (unset) {
@@ -4151,7 +4164,7 @@ static int option_parse_unpack_unreachable(const struct option *opt,
        return 0;
 }
 
-static int option_parse_cruft_expiration(const struct option *opt,
+static int option_parse_cruft_expiration(const struct option *opt UNUSED,
                                         const char *arg, int unset)
 {
        if (unset) {
@@ -4179,8 +4192,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                LIST_OBJECTS_FILTER_INIT;
 
        struct option pack_objects_options[] = {
-               OPT_SET_INT('q', "quiet", &progress,
-                           N_("do not show progress meter"), 0),
+               OPT_CALLBACK_F('q', "quiet", &progress, NULL,
+                              N_("do not show progress meter"),
+                              PARSE_OPT_NOARG, option_parse_quiet),
                OPT_SET_INT(0, "progress", &progress,
                            N_("show progress meter"), 1),
                OPT_SET_INT(0, "all-progress", &progress,
@@ -4188,7 +4202,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "all-progress-implied",
                         &all_progress_implied,
                         N_("similar to --all-progress when progress meter is shown")),
-               OPT_CALLBACK_F(0, "index-version", NULL, N_("<version>[,<offset>]"),
+               OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"),
                  N_("write the pack index file in the specified idx format version"),
                  PARSE_OPT_NONEG, option_parse_index_version),
                OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
@@ -4256,8 +4270,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                                N_("ignore this pack")),
                OPT_INTEGER(0, "compression", &pack_compression_level,
                            N_("pack compression level")),
-               OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
-                           N_("do not hide commits by grafts"), 0),
+               OPT_BOOL(0, "keep-true-parents", &grafts_keep_true_parents,
+                        N_("do not hide commits by grafts")),
                OPT_BOOL(0, "use-bitmap-index", &use_bitmap_index,
                         N_("use a bitmap index if available to speed up counting objects")),
                OPT_SET_INT(0, "write-bitmap-index", &write_bitmap_index,
@@ -4284,7 +4298,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
                BUG("too many dfs states, increase OE_DFS_STATE_BITS");
 
-       read_replace_refs = 0;
+       disable_replace_refs();
 
        sparse = git_env_bool("GIT_TEST_PACK_SPARSE", -1);
        if (the_repository->gitdir) {
@@ -4371,7 +4385,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 
        if (!HAVE_THREADS && delta_search_threads != 1)
                warning(_("no threads support, ignoring --threads"));
-       if (!pack_to_stdout && !pack_size_limit && !cruft)
+       if (!pack_to_stdout && !pack_size_limit)
                pack_size_limit = pack_size_limit_cfg;
        if (pack_to_stdout && pack_size_limit)
                die(_("--max-pack-size cannot be used to build a pack for transfer"));
@@ -4388,12 +4402,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (!rev_list_all || !rev_list_reflog || !rev_list_index)
                unpack_unreachable_expiration = 0;
 
-       if (filter_options.choice) {
-               if (!pack_to_stdout)
-                       die(_("cannot use --filter without --stdout"));
-               if (stdin_packs)
-                       die(_("cannot use --filter with --stdin-packs"));
-       }
+       if (stdin_packs && filter_options.choice)
+               die(_("cannot use --filter with --stdin-packs"));
 
        if (stdin_packs && use_internal_rev_list)
                die(_("cannot use internal rev list with --stdin-packs"));
@@ -4403,8 +4413,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        die(_("cannot use internal rev list with --cruft"));
                if (stdin_packs)
                        die(_("cannot use --stdin-packs with --cruft"));
-               if (pack_size_limit)
-                       die(_("cannot use --max-pack-size with --cruft"));
        }
 
        /*
index 43e9d12dfdc2075efd9f3aab5e0f4d38a5ad73a4..4c735ba069caf6626791d85741f78c3869a5c89d 100644 (file)
@@ -11,7 +11,7 @@
 #include "hex.h"
 #include "repository.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 #define BLKSIZE 512
 
index 9833815fb30a3aae55c9512dc53094d1862e4be6..bcf383cac9dd875354d3c91152f7b8d635f82ff4 100644 (file)
@@ -4,22 +4,45 @@
 #include "parse-options.h"
 #include "refs.h"
 #include "repository.h"
+#include "revision.h"
 
 static char const * const pack_refs_usage[] = {
-       N_("git pack-refs [--all] [--no-prune]"),
+       N_("git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]"),
        NULL
 };
 
 int cmd_pack_refs(int argc, const char **argv, const char *prefix)
 {
        unsigned int flags = PACK_REFS_PRUNE;
+       static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
+       static struct string_list included_refs = STRING_LIST_INIT_NODUP;
+       struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
+                                                .includes = &included_refs,
+                                                .flags = flags };
+       static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
+       struct string_list_item *item;
+
        struct option opts[] = {
-               OPT_BIT(0, "all",   &flags, N_("pack everything"), PACK_REFS_ALL),
-               OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+               OPT_BIT(0, "all",   &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
+               OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+               OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
+                       N_("references to include")),
+               OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
+                       N_("references to exclude")),
                OPT_END(),
        };
        git_config(git_default_config, NULL);
        if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
                usage_with_options(pack_refs_usage, opts);
-       return refs_pack_refs(get_main_ref_store(the_repository), flags);
+
+       for_each_string_list_item(item, &option_excluded_refs)
+               add_ref_exclusion(pack_refs_opts.exclusions, item->string);
+
+       if (pack_refs_opts.flags & PACK_REFS_ALL)
+               string_list_append(pack_refs_opts.includes, "*");
+
+       if (!pack_refs_opts.includes->nr)
+               string_list_append(pack_refs_opts.includes, "refs/tags/*");
+
+       return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
 }
index 9d5585d3a72459725c14598738faa73529175b81..3894d2b970612cab4a47250dd53da5b0908c820e 100644 (file)
@@ -1,8 +1,8 @@
-#include "cache.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "parse-options.h"
 
@@ -196,7 +196,8 @@ struct patch_id_opts {
        int verbatim;
 };
 
-static int git_patch_id_config(const char *var, const char *value, void *cb)
+static int git_patch_id_config(const char *var, const char *value,
+                              const struct config_context *ctx, void *cb)
 {
        struct patch_id_opts *opts = cb;
 
@@ -209,7 +210,7 @@ static int git_patch_id_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 int cmd_patch_id(int argc, const char **argv, const char *prefix)
index 5dc9b20720006700584069a3b6aa1211088ff5d7..57fe31467fe5ac9768f1b04f7c7e6dd3e9409468 100644 (file)
@@ -1,19 +1,20 @@
-#include "cache.h"
+#include "builtin.h"
 #include "commit.h"
 #include "diff.h"
+#include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "revision.h"
-#include "builtin.h"
 #include "reachable.h"
 #include "parse-options.h"
+#include "path.h"
 #include "progress.h"
 #include "prune-packed.h"
 #include "replace-object.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "shallow.h"
 
 static const char * const prune_usage[] = {
@@ -164,7 +165,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 
        expire = TIME_MAX;
        save_commit_buffer = 0;
-       read_replace_refs = 0;
+       disable_replace_refs();
        repo_init_revisions(the_repository, &revs, prefix);
 
        argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
index 0c7bac97b75b5e8685d45a3a653f3348d7702c6a..be2b2c9ebc97b2a1620b93e1766e0ccfa6c7843a 100644 (file)
@@ -6,12 +6,12 @@
  * Fetch one or more remote refs and merge it/them into the current HEAD.
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "advice.h"
 #include "config.h"
-#include "builtin.h"
 #include "gettext.h"
 #include "hex.h"
+#include "merge.h"
 #include "object-name.h"
 #include "parse-options.h"
 #include "exec-cmd.h"
@@ -19,6 +19,8 @@
 #include "oid-array.h"
 #include "remote.h"
 #include "dir.h"
+#include "path.h"
+#include "read-cache-ll.h"
 #include "rebase.h"
 #include "refs.h"
 #include "refspec.h"
@@ -361,7 +363,8 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
 /**
  * Read config variables.
  */
-static int git_pull_config(const char *var, const char *value, void *cb)
+static int git_pull_config(const char *var, const char *value,
+                          const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "rebase.autostash")) {
                config_autostash = git_config_bool(var, value);
@@ -374,7 +377,7 @@ static int git_pull_config(const char *var, const char *value, void *cb)
                check_trust_level = 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 /**
index dbdf609daf33172cb95ff082f3e23edb88c3d806..2e708383c24ba86e07fc14b0139afb28d489c014 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "git push"
  */
-#include "cache.h"
+#include "builtin.h"
 #include "advice.h"
 #include "branch.h"
 #include "config.h"
@@ -10,7 +10,6 @@
 #include "refs.h"
 #include "refspec.h"
 #include "run-command.h"
-#include "builtin.h"
 #include "remote.h"
 #include "transport.h"
 #include "parse-options.h"
@@ -302,21 +301,21 @@ static void setup_default_push_refspecs(int *flags, struct remote *remote)
 
 static const char message_advice_pull_before_push[] =
        N_("Updates were rejected because the tip of your current branch is behind\n"
-          "its remote counterpart. Integrate the remote changes (e.g.\n"
-          "'git pull ...') before pushing again.\n"
+          "its remote counterpart. If you want to integrate the remote changes,\n"
+          "use 'git pull' before pushing again.\n"
           "See the 'Note about fast-forwards' in 'git push --help' for details.");
 
 static const char message_advice_checkout_pull_push[] =
        N_("Updates were rejected because a pushed branch tip is behind its remote\n"
-          "counterpart. Check out this branch and integrate the remote changes\n"
-          "(e.g. 'git pull ...') before pushing again.\n"
+          "counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+          "before pushing again.\n"
           "See the 'Note about fast-forwards' in 'git push --help' for details.");
 
 static const char message_advice_ref_fetch_first[] =
-       N_("Updates were rejected because the remote contains work that you do\n"
-          "not have locally. This is usually caused by another repository pushing\n"
-          "to the same ref. You may want to first integrate the remote changes\n"
-          "(e.g., 'git pull ...') before pushing again.\n"
+       N_("Updates were rejected because the remote contains work that you do not\n"
+          "have locally. This is usually caused by another repository pushing to\n"
+          "the same ref. If you want to integrate the remote changes, use\n"
+          "'git pull' before pushing again.\n"
           "See the 'Note about fast-forwards' in 'git push --help' for details.");
 
 static const char message_advice_ref_already_exists[] =
@@ -328,10 +327,10 @@ static const char message_advice_ref_needs_force[] =
           "without using the '--force' option.\n");
 
 static const char message_advice_ref_needs_update[] =
-       N_("Updates were rejected because the tip of the remote-tracking\n"
-          "branch has been updated since the last checkout. You may want\n"
-          "to integrate those changes locally (e.g., 'git pull ...')\n"
-          "before forcing an update.\n");
+       N_("Updates were rejected because the tip of the remote-tracking branch has\n"
+          "been updated since the last checkout. If you want to integrate the\n"
+          "remote changes, use 'git pull' before pushing again.\n"
+          "See the 'Note about fast-forwards' in 'git push --help' for details.");
 
 static void advise_pull_before_push(void)
 {
@@ -510,7 +509,8 @@ static void set_push_cert_flags(int *flags, int v)
 }
 
 
-static int git_push_config(const char *k, const char *v, void *cb)
+static int git_push_config(const char *k, const char *v,
+                          const struct config_context *ctx, void *cb)
 {
        const char *slot_name;
        int *flags = cb;
@@ -577,7 +577,7 @@ static int git_push_config(const char *k, const char *v, void *cb)
                return 0;
        }
 
-       return git_default_config(k, v, NULL);
+       return git_default_config(k, v, ctx, NULL);
 }
 
 int cmd_push(int argc, const char **argv, const char *prefix)
@@ -627,10 +627,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                                PARSE_OPT_OPTARG, option_parse_push_signed),
                OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
                OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
-               OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
-                               TRANSPORT_FAMILY_IPV4),
-               OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
-                               TRANSPORT_FAMILY_IPV6),
+               OPT_IPVERSION(&family),
                OPT_END()
        };
 
index 04339a92ea5d1a62df2aa63b73619c2a6c2167ae..e455a4795cc8101576a806ee68df71a56c7661ce 100644 (file)
@@ -1,10 +1,10 @@
-#include "cache.h"
 #include "builtin.h"
 #include "gettext.h"
 #include "object-name.h"
 #include "parse-options.h"
 #include "range-diff.h"
 #include "config.h"
+#include "repository.h"
 #include "revision.h"
 
 static const char * const builtin_range_diff_usage[] = {
index 440f19b1b8759a0852bb9c244fb79536ee94f859..8196ca9dd85828890cf5e7088d19e51990a00c66 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "dir.h"
-#include "builtin.h"
 #include "parse-options.h"
 #include "repository.h"
 #include "resolve-undo.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule.h"
 #include "submodule-config.h"
 
@@ -49,7 +49,7 @@ static const char * const read_tree_usage[] = {
        NULL
 };
 
-static int index_output_cb(const struct option *opt, const char *arg,
+static int index_output_cb(const struct option *opt UNUSED, const char *arg,
                                 int unset)
 {
        BUG_ON_OPT_NEG(unset);
@@ -102,12 +102,13 @@ static int debug_merge(const struct cache_entry * const *stages,
        return 0;
 }
 
-static int git_read_tree_config(const char *var, const char *value, void *cb)
+static int git_read_tree_config(const char *var, const char *value,
+                               const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "submodule.recurse"))
                return git_default_submodule_config(var, value, cb);
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
index ace1d5e8d11afee64ce0e400867b97b627282f2f..043c65dccd9f19667a1eb6af993dfb9c1f4d8669 100644 (file)
@@ -24,6 +24,7 @@
 #include "object-file.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "path.h"
 #include "commit.h"
 #include "diff.h"
 #include "wt-status.h"
@@ -36,7 +37,6 @@
 #include "reset.h"
 #include "trace2.h"
 #include "hook.h"
-#include "wrapper.h"
 
 static char const * const builtin_rebase_usage[] = {
        N_("git rebase [-i] [options] [--exec <cmd>] "
@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)
        if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
                return error_errno(_("could not read '%s'."), todo_file);
 
-       strbuf_stripspace(&todo_list.buf, 1);
+       strbuf_stripspace(&todo_list.buf, comment_line_char);
        res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
        if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
                                            NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
@@ -376,20 +376,6 @@ static int run_sequencer_rebase(struct rebase_options *opts)
        return ret;
 }
 
-static void imply_merge(struct rebase_options *opts, const char *option);
-static int parse_opt_keep_empty(const struct option *opt, const char *arg,
-                               int unset)
-{
-       struct rebase_options *opts = opt->value;
-
-       BUG_ON_OPT_ARG(arg);
-
-       imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
-       opts->keep_empty = !unset;
-       opts->type = REBASE_MERGE;
-       return 0;
-}
-
 static int is_merge(struct rebase_options *opts)
 {
        return opts->type == REBASE_MERGE;
@@ -772,7 +758,8 @@ static void parse_rebase_merges_value(struct rebase_options *options, const char
                die(_("Unknown rebase-merges mode: %s"), value);
 }
 
-static int rebase_config(const char *var, const char *value, void *data)
+static int rebase_config(const char *var, const char *value,
+                        const struct config_context *ctx, void *data)
 {
        struct rebase_options *opts = data;
 
@@ -831,7 +818,7 @@ static int rebase_config(const char *var, const char *value, void *data)
                return git_config_string(&opts->default_backend, var, value);
        }
 
-       return git_default_config(var, value, data);
+       return git_default_config(var, value, ctx, data);
 }
 
 static int checkout_up_to_date(struct rebase_options *options)
@@ -982,6 +969,18 @@ static enum empty_type parse_empty_value(const char *value)
        die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), value);
 }
 
+static int parse_opt_keep_empty(const struct option *opt, const char *arg,
+                               int unset)
+{
+       struct rebase_options *opts = opt->value;
+
+       BUG_ON_OPT_ARG(arg);
+
+       imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
+       opts->keep_empty = !unset;
+       return 0;
+}
+
 static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
 {
        struct rebase_options *options = opt->value;
@@ -1146,7 +1145,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                                 "instead of ignoring them"),
                              1, PARSE_OPT_HIDDEN),
                OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
-               OPT_CALLBACK_F(0, "empty", &options, "{drop,keep,ask}",
+               OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|ask)",
                               N_("how to handle commits that become empty"),
                               PARSE_OPT_NONEG, parse_opt_empty),
                OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
@@ -1490,23 +1489,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
        if (options.strategy) {
                options.strategy = xstrdup(options.strategy);
-               switch (options.type) {
-               case REBASE_APPLY:
-                       die(_("--strategy requires --merge or --interactive"));
-               case REBASE_MERGE:
-                       /* compatible */
-                       break;
-               case REBASE_UNSPECIFIED:
-                       options.type = REBASE_MERGE;
-                       break;
-               default:
-                       BUG("unhandled rebase type (%d)", options.type);
-               }
+               imply_merge(&options, "--strategy");
        }
 
-       if (options.type == REBASE_MERGE)
-               imply_merge(&options, "--merge");
-
        if (options.root && !options.onto_name)
                imply_merge(&options, "--root without --onto");
 
@@ -1551,7 +1536,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
        if (options.type == REBASE_UNSPECIFIED) {
                if (!strcmp(options.default_backend, "merge"))
-                       imply_merge(&options, "--merge");
+                       options.type = REBASE_MERGE;
                else if (!strcmp(options.default_backend, "apply"))
                        options.type = REBASE_APPLY;
                else
@@ -1802,8 +1787,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
                /* We want color (if set), but no pager */
                repo_diff_setup(the_repository, &opts);
-               opts.stat_width = -1; /* use full terminal width */
-               opts.stat_graph_width = -1; /* respect statGraphWidth config */
+               init_diffstat_widths(&opts);
                opts.output_format |=
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
index 1a31a583674bcef24c4c33b3fa8806bac9bf7843..8c4f0cb90a936b2b24b8b7b9e8b1b789c33bff51 100644 (file)
@@ -30,7 +30,8 @@
 #include "oidset.h"
 #include "packfile.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "protocol.h"
 #include "commit-reach.h"
 #include "server-info.h"
@@ -39,7 +40,6 @@
 #include "worktree.h"
 #include "shallow.h"
 #include "parse-options.h"
-#include "wrapper.h"
 
 static const char * const receive_pack_usage[] = {
        N_("git receive-pack <git-dir>"),
@@ -90,7 +90,7 @@ static struct object_id push_cert_oid;
 static struct signature_check sigcheck;
 static const char *push_cert_nonce;
 static const char *cert_nonce_seed;
-static struct string_list hidden_refs = STRING_LIST_INIT_DUP;
+static struct strvec hidden_refs = STRVEC_INIT;
 
 static const char *NONCE_UNSOLICITED = "UNSOLICITED";
 static const char *NONCE_BAD = "BAD";
@@ -139,7 +139,8 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
        return DENY_IGNORE;
 }
 
-static int receive_pack_config(const char *var, const char *value, void *cb)
+static int receive_pack_config(const char *var, const char *value,
+                              const struct config_context *ctx, void *cb)
 {
        int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
 
@@ -157,12 +158,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
        }
 
        if (strcmp(var, "receive.unpacklimit") == 0) {
-               receive_unpack_limit = git_config_int(var, value);
+               receive_unpack_limit = git_config_int(var, value, ctx->kvi);
                return 0;
        }
 
        if (strcmp(var, "transfer.unpacklimit") == 0) {
-               transfer_unpack_limit = git_config_int(var, value);
+               transfer_unpack_limit = git_config_int(var, value, ctx->kvi);
                return 0;
        }
 
@@ -230,7 +231,7 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
                return git_config_string(&cert_nonce_seed, var, value);
 
        if (strcmp(var, "receive.certnonceslop") == 0) {
-               nonce_stamp_slop_limit = git_config_ulong(var, value);
+               nonce_stamp_slop_limit = git_config_ulong(var, value, ctx->kvi);
                return 0;
        }
 
@@ -245,12 +246,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
        }
 
        if (strcmp(var, "receive.keepalive") == 0) {
-               keepalive_in_sec = git_config_int(var, value);
+               keepalive_in_sec = git_config_int(var, value, ctx->kvi);
                return 0;
        }
 
        if (strcmp(var, "receive.maxinputsize") == 0) {
-               max_input_size = git_config_int64(var, value);
+               max_input_size = git_config_int64(var, value, ctx->kvi);
                return 0;
        }
 
@@ -266,7 +267,7 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static void show_ref(const char *path, const struct object_id *oid)
@@ -337,7 +338,9 @@ static void write_head_info(void)
 {
        static struct oidset seen = OIDSET_INIT;
 
-       for_each_ref(show_ref_cb, &seen);
+       refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
+                                hidden_refs_to_excludes(&hidden_refs),
+                                show_ref_cb, &seen);
        for_each_alternate_ref(show_one_alternate_ref, &seen);
        oidset_clear(&seen);
        if (!sent_capabilities)
@@ -2524,10 +2527,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        if (cert_nonce_seed)
                push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
 
-       if (0 <= transfer_unpack_limit)
-               unpack_limit = transfer_unpack_limit;
-       else if (0 <= receive_unpack_limit)
+       if (0 <= receive_unpack_limit)
                unpack_limit = receive_unpack_limit;
+       else if (0 <= transfer_unpack_limit)
+               unpack_limit = transfer_unpack_limit;
 
        switch (determine_protocol_version_server()) {
        case protocol_v2:
@@ -2619,7 +2622,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                packet_flush(1);
        oid_array_clear(&shallow);
        oid_array_clear(&ref);
-       string_list_clear(&hidden_refs, 0);
+       strvec_clear(&hidden_refs);
        free((void *)push_cert_nonce);
        return 0;
 }
index a1fa0c855f4ae74188e5e258c8a7b0f9ba57ed19..21337292f5206726a1de7b3cbbef8a9d7cb88d4a 100644 (file)
@@ -1,8 +1,10 @@
 #include "builtin.h"
 #include "config.h"
 #include "gettext.h"
+#include "repository.h"
 #include "revision.h"
 #include "reachable.h"
+#include "wildmatch.h"
 #include "worktree.h"
 #include "reflog.h"
 #include "parse-options.h"
@@ -108,7 +110,8 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
 #define EXPIRE_TOTAL   01
 #define EXPIRE_UNREACH 02
 
-static int reflog_expire_config(const char *var, const char *value, void *cb)
+static int reflog_expire_config(const char *var, const char *value,
+                               const struct config_context *ctx, void *cb)
 {
        const char *pattern, *key;
        size_t pattern_len;
@@ -117,7 +120,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
        struct reflog_expire_cfg *ent;
 
        if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
-               return git_default_config(var, value, cb);
+               return git_default_config(var, value, ctx, cb);
 
        if (!strcmp(key, "reflogexpire")) {
                slot = EXPIRE_TOTAL;
@@ -128,7 +131,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
                if (git_config_expiry_date(&expire, var, value))
                        return -1;
        } else
-               return git_default_config(var, value, cb);
+               return git_default_config(var, value, ctx, cb);
 
        if (!pattern) {
                switch (slot) {
@@ -240,7 +243,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 {
        struct cmd_reflog_expire_cb cmd = { 0 };
        timestamp_t now = time(NULL);
-       int i, status, do_all, all_worktrees = 1;
+       int i, status, do_all, single_worktree = 0;
        unsigned int flags = 0;
        int verbose = 0;
        reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
@@ -265,7 +268,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "stale-fix", &cmd.stalefix,
                         N_("prune any reflog entries that point to broken commits")),
                OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
-               OPT_BOOL(1, "single-worktree", &all_worktrees,
+               OPT_BOOL(0, "single-worktree", &single_worktree,
                         N_("limits processing to reflogs from the current worktree only")),
                OPT_END()
        };
@@ -315,7 +318,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 
                worktrees = get_worktrees();
                for (p = worktrees; *p; p++) {
-                       if (!all_worktrees && !(*p)->is_current)
+                       if (single_worktree && !(*p)->is_current)
                                continue;
                        collected.worktree = *p;
                        refs_for_each_reflog(get_worktree_ref_store(*p),
index 1e0b137d977bb74da381cf173f82e25c5c548537..d91bbe728d739e074e5f4fa54f70c186f371c1b7 100644 (file)
@@ -2,6 +2,7 @@
 #include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
+#include "path.h"
 #include "transport.h"
 #include "remote.h"
 #include "string-list.h"
@@ -10,7 +11,7 @@
 #include "rebase.h"
 #include "refs.h"
 #include "refspec.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "strvec.h"
 #include "commit-reach.h"
 #include "progress.h"
@@ -167,10 +168,9 @@ static int add(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
                OPT_SET_INT(0, "tags", &fetch_tags,
-                           N_("import all tags and associated objects when fetching"),
+                           N_("import all tags and associated objects when fetching\n"
+                              "or do not fetch any tag at all (--no-tags)"),
                            TAGS_SET),
-               OPT_SET_INT(0, NULL, &fetch_tags,
-                           N_("or do not fetch any tag at all (--no-tags)"), TAGS_UNSET),
                OPT_STRING_LIST('t', "track", &track, N_("branch"),
                                N_("branch(es) to track")),
                OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
@@ -268,6 +268,7 @@ 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,
+                               const struct config_context *ctx UNUSED,
                                void *data UNUSED)
 {
        const char *orig_key = key;
@@ -645,17 +646,19 @@ struct push_default_info
 };
 
 static int config_read_push_default(const char *key, const char *value,
-       void *cb)
+       const struct config_context *ctx, void *cb)
 {
+       const struct key_value_info *kvi = ctx->kvi;
+
        struct push_default_info* info = cb;
        if (strcmp(key, "remote.pushdefault") ||
            !value || strcmp(value, info->old_name))
                return 0;
 
-       info->scope = current_config_scope();
+       info->scope = kvi->scope;
        strbuf_reset(&info->origin);
-       strbuf_addstr(&info->origin, current_config_name());
-       info->linenr = current_config_line();
+       strbuf_addstr(&info->origin, config_origin_type_name(kvi->origin_type));
+       info->linenr = kvi->linenr;
 
        return 0;
 }
@@ -1494,7 +1497,9 @@ static int prune(int argc, const char **argv, const char *prefix)
        return result;
 }
 
-static int get_remote_default(const char *key, const char *value UNUSED, void *priv)
+static int get_remote_default(const char *key, const char *value UNUSED,
+                             const struct config_context *ctx UNUSED,
+                             void *priv)
 {
        if (strcmp(key, "remotes.default") == 0) {
                int *found = priv;
index 0541c3ce1576c7faf7806c03e6193d01d719fd88..edaee4dbec7b01624b5d272a7c402c49f46dba5d 100644 (file)
@@ -1,11 +1,11 @@
 #include "builtin.h"
-#include "alloc.h"
 #include "config.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "parse-options.h"
+#include "path.h"
 #include "run-command.h"
 #include "server-info.h"
 #include "sigchain.h"
 #include "midx.h"
 #include "packfile.h"
 #include "prune-packed.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "promisor-remote.h"
 #include "shallow.h"
 #include "pack.h"
 #include "pack-bitmap.h"
 #include "refs.h"
+#include "list-objects-filter-options.h"
 
 #define ALL_INTO_ONE 1
 #define LOOSEN_UNREACHABLE 2
 #define PACK_CRUFT 4
 
 #define DELETE_PACK 1
-#define CRUFT_PACK 2
+#define RETAIN_PACK 2
 
 static int pack_everything;
 static int delta_base_offset = 1;
@@ -52,14 +53,16 @@ struct pack_objects_args {
        const char *window_memory;
        const char *depth;
        const char *threads;
-       const char *max_pack_size;
+       unsigned long max_pack_size;
        int no_reuse_delta;
        int no_reuse_object;
        int quiet;
        int local;
+       struct list_objects_filter_options filter_options;
 };
 
-static int repack_config(const char *var, const char *value, void *cb)
+static int repack_config(const char *var, const char *value,
+                        const struct config_context *ctx, void *cb)
 {
        struct pack_objects_args *cruft_po_args = cb;
        if (!strcmp(var, "repack.usedeltabaseoffset")) {
@@ -91,53 +94,102 @@ static int repack_config(const char *var, const char *value, void *cb)
                return git_config_string(&cruft_po_args->depth, var, value);
        if (!strcmp(var, "repack.cruftthreads"))
                return git_config_string(&cruft_po_args->threads, var, value);
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
-/*
- * Adds all packs hex strings to either fname_nonkept_list or
- * fname_kept_list based on whether each pack has a corresponding
- * .keep file or not.  Packs without a .keep file are not to be kept
- * if we are going to pack everything into one file.
- */
-static void collect_pack_filenames(struct string_list *fname_nonkept_list,
-                                  struct string_list *fname_kept_list,
-                                  const struct string_list *extra_keep)
+struct existing_packs {
+       struct string_list kept_packs;
+       struct string_list non_kept_packs;
+       struct string_list cruft_packs;
+};
+
+#define EXISTING_PACKS_INIT { \
+       .kept_packs = STRING_LIST_INIT_DUP, \
+       .non_kept_packs = STRING_LIST_INIT_DUP, \
+       .cruft_packs = STRING_LIST_INIT_DUP, \
+}
+
+static int has_existing_non_kept_packs(const struct existing_packs *existing)
 {
-       DIR *dir;
-       struct dirent *e;
-       char *fname;
+       return existing->non_kept_packs.nr || existing->cruft_packs.nr;
+}
 
-       if (!(dir = opendir(packdir)))
-               return;
+static void pack_mark_for_deletion(struct string_list_item *item)
+{
+       item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
+}
 
-       while ((e = readdir(dir)) != NULL) {
-               size_t len;
-               int i;
+static void pack_unmark_for_deletion(struct string_list_item *item)
+{
+       item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
+}
 
-               if (!strip_suffix(e->d_name, ".pack", &len))
-                       continue;
+static int pack_is_marked_for_deletion(struct string_list_item *item)
+{
+       return (uintptr_t)item->util & DELETE_PACK;
+}
 
-               for (i = 0; i < extra_keep->nr; i++)
-                       if (!fspathcmp(e->d_name, extra_keep->items[i].string))
-                               break;
+static void pack_mark_retained(struct string_list_item *item)
+{
+       item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
+}
 
-               fname = xmemdupz(e->d_name, len);
+static int pack_is_retained(struct string_list_item *item)
+{
+       return (uintptr_t)item->util & RETAIN_PACK;
+}
 
-               if ((extra_keep->nr > 0 && i < extra_keep->nr) ||
-                   (file_exists(mkpath("%s/%s.keep", packdir, fname)))) {
-                       string_list_append_nodup(fname_kept_list, fname);
-               } else {
-                       struct string_list_item *item;
-                       item = string_list_append_nodup(fname_nonkept_list,
-                                                       fname);
-                       if (file_exists(mkpath("%s/%s.mtimes", packdir, fname)))
-                               item->util = (void*)(uintptr_t)CRUFT_PACK;
+static void mark_packs_for_deletion_1(struct string_list *names,
+                                     struct string_list *list)
+{
+       struct string_list_item *item;
+       const int hexsz = the_hash_algo->hexsz;
+
+       for_each_string_list_item(item, list) {
+               char *sha1;
+               size_t len = strlen(item->string);
+               if (len < hexsz)
+                       continue;
+               sha1 = item->string + len - hexsz;
+
+               if (pack_is_retained(item)) {
+                       pack_unmark_for_deletion(item);
+               } else if (!string_list_has_string(names, sha1)) {
+                       /*
+                        * Mark this pack for deletion, which ensures
+                        * that this pack won't be included in a MIDX
+                        * (if `--write-midx` was given) and that we
+                        * will actually delete this pack (if `-d` was
+                        * given).
+                        */
+                       pack_mark_for_deletion(item);
                }
        }
-       closedir(dir);
+}
 
-       string_list_sort(fname_kept_list);
+static void retain_cruft_pack(struct existing_packs *existing,
+                             struct packed_git *cruft)
+{
+       struct strbuf buf = STRBUF_INIT;
+       struct string_list_item *item;
+
+       strbuf_addstr(&buf, pack_basename(cruft));
+       strbuf_strip_suffix(&buf, ".pack");
+
+       item = string_list_lookup(&existing->cruft_packs, buf.buf);
+       if (!item)
+               BUG("could not find cruft pack '%s'", pack_basename(cruft));
+
+       pack_mark_retained(item);
+       strbuf_release(&buf);
+}
+
+static void mark_packs_for_deletion(struct existing_packs *existing,
+                                   struct string_list *names)
+
+{
+       mark_packs_for_deletion_1(names, &existing->non_kept_packs);
+       mark_packs_for_deletion_1(names, &existing->cruft_packs);
 }
 
 static void remove_redundant_pack(const char *dir_name, const char *base_name)
@@ -152,6 +204,72 @@ static void remove_redundant_pack(const char *dir_name, const char *base_name)
        strbuf_release(&buf);
 }
 
+static void remove_redundant_packs_1(struct string_list *packs)
+{
+       struct string_list_item *item;
+       for_each_string_list_item(item, packs) {
+               if (!pack_is_marked_for_deletion(item))
+                       continue;
+               remove_redundant_pack(packdir, item->string);
+       }
+}
+
+static void remove_redundant_existing_packs(struct existing_packs *existing)
+{
+       remove_redundant_packs_1(&existing->non_kept_packs);
+       remove_redundant_packs_1(&existing->cruft_packs);
+}
+
+static void existing_packs_release(struct existing_packs *existing)
+{
+       string_list_clear(&existing->kept_packs, 0);
+       string_list_clear(&existing->non_kept_packs, 0);
+       string_list_clear(&existing->cruft_packs, 0);
+}
+
+/*
+ * Adds all packs hex strings (pack-$HASH) to either packs->non_kept
+ * or packs->kept based on whether each pack has a corresponding
+ * .keep file or not.  Packs without a .keep file are not to be kept
+ * if we are going to pack everything into one file.
+ */
+static void collect_pack_filenames(struct existing_packs *existing,
+                                  const struct string_list *extra_keep)
+{
+       struct packed_git *p;
+       struct strbuf buf = STRBUF_INIT;
+
+       for (p = get_all_packs(the_repository); p; p = p->next) {
+               int i;
+               const char *base;
+
+               if (!p->pack_local)
+                       continue;
+
+               base = pack_basename(p);
+
+               for (i = 0; i < extra_keep->nr; i++)
+                       if (!fspathcmp(base, extra_keep->items[i].string))
+                               break;
+
+               strbuf_reset(&buf);
+               strbuf_addstr(&buf, base);
+               strbuf_strip_suffix(&buf, ".pack");
+
+               if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
+                       string_list_append(&existing->kept_packs, buf.buf);
+               else if (p->is_cruft)
+                       string_list_append(&existing->cruft_packs, buf.buf);
+               else
+                       string_list_append(&existing->non_kept_packs, buf.buf);
+       }
+
+       string_list_sort(&existing->kept_packs);
+       string_list_sort(&existing->non_kept_packs);
+       string_list_sort(&existing->cruft_packs);
+       strbuf_release(&buf);
+}
+
 static void prepare_pack_objects(struct child_process *cmd,
                                 const struct pack_objects_args *args,
                                 const char *out)
@@ -166,7 +284,7 @@ static void prepare_pack_objects(struct child_process *cmd,
        if (args->threads)
                strvec_pushf(&cmd->args, "--threads=%s", args->threads);
        if (args->max_pack_size)
-               strvec_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
+               strvec_pushf(&cmd->args, "--max-pack-size=%lu", args->max_pack_size);
        if (args->no_reuse_delta)
                strvec_pushf(&cmd->args, "--no-reuse-delta");
        if (args->no_reuse_object)
@@ -239,6 +357,18 @@ static struct generated_pack_data *populate_pack_exts(const char *name)
        return data;
 }
 
+static int has_pack_ext(const struct generated_pack_data *data,
+                       const char *ext)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(exts); i++) {
+               if (strcmp(exts[i].name, ext))
+                       continue;
+               return !!data->tempfiles[i];
+       }
+       BUG("unknown pack extension: '%s'", ext);
+}
+
 static void repack_promisor_objects(const struct pack_objects_args *args,
                                    struct string_list *names)
 {
@@ -304,6 +434,8 @@ struct pack_geometry {
        struct packed_git **pack;
        uint32_t pack_nr, pack_alloc;
        uint32_t split;
+
+       int split_factor;
 };
 
 static uint32_t geometry_pack_weight(struct packed_git *p)
@@ -325,17 +457,13 @@ static int geometry_cmp(const void *va, const void *vb)
        return 0;
 }
 
-static void init_pack_geometry(struct pack_geometry **geometry_p,
-                              struct string_list *existing_kept_packs,
+static void init_pack_geometry(struct pack_geometry *geometry,
+                              struct existing_packs *existing,
                               const struct pack_objects_args *args)
 {
        struct packed_git *p;
-       struct pack_geometry *geometry;
        struct strbuf buf = STRBUF_INIT;
 
-       *geometry_p = xcalloc(1, sizeof(struct pack_geometry));
-       geometry = *geometry_p;
-
        for (p = get_all_packs(the_repository); p; p = p->next) {
                if (args->local && !p->pack_local)
                        /*
@@ -347,23 +475,24 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
 
                if (!pack_kept_objects) {
                        /*
-                        * Any pack that has its pack_keep bit set will appear
-                        * in existing_kept_packs below, but this saves us from
-                        * doing a more expensive check.
+                        * Any pack that has its pack_keep bit set will
+                        * appear in existing->kept_packs below, but
+                        * this saves us from doing a more expensive
+                        * check.
                         */
                        if (p->pack_keep)
                                continue;
 
                        /*
-                        * The pack may be kept via the --keep-pack option;
-                        * check 'existing_kept_packs' to determine whether to
-                        * ignore it.
+                        * The pack may be kept via the --keep-pack
+                        * option; check 'existing->kept_packs' to
+                        * determine whether to ignore it.
                         */
                        strbuf_reset(&buf);
                        strbuf_addstr(&buf, pack_basename(p));
                        strbuf_strip_suffix(&buf, ".pack");
 
-                       if (string_list_has_string(existing_kept_packs, buf.buf))
+                       if (string_list_has_string(&existing->kept_packs, buf.buf))
                                continue;
                }
                if (p->is_cruft)
@@ -381,7 +510,7 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
        strbuf_release(&buf);
 }
 
-static void split_pack_geometry(struct pack_geometry *geometry, int factor)
+static void split_pack_geometry(struct pack_geometry *geometry)
 {
        uint32_t i;
        uint32_t split;
@@ -400,12 +529,14 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
                struct packed_git *ours = geometry->pack[i];
                struct packed_git *prev = geometry->pack[i - 1];
 
-               if (unsigned_mult_overflows(factor, geometry_pack_weight(prev)))
+               if (unsigned_mult_overflows(geometry->split_factor,
+                                           geometry_pack_weight(prev)))
                        die(_("pack %s too large to consider in geometric "
                              "progression"),
                            prev->pack_name);
 
-               if (geometry_pack_weight(ours) < factor * geometry_pack_weight(prev))
+               if (geometry_pack_weight(ours) <
+                   geometry->split_factor * geometry_pack_weight(prev))
                        break;
        }
 
@@ -440,10 +571,12 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
        for (i = split; i < geometry->pack_nr; i++) {
                struct packed_git *ours = geometry->pack[i];
 
-               if (unsigned_mult_overflows(factor, total_size))
+               if (unsigned_mult_overflows(geometry->split_factor,
+                                           total_size))
                        die(_("pack %s too large to roll up"), ours->pack_name);
 
-               if (geometry_pack_weight(ours) < factor * total_size) {
+               if (geometry_pack_weight(ours) <
+                   geometry->split_factor * total_size) {
                        if (unsigned_add_overflows(total_size,
                                                   geometry_pack_weight(ours)))
                                die(_("pack %s too large to roll up"),
@@ -493,15 +626,38 @@ static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
        return NULL;
 }
 
-static void clear_pack_geometry(struct pack_geometry *geometry)
+static void geometry_remove_redundant_packs(struct pack_geometry *geometry,
+                                           struct string_list *names,
+                                           struct existing_packs *existing)
+{
+       struct strbuf buf = STRBUF_INIT;
+       uint32_t i;
+
+       for (i = 0; i < geometry->split; i++) {
+               struct packed_git *p = geometry->pack[i];
+               if (string_list_has_string(names, hash_to_hex(p->hash)))
+                       continue;
+
+               strbuf_reset(&buf);
+               strbuf_addstr(&buf, pack_basename(p));
+               strbuf_strip_suffix(&buf, ".pack");
+
+               if ((p->pack_keep) ||
+                   (string_list_has_string(&existing->kept_packs, buf.buf)))
+                       continue;
+
+               remove_redundant_pack(packdir, buf.buf);
+       }
+
+       strbuf_release(&buf);
+}
+
+static void free_pack_geometry(struct pack_geometry *geometry)
 {
        if (!geometry)
                return;
 
        free(geometry->pack);
-       geometry->pack_nr = 0;
-       geometry->pack_alloc = 0;
-       geometry->split = 0;
 }
 
 struct midx_snapshot_ref_data {
@@ -567,18 +723,17 @@ static void midx_snapshot_refs(struct tempfile *f)
 }
 
 static void midx_included_packs(struct string_list *include,
-                               struct string_list *existing_nonkept_packs,
-                               struct string_list *existing_kept_packs,
+                               struct existing_packs *existing,
                                struct string_list *names,
                                struct pack_geometry *geometry)
 {
        struct string_list_item *item;
 
-       for_each_string_list_item(item, existing_kept_packs)
+       for_each_string_list_item(item, &existing->kept_packs)
                string_list_insert(include, xstrfmt("%s.idx", item->string));
        for_each_string_list_item(item, names)
                string_list_insert(include, xstrfmt("pack-%s.idx", item->string));
-       if (geometry) {
+       if (geometry->split_factor) {
                struct strbuf buf = STRBUF_INIT;
                uint32_t i;
                for (i = geometry->split; i < geometry->pack_nr; i++) {
@@ -601,28 +756,37 @@ static void midx_included_packs(struct string_list *include,
 
                        string_list_insert(include, strbuf_detach(&buf, NULL));
                }
-
-               for_each_string_list_item(item, existing_nonkept_packs) {
-                       if (!((uintptr_t)item->util & CRUFT_PACK)) {
-                               /*
-                                * no need to check DELETE_PACK, since we're not
-                                * doing an ALL_INTO_ONE repack
-                                */
-                               continue;
-                       }
-                       string_list_insert(include, xstrfmt("%s.idx", item->string));
-               }
        } else {
-               for_each_string_list_item(item, existing_nonkept_packs) {
-                       if ((uintptr_t)item->util & DELETE_PACK)
+               for_each_string_list_item(item, &existing->non_kept_packs) {
+                       if (pack_is_marked_for_deletion(item))
                                continue;
                        string_list_insert(include, xstrfmt("%s.idx", item->string));
                }
        }
+
+       for_each_string_list_item(item, &existing->cruft_packs) {
+               /*
+                * When doing a --geometric repack, there is no need to check
+                * for deleted packs, since we're by definition not doing an
+                * ALL_INTO_ONE repack (hence no packs will be deleted).
+                * Otherwise we must check for and exclude any packs which are
+                * enqueued for deletion.
+                *
+                * So we could omit the conditional below in the --geometric
+                * case, but doing so is unnecessary since no packs are marked
+                * as pending deletion (since we only call
+                * `mark_packs_for_deletion()` when doing an all-into-one
+                * repack).
+                */
+               if (pack_is_marked_for_deletion(item))
+                       continue;
+               string_list_insert(include, xstrfmt("%s.idx", item->string));
+       }
 }
 
 static int write_midx_included_packs(struct string_list *include,
                                     struct pack_geometry *geometry,
+                                    struct string_list *names,
                                     const char *refs_snapshot,
                                     int show_progress, int write_bitmaps)
 {
@@ -652,6 +816,38 @@ static int write_midx_included_packs(struct string_list *include,
        if (preferred)
                strvec_pushf(&cmd.args, "--preferred-pack=%s",
                             pack_basename(preferred));
+       else if (names->nr) {
+               /* The largest pack was repacked, meaning that either
+                * one or two packs exist depending on whether the
+                * repository has a cruft pack or not.
+                *
+                * Select the non-cruft one as preferred to encourage
+                * pack-reuse among packs containing reachable objects
+                * over unreachable ones.
+                *
+                * (Note we could write multiple packs here if
+                * `--max-pack-size` was given, but any one of them
+                * will suffice, so pick the first one.)
+                */
+               for_each_string_list_item(item, names) {
+                       struct generated_pack_data *data = item->util;
+                       if (has_pack_ext(data, ".mtimes"))
+                               continue;
+
+                       strvec_pushf(&cmd.args, "--preferred-pack=pack-%s.pack",
+                                    item->string);
+                       break;
+               }
+       } else {
+               /*
+                * No packs were kept, and no packs were written. The
+                * only thing remaining are .keep packs (unless
+                * --pack-kept-objects was given).
+                *
+                * Set the `--preferred-pack` arbitrarily here.
+                */
+               ;
+       }
 
        if (refs_snapshot)
                strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -697,18 +893,163 @@ static void remove_redundant_bitmaps(struct string_list *include,
        strbuf_release(&path);
 }
 
+static int finish_pack_objects_cmd(struct child_process *cmd,
+                                  struct string_list *names,
+                                  int local)
+{
+       FILE *out;
+       struct strbuf line = STRBUF_INIT;
+
+       out = xfdopen(cmd->out, "r");
+       while (strbuf_getline_lf(&line, out) != EOF) {
+               struct string_list_item *item;
+
+               if (line.len != the_hash_algo->hexsz)
+                       die(_("repack: Expecting full hex object ID lines only "
+                             "from pack-objects."));
+               /*
+                * Avoid putting packs written outside of the repository in the
+                * list of names.
+                */
+               if (local) {
+                       item = string_list_append(names, line.buf);
+                       item->util = populate_pack_exts(line.buf);
+               }
+       }
+       fclose(out);
+
+       strbuf_release(&line);
+
+       return finish_command(cmd);
+}
+
+static int write_filtered_pack(const struct pack_objects_args *args,
+                              const char *destination,
+                              const char *pack_prefix,
+                              struct existing_packs *existing,
+                              struct string_list *names)
+{
+       struct child_process cmd = CHILD_PROCESS_INIT;
+       struct string_list_item *item;
+       FILE *in;
+       int ret;
+       const char *caret;
+       const char *scratch;
+       int local = skip_prefix(destination, packdir, &scratch);
+
+       prepare_pack_objects(&cmd, args, destination);
+
+       strvec_push(&cmd.args, "--stdin-packs");
+
+       if (!pack_kept_objects)
+               strvec_push(&cmd.args, "--honor-pack-keep");
+       for_each_string_list_item(item, &existing->kept_packs)
+               strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
+
+       cmd.in = -1;
+
+       ret = start_command(&cmd);
+       if (ret)
+               return ret;
+
+       /*
+        * Here 'names' contains only the pack(s) that were just
+        * written, which is exactly the packs we want to keep. Also
+        * 'existing_kept_packs' already contains the packs in
+        * 'keep_pack_list'.
+        */
+       in = xfdopen(cmd.in, "w");
+       for_each_string_list_item(item, names)
+               fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
+       for_each_string_list_item(item, &existing->non_kept_packs)
+               fprintf(in, "%s.pack\n", item->string);
+       for_each_string_list_item(item, &existing->cruft_packs)
+               fprintf(in, "%s.pack\n", item->string);
+       caret = pack_kept_objects ? "" : "^";
+       for_each_string_list_item(item, &existing->kept_packs)
+               fprintf(in, "%s%s.pack\n", caret, item->string);
+       fclose(in);
+
+       return finish_pack_objects_cmd(&cmd, names, local);
+}
+
+static int existing_cruft_pack_cmp(const void *va, const void *vb)
+{
+       struct packed_git *a = *(struct packed_git **)va;
+       struct packed_git *b = *(struct packed_git **)vb;
+
+       if (a->pack_size < b->pack_size)
+               return -1;
+       if (a->pack_size > b->pack_size)
+               return 1;
+       return 0;
+}
+
+static void collapse_small_cruft_packs(FILE *in, size_t max_size,
+                                      struct existing_packs *existing)
+{
+       struct packed_git **existing_cruft, *p;
+       struct strbuf buf = STRBUF_INIT;
+       size_t total_size = 0;
+       size_t existing_cruft_nr = 0;
+       size_t i;
+
+       ALLOC_ARRAY(existing_cruft, existing->cruft_packs.nr);
+
+       for (p = get_all_packs(the_repository); p; p = p->next) {
+               if (!(p->is_cruft && p->pack_local))
+                       continue;
+
+               strbuf_reset(&buf);
+               strbuf_addstr(&buf, pack_basename(p));
+               strbuf_strip_suffix(&buf, ".pack");
+
+               if (!string_list_has_string(&existing->cruft_packs, buf.buf))
+                       continue;
+
+               if (existing_cruft_nr >= existing->cruft_packs.nr)
+                       BUG("too many cruft packs (found %"PRIuMAX", but knew "
+                           "of %"PRIuMAX")",
+                           (uintmax_t)existing_cruft_nr + 1,
+                           (uintmax_t)existing->cruft_packs.nr);
+               existing_cruft[existing_cruft_nr++] = p;
+       }
+
+       QSORT(existing_cruft, existing_cruft_nr, existing_cruft_pack_cmp);
+
+       for (i = 0; i < existing_cruft_nr; i++) {
+               size_t proposed;
+
+               p = existing_cruft[i];
+               proposed = st_add(total_size, p->pack_size);
+
+               if (proposed <= max_size) {
+                       total_size = proposed;
+                       fprintf(in, "-%s\n", pack_basename(p));
+               } else {
+                       retain_cruft_pack(existing, p);
+                       fprintf(in, "%s\n", pack_basename(p));
+               }
+       }
+
+       for (i = 0; i < existing->non_kept_packs.nr; i++)
+               fprintf(in, "-%s.pack\n",
+                       existing->non_kept_packs.items[i].string);
+
+       strbuf_release(&buf);
+       free(existing_cruft);
+}
+
 static int write_cruft_pack(const struct pack_objects_args *args,
                            const char *destination,
                            const char *pack_prefix,
                            const char *cruft_expiration,
                            struct string_list *names,
-                           struct string_list *existing_packs,
-                           struct string_list *existing_kept_packs)
+                           struct existing_packs *existing)
 {
        struct child_process cmd = CHILD_PROCESS_INIT;
-       struct strbuf line = STRBUF_INIT;
        struct string_list_item *item;
-       FILE *in, *out;
+       FILE *in;
        int ret;
        const char *scratch;
        int local = skip_prefix(destination, packdir, &scratch);
@@ -722,7 +1063,6 @@ static int write_cruft_pack(const struct pack_objects_args *args,
 
        strvec_push(&cmd.args, "--honor-pack-keep");
        strvec_push(&cmd.args, "--non-empty");
-       strvec_push(&cmd.args, "--max-pack-size=0");
 
        cmd.in = -1;
 
@@ -746,33 +1086,30 @@ static int write_cruft_pack(const struct pack_objects_args *args,
        in = xfdopen(cmd.in, "w");
        for_each_string_list_item(item, names)
                fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
-       for_each_string_list_item(item, existing_packs)
-               fprintf(in, "-%s.pack\n", item->string);
-       for_each_string_list_item(item, existing_kept_packs)
+       if (args->max_pack_size && !cruft_expiration) {
+               collapse_small_cruft_packs(in, args->max_pack_size, existing);
+       } else {
+               for_each_string_list_item(item, &existing->non_kept_packs)
+                       fprintf(in, "-%s.pack\n", item->string);
+               for_each_string_list_item(item, &existing->cruft_packs)
+                       fprintf(in, "-%s.pack\n", item->string);
+       }
+       for_each_string_list_item(item, &existing->kept_packs)
                fprintf(in, "%s.pack\n", item->string);
        fclose(in);
 
-       out = xfdopen(cmd.out, "r");
-       while (strbuf_getline_lf(&line, out) != EOF) {
-               struct string_list_item *item;
-
-               if (line.len != the_hash_algo->hexsz)
-                       die(_("repack: Expecting full hex object ID lines only "
-                             "from pack-objects."));
-               /*
-                * avoid putting packs written outside of the repository in the
-                * list of names
-                */
-               if (local) {
-                       item = string_list_append(names, line.buf);
-                       item->util = populate_pack_exts(line.buf);
-               }
-       }
-       fclose(out);
-
-       strbuf_release(&line);
+       return finish_pack_objects_cmd(&cmd, names, local);
+}
 
-       return finish_command(&cmd);
+static const char *find_pack_prefix(const char *packdir, const char *packtmp)
+{
+       const char *pack_prefix;
+       if (!skip_prefix(packtmp, packdir, &pack_prefix))
+               die(_("pack prefix %s does not begin with objdir %s"),
+                   packtmp, packdir);
+       if (*pack_prefix == '/')
+               pack_prefix++;
+       return pack_prefix;
 }
 
 int cmd_repack(int argc, const char **argv, const char *prefix)
@@ -780,13 +1117,10 @@ 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 existing_nonkept_packs = STRING_LIST_INIT_DUP;
-       struct string_list existing_kept_packs = STRING_LIST_INIT_DUP;
-       struct pack_geometry *geometry = NULL;
-       struct strbuf line = STRBUF_INIT;
+       struct existing_packs existing = EXISTING_PACKS_INIT;
+       struct pack_geometry geometry = { 0 };
        struct tempfile *refs_snapshot = NULL;
        int i, ext, ret;
-       FILE *out;
        int show_progress;
 
        /* variables to be filled by option parsing */
@@ -796,10 +1130,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
        struct pack_objects_args po_args = {NULL};
        struct pack_objects_args cruft_po_args = {NULL};
-       int geometric_factor = 0;
        int write_midx = 0;
        const char *cruft_expiration = NULL;
        const char *expire_to = NULL;
+       const char *filter_to = NULL;
 
        struct option builtin_repack_options[] = {
                OPT_BIT('a', NULL, &pack_everything,
@@ -812,6 +1146,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                   PACK_CRUFT),
                OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
                                N_("with --cruft, expire objects older than this")),
+               OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size,
+                               N_("with --cruft, limit the size of new cruft packs")),
                OPT_BOOL('d', NULL, &delete_redundant,
                                N_("remove redundant packs, and run git-prune-packed")),
                OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -839,21 +1175,26 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                N_("limits the maximum delta depth")),
                OPT_STRING(0, "threads", &po_args.threads, N_("n"),
                                N_("limits the maximum number of threads")),
-               OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"),
+               OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size,
                                N_("maximum size of each packfile")),
+               OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
                OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
                                N_("repack objects in packs marked with .keep")),
                OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
                                N_("do not repack this pack")),
-               OPT_INTEGER('g', "geometric", &geometric_factor,
+               OPT_INTEGER('g', "geometric", &geometry.split_factor,
                            N_("find a geometric progression with factor <N>")),
                OPT_BOOL('m', "write-midx", &write_midx,
                           N_("write a multi-pack index of the resulting packs")),
                OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
                           N_("pack prefix to store a pack containing pruned objects")),
+               OPT_STRING(0, "filter-to", &filter_to, N_("dir"),
+                          N_("pack prefix to store a pack containing filtered out objects")),
                OPT_END()
        };
 
+       list_objects_filter_init(&po_args.filter_options);
+
        git_config(repack_config, &cruft_po_args);
 
        argc = parse_options(argc, argv, prefix, builtin_repack_options,
@@ -918,14 +1259,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
        packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
 
-       collect_pack_filenames(&existing_nonkept_packs, &existing_kept_packs,
-                              &keep_pack_list);
+       collect_pack_filenames(&existing, &keep_pack_list);
 
-       if (geometric_factor) {
+       if (geometry.split_factor) {
                if (pack_everything)
                        die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
-               init_pack_geometry(&geometry, &existing_kept_packs, &po_args);
-               split_pack_geometry(geometry, geometric_factor);
+               init_pack_geometry(&geometry, &existing, &po_args);
+               split_pack_geometry(&geometry);
        }
 
        prepare_pack_objects(&cmd, &po_args, packtmp);
@@ -939,7 +1279,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                strvec_pushf(&cmd.args, "--keep-pack=%s",
                             keep_pack_list.items[i].string);
        strvec_push(&cmd.args, "--non-empty");
-       if (!geometry) {
+       if (!geometry.split_factor) {
                /*
                 * We need to grab all reachable objects, including those that
                 * are reachable from reflogs and the index.
@@ -968,7 +1308,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (pack_everything & ALL_INTO_ONE) {
                repack_promisor_objects(&po_args, &names);
 
-               if (existing_nonkept_packs.nr && delete_redundant &&
+               if (has_existing_non_kept_packs(&existing) &&
+                   delete_redundant &&
                    !(pack_everything & PACK_CRUFT)) {
                        for_each_string_list_item(item, &names) {
                                strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
@@ -986,7 +1327,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                strvec_push(&cmd.args, "--pack-loose-unreachable");
                        }
                }
-       } else if (geometry) {
+       } else if (geometry.split_factor) {
                strvec_push(&cmd.args, "--stdin-packs");
                strvec_push(&cmd.args, "--unpacked");
        } else {
@@ -994,7 +1335,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                strvec_push(&cmd.args, "--incremental");
        }
 
-       if (geometry)
+       if (po_args.filter_options.choice)
+               strvec_pushf(&cmd.args, "--filter=%s",
+                            expand_list_objects_filter_spec(&po_args.filter_options));
+       else if (filter_to)
+               die(_("option '%s' can only be used along with '%s'"), "--filter-to", "--filter");
+
+       if (geometry.split_factor)
                cmd.in = -1;
        else
                cmd.no_stdin = 1;
@@ -1003,32 +1350,21 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (ret)
                goto cleanup;
 
-       if (geometry) {
+       if (geometry.split_factor) {
                FILE *in = xfdopen(cmd.in, "w");
                /*
                 * The resulting pack should contain all objects in packs that
                 * are going to be rolled up, but exclude objects in packs which
                 * are being left alone.
                 */
-               for (i = 0; i < geometry->split; i++)
-                       fprintf(in, "%s\n", pack_basename(geometry->pack[i]));
-               for (i = geometry->split; i < geometry->pack_nr; i++)
-                       fprintf(in, "^%s\n", pack_basename(geometry->pack[i]));
+               for (i = 0; i < geometry.split; i++)
+                       fprintf(in, "%s\n", pack_basename(geometry.pack[i]));
+               for (i = geometry.split; i < geometry.pack_nr; i++)
+                       fprintf(in, "^%s\n", pack_basename(geometry.pack[i]));
                fclose(in);
        }
 
-       out = xfdopen(cmd.out, "r");
-       while (strbuf_getline_lf(&line, out) != EOF) {
-               struct string_list_item *item;
-
-               if (line.len != the_hash_algo->hexsz)
-                       die(_("repack: Expecting full hex object ID lines only from pack-objects."));
-               item = string_list_append(&names, line.buf);
-               item->util = populate_pack_exts(item->string);
-       }
-       strbuf_release(&line);
-       fclose(out);
-       ret = finish_command(&cmd);
+       ret = finish_pack_objects_cmd(&cmd, &names, 1);
        if (ret)
                goto cleanup;
 
@@ -1036,12 +1372,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                printf_ln(_("Nothing new to pack."));
 
        if (pack_everything & PACK_CRUFT) {
-               const char *pack_prefix;
-               if (!skip_prefix(packtmp, packdir, &pack_prefix))
-                       die(_("pack prefix %s does not begin with objdir %s"),
-                           packtmp, packdir);
-               if (*pack_prefix == '/')
-                       pack_prefix++;
+               const char *pack_prefix = find_pack_prefix(packdir, packtmp);
 
                if (!cruft_po_args.window)
                        cruft_po_args.window = po_args.window;
@@ -1051,14 +1382,15 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                        cruft_po_args.depth = po_args.depth;
                if (!cruft_po_args.threads)
                        cruft_po_args.threads = po_args.threads;
+               if (!cruft_po_args.max_pack_size)
+                       cruft_po_args.max_pack_size = po_args.max_pack_size;
 
                cruft_po_args.local = po_args.local;
                cruft_po_args.quiet = po_args.quiet;
 
                ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
                                       cruft_expiration, &names,
-                                      &existing_nonkept_packs,
-                                      &existing_kept_packs);
+                                      &existing);
                if (ret)
                        goto cleanup;
 
@@ -1089,13 +1421,25 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                               pack_prefix,
                                               NULL,
                                               &names,
-                                              &existing_nonkept_packs,
-                                              &existing_kept_packs);
+                                              &existing);
                        if (ret)
                                goto cleanup;
                }
        }
 
+       if (po_args.filter_options.choice) {
+               if (!filter_to)
+                       filter_to = packtmp;
+
+               ret = write_filtered_pack(&po_args,
+                                         filter_to,
+                                         find_pack_prefix(packdir, packtmp),
+                                         &existing,
+                                         &names);
+               if (ret)
+                       goto cleanup;
+       }
+
        string_list_sort(&names);
 
        close_object_store(the_repository->objects);
@@ -1134,31 +1478,14 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        }
        /* End of pack replacement. */
 
-       if (delete_redundant && pack_everything & ALL_INTO_ONE) {
-               const int hexsz = the_hash_algo->hexsz;
-               for_each_string_list_item(item, &existing_nonkept_packs) {
-                       char *sha1;
-                       size_t len = strlen(item->string);
-                       if (len < hexsz)
-                               continue;
-                       sha1 = item->string + len - hexsz;
-                       /*
-                        * Mark this pack for deletion, which ensures that this
-                        * pack won't be included in a MIDX (if `--write-midx`
-                        * was given) and that we will actually delete this pack
-                        * (if `-d` was given).
-                        */
-                       if (!string_list_has_string(&names, sha1))
-                               item->util = (void*)(uintptr_t)((size_t)item->util | DELETE_PACK);
-               }
-       }
+       if (delete_redundant && pack_everything & ALL_INTO_ONE)
+               mark_packs_for_deletion(&existing, &names);
 
        if (write_midx) {
                struct string_list include = STRING_LIST_INIT_NODUP;
-               midx_included_packs(&include, &existing_nonkept_packs,
-                                   &existing_kept_packs, &names, geometry);
+               midx_included_packs(&include, &existing, &names, &geometry);
 
-               ret = write_midx_included_packs(&include, geometry,
+               ret = write_midx_included_packs(&include, &geometry, &names,
                                                refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
                                                show_progress, write_bitmaps > 0);
 
@@ -1175,35 +1502,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
        if (delete_redundant) {
                int opts = 0;
-               for_each_string_list_item(item, &existing_nonkept_packs) {
-                       if (!((uintptr_t)item->util & DELETE_PACK))
-                               continue;
-                       remove_redundant_pack(packdir, item->string);
-               }
-
-               if (geometry) {
-                       struct strbuf buf = STRBUF_INIT;
-
-                       uint32_t i;
-                       for (i = 0; i < geometry->split; i++) {
-                               struct packed_git *p = geometry->pack[i];
-                               if (string_list_has_string(&names,
-                                                          hash_to_hex(p->hash)))
-                                       continue;
+               remove_redundant_existing_packs(&existing);
 
-                               strbuf_reset(&buf);
-                               strbuf_addstr(&buf, pack_basename(p));
-                               strbuf_strip_suffix(&buf, ".pack");
-
-                               if ((p->pack_keep) ||
-                                   (string_list_has_string(&existing_kept_packs,
-                                                           buf.buf)))
-                                       continue;
-
-                               remove_redundant_pack(packdir, buf.buf);
-                       }
-                       strbuf_release(&buf);
-               }
+               if (geometry.split_factor)
+                       geometry_remove_redundant_packs(&geometry, &names,
+                                                       &existing);
                if (show_progress)
                        opts |= PRUNE_PACKED_VERBOSE;
                prune_packed_objects(opts);
@@ -1227,9 +1530,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
 cleanup:
        string_list_clear(&names, 1);
-       string_list_clear(&existing_nonkept_packs, 0);
-       string_list_clear(&existing_kept_packs, 0);
-       clear_pack_geometry(geometry);
+       existing_packs_release(&existing);
+       free_pack_geometry(&geometry);
+       list_objects_filter_release(&po_args.filter_options);
 
        return ret;
 }
index 981f1894436dd3c3d2df15c0926e2a808557703d..da59600ad22fda16155a278a210478fb55d0d94e 100644 (file)
@@ -8,22 +8,23 @@
  * git-tag.sh and mktag.c by Linus Torvalds.
  */
 
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
 #include "editor.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "refs.h"
 #include "parse-options.h"
+#include "path.h"
 #include "run-command.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "replace-object.h"
 #include "repository.h"
 #include "tag.h"
+#include "wildmatch.h"
 
 static const char * const git_replace_usage[] = {
        N_("git replace [-f] <object> <replacement>"),
@@ -48,7 +49,7 @@ struct show_data {
 
 static int show_reference(struct repository *r, const char *refname,
                          const struct object_id *oid,
-                         int flag, void *cb_data)
+                         int flag UNUSED, void *cb_data)
 {
        struct show_data *data = cb_data;
 
@@ -408,7 +409,7 @@ struct check_mergetag_data {
        const char **argv;
 };
 
-static int check_one_mergetag(struct commit *commit,
+static int check_one_mergetag(struct commit *commit UNUSED,
                               struct commit_extra_header *extra,
                               void *data)
 {
@@ -566,7 +567,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
-       read_replace_refs = 0;
+       disable_replace_refs();
        git_config(git_default_config, NULL);
 
        argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
index d4bd52797f4624d31e39a2ca263c21e3130afe8f..07a9d37275cbbc52cc8cddbae4a6143df2e49a82 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
 #include "gettext.h"
@@ -7,7 +6,6 @@
 #include "repository.h"
 #include "string-list.h"
 #include "rerere.h"
-#include "wrapper.h"
 #include "xdiff/xdiff.h"
 #include "xdiff-interface.h"
 #include "pathspec.h"
index f99f32d5802fc537441982e45ec6539cc0241e94..4b018d20e3b2200e44a04f1f759837a571e4bc4f 100644 (file)
@@ -13,6 +13,7 @@
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "lockfile.h"
 #include "tag.h"
 #include "branch.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "path.h"
 #include "unpack-trees.h"
 #include "cache-tree.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule.h"
 #include "submodule-config.h"
 #include "trace.h"
@@ -312,12 +315,13 @@ static int reset_refs(const char *rev, const struct object_id *oid)
        return update_ref_status;
 }
 
-static int git_reset_config(const char *var, const char *value, void *cb)
+static int git_reset_config(const char *var, const char *value,
+                           const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "submodule.recurse"))
                return git_default_submodule_config(var, value, cb);
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 int cmd_reset(int argc, const char **argv, const char *prefix)
@@ -334,18 +338,25 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                OPT__QUIET(&quiet, N_("be quiet, only report errors")),
                OPT_BOOL(0, "no-refresh", &no_refresh,
                                N_("skip refreshing the index after reset")),
-               OPT_SET_INT(0, "mixed", &reset_type,
-                                               N_("reset HEAD and index"), MIXED),
-               OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
-               OPT_SET_INT(0, "hard", &reset_type,
-                               N_("reset HEAD, index and working tree"), HARD),
-               OPT_SET_INT(0, "merge", &reset_type,
-                               N_("reset HEAD, index and working tree"), MERGE),
-               OPT_SET_INT(0, "keep", &reset_type,
-                               N_("reset HEAD but keep local changes"), KEEP),
+               OPT_SET_INT_F(0, "mixed", &reset_type,
+                             N_("reset HEAD and index"),
+                             MIXED, PARSE_OPT_NONEG),
+               OPT_SET_INT_F(0, "soft", &reset_type,
+                             N_("reset only HEAD"),
+                             SOFT, PARSE_OPT_NONEG),
+               OPT_SET_INT_F(0, "hard", &reset_type,
+                             N_("reset HEAD, index and working tree"),
+                             HARD, PARSE_OPT_NONEG),
+               OPT_SET_INT_F(0, "merge", &reset_type,
+                             N_("reset HEAD, index and working tree"),
+                             MERGE, PARSE_OPT_NONEG),
+               OPT_SET_INT_F(0, "keep", &reset_type,
+                             N_("reset HEAD but keep local changes"),
+                             KEEP, PARSE_OPT_NONEG),
                OPT_CALLBACK_F(0, "recurse-submodules", NULL,
-                           "reset", "control recursive updating of submodules",
-                           PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
+                              "reset", "control recursive updating of submodules",
+                              PARSE_OPT_OPTARG,
+                              option_parse_recurse_submodules_worktree_updater),
                OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
                OPT_BOOL('N', "intent-to-add", &intent_to_add,
                                N_("record only the fact that removed paths will be added later")),
index 6dc8be492a2c424623de0dddc0006a1b0a242f7e..ff715d6918f004265cf8801879f13fc189f09709 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "commit.h"
 #include "diff.h"
 #include "object.h"
 #include "object-name.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pack.h"
 #include "pack-bitmap.h"
-#include "builtin.h"
 #include "log-tree.h"
 #include "graph.h"
 #include "bisect.h"
index 852e49e3403119707118973f6285e26c0893c355..fde8861ca4e07990078258843890aef6334dd4c9 100644 (file)
@@ -4,20 +4,21 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "commit.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "refs.h"
 #include "quote.h"
-#include "builtin.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "path.h"
 #include "diff.h"
+#include "read-cache-ll.h"
 #include "revision.h"
 #include "setup.h"
 #include "split-index.h"
@@ -156,9 +157,12 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
                                 */
                                break;
                        case 1: /* happy */
-                               if (abbrev_ref)
+                               if (abbrev_ref) {
+                                       char *old = full;
                                        full = shorten_unambiguous_ref(full,
                                                abbrev_ref_strict);
+                                       free(old);
+                               }
                                show_with_type(type, full);
                                break;
                        default: /* ambiguous */
@@ -221,7 +225,7 @@ static int anti_reference(const char *refname, const struct object_id *oid,
        return 0;
 }
 
-static int show_abbrev(const struct object_id *oid, void *cb_data)
+static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
 {
        show_rev(NORMAL, oid, NULL);
        return 0;
index 0240ec8593b27dbb44e9d5720340c8362bcec025..e6f9a1ad26721c450258849cb8e415156052e442 100644 (file)
@@ -1,10 +1,10 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "builtin.h"
 #include "parse-options.h"
 #include "diff.h"
 #include "gettext.h"
+#include "repository.h"
 #include "revision.h"
 #include "rerere.h"
 #include "dir.h"
index b4589c824c00d4abbf5b63b7df561a9369e64835..dff819ae5098ff2ee0c72bae00b35da39bf4979d 100644 (file)
@@ -5,7 +5,6 @@
  */
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "alloc.h"
 #include "advice.h"
 #include "config.h"
 #include "lockfile.h"
 #include "tree-walk.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "read-cache.h"
 #include "repository.h"
 #include "string-list.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule.h"
 #include "pathspec.h"
 
index 4784143004df1875cba4529e510679c7d058f921..cd6d9e41129a21d7f9c21cebae0a322812ebcbcd 100644 (file)
@@ -131,7 +131,8 @@ static void print_helper_status(struct ref *ref)
        strbuf_release(&buf);
 }
 
-static int send_pack_config(const char *k, const char *v, void *cb)
+static int send_pack_config(const char *k, const char *v,
+                           const struct config_context *ctx, void *cb)
 {
        if (!strcmp(k, "push.gpgsign")) {
                const char *value;
@@ -151,7 +152,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
                        }
                }
        }
-       return git_default_config(k, v, cb);
+       return git_default_config(k, v, ctx, cb);
 }
 
 int cmd_send_pack(int argc, const char **argv, const char *prefix)
index 46f4e0832ac6258e636f8064365811da6d55c449..1307ed2b88a77dbb93d38528b8d39e2b87452d07 100644 (file)
@@ -1,11 +1,11 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "commit.h"
 #include "diff.h"
 #include "environment.h"
 #include "gettext.h"
 #include "string-list.h"
+#include "repository.h"
 #include "revision.h"
 #include "utf8.h"
 #include "mailmap.h"
index 7ef4a642c17a63ba2060a1f5731c05a8d8d88a25..b01ec761d2596c6a524994b99e1ef0aa719735d2 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -6,7 +6,6 @@
 #include "hex.h"
 #include "pretty.h"
 #include "refs.h"
-#include "builtin.h"
 #include "color.h"
 #include "strvec.h"
 #include "object-name.h"
@@ -15,6 +14,7 @@
 #include "dir.h"
 #include "commit-slab.h"
 #include "date.h"
+#include "wildmatch.h"
 
 static const char* show_branch_usage[] = {
     N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
@@ -559,7 +559,8 @@ static void append_one_rev(const char *av)
        die("bad sha1 reference %s", av);
 }
 
-static int git_show_branch_config(const char *var, const char *value, void *cb)
+static int git_show_branch_config(const char *var, const char *value,
+                                 const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "showbranch.default")) {
                if (!value)
@@ -579,7 +580,10 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_color_default_config(var, value, cb);
+       if (git_color_config(var, value, cb) < 0)
+               return -1;
+
+       return git_default_config(var, value, ctx, cb);
 }
 
 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -645,7 +649,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
        int with_current_branch = 0;
        int head_at = -1;
        int topics = 0;
-       int dense = 1;
+       int sparse = 0;
        const char *reflog_base = NULL;
        struct option builtin_show_branch_options[] = {
                OPT_BOOL('a', "all", &all_heads,
@@ -667,17 +671,17 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                         N_("show possible merge bases")),
                OPT_BOOL(0, "independent", &independent,
                            N_("show refs unreachable from any other ref")),
-               OPT_SET_INT(0, "topo-order", &sort_order,
-                           N_("show commits in topological order"),
-                           REV_SORT_IN_GRAPH_ORDER),
+               OPT_SET_INT_F(0, "topo-order", &sort_order,
+                             N_("show commits in topological order"),
+                             REV_SORT_IN_GRAPH_ORDER, PARSE_OPT_NONEG),
                OPT_BOOL(0, "topics", &topics,
                         N_("show only commits not on the first branch")),
-               OPT_SET_INT(0, "sparse", &dense,
-                           N_("show merges reachable from only one tip"), 0),
-               OPT_SET_INT(0, "date-order", &sort_order,
-                           N_("topologically sort, maintaining date order "
-                              "where possible"),
-                           REV_SORT_BY_COMMIT_DATE),
+               OPT_SET_INT(0, "sparse", &sparse,
+                           N_("show merges reachable from only one tip"), 1),
+               OPT_SET_INT_F(0, "date-order", &sort_order,
+                             N_("topologically sort, maintaining date order "
+                                "where possible"),
+                             REV_SORT_BY_COMMIT_DATE, PARSE_OPT_NONEG),
                OPT_CALLBACK_F('g', "reflog", &reflog_base, N_("<n>[,<base>]"),
                            N_("show <n> most recent ref-log entries starting at "
                               "base"),
@@ -936,7 +940,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                            !is_merge_point &&
                            (this_flag & (1u << REV_SHIFT)))
                                continue;
-                       if (dense && is_merge &&
+                       if (!sparse && is_merge &&
                            omit_in_dense(commit, rev, num_rev))
                                continue;
                        for (i = 0; i < num_rev; i++) {
index d839e55335d7a841f5d1b37887a2c963ac89e3c2..540dc3dad1c1e3e4308c5058151dfb1dcaee6d21 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "gettext.h"
 #include "hash.h"
 #include "hex.h"
index a2243b42195b1b89c49a26f0c80b2bc09de142da..5110814f7960870aa4f1df60965f2234088f859f 100644 (file)
@@ -1,11 +1,10 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
 #include "refs.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "object.h"
 #include "tag.h"
 #include "string-list.h"
index 40d420f06cb0c58e57b957f322dd0485b7669023..5c8ffb1f7598b056fadcdd8fb98182d34928e6f3 100644 (file)
@@ -1,5 +1,4 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "dir.h"
 #include "environment.h"
index a7e17ffe3844a5b5567450c61a830e18de4b1361..4a6771c9f4c493a5dd41df2bf285f40784fa8cff 100644 (file)
@@ -4,6 +4,7 @@
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "object-name.h"
 #include "parse-options.h"
 #include "run-command.h"
 #include "dir.h"
 #include "entry.h"
+#include "preload-index.h"
+#include "read-cache.h"
 #include "rerere.h"
 #include "revision.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "log-tree.h"
 #include "diffcore.h"
 #include "exec-cmd.h"
@@ -358,7 +362,7 @@ static int is_path_a_directory(const char *path)
 }
 
 static void add_diff_to_buf(struct diff_queue_struct *q,
-                           struct diff_options *options,
+                           struct diff_options *options UNUSED,
                            void *data)
 {
        int i;
@@ -837,7 +841,8 @@ static int show_stat = 1;
 static int show_patch;
 static int show_include_untracked;
 
-static int git_stash_config(const char *var, const char *value, void *cb)
+static int git_stash_config(const char *var, const char *value,
+                           const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "stash.showstat")) {
                show_stat = git_config_bool(var, value);
@@ -851,7 +856,7 @@ static int git_stash_config(const char *var, const char *value, void *cb)
                show_include_untracked = git_config_bool(var, value);
                return 0;
        }
-       return git_diff_basic_config(var, value, cb);
+       return git_diff_basic_config(var, value, ctx, cb);
 }
 
 static void diff_include_untracked(const struct stash_info *info, struct diff_options *diff_opt)
@@ -968,7 +973,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
        }
        log_tree_diff_flush(&rev);
 
-       ret = diff_result_code(&rev.diffopt, 0);
+       ret = diff_result_code(&rev.diffopt);
 cleanup:
        strvec_clear(&stash_args);
        free_stash_info(&info);
@@ -984,6 +989,12 @@ usage:
 static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
                          int quiet)
 {
+       struct stash_info info;
+       char revision[GIT_MAX_HEXSZ];
+
+       oid_to_hex_r(revision, w_commit);
+       assert_stash_like(&info, revision);
+
        if (!stash_msg)
                stash_msg = "Created via \"git stash store\".";
 
@@ -1084,7 +1095,6 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
  */
 static int check_changes_tracked_files(const struct pathspec *ps)
 {
-       int result;
        struct rev_info rev;
        struct object_id dummy;
        int ret = 0;
@@ -1106,14 +1116,14 @@ static int check_changes_tracked_files(const struct pathspec *ps)
        add_head_to_pending(&rev);
        diff_setup_done(&rev.diffopt);
 
-       result = run_diff_index(&rev, 1);
-       if (diff_result_code(&rev.diffopt, result)) {
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
+       if (diff_result_code(&rev.diffopt)) {
                ret = 1;
                goto done;
        }
 
-       result = run_diff_files(&rev, 0);
-       if (diff_result_code(&rev.diffopt, result)) {
+       run_diff_files(&rev, 0);
+       if (diff_result_code(&rev.diffopt)) {
                ret = 1;
                goto done;
        }
@@ -1304,10 +1314,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
 
        add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
                           "");
-       if (run_diff_index(&rev, 0)) {
-               ret = -1;
-               goto done;
-       }
+       run_diff_index(&rev, 0);
 
        cp_upd_index.git_cmd = 1;
        strvec_pushl(&cp_upd_index.args, "update-index",
index 9451eb69ff4771931118e948669114e9f3d4e63d..7b700a9fb1c2a355af6ee6935edbeec49f3f4135 100644 (file)
@@ -1,6 +1,6 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
+#include "environment.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "setup.h"
@@ -13,7 +13,7 @@ static void comment_lines(struct strbuf *buf)
        size_t len;
 
        msg = strbuf_detach(buf, &len);
-       strbuf_add_commented_lines(buf, msg, len);
+       strbuf_add_commented_lines(buf, msg, len, comment_line_char);
        free(msg);
 }
 
@@ -58,7 +58,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
                die_errno("could not read the input");
 
        if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
-               strbuf_stripspace(&buf, mode == STRIP_COMMENTS);
+               strbuf_stripspace(&buf,
+                         mode == STRIP_COMMENTS ? comment_line_char : '\0');
        else
                comment_lines(&buf);
 
index 6bf8d666ce91203024b69192ab427df40912904c..cce46450abe95ea6a24d28026a1686cb930cb75a 100644 (file)
@@ -1,18 +1,20 @@
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "repository.h"
-#include "cache.h"
 #include "config.h"
 #include "parse-options.h"
 #include "quote.h"
+#include "path.h"
 #include "pathspec.h"
+#include "preload-index.h"
 #include "dir.h"
+#include "read-cache.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule.h"
 #include "submodule-config.h"
 #include "string-list.h"
@@ -26,7 +28,7 @@
 #include "diff.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "advice.h"
 #include "branch.h"
 #include "list-objects-filter-options.h"
@@ -627,7 +629,6 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
        char *displaypath;
        struct strvec diff_files_args = STRVEC_INIT;
        struct rev_info rev = REV_INFO_INIT;
-       int diff_files_result;
        struct strbuf buf = STRBUF_INIT;
        const char *git_dir;
        struct setup_revision_opt opt = {
@@ -667,9 +668,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
        repo_init_revisions(the_repository, &rev, NULL);
        rev.abbrev = 0;
        setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
-       diff_files_result = run_diff_files(&rev, 0);
+       run_diff_files(&rev, 0);
 
-       if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+       if (!diff_result_code(&rev.diffopt)) {
                print_status(flags, ' ', path, ce_oid,
                             displaypath);
        } else if (!(flags & OPT_CACHED)) {
@@ -1139,7 +1140,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
        }
 
        if (diff_cmd == DIFF_INDEX)
-               run_diff_index(&rev, info->cached);
+               run_diff_index(&rev, info->cached ? DIFF_INDEX_CACHED : 0);
        else
                run_diff_files(&rev, 0);
        prepare_submodule_summary(info, &list);
@@ -2024,14 +2025,17 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
        strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
        if (repo_config_get_string_tmp(the_repository, sb.buf, &url)) {
-               if (starts_with_dot_slash(sub->url) ||
-                   starts_with_dot_dot_slash(sub->url)) {
+               if (sub->url && (starts_with_dot_slash(sub->url) ||
+                                starts_with_dot_dot_slash(sub->url))) {
                        url = resolve_relative_url(sub->url, NULL, 0);
                        need_free_url = 1;
                } else
                        url = sub->url;
        }
 
+       if (!url)
+               die(_("cannot clone submodule '%s' without a URL"), sub->name);
+
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/.git", ce->name);
        needs_cloning = !file_exists(sb.buf);
@@ -2189,12 +2193,13 @@ static int update_clone_task_finished(int result,
 }
 
 static int git_update_clone_config(const char *var, const char *value,
+                                  const struct config_context *ctx,
                                   void *cb)
 {
        int *max_jobs = cb;
 
        if (!strcmp(var, "submodule.fetchjobs"))
-               *max_jobs = parse_submodule_fetchjobs(var, value);
+               *max_jobs = parse_submodule_fetchjobs(var, value, ctx->kvi);
        return 0;
 }
 
@@ -2884,7 +2889,7 @@ cleanup:
 
 static int module_set_url(int argc, const char **argv, const char *prefix)
 {
-       int quiet = 0;
+       int quiet = 0, ret;
        const char *newurl;
        const char *path;
        char *config_name;
@@ -2896,20 +2901,29 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
                N_("git submodule set-url [--quiet] <path> <newurl>"),
                NULL
        };
+       const struct submodule *sub;
 
        argc = parse_options(argc, argv, prefix, options, usage, 0);
 
        if (argc != 2 || !(path = argv[0]) || !(newurl = argv[1]))
                usage_with_options(usage, options);
 
-       config_name = xstrfmt("submodule.%s.url", path);
+       sub = submodule_from_path(the_repository, null_oid(), path);
 
-       config_set_in_gitmodules_file_gently(config_name, newurl);
-       sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
+       if (!sub)
+               die(_("no submodule mapping found in .gitmodules for path '%s'"),
+                   path);
 
-       free(config_name);
+       config_name = xstrfmt("submodule.%s.url", sub->name);
+       ret = config_set_in_gitmodules_file_gently(config_name, newurl);
 
-       return 0;
+       if (!ret) {
+               repo_read_gitmodules(the_repository, 0);
+               sync_submodule(sub->path, prefix, NULL, quiet ? OPT_QUIET : 0);
+       }
+
+       free(config_name);
+       return !!ret;
 }
 
 static int module_set_branch(int argc, const char **argv, const char *prefix)
@@ -2936,6 +2950,7 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
                N_("git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
                NULL
        };
+       const struct submodule *sub;
 
        argc = parse_options(argc, argv, prefix, options, usage, 0);
 
@@ -2948,7 +2963,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
        if (argc != 1 || !(path = argv[0]))
                usage_with_options(usage, options);
 
-       config_name = xstrfmt("submodule.%s.branch", path);
+       sub = submodule_from_path(the_repository, null_oid(), path);
+
+       if (!sub)
+               die(_("no submodule mapping found in .gitmodules for path '%s'"),
+                   path);
+
+       config_name = xstrfmt("submodule.%s.branch", sub->name);
        ret = config_set_in_gitmodules_file_gently(config_name, opt_branch);
 
        free(config_name);
index 10198a74faee55d0dfcfccb36b75c2e5bc5da8f5..c9defe4d2e4ff057bce4dc31330ae1f964225ede 100644 (file)
@@ -1,9 +1,9 @@
 #include "builtin.h"
 #include "config.h"
-#include "cache.h"
 #include "gettext.h"
 #include "refs.h"
 #include "parse-options.h"
+#include "strbuf.h"
 
 static const char * const git_symbolic_ref_usage[] = {
        N_("git symbolic-ref [-m <reason>] <name> <ref>"),
index 1850a6a6fdcf82f18ad3f1f1aefd5d22fc527e3f..3918eacbb57bd9e0d2b90ecbbf6cc07c16fad73b 100644 (file)
@@ -6,17 +6,17 @@
  * Based on git-tag.sh and mktag.c by Linus Torvalds.
  */
 
-#include "cache.h"
+#include "builtin.h"
 #include "advice.h"
 #include "config.h"
-#include "builtin.h"
 #include "editor.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "refs.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "tag.h"
 #include "run-command.h"
 #include "parse-options.h"
@@ -121,7 +121,7 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
        return had_error;
 }
 
-static int collect_tags(const char *name, const char *ref,
+static int collect_tags(const char *name UNUSED, const char *ref,
                        const struct object_id *oid, void *cb_data)
 {
        struct string_list *ref_list = cb_data;
@@ -155,7 +155,7 @@ static int delete_tags(const char **argv)
        return result;
 }
 
-static int verify_tag(const char *name, const char *ref,
+static int verify_tag(const char *name, const char *ref UNUSED,
                      const struct object_id *oid, void *cb_data)
 {
        int flags;
@@ -188,7 +188,8 @@ static const char tag_template_nocleanup[] =
        "Lines starting with '%c' will be kept; you may remove them"
        " yourself if you want to.\n");
 
-static int git_tag_config(const char *var, const char *value, void *cb)
+static int git_tag_config(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "tag.gpgsign")) {
                config_sign_tag = git_config_bool(var, value);
@@ -209,7 +210,11 @@ static int git_tag_config(const char *var, const char *value, void *cb)
 
        if (starts_with(var, "column."))
                return git_column_config(var, value, "tag", &colopts);
-       return git_color_default_config(var, value, cb);
+
+       if (git_color_config(var, value, cb) < 0)
+               return -1;
+
+       return git_default_config(var, value, ctx, cb);
 }
 
 static void write_tag_body(int fd, const struct object_id *oid)
@@ -271,11 +276,10 @@ static const char message_advice_nested_tag[] =
 static void create_tag(const struct object_id *object, const char *object_ref,
                       const char *tag,
                       struct strbuf *buf, struct create_tag_options *opt,
-                      struct object_id *prev, struct object_id *result)
+                      struct object_id *prev, struct object_id *result, char *path)
 {
        enum object_type type;
        struct strbuf header = STRBUF_INIT;
-       char *path = NULL;
 
        type = oid_object_info(the_repository, object, NULL);
        if (type <= OBJ_NONE)
@@ -299,7 +303,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
                int fd;
 
                /* write the template message before editing: */
-               path = git_pathdup("TAG_EDITMSG");
                fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
 
                if (opt->message_given) {
@@ -311,9 +314,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,
                        struct strbuf buf = STRBUF_INIT;
                        strbuf_addch(&buf, '\n');
                        if (opt->cleanup_mode == CLEANUP_ALL)
-                               strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);
+                               strbuf_commented_addf(&buf, comment_line_char,
+                                     _(tag_template), tag, comment_line_char);
                        else
-                               strbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);
+                               strbuf_commented_addf(&buf, comment_line_char,
+                                     _(tag_template_nocleanup), tag, comment_line_char);
                        write_or_die(fd, buf.buf, buf.len);
                        strbuf_release(&buf);
                }
@@ -327,7 +332,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,
        }
 
        if (opt->cleanup_mode != CLEANUP_NONE)
-               strbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);
+               strbuf_stripspace(buf,
+                 opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
 
        if (!opt->message_given && !buf->len)
                die(_("no tag message?"));
@@ -341,10 +347,6 @@ static void create_tag(const struct object_id *object, const char *object_ref,
                                path);
                exit(128);
        }
-       if (path) {
-               unlink_or_warn(path);
-               free(path);
-       }
 }
 
 static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
@@ -443,7 +445,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct msg_arg msg = { .buf = STRBUF_INIT };
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
-       struct ref_filter filter;
+       struct ref_filter filter = REF_FILTER_INIT;
        struct ref_sorting *sorting;
        struct string_list sorting_options = STRING_LIST_INIT_DUP;
        struct ref_format format = REF_FORMAT_INIT;
@@ -495,13 +497,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        };
        int ret = 0;
        const char *only_in_list = NULL;
+       char *path = NULL;
 
        setup_ref_filter_porcelain_msg();
 
        git_config(git_tag_config, &sorting_options);
 
        memset(&opt, 0, sizeof(opt));
-       memset(&filter, 0, sizeof(filter));
        filter.lines = -1;
        opt.sign = -1;
 
@@ -629,7 +631,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (create_tag_object) {
                if (force_sign_annotate && !annotate)
                        opt.sign = 1;
-               create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object);
+               path = git_pathdup("TAG_EDITMSG");
+               create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
+                          path);
        }
 
        transaction = ref_transaction_begin(&err);
@@ -637,8 +641,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
            ref_transaction_update(transaction, ref.buf, &object, &prev,
                                   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
                                   reflog_msg.buf, &err) ||
-           ref_transaction_commit(transaction, &err))
+           ref_transaction_commit(transaction, &err)) {
+               if (path)
+                       fprintf(stderr,
+                               _("The tag message has been left in %s\n"),
+                               path);
                die("%s", err.buf);
+       }
+       if (path) {
+               unlink_or_warn(path);
+               free(path);
+       }
        ref_transaction_free(transaction);
        if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
                printf(_("Updated tag '%s' (was %s)\n"), tag,
@@ -646,6 +659,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 cleanup:
        ref_sorting_release(sorting);
+       ref_filter_clear(&filter);
        strbuf_release(&buf);
        strbuf_release(&ref);
        strbuf_release(&reflog_msg);
index b35a4b9dfee83e9050771bf0f6d51555f1b32dcd..c129e2bb6cbffaf80898c8a9c1c4e49fdeb001a4 100644 (file)
@@ -2,8 +2,7 @@
 #include "config.h"
 #include "hex.h"
 #include "object-name.h"
-#include "object-store.h"
-#include "wrapper.h"
+#include "object-store-ll.h"
 
 static char *create_temp_file(struct object_id *oid)
 {
index 2c52c3a741fbd49d7782f6388e2ebe38f54cb8fb..fef7423448804006a04286ce18adedbaaf950229 100644 (file)
@@ -1,18 +1,18 @@
 #include "builtin.h"
-#include "cache.h"
 #include "bulk-checkin.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
 #include "git-zlib.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "object.h"
 #include "delta.h"
 #include "pack.h"
 #include "blob.h"
 #include "commit.h"
 #include "replace-object.h"
+#include "strbuf.h"
 #include "tag.h"
 #include "tree.h"
 #include "tree-walk.h"
@@ -215,7 +215,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
  * Verify its reachability and validity recursively and write it out.
  */
 static int check_object(struct object *obj, enum object_type type,
-                       void *data, struct fsck_options *options)
+                       void *data UNUSED,
+                       struct fsck_options *options UNUSED)
 {
        struct obj_buffer *obj_buf;
 
@@ -608,8 +609,9 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
 {
        int i;
        struct object_id oid;
+       git_hash_ctx tmp_ctx;
 
-       read_replace_refs = 0;
+       disable_replace_refs();
 
        git_config(git_default_config, NULL);
 
@@ -668,7 +670,9 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
        the_hash_algo->init_fn(&ctx);
        unpack_all();
        the_hash_algo->update_fn(&ctx, buffer, offset);
-       the_hash_algo->final_oid_fn(&oid, &ctx);
+       the_hash_algo->init_fn(&tmp_ctx);
+       the_hash_algo->clone_fn(&tmp_ctx, &ctx);
+       the_hash_algo->final_oid_fn(&oid, &tmp_ctx);
        if (strict) {
                write_rest();
                if (fsck_finish(&fsck_options))
index 5fab9ad2ec46fda2f114a64ad16933126b37e85c..7bcaa1476c0fd5233475cac56a22db8c7714a570 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "builtin.h"
 #include "bulk-checkin.h"
 #include "config.h"
 #include "environment.h"
 #include "quote.h"
 #include "cache-tree.h"
 #include "tree-walk.h"
-#include "builtin.h"
 #include "object-file.h"
 #include "refs.h"
 #include "resolve-undo.h"
 #include "parse-options.h"
 #include "pathspec.h"
 #include "dir.h"
+#include "read-cache.h"
 #include "repository.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "split-index.h"
 #include "symlinks.h"
 #include "fsmonitor.h"
@@ -608,9 +609,6 @@ static const char * const update_index_usage[] = {
        NULL
 };
 
-static struct object_id head_oid;
-static struct object_id merge_head_oid;
-
 static struct cache_entry *read_one_ent(const char *which,
                                        struct object_id *ent, const char *path,
                                        int namelen, int stage)
@@ -641,84 +639,17 @@ static struct cache_entry *read_one_ent(const char *which,
 
 static int unresolve_one(const char *path)
 {
-       int namelen = strlen(path);
-       int pos;
-       int ret = 0;
-       struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
-
-       /* See if there is such entry in the index. */
-       pos = index_name_pos(&the_index, path, namelen);
-       if (0 <= pos) {
-               /* already merged */
-               pos = unmerge_index_entry_at(&the_index, pos);
-               if (pos < the_index.cache_nr) {
-                       const struct cache_entry *ce = the_index.cache[pos];
-                       if (ce_stage(ce) &&
-                           ce_namelen(ce) == namelen &&
-                           !memcmp(ce->name, path, namelen))
-                               return 0;
-               }
-               /* no resolve-undo information; fall back */
-       } else {
-               /* If there isn't, either it is unmerged, or
-                * resolved as "removed" by mistake.  We do not
-                * want to do anything in the former case.
-                */
-               pos = -pos-1;
-               if (pos < the_index.cache_nr) {
-                       const struct cache_entry *ce = the_index.cache[pos];
-                       if (ce_namelen(ce) == namelen &&
-                           !memcmp(ce->name, path, namelen)) {
-                               fprintf(stderr,
-                                       "%s: skipping still unmerged path.\n",
-                                       path);
-                               goto free_return;
-                       }
-               }
-       }
-
-       /* Grab blobs from given path from HEAD and MERGE_HEAD,
-        * stuff HEAD version in stage #2,
-        * stuff MERGE_HEAD version in stage #3.
-        */
-       ce_2 = read_one_ent("our", &head_oid, path, namelen, 2);
-       ce_3 = read_one_ent("their", &merge_head_oid, path, namelen, 3);
-
-       if (!ce_2 || !ce_3) {
-               ret = -1;
-               goto free_return;
-       }
-       if (oideq(&ce_2->oid, &ce_3->oid) &&
-           ce_2->ce_mode == ce_3->ce_mode) {
-               fprintf(stderr, "%s: identical in both, skipping.\n",
-                       path);
-               goto free_return;
-       }
-
-       remove_file_from_index(&the_index, path);
-       if (add_index_entry(&the_index, ce_2, ADD_CACHE_OK_TO_ADD)) {
-               error("%s: cannot add our version to the index.", path);
-               ret = -1;
-               goto free_return;
-       }
-       if (!add_index_entry(&the_index, ce_3, ADD_CACHE_OK_TO_ADD))
-               return 0;
-       error("%s: cannot add their version to the index.", path);
-       ret = -1;
- free_return:
-       discard_cache_entry(ce_2);
-       discard_cache_entry(ce_3);
-       return ret;
-}
-
-static void read_head_pointers(void)
-{
-       if (read_ref("HEAD", &head_oid))
-               die("No HEAD -- no initial commit yet?");
-       if (read_ref("MERGE_HEAD", &merge_head_oid)) {
-               fprintf(stderr, "Not in the middle of a merge.\n");
-               exit(0);
-       }
+       struct string_list_item *item;
+       int res = 0;
+
+       if (!the_index.resolve_undo)
+               return res;
+       item = string_list_lookup(the_index.resolve_undo, path);
+       if (!item)
+               return res; /* no resolve-undo record for the path */
+       res = unmerge_index_entry(&the_index, path, item->util, 0);
+       FREE_AND_NULL(item->util);
+       return res;
 }
 
 static int do_unresolve(int ac, const char **av,
@@ -727,11 +658,6 @@ static int do_unresolve(int ac, const char **av,
        int i;
        int err = 0;
 
-       /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
-        * are not doing a merge, so exit with success status.
-        */
-       read_head_pointers();
-
        for (i = 1; i < ac; i++) {
                const char *arg = av[i];
                char *p = prefix_path(prefix, prefix_length, arg);
@@ -750,6 +676,7 @@ static int do_reupdate(const char **paths,
        int pos;
        int has_head = 1;
        struct pathspec pathspec;
+       struct object_id head_oid;
 
        parse_pathspec(&pathspec, 0,
                       PATHSPEC_PREFER_CWD,
@@ -855,7 +782,7 @@ static int chmod_callback(const struct option *opt,
        return 0;
 }
 
-static int resolve_undo_clear_callback(const struct option *opt,
+static int resolve_undo_clear_callback(const struct option *opt UNUSED,
                                const char *arg, int unset)
 {
        BUG_ON_OPT_NEG(unset);
@@ -889,7 +816,7 @@ static int parse_new_style_cacheinfo(const char *arg,
 }
 
 static enum parse_opt_result cacheinfo_callback(
-       struct parse_opt_ctx_t *ctx, const struct option *opt,
+       struct parse_opt_ctx_t *ctx, const struct option *opt UNUSED,
        const char *arg, int unset)
 {
        struct object_id oid;
@@ -1089,6 +1016,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                        resolve_undo_clear_callback),
                OPT_INTEGER(0, "index-version", &preferred_index_format,
                        N_("write index in this format")),
+               OPT_SET_INT(0, "show-index-version", &preferred_index_format,
+                           N_("report on-disk index format version"), -1),
                OPT_BOOL(0, "split-index", &split_index,
                        N_("enable or disable split index")),
                OPT_BOOL(0, "untracked-cache", &untracked_cache,
@@ -1181,15 +1110,20 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 
        getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
        if (preferred_index_format) {
-               if (preferred_index_format < INDEX_FORMAT_LB ||
-                   INDEX_FORMAT_UB < preferred_index_format)
+               if (preferred_index_format < 0) {
+                       printf(_("%d\n"), the_index.version);
+               } else if (preferred_index_format < INDEX_FORMAT_LB ||
+                          INDEX_FORMAT_UB < preferred_index_format) {
                        die("index-version %d not in range: %d..%d",
                            preferred_index_format,
                            INDEX_FORMAT_LB, INDEX_FORMAT_UB);
-
-               if (the_index.version != preferred_index_format)
-                       the_index.cache_changed |= SOMETHING_CHANGED;
-               the_index.version = preferred_index_format;
+               } else {
+                       if (the_index.version != preferred_index_format)
+                               the_index.cache_changed |= SOMETHING_CHANGED;
+                       report(_("index-version: was %d, set to %d"),
+                              the_index.version, preferred_index_format);
+                       the_index.version = preferred_index_format;
+               }
        }
 
        if (read_from_stdin) {
index 0c59b1c9eff0993821f49cd2de31eaf538733d6e..c0c4e65e6fb1986fadf2e98f0d19449e95905fe6 100644 (file)
@@ -1,9 +1,8 @@
-#include "cache.h"
+#include "builtin.h"
 #include "config.h"
 #include "gettext.h"
 #include "hash.h"
 #include "refs.h"
-#include "builtin.h"
 #include "object-name.h"
 #include "parse-options.h"
 #include "quote.h"
@@ -312,8 +311,8 @@ static void report_ok(const char *command)
        fflush(stdout);
 }
 
-static void parse_cmd_option(struct ref_transaction *transaction,
-                            const char *next, const char *end)
+static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
+                            const char *next, const char *end UNUSED)
 {
        const char *rest;
        if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination)
@@ -322,8 +321,8 @@ static void parse_cmd_option(struct ref_transaction *transaction,
                die("option unknown: %s", next);
 }
 
-static void parse_cmd_start(struct ref_transaction *transaction,
-                           const char *next, const char *end)
+static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
+                           const char *next, const char *end UNUSED)
 {
        if (*next != line_termination)
                die("start: extra input: %s", next);
@@ -331,7 +330,7 @@ static void parse_cmd_start(struct ref_transaction *transaction,
 }
 
 static void parse_cmd_prepare(struct ref_transaction *transaction,
-                             const char *next, const char *end)
+                             const char *next, const char *end UNUSED)
 {
        struct strbuf error = STRBUF_INIT;
        if (*next != line_termination)
@@ -342,7 +341,7 @@ static void parse_cmd_prepare(struct ref_transaction *transaction,
 }
 
 static void parse_cmd_abort(struct ref_transaction *transaction,
-                           const char *next, const char *end)
+                           const char *next, const char *end UNUSED)
 {
        struct strbuf error = STRBUF_INIT;
        if (*next != line_termination)
@@ -353,7 +352,7 @@ static void parse_cmd_abort(struct ref_transaction *transaction,
 }
 
 static void parse_cmd_commit(struct ref_transaction *transaction,
-                            const char *next, const char *end)
+                            const char *next, const char *end UNUSED)
 {
        struct strbuf error = STRBUF_INIT;
        if (*next != line_termination)
index 19dce3c06552e2e3d120b27b4563ebadf02dc18c..1dc3971edeb3837a1479ce519197880d28ba7699 100644 (file)
@@ -1,6 +1,5 @@
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "server-info.h"
index 44ad400e183464fd3b90c74165ded03a3129962d..1b09e5e1aa3f08e91bf6de731b111864ef405573 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Copyright (c) 2006 Franck Bui-Huu
  */
-#include "cache.h"
 #include "builtin.h"
 #include "archive.h"
+#include "path.h"
 #include "pkt-line.h"
 #include "sideband.h"
 #include "repository.h"
index beb9dd08610000f94d2365437e43bf0518c20c55..9b021ef026c28c97ece12b924833dff87c15a103 100644 (file)
@@ -1,9 +1,9 @@
-#include "cache.h"
 #include "builtin.h"
 #include "exec-cmd.h"
 #include "gettext.h"
 #include "pkt-line.h"
 #include "parse-options.h"
+#include "path.h"
 #include "protocol.h"
 #include "replace-object.h"
 #include "upload-pack.h"
@@ -36,7 +36,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
        };
 
        packet_trace_identity("upload-pack");
-       read_replace_refs = 0;
+       disable_replace_refs();
 
        argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
 
index 214999898079454affe0882be5b4e7a24a7a569b..8cf7dd9e2e5cef1d9238c22ed64ea07440d31528 100644 (file)
  * Copyright (C) Eric Biederman, 2005
  */
 #include "builtin.h"
+#include "attr.h"
 #include "config.h"
 #include "editor.h"
 #include "ident.h"
 #include "pager.h"
 #include "refs.h"
+#include "path.h"
+#include "strbuf.h"
 
 static const char var_usage[] = "git var (-l | <variable>)";
 
-static const char *editor(int flag)
+static char *committer(int ident_flag)
 {
-       return git_editor();
+       return xstrdup_or_null(git_committer_info(ident_flag));
 }
 
-static const char *sequence_editor(int flag)
+static char *author(int ident_flag)
 {
-       return git_sequence_editor();
+       return xstrdup_or_null(git_author_info(ident_flag));
 }
 
-static const char *pager(int flag)
+static char *editor(int ident_flag UNUSED)
+{
+       return xstrdup_or_null(git_editor());
+}
+
+static char *sequence_editor(int ident_flag UNUSED)
+{
+       return xstrdup_or_null(git_sequence_editor());
+}
+
+static char *pager(int ident_flag UNUSED)
 {
        const char *pgm = git_pager(1);
 
        if (!pgm)
                pgm = "cat";
-       return pgm;
+       return xstrdup(pgm);
+}
+
+static char *default_branch(int ident_flag UNUSED)
+{
+       return xstrdup_or_null(git_default_branch_name(1));
+}
+
+static char *shell_path(int ident_flag UNUSED)
+{
+       return xstrdup(SHELL_PATH);
 }
 
-static const char *default_branch(int flag)
+static char *git_attr_val_system(int ident_flag UNUSED)
 {
-       return git_default_branch_name(1);
+       if (git_attr_system_is_enabled()) {
+               char *file = xstrdup(git_attr_system_file());
+               normalize_path_copy(file, file);
+               return file;
+       }
+       return NULL;
+}
+
+static char *git_attr_val_global(int ident_flag UNUSED)
+{
+       char *file = xstrdup_or_null(git_attr_global_file());
+       if (file) {
+               normalize_path_copy(file, file);
+               return file;
+       }
+       return NULL;
+}
+
+static char *git_config_val_system(int ident_flag UNUSED)
+{
+       if (git_config_system()) {
+               char *file = git_system_config();
+               normalize_path_copy(file, file);
+               return file;
+       }
+       return NULL;
+}
+
+static char *git_config_val_global(int ident_flag UNUSED)
+{
+       struct strbuf buf = STRBUF_INIT;
+       char *user, *xdg;
+       size_t unused;
+
+       git_global_config(&user, &xdg);
+       if (xdg && *xdg) {
+               normalize_path_copy(xdg, xdg);
+               strbuf_addf(&buf, "%s\n", xdg);
+       }
+       if (user && *user) {
+               normalize_path_copy(user, user);
+               strbuf_addf(&buf, "%s\n", user);
+       }
+       free(xdg);
+       free(user);
+       strbuf_trim_trailing_newline(&buf);
+       if (buf.len == 0) {
+               strbuf_release(&buf);
+               return NULL;
+       }
+       return strbuf_detach(&buf, &unused);
 }
 
 struct git_var {
        const char *name;
-       const char *(*read)(int);
+       char *(*read)(int);
+       int multivalued;
 };
 static struct git_var git_vars[] = {
-       { "GIT_COMMITTER_IDENT", git_committer_info },
-       { "GIT_AUTHOR_IDENT",   git_author_info },
-       { "GIT_EDITOR", editor },
-       { "GIT_SEQUENCE_EDITOR", sequence_editor },
-       { "GIT_PAGER", pager },
-       { "GIT_DEFAULT_BRANCH", default_branch },
-       { "", NULL },
+       {
+               .name = "GIT_COMMITTER_IDENT",
+               .read = committer,
+       },
+       {
+               .name = "GIT_AUTHOR_IDENT",
+               .read = author,
+       },
+       {
+               .name = "GIT_EDITOR",
+               .read = editor,
+       },
+       {
+               .name = "GIT_SEQUENCE_EDITOR",
+               .read = sequence_editor,
+       },
+       {
+               .name = "GIT_PAGER",
+               .read = pager,
+       },
+       {
+               .name = "GIT_DEFAULT_BRANCH",
+               .read = default_branch,
+       },
+       {
+               .name = "GIT_SHELL_PATH",
+               .read = shell_path,
+       },
+       {
+               .name = "GIT_ATTR_SYSTEM",
+               .read = git_attr_val_system,
+       },
+       {
+               .name = "GIT_ATTR_GLOBAL",
+               .read = git_attr_val_global,
+       },
+       {
+               .name = "GIT_CONFIG_SYSTEM",
+               .read = git_config_val_system,
+       },
+       {
+               .name = "GIT_CONFIG_GLOBAL",
+               .read = git_config_val_global,
+               .multivalued = 1,
+       },
+       {
+               .name = "",
+               .read = NULL,
+       },
 };
 
 static void list_vars(void)
 {
        struct git_var *ptr;
-       const char *val;
+       char *val;
 
        for (ptr = git_vars; ptr->read; ptr++)
-               if ((val = ptr->read(0)))
-                       printf("%s=%s\n", ptr->name, val);
+               if ((val = ptr->read(0))) {
+                       if (ptr->multivalued && *val) {
+                               struct string_list list = STRING_LIST_INIT_DUP;
+                               int i;
+
+                               string_list_split(&list, val, '\n', -1);
+                               for (i = 0; i < list.nr; i++)
+                                       printf("%s=%s\n", ptr->name, list.items[i].string);
+                               string_list_clear(&list, 0);
+                       } else {
+                               printf("%s=%s\n", ptr->name, val);
+                       }
+                       free(val);
+               }
 }
 
 static const struct git_var *get_git_var(const char *var)
@@ -71,19 +199,20 @@ static const struct git_var *get_git_var(const char *var)
        return NULL;
 }
 
-static int show_config(const char *var, const char *value, void *cb)
+static int show_config(const char *var, const char *value,
+                      const struct config_context *ctx, void *cb)
 {
        if (value)
                printf("%s=%s\n", var, value);
        else
                printf("%s\n", var);
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
 {
        const struct git_var *git_var;
-       const char *val;
+       char *val;
 
        if (argc != 2)
                usage(var_usage);
@@ -104,6 +233,7 @@ int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
                return 1;
 
        printf("%s\n", val);
+       free(val);
 
        return 0;
 }
index 5d99b82a64f65efcc673ee8da144748f5e62fc82..9680b5870130615b7b4432a5ce456279db750aa4 100644 (file)
@@ -5,12 +5,11 @@
  *
  * Based on git-verify-tag
  */
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
 #include "gettext.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "commit.h"
 #include "run-command.h"
index 190fd6954092fe16f5e5e59dc01ba10445f30d45..011dddd2dc329292c363fbcfb10b71c218ffa034 100644 (file)
@@ -1,9 +1,9 @@
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "gettext.h"
 #include "run-command.h"
 #include "parse-options.h"
+#include "strbuf.h"
 
 #define VERIFY_PACK_VERBOSE 01
 #define VERIFY_PACK_STAT_ONLY 02
index c6019a0ad8cf79f92df9e1e443df373516f67db9..d8753270ebee4df6eed4b2dd5037f3fee97eb2c6 100644 (file)
@@ -5,9 +5,8 @@
  *
  * Based on git-verify-tag.sh
  */
-#include "cache.h"
-#include "config.h"
 #include "builtin.h"
+#include "config.h"
 #include "gettext.h"
 #include "tag.h"
 #include "run-command.h"
index f3180463be2a9801bb941eafcdf651181ac800fa..62b7e26f4bdb17f524914ab6e60143915d8f2565 100644 (file)
@@ -1,9 +1,9 @@
-#include "cache.h"
+#include "builtin.h"
 #include "abspath.h"
+#include "advice.h"
 #include "checkout.h"
 #include "config.h"
 #include "copy.h"
-#include "builtin.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "object-file.h"
 #include "object-name.h"
 #include "parse-options.h"
+#include "path.h"
 #include "strvec.h"
 #include "branch.h"
+#include "read-cache-ll.h"
 #include "refs.h"
+#include "remote.h"
 #include "repository.h"
 #include "run-command.h"
 #include "hook.h"
 #include "submodule.h"
 #include "utf8.h"
 #include "worktree.h"
-#include "wrapper.h"
 #include "quote.h"
 
 #define BUILTIN_WORKTREE_ADD_USAGE \
        N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n" \
-          "                 [-b <new-branch>] <path> [<commit-ish>]")
+          "                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]")
+
 #define BUILTIN_WORKTREE_LIST_USAGE \
        N_("git worktree list [-v | --porcelain [-z]]")
 #define BUILTIN_WORKTREE_LOCK_USAGE \
 #define BUILTIN_WORKTREE_UNLOCK_USAGE \
        N_("git worktree unlock <worktree>")
 
+#define WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT \
+       _("No possible source branch, inferring '--orphan'")
+
+#define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \
+       _("If you meant to create a worktree containing a new orphan branch\n" \
+       "(branch with no commits) for this repository, you can do so\n" \
+       "using the --orphan flag:\n" \
+       "\n" \
+       "    git worktree add --orphan -b %s %s\n")
+
+#define WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT \
+       _("If you meant to create a worktree containing a new orphan branch\n" \
+       "(branch with no commits) for this repository, you can do so\n" \
+       "using the --orphan flag:\n" \
+       "\n" \
+       "    git worktree add --orphan %s\n")
+
 static const char * const git_worktree_usage[] = {
        BUILTIN_WORKTREE_ADD_USAGE,
        BUILTIN_WORKTREE_LIST_USAGE,
@@ -99,6 +119,7 @@ struct add_opts {
        int detach;
        int quiet;
        int checkout;
+       int orphan;
        const char *keep_locked;
 };
 
@@ -107,14 +128,15 @@ static int verbose;
 static int guess_remote;
 static timestamp_t expire;
 
-static int git_worktree_config(const char *var, const char *value, void *cb)
+static int git_worktree_config(const char *var, const char *value,
+                              const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "worktree.guessremote")) {
                guess_remote = git_config_bool(var, value);
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static int delete_git_dir(const char *id)
@@ -372,6 +394,22 @@ static int checkout_worktree(const struct add_opts *opts,
        return run_command(&cp);
 }
 
+static int make_worktree_orphan(const char * ref, const struct add_opts *opts,
+                               struct strvec *child_env)
+{
+       struct strbuf symref = STRBUF_INIT;
+       struct child_process cp = CHILD_PROCESS_INIT;
+
+       validate_new_branchname(ref, &symref, 0);
+       strvec_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL);
+       if (opts->quiet)
+               strvec_push(&cp.args, "--quiet");
+       strvec_pushv(&cp.env, child_env->v);
+       strbuf_release(&symref);
+       cp.git_cmd = 1;
+       return run_command(&cp);
+}
+
 static int add_worktree(const char *path, const char *refname,
                        const struct add_opts *opts)
 {
@@ -401,7 +439,7 @@ static int add_worktree(const char *path, const char *refname,
                        die_if_checked_out(symref.buf, 0);
        }
        commit = lookup_commit_reference_by_name(refname);
-       if (!commit)
+       if (!commit && !opts->orphan)
                die(_("invalid reference: %s"), refname);
 
        name = worktree_basename(path, &len);
@@ -483,17 +521,17 @@ static int add_worktree(const char *path, const char *refname,
         * values from the current worktree into the new one, that way the
         * new worktree behaves the same as this one.
         */
-       if (repository_format_worktree_config)
+       if (the_repository->repository_format_worktree_config)
                copy_filtered_worktree_config(sb_repo.buf);
 
        strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
        strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
        cp.git_cmd = 1;
 
-       if (!is_branch)
+       if (!is_branch && commit) {
                strvec_pushl(&cp.args, "update-ref", "HEAD",
                             oid_to_hex(&commit->object.oid), NULL);
-       else {
+       else {
                strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
                             symref.buf, NULL);
                if (opts->quiet)
@@ -505,6 +543,10 @@ static int add_worktree(const char *path, const char *refname,
        if (ret)
                goto done;
 
+       if (opts->orphan &&
+           (ret = make_worktree_orphan(refname, opts, &child_env)))
+               goto done;
+
        if (opts->checkout &&
            (ret = checkout_worktree(opts, &child_env)))
                goto done;
@@ -524,7 +566,7 @@ done:
         * Hook failure does not warrant worktree deletion, so run hook after
         * is_junk is cleared, but do return appropriate code when hook fails.
         */
-       if (!ret && opts->checkout) {
+       if (!ret && opts->checkout && !opts->orphan) {
                struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
 
                strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
@@ -572,7 +614,7 @@ static void print_preparing_worktree_line(int detach,
                else {
                        struct commit *commit = lookup_commit_reference_by_name(branch);
                        if (!commit)
-                               die(_("invalid reference: %s"), branch);
+                               BUG(_("unreachable: invalid reference: %s"), branch);
                        fprintf_ln(stderr, _("Preparing worktree (detached HEAD %s)"),
                                  repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
                }
@@ -580,6 +622,123 @@ static void print_preparing_worktree_line(int detach,
        }
 }
 
+/**
+ * Callback to short circuit iteration over refs on the first reference
+ * corresponding to a valid oid.
+ *
+ * Returns 0 on failure and non-zero on success.
+ */
+static int first_valid_ref(const char *refname UNUSED,
+                          const struct object_id *oid UNUSED,
+                          int flags UNUSED,
+                          void *cb_data UNUSED)
+{
+       return 1;
+}
+
+/**
+ * Verifies HEAD and determines whether there exist any valid local references.
+ *
+ * - Checks whether HEAD points to a valid reference.
+ *
+ * - Checks whether any valid local branches exist.
+ *
+ * - Emits a warning if there exist any valid branches but HEAD does not point
+ *   to a valid reference.
+ *
+ * Returns 1 if any of the previous checks are true, otherwise returns 0.
+ */
+static int can_use_local_refs(const struct add_opts *opts)
+{
+       if (head_ref(first_valid_ref, NULL)) {
+               return 1;
+       } else if (for_each_branch_ref(first_valid_ref, NULL)) {
+               if (!opts->quiet) {
+                       struct strbuf path = STRBUF_INIT;
+                       struct strbuf contents = STRBUF_INIT;
+
+                       strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
+                       strbuf_addstr(&path, "/HEAD");
+                       strbuf_read_file(&contents, path.buf, 64);
+                       strbuf_stripspace(&contents, 0);
+                       strbuf_strip_suffix(&contents, "\n");
+
+                       warning(_("HEAD points to an invalid (or orphaned) reference.\n"
+                                 "HEAD path: '%s'\n"
+                                 "HEAD contents: '%s'"),
+                                 path.buf, contents.buf);
+                       strbuf_release(&path);
+                       strbuf_release(&contents);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * Reports whether the necessary flags were set and whether the repository has
+ * remote references to attempt DWIM tracking of upstream branches.
+ *
+ * 1. Checks that `--guess-remote` was used or `worktree.guessRemote = true`.
+ *
+ * 2. Checks whether any valid remote branches exist.
+ *
+ * 3. Checks that there exists at least one remote and emits a warning/error
+ *    if both checks 1. and 2. are false (can be bypassed with `--force`).
+ *
+ * Returns 1 if checks 1. and 2. are true, otherwise 0.
+ */
+static int can_use_remote_refs(const struct add_opts *opts)
+{
+       if (!guess_remote) {
+               return 0;
+       } else if (for_each_remote_ref(first_valid_ref, NULL)) {
+               return 1;
+       } else if (!opts->force && remote_get(NULL)) {
+               die(_("No local or remote refs exist despite at least one remote\n"
+                     "present, stopping; use 'add -f' to override or fetch a remote first"));
+       }
+       return 0;
+}
+
+/**
+ * Determines whether `--orphan` should be inferred in the evaluation of
+ * `worktree add path/` or `worktree add -b branch path/` and emits an error
+ * if the supplied arguments would produce an illegal combination when the
+ * `--orphan` flag is included.
+ *
+ * `opts` and `opt_track` contain the other options & flags supplied to the
+ * command.
+ *
+ * remote determines whether to check `can_use_remote_refs()` or not. This
+ * is primarily to differentiate between the basic `add` DWIM and `add -b`.
+ *
+ * Returns 1 when inferring `--orphan`, 0 otherwise, and emits an error when
+ * `--orphan` is inferred but doing so produces an illegal combination of
+ * options and flags. Additionally produces an error when remote refs are
+ * checked and the repo is in a state that looks like the user added a remote
+ * but forgot to fetch (and did not override the warning with -f).
+ */
+static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
+{
+       if (can_use_local_refs(opts)) {
+               return 0;
+       } else if (remote && can_use_remote_refs(opts)) {
+               return 0;
+       } else if (!opts->quiet) {
+               fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);
+       }
+
+       if (opt_track) {
+               die(_("'%s' and '%s' cannot be used together"), "--orphan",
+                   "--track");
+       } else if (!opts->checkout) {
+               die(_("'%s' and '%s' cannot be used together"), "--orphan",
+                   "--no-checkout");
+       }
+       return 1;
+}
+
 static const char *dwim_branch(const char *path, const char **new_branch)
 {
        int n;
@@ -616,6 +775,7 @@ static int add(int ac, const char **av, const char *prefix)
        const char *opt_track = NULL;
        const char *lock_reason = NULL;
        int keep_locked = 0;
+       int used_new_branch_options;
        struct option options[] = {
                OPT__FORCE(&opts.force,
                           N_("checkout <branch> even if already checked out in other worktree"),
@@ -624,6 +784,7 @@ static int add(int ac, const char **av, const char *prefix)
                           N_("create a new branch")),
                OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
                           N_("create or reset a branch")),
+               OPT_BOOL(0, "orphan", &opts.orphan, N_("create unborn/orphaned branch")),
                OPT_BOOL('d', "detach", &opts.detach, N_("detach HEAD at named commit")),
                OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
                OPT_BOOL(0, "lock", &keep_locked, N_("keep the new working tree locked")),
@@ -644,6 +805,17 @@ static int add(int ac, const char **av, const char *prefix)
        ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
        if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
                die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
+       if (opts.detach && opts.orphan)
+               die(_("options '%s', and '%s' cannot be used together"),
+                   "--orphan", "--detach");
+       if (opts.orphan && opt_track)
+               die(_("'%s' and '%s' cannot be used together"), "--orphan", "--track");
+       if (opts.orphan && !opts.checkout)
+               die(_("'%s' and '%s' cannot be used together"), "--orphan",
+                   "--no-checkout");
+       if (opts.orphan && ac == 2)
+               die(_("'%s' and '%s' cannot be used together"), "--orphan",
+                   _("<commit-ish>"));
        if (lock_reason && !keep_locked)
                die(_("the option '%s' requires '%s'"), "--reason", "--lock");
        if (lock_reason)
@@ -656,6 +828,7 @@ static int add(int ac, const char **av, const char *prefix)
 
        path = prefix_filename(prefix, av[0]);
        branch = ac < 2 ? "HEAD" : av[1];
+       used_new_branch_options = new_branch || new_branch_force;
 
        if (!strcmp(branch, "-"))
                branch = "@{-1}";
@@ -672,13 +845,28 @@ static int add(int ac, const char **av, const char *prefix)
                strbuf_release(&symref);
        }
 
-       if (ac < 2 && !new_branch && !opts.detach) {
+       if (opts.orphan && !new_branch) {
+               int n;
+               const char *s = worktree_basename(path, &n);
+               new_branch = xstrndup(s, n);
+       } else if (opts.orphan) {
+               // No-op
+       } else if (opts.detach) {
+               // Check HEAD
+               if (!strcmp(branch, "HEAD"))
+                       can_use_local_refs(&opts);
+       } else if (ac < 2 && new_branch) {
+               // DWIM: Infer --orphan when repo has no refs.
+               opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
+       } else if (ac < 2) {
+               // DWIM: Guess branch name from path.
                const char *s = dwim_branch(path, &new_branch);
                if (s)
                        branch = s;
-       }
 
-       if (ac == 2 && !new_branch && !opts.detach) {
+               // DWIM: Infer --orphan when repo has no refs.
+               opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
+       } else if (ac == 2) {
                struct object_id oid;
                struct commit *commit;
                const char *remote;
@@ -691,11 +879,31 @@ static int add(int ac, const char **av, const char *prefix)
                                branch = remote;
                        }
                }
+
+               if (!strcmp(branch, "HEAD"))
+                       can_use_local_refs(&opts);
+
+       }
+
+       if (!opts.orphan && !lookup_commit_reference_by_name(branch)) {
+               int attempt_hint = !opts.quiet && (ac < 2);
+               if (attempt_hint && used_new_branch_options) {
+                       advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+                               WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT,
+                               new_branch, path);
+               } else if (attempt_hint) {
+                       advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+                               WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT, path);
+               }
+               die(_("invalid reference: %s"), branch);
        }
+
        if (!opts.quiet)
                print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
 
-       if (new_branch) {
+       if (opts.orphan) {
+               branch = new_branch;
+       } else if (new_branch) {
                struct child_process cp = CHILD_PROCESS_INIT;
                cp.git_cmd = 1;
                strvec_push(&cp.args, "branch");
@@ -1200,5 +1408,9 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
                prefix = "";
 
        ac = parse_options(ac, av, prefix, options, git_worktree_usage, 0);
+
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
+
        return fn(ac, av, prefix);
 }
index 84b83318c967d1401792a99ca85ca433812e6885..66e83d0ecba04c90d1e12a2529cc40210808035c 100644 (file)
@@ -5,7 +5,6 @@
  */
 #define USE_THE_INDEX_VARIABLE
 #include "builtin.h"
-#include "cache.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
index d843279715c3369ed92f853bd91c0e846af55049..6ce62999e58523e20a686801446daaf0d924e9be 100644 (file)
@@ -2,7 +2,6 @@
  * Copyright (c) 2011, Google Inc.
  */
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "bulk-checkin.h"
 #include "environment.h"
 #include "gettext.h"
@@ -16,8 +15,7 @@
 #include "tmp-objdir.h"
 #include "packfile.h"
 #include "object-file.h"
-#include "object-store.h"
-#include "wrapper.h"
+#include "object-store-ll.h"
 
 static int odb_transaction_nesting;
 
@@ -157,10 +155,10 @@ static int already_written(struct bulk_checkin_packfile *state, struct object_id
  * status before calling us just in case we ask it to call us again
  * with a new pack.
  */
-static int stream_to_pack(struct bulk_checkin_packfile *state,
-                         git_hash_ctx *ctx, off_t *already_hashed_to,
-                         int fd, size_t size, enum object_type type,
-                         const char *path, unsigned flags)
+static int stream_blob_to_pack(struct bulk_checkin_packfile *state,
+                              git_hash_ctx *ctx, off_t *already_hashed_to,
+                              int fd, size_t size, const char *path,
+                              unsigned flags)
 {
        git_zstream s;
        unsigned char ibuf[16384];
@@ -172,7 +170,7 @@ static int stream_to_pack(struct bulk_checkin_packfile *state,
 
        git_deflate_init(&s, pack_compression_level);
 
-       hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), type, size);
+       hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);
        s.next_out = obuf + hdrlen;
        s.avail_out = sizeof(obuf) - hdrlen;
 
@@ -249,11 +247,10 @@ static void prepare_to_stream(struct bulk_checkin_packfile *state,
                die_errno("unable to write pack header");
 }
 
-static int deflate_to_pack(struct bulk_checkin_packfile *state,
-                          struct object_id *result_oid,
-                          int fd, size_t size,
-                          enum object_type type, const char *path,
-                          unsigned flags)
+static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
+                               struct object_id *result_oid,
+                               int fd, size_t size,
+                               const char *path, unsigned flags)
 {
        off_t seekback, already_hashed_to;
        git_hash_ctx ctx;
@@ -267,9 +264,10 @@ static int deflate_to_pack(struct bulk_checkin_packfile *state,
                return error("cannot find the current offset");
 
        header_len = format_object_header((char *)obuf, sizeof(obuf),
-                                         type, size);
+                                         OBJ_BLOB, size);
        the_hash_algo->init_fn(&ctx);
        the_hash_algo->update_fn(&ctx, obuf, header_len);
+       the_hash_algo->init_fn(&checkpoint.ctx);
 
        /* Note: idx is non-NULL when we are writing */
        if ((flags & HASH_WRITE_OBJECT) != 0)
@@ -284,8 +282,8 @@ static int deflate_to_pack(struct bulk_checkin_packfile *state,
                        idx->offset = state->offset;
                        crc32_begin(state->f);
                }
-               if (!stream_to_pack(state, &ctx, &already_hashed_to,
-                                   fd, size, type, path, flags))
+               if (!stream_blob_to_pack(state, &ctx, &already_hashed_to,
+                                        fd, size, path, flags))
                        break;
                /*
                 * Writing this object to the current pack will make
@@ -352,12 +350,12 @@ void fsync_loose_object_bulk_checkin(int fd, const char *filename)
        }
 }
 
-int index_bulk_checkin(struct object_id *oid,
-                      int fd, size_t size, enum object_type type,
-                      const char *path, unsigned flags)
+int index_blob_bulk_checkin(struct object_id *oid,
+                           int fd, size_t size,
+                           const char *path, unsigned flags)
 {
-       int status = deflate_to_pack(&bulk_checkin_packfile, oid, fd, size, type,
-                                    path, flags);
+       int status = deflate_blob_to_pack(&bulk_checkin_packfile, oid, fd, size,
+                                         path, flags);
        if (!odb_transaction_nesting)
                flush_bulk_checkin_packfile(&bulk_checkin_packfile);
        return status;
index 48fe9a6e9171e77aba4f2a3c7ab1edd79e9291b8..aa7286a7b3e127bbd4ee14cf99e3fd21f46df445 100644 (file)
@@ -9,9 +9,9 @@
 void prepare_loose_object_bulk_checkin(void);
 void fsync_loose_object_bulk_checkin(int fd, const char *filename);
 
-int index_bulk_checkin(struct object_id *oid,
-                      int fd, size_t size, enum object_type type,
-                      const char *path, unsigned flags);
+int index_blob_bulk_checkin(struct object_id *oid,
+                           int fd, size_t size,
+                           const char *path, unsigned flags);
 
 /*
  * Tell the object database to optimize for adding
index 2a2db1a1d390f89be51cbad4b5313d4ac67ad5c0..8492fffd2f759f97e750063c4de0eefdc0763d99 100644 (file)
@@ -4,7 +4,7 @@
 #include "copy.h"
 #include "environment.h"
 #include "gettext.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "refs.h"
 #include "run-command.h"
 #include "hashmap.h"
@@ -20,7 +20,7 @@ static struct {
        { BUNDLE_HEURISTIC_CREATIONTOKEN, "creationToken" },
 };
 
-static int compare_bundles(const void *hashmap_cmp_fn_data,
+static int compare_bundles(const void *hashmap_cmp_fn_data UNUSED,
                           const struct hashmap_entry *he1,
                           const struct hashmap_entry *he2,
                           const void *id)
@@ -45,7 +45,7 @@ void init_bundle_list(struct bundle_list *list)
 }
 
 static int clear_remote_bundle_info(struct remote_bundle_info *bundle,
-                                   void *data)
+                                   void *data UNUSED)
 {
        FREE_AND_NULL(bundle->id);
        FREE_AND_NULL(bundle->uri);
@@ -224,7 +224,9 @@ static int bundle_list_update(const char *key, const char *value,
        return 0;
 }
 
-static int config_to_bundle_list(const char *key, const char *value, void *data)
+static int config_to_bundle_list(const char *key, const char *value,
+                                const struct config_context *ctx UNUSED,
+                                void *data)
 {
        struct bundle_list *list = data;
        return bundle_list_update(key, value, list);
@@ -253,6 +255,7 @@ int bundle_uri_parse_config_format(const char *uri,
        }
        result = git_config_from_file_with_options(config_to_bundle_list,
                                                   filename, list,
+                                                  CONFIG_SCOPE_UNKNOWN,
                                                   &opts);
 
        if (!result && list->mode == BUNDLE_MODE_NONE) {
@@ -776,7 +779,7 @@ static int unbundle_all_bundles(struct repository *r,
        return 0;
 }
 
-static int unlink_bundle(struct remote_bundle_info *info, void *data)
+static int unlink_bundle(struct remote_bundle_info *info, void *data UNUSED)
 {
        if (info->file)
                unlink_or_warn(info->file);
@@ -871,7 +874,9 @@ cached:
        return advertise_bundle_uri;
 }
 
-static int config_to_packet_line(const char *key, const char *value, void *data)
+static int config_to_packet_line(const char *key, const char *value,
+                                const struct config_context *ctx UNUSED,
+                                void *data)
 {
        struct packet_reader *writer = data;
 
index a5505368de5a9190e0ee6238b6f905cfca5f0efe..a9744da255c6d527e53e65b71c1f4b9a9d6db4bd 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -4,7 +4,7 @@
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "object.h"
 #include "commit.h"
@@ -271,10 +271,10 @@ int verify_bundle(struct repository *r,
                        list_refs(r, 0, NULL);
                }
 
-               printf_ln("The bundle uses this hash algorithm: %s",
+               printf_ln(_("The bundle uses this hash algorithm: %s"),
                          header->hash_algo->name);
                if (header->filter.choice)
-                       printf_ln("The bundle uses this filter: %s",
+                       printf_ln(_("The bundle uses this filter: %s"),
                                  list_objects_filter_spec(&header->filter));
        }
 cleanup:
index ebfe649b330760eb5f13f172c4d5a9f4ed29da41..641427ed410af39be80be22460a103dbad2d3d35 100644 (file)
@@ -1,5 +1,4 @@
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "environment.h"
 #include "hex.h"
 #include "lockfile.h"
@@ -8,7 +7,8 @@
 #include "cache-tree.h"
 #include "bulk-checkin.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
 #include "replace-object.h"
 #include "promisor-remote.h"
 #include "sparse-index.h"
index e7d613c907e9f120109128b97f9e72038855d679..cdc7f39b7039b94a14a42ec74b0e27917c43fe4f 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "chunk-format.h"
 #include "csum-file.h"
 #include "gettext.h"
@@ -103,7 +102,8 @@ int read_table_of_contents(struct chunkfile *cf,
                           const unsigned char *mfile,
                           size_t mfile_size,
                           uint64_t toc_offset,
-                          int toc_length)
+                          int toc_length,
+                          unsigned expected_alignment)
 {
        int i;
        uint32_t chunk_id;
@@ -121,6 +121,11 @@ int read_table_of_contents(struct chunkfile *cf,
                        error(_("terminating chunk id appears earlier than expected"));
                        return 1;
                }
+               if (chunk_offset % expected_alignment != 0) {
+                       error(_("chunk id %"PRIx32" not %d-byte aligned"),
+                             chunk_id, expected_alignment);
+                       return 1;
+               }
 
                table_of_contents += CHUNK_TOC_ENTRY_SIZE;
                next_chunk_offset = get_be64(table_of_contents + 4);
@@ -155,20 +160,28 @@ int read_table_of_contents(struct chunkfile *cf,
        return 0;
 }
 
+struct pair_chunk_data {
+       const unsigned char **p;
+       size_t *size;
+};
+
 static int pair_chunk_fn(const unsigned char *chunk_start,
                         size_t chunk_size,
                         void *data)
 {
-       const unsigned char **p = data;
-       *p = chunk_start;
+       struct pair_chunk_data *pcd = data;
+       *pcd->p = chunk_start;
+       *pcd->size = chunk_size;
        return 0;
 }
 
 int pair_chunk(struct chunkfile *cf,
               uint32_t chunk_id,
-              const unsigned char **p)
+              const unsigned char **p,
+              size_t *size)
 {
-       return read_chunk(cf, chunk_id, pair_chunk_fn, p);
+       struct pair_chunk_data pcd = { .p = p, .size = size };
+       return read_chunk(cf, chunk_id, pair_chunk_fn, &pcd);
 }
 
 int read_chunk(struct chunkfile *cf,
index c7794e84adda364bc0ad14a3d1d61467d73eaadd..14b76180ef768f6b5c38aa1cda128ab87d2327ae 100644 (file)
@@ -36,20 +36,23 @@ int read_table_of_contents(struct chunkfile *cf,
                           const unsigned char *mfile,
                           size_t mfile_size,
                           uint64_t toc_offset,
-                          int toc_length);
+                          int toc_length,
+                          unsigned expected_alignment);
 
 #define CHUNK_NOT_FOUND (-2)
 
 /*
  * Find 'chunk_id' in the given chunkfile and assign the
  * given pointer to the position in the mmap'd file where
- * that chunk begins.
+ * that chunk begins. Likewise the "size" parameter is filled
+ * with the size of the chunk.
  *
  * Returns CHUNK_NOT_FOUND if the chunk does not exist.
  */
 int pair_chunk(struct chunkfile *cf,
               uint32_t chunk_id,
-              const unsigned char **p);
+              const unsigned char **p,
+              size_t *size);
 
 typedef int (*chunk_read_fn)(const unsigned char *chunk_start,
                             size_t chunk_size, void *data);
diff --git a/ci/config/README b/ci/config/README
new file mode 100644 (file)
index 0000000..8de3a04
--- /dev/null
@@ -0,0 +1,14 @@
+You can configure some aspects of the GitHub Actions-based CI on a
+per-repository basis by setting "variables" and "secrets" from with the
+GitHub web interface. These can be found at:
+
+  https://github.com/<user>/git/settings/secrets/actions
+
+The following variables can be used:
+
+ - CI_BRANCHES
+
+   By default, CI is run when any branch is pushed. If this variable is
+   non-empty, then only the branches it lists will run CI. Branch names
+   should be separated by spaces, and should use their shortened form
+   (e.g., "main", not "refs/heads/main").
diff --git a/ci/config/allow-ref.sample b/ci/config/allow-ref.sample
deleted file mode 100755 (executable)
index af0e076..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-#
-# Sample script for enabling/disabling GitHub Actions CI runs on
-# particular refs. By default, CI is run for all branches pushed to
-# GitHub. You can override this by dropping the ".sample" from the script,
-# editing it, committing, and pushing the result to the "ci-config" branch of
-# your repository:
-#
-#   git checkout -b ci-config
-#   cp allow-ref.sample allow-ref
-#   $EDITOR allow-ref
-#   git add allow-ref
-#   git commit -am "implement my ci preferences"
-#   git push
-#
-# This script will then be run when any refs are pushed to that repository. It
-# gets the fully qualified refname as the first argument, and should exit with
-# success only for refs for which you want to run CI.
-
-case "$1" in
-# allow one-off tests by pushing to "for-ci" or "for-ci/mybranch"
-refs/heads/for-ci*) true ;;
-# always build your integration branch
-refs/heads/my-integration-branch) true ;;
-# don't build any other branches or tags
-*) false ;;
-esac
index db7105e8a8dcdff1432d5ec972e3262e4f787c16..6fbb5bade127c33c969f4a3c4d3af40d04fe9d24 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -278,11 +278,10 @@ linux-leaks)
        export GIT_TEST_PASSING_SANITIZE_LEAK=true
        export GIT_TEST_SANITIZE_LEAK_LOG=true
        ;;
-linux-asan)
-       export SANITIZE=address
-       ;;
-linux-ubsan)
-       export SANITIZE=undefined
+linux-asan-ubsan)
+       export SANITIZE=address,undefined
+       export NO_SVN_TESTS=LetsSaveSomeTime
+       MAKEFLAGS="$MAKEFLAGS NO_PYTHON=YepBecauseP4FlakesTooOften"
        ;;
 esac
 
index a18b13a41dd462edd3643b3fc9cd59404c2de6c3..2528f25e31d3c860d1f2dc435af320a4f1b4973c 100755 (executable)
@@ -29,6 +29,7 @@ linux-TEST-vars)
        export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
        export GIT_TEST_NO_WRITE_REV_INDEX=1
        export GIT_TEST_CHECKOUT_WORKERS=2
+       export GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=1
        ;;
 linux-clang)
        export GIT_TEST_DEFAULT_HASH=sha1
diff --git a/color.c b/color.c
index 83abb11eda095e15e2b33a4588cecaa6eb1c3a28..f663c06ac4eddc7b8085739318ddfc99a3ee7583 100644 (file)
--- a/color.c
+++ b/color.c
@@ -3,7 +3,7 @@
 #include "color.h"
 #include "editor.h"
 #include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
 #include "pager.h"
 #include "strbuf.h"
 
@@ -430,14 +430,6 @@ int git_color_config(const char *var, const char *value, void *cb UNUSED)
        return 0;
 }
 
-int git_color_default_config(const char *var, const char *value, void *cb)
-{
-       if (git_color_config(var, value, cb) < 0)
-               return -1;
-
-       return git_default_config(var, value, cb);
-}
-
 void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
 {
        if (*color)
diff --git a/color.h b/color.h
index cfc8f841b237c72a0a2ea8b7e42d58dc1cab5f9f..bb28343be210643b57201c6a68ac4f718fa8ebc8 100644 (file)
--- a/color.h
+++ b/color.h
@@ -88,12 +88,8 @@ extern const int column_colors_ansi_max;
  */
 extern int color_stdout_is_tty;
 
-/*
- * Use the first one if you need only color config; the second is a convenience
- * if you are just going to change to git_default_config, too.
- */
+/* Parse color config. */
 int git_color_config(const char *var, const char *value, void *cb);
-int git_color_default_config(const char *var, const char *value, void *cb);
 
 /*
  * Parse a config option, which can be a boolean or one of
index 1e3cd7fb170413eb47677269a77526b41e0ba5c7..f90f442482932e618cc7399924c00ddde8c50eaf 100644 (file)
@@ -1,5 +1,5 @@
 #include "git-compat-util.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "convert.h"
 #include "blob.h"
@@ -17,7 +17,6 @@
 #include "userdiff.h"
 #include "oid-array.h"
 #include "revision.h"
-#include "wrapper.h"
 
 static int compare_paths(const struct combine_diff_path *one,
                          const struct diff_filespec *two)
index 843bdb458d02fbd2aa4721047aa376a1fe25891f..c2b782af3b649fbf3deea7d90c959e10f951a003 100644 (file)
@@ -12,8 +12,9 @@
 #include "hash-lookup.h"
 #include "commit-graph.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oid-array.h"
+#include "path.h"
 #include "alloc.h"
 #include "hashmap.h"
 #include "replace-object.h"
@@ -25,7 +26,6 @@
 #include "trace2.h"
 #include "tree.h"
 #include "chunk-format.h"
-#include "wrapper.h"
 
 void git_test_write_commit_graph_or_die(void)
 {
@@ -128,6 +128,16 @@ timestamp_t commit_graph_generation(const struct commit *c)
        return GENERATION_NUMBER_INFINITY;
 }
 
+static timestamp_t commit_graph_generation_from_graph(const struct commit *c)
+{
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       if (!data || data->graph_pos == COMMIT_NOT_FROM_GRAPH)
+               return GENERATION_NUMBER_INFINITY;
+       return data->generation;
+}
+
 static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
 {
        unsigned int i, nth_slab;
@@ -204,14 +214,12 @@ static struct commit_graph *alloc_commit_graph(void)
        return g;
 }
 
-extern int read_replace_refs;
-
 static int commit_graph_compatible(struct repository *r)
 {
        if (!r->gitdir)
                return 0;
 
-       if (read_replace_refs) {
+       if (replace_refs_enabled(r)) {
                prepare_replace_object(r);
                if (hashmap_get_size(&r->objects->replace_map->map))
                        return 0;
@@ -269,6 +277,8 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
 
 static int verify_commit_graph_lite(struct commit_graph *g)
 {
+       int i;
+
        /*
         * Basic validation shared between parse_commit_graph()
         * which'll be called every time the graph is used, and the
@@ -294,6 +304,30 @@ static int verify_commit_graph_lite(struct commit_graph *g)
                return 1;
        }
 
+       for (i = 0; i < 255; i++) {
+               uint32_t oid_fanout1 = ntohl(g->chunk_oid_fanout[i]);
+               uint32_t oid_fanout2 = ntohl(g->chunk_oid_fanout[i + 1]);
+
+               if (oid_fanout1 > oid_fanout2) {
+                       error("commit-graph fanout values out of order");
+                       return 1;
+               }
+       }
+       if (ntohl(g->chunk_oid_fanout[255]) != g->num_commits) {
+               error("commit-graph oid table and fanout disagree on size");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int graph_read_oid_fanout(const unsigned char *chunk_start,
+                                size_t chunk_size, void *data)
+{
+       struct commit_graph *g = data;
+       if (chunk_size != 256 * sizeof(uint32_t))
+               return error("commit-graph oid fanout chunk is wrong size");
+       g->chunk_oid_fanout = (const uint32_t *)chunk_start;
        return 0;
 }
 
@@ -306,12 +340,54 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,
        return 0;
 }
 
+static int graph_read_commit_data(const unsigned char *chunk_start,
+                                 size_t chunk_size, void *data)
+{
+       struct commit_graph *g = data;
+       if (chunk_size != g->num_commits * GRAPH_DATA_WIDTH)
+               return error("commit-graph commit data chunk is wrong size");
+       g->chunk_commit_data = chunk_start;
+       return 0;
+}
+
+static int graph_read_generation_data(const unsigned char *chunk_start,
+                                     size_t chunk_size, void *data)
+{
+       struct commit_graph *g = data;
+       if (chunk_size != g->num_commits * sizeof(uint32_t))
+               return error("commit-graph generations chunk is wrong size");
+       g->chunk_generation_data = chunk_start;
+       return 0;
+}
+
+static int graph_read_bloom_index(const unsigned char *chunk_start,
+                                 size_t chunk_size, void *data)
+{
+       struct commit_graph *g = data;
+       if (chunk_size != g->num_commits * 4) {
+               warning("commit-graph changed-path index chunk is too small");
+               return -1;
+       }
+       g->chunk_bloom_indexes = chunk_start;
+       return 0;
+}
+
 static int graph_read_bloom_data(const unsigned char *chunk_start,
                                  size_t chunk_size, void *data)
 {
        struct commit_graph *g = data;
        uint32_t hash_version;
+
+       if (chunk_size < BLOOMDATA_CHUNK_HEADER_SIZE) {
+               warning("ignoring too-small changed-path chunk"
+                       " (%"PRIuMAX" < %"PRIuMAX") in commit-graph file",
+                       (uintmax_t)chunk_size,
+                       (uintmax_t)BLOOMDATA_CHUNK_HEADER_SIZE);
+               return -1;
+       }
+
        g->chunk_bloom_data = chunk_start;
+       g->chunk_bloom_data_size = chunk_size;
        hash_version = get_be32(chunk_start);
 
        if (hash_version != 1)
@@ -383,29 +459,31 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,
        cf = init_chunkfile(NULL);
 
        if (read_table_of_contents(cf, graph->data, graph_size,
-                                  GRAPH_HEADER_SIZE, graph->num_chunks))
+                                  GRAPH_HEADER_SIZE, graph->num_chunks, 1))
                goto free_and_return;
 
-       pair_chunk(cf, GRAPH_CHUNKID_OIDFANOUT,
-                  (const unsigned char **)&graph->chunk_oid_fanout);
+       read_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, graph_read_oid_fanout, graph);
        read_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, graph_read_oid_lookup, graph);
-       pair_chunk(cf, GRAPH_CHUNKID_DATA, &graph->chunk_commit_data);
-       pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges);
-       pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs);
+       read_chunk(cf, GRAPH_CHUNKID_DATA, graph_read_commit_data, graph);
+       pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges,
+                  &graph->chunk_extra_edges_size);
+       pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,
+                  &graph->chunk_base_graphs_size);
 
        if (s->commit_graph_generation_version >= 2) {
-               pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
-                       &graph->chunk_generation_data);
+               read_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
+                          graph_read_generation_data, graph);
                pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
-                       &graph->chunk_generation_data_overflow);
+                          &graph->chunk_generation_data_overflow,
+                          &graph->chunk_generation_data_overflow_size);
 
                if (graph->chunk_generation_data)
                        graph->read_generation_data = 1;
        }
 
        if (s->commit_graph_read_changed_paths) {
-               pair_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
-                          &graph->chunk_bloom_indexes);
+               read_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
+                          graph_read_bloom_index, graph);
                read_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
                           graph_read_bloom_data, graph);
        }
@@ -465,6 +543,31 @@ static struct commit_graph *load_commit_graph_v1(struct repository *r,
        return g;
 }
 
+/*
+ * returns 1 if and only if all graphs in the chain have
+ * corrected commit dates stored in the generation_data chunk.
+ */
+static int validate_mixed_generation_chain(struct commit_graph *g)
+{
+       int read_generation_data = 1;
+       struct commit_graph *p = g;
+
+       while (read_generation_data && p) {
+               read_generation_data = p->read_generation_data;
+               p = p->base_graph;
+       }
+
+       if (read_generation_data)
+               return 1;
+
+       while (g) {
+               g->read_generation_data = 0;
+               g = g->base_graph;
+       }
+
+       return 0;
+}
+
 static int add_graph_to_chain(struct commit_graph *g,
                              struct commit_graph *chain,
                              struct object_id *oids,
@@ -477,12 +580,17 @@ static int add_graph_to_chain(struct commit_graph *g,
                return 0;
        }
 
+       if (g->chunk_base_graphs_size / g->hash_len < n) {
+               warning(_("commit-graph base graphs chunk is too small"));
+               return 0;
+       }
+
        while (n) {
                n--;
 
                if (!cur_g ||
                    !oideq(&oids[n], &cur_g->oid) ||
-                   !hasheq(oids[n].hash, g->chunk_base_graphs + g->hash_len * n)) {
+                   !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n))) {
                        warning(_("commit-graph chain does not match"));
                        return 0;
                }
@@ -490,39 +598,56 @@ static int add_graph_to_chain(struct commit_graph *g,
                cur_g = cur_g->base_graph;
        }
 
+       if (chain) {
+               if (unsigned_add_overflows(chain->num_commits,
+                                          chain->num_commits_in_base)) {
+                       warning(_("commit count in base graph too high: %"PRIuMAX),
+                               (uintmax_t)chain->num_commits_in_base);
+                       return 0;
+               }
+               g->num_commits_in_base = chain->num_commits + chain->num_commits_in_base;
+       }
+
        g->base_graph = chain;
 
-       if (chain)
-               g->num_commits_in_base = chain->num_commits + chain->num_commits_in_base;
+       return 1;
+}
 
+int open_commit_graph_chain(const char *chain_file,
+                           int *fd, struct stat *st)
+{
+       *fd = git_open(chain_file);
+       if (*fd < 0)
+               return 0;
+       if (fstat(*fd, st)) {
+               close(*fd);
+               return 0;
+       }
+       if (st->st_size < the_hash_algo->hexsz) {
+               close(*fd);
+               if (!st->st_size) {
+                       /* treat empty files the same as missing */
+                       errno = ENOENT;
+               } else {
+                       warning("commit-graph chain file too small");
+                       errno = EINVAL;
+               }
+               return 0;
+       }
        return 1;
 }
 
-static struct commit_graph *load_commit_graph_chain(struct repository *r,
-                                                   struct object_directory *odb)
+struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,
+                                                  int fd, struct stat *st,
+                                                  int *incomplete_chain)
 {
        struct commit_graph *graph_chain = NULL;
        struct strbuf line = STRBUF_INIT;
-       struct stat st;
        struct object_id *oids;
        int i = 0, valid = 1, count;
-       char *chain_name = get_commit_graph_chain_filename(odb);
-       FILE *fp;
-       int stat_res;
-
-       fp = fopen(chain_name, "r");
-       stat_res = stat(chain_name, &st);
-       free(chain_name);
-
-       if (!fp)
-               return NULL;
-       if (stat_res ||
-           st.st_size <= the_hash_algo->hexsz) {
-               fclose(fp);
-               return NULL;
-       }
+       FILE *fp = xfdopen(fd, "r");
 
-       count = st.st_size / (the_hash_algo->hexsz + 1);
+       count = st->st_size / (the_hash_algo->hexsz + 1);
        CALLOC_ARRAY(oids, count);
 
        prepare_alt_odb(r);
@@ -551,6 +676,8 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
                                if (add_graph_to_chain(g, graph_chain, oids, i)) {
                                        graph_chain = g;
                                        valid = 1;
+                               } else {
+                                       free_commit_graph(g);
                                }
 
                                break;
@@ -563,36 +690,32 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
                }
        }
 
+       validate_mixed_generation_chain(graph_chain);
+
        free(oids);
        fclose(fp);
        strbuf_release(&line);
 
+       *incomplete_chain = !valid;
        return graph_chain;
 }
 
-/*
- * returns 1 if and only if all graphs in the chain have
- * corrected commit dates stored in the generation_data chunk.
- */
-static int validate_mixed_generation_chain(struct commit_graph *g)
+static struct commit_graph *load_commit_graph_chain(struct repository *r,
+                                                   struct object_directory *odb)
 {
-       int read_generation_data = 1;
-       struct commit_graph *p = g;
-
-       while (read_generation_data && p) {
-               read_generation_data = p->read_generation_data;
-               p = p->base_graph;
-       }
-
-       if (read_generation_data)
-               return 1;
+       char *chain_file = get_commit_graph_chain_filename(odb);
+       struct stat st;
+       int fd;
+       struct commit_graph *g = NULL;
 
-       while (g) {
-               g->read_generation_data = 0;
-               g = g->base_graph;
+       if (open_commit_graph_chain(chain_file, &fd, &st)) {
+               int incomplete;
+               /* ownership of fd is taken over by load function */
+               g = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);
        }
 
-       return 0;
+       free(chain_file);
+       return g;
 }
 
 struct commit_graph *read_commit_graph_one(struct repository *r,
@@ -603,8 +726,6 @@ struct commit_graph *read_commit_graph_one(struct repository *r,
        if (!g)
                g = load_commit_graph_chain(r, odb);
 
-       validate_mixed_generation_chain(g);
-
        return g;
 }
 
@@ -708,19 +829,10 @@ struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r)
        return NULL;
 }
 
-static void close_commit_graph_one(struct commit_graph *g)
-{
-       if (!g)
-               return;
-
-       clear_commit_graph_data_slab(&commit_graph_data_slab);
-       close_commit_graph_one(g->base_graph);
-       free_commit_graph(g);
-}
-
 void close_commit_graph(struct raw_object_store *o)
 {
-       close_commit_graph_one(o->commit_graph);
+       clear_commit_graph_data_slab(&commit_graph_data_slab);
+       free_commit_graph(o->commit_graph);
        o->commit_graph = NULL;
 }
 
@@ -747,7 +859,7 @@ static void load_oid_from_graph(struct commit_graph *g,
 
        lex_index = pos - g->num_commits_in_base;
 
-       oidread(oid, g->chunk_oid_lookup + g->hash_len * lex_index);
+       oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index));
 }
 
 static struct commit_list **insert_parent_or_die(struct repository *r,
@@ -783,7 +895,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
                die(_("invalid commit position. commit-graph is likely corrupt"));
 
        lex_index = pos - g->num_commits_in_base;
-       commit_data = g->chunk_commit_data + GRAPH_DATA_WIDTH * lex_index;
+       commit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index);
 
        graph_data = commit_graph_data_at(item);
        graph_data->graph_pos = pos;
@@ -793,14 +905,17 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
        item->date = (timestamp_t)((date_high << 32) | date_low);
 
        if (g->read_generation_data) {
-               offset = (timestamp_t)get_be32(g->chunk_generation_data + sizeof(uint32_t) * lex_index);
+               offset = (timestamp_t)get_be32(g->chunk_generation_data + st_mult(sizeof(uint32_t), lex_index));
 
                if (offset & CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW) {
                        if (!g->chunk_generation_data_overflow)
                                die(_("commit-graph requires overflow generation data but has none"));
 
                        offset_pos = offset ^ CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW;
-                       graph_data->generation = item->date + get_be64(g->chunk_generation_data_overflow + 8 * offset_pos);
+                       if (g->chunk_generation_data_overflow_size / sizeof(uint64_t) <= offset_pos)
+                               die(_("commit-graph overflow generation data is too small"));
+                       graph_data->generation = item->date +
+                               get_be64(g->chunk_generation_data_overflow + sizeof(uint64_t) * offset_pos);
                } else
                        graph_data->generation = item->date + offset;
        } else
@@ -820,7 +935,7 @@ static int fill_commit_in_graph(struct repository *r,
                                struct commit_graph *g, uint32_t pos)
 {
        uint32_t edge_value;
-       uint32_t *parent_data_ptr;
+       uint32_t parent_data_pos;
        struct commit_list **pptr;
        const unsigned char *commit_data;
        uint32_t lex_index;
@@ -831,7 +946,7 @@ static int fill_commit_in_graph(struct repository *r,
        fill_commit_graph_info(item, g, pos);
 
        lex_index = pos - g->num_commits_in_base;
-       commit_data = g->chunk_commit_data + (g->hash_len + 16) * lex_index;
+       commit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index);
 
        item->object.parsed = 1;
 
@@ -852,14 +967,21 @@ static int fill_commit_in_graph(struct repository *r,
                return 1;
        }
 
-       parent_data_ptr = (uint32_t*)(g->chunk_extra_edges +
-                         4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK));
+       parent_data_pos = edge_value & GRAPH_EDGE_LAST_MASK;
        do {
-               edge_value = get_be32(parent_data_ptr);
+               if (g->chunk_extra_edges_size / sizeof(uint32_t) <= parent_data_pos) {
+                       error("commit-graph extra-edges pointer out of bounds");
+                       free_commit_list(item->parents);
+                       item->parents = NULL;
+                       item->object.parsed = 0;
+                       return 0;
+               }
+               edge_value = get_be32(g->chunk_extra_edges +
+                                     sizeof(uint32_t) * parent_data_pos);
                pptr = insert_parent_or_die(r, g,
                                            edge_value & GRAPH_EDGE_LAST_MASK,
                                            pptr);
-               parent_data_ptr++;
+               parent_data_pos++;
        } while (!(edge_value & GRAPH_LAST_EDGE));
 
        return 1;
@@ -973,7 +1095,7 @@ static struct tree *load_tree_for_commit(struct repository *r,
                g = g->base_graph;
 
        commit_data = g->chunk_commit_data +
-                       GRAPH_DATA_WIDTH * (graph_pos - g->num_commits_in_base);
+                       st_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);
 
        oidread(&oid, commit_data);
        set_commit_tree(c, lookup_tree(r, &oid));
@@ -1563,12 +1685,14 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)
        stop_progress(&ctx->progress);
 }
 
-static timestamp_t get_generation_from_graph_data(struct commit *c, void *data)
+static timestamp_t get_generation_from_graph_data(struct commit *c,
+                                                 void *data UNUSED)
 {
        return commit_graph_data_at(c)->generation;
 }
 
-static void set_generation_v2(struct commit *c, timestamp_t t, void *data)
+static void set_generation_v2(struct commit *c, timestamp_t t,
+                             void *data UNUSED)
 {
        struct commit_graph_data *g = commit_graph_data_at(c);
        g->generation = t;
@@ -1582,7 +1706,6 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                .commits = &ctx->commits,
                .get_generation = get_generation_from_graph_data,
                .set_generation = set_generation_v2,
-               .data = ctx,
        };
 
        if (ctx->report_progress)
@@ -1611,7 +1734,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
 }
 
 static void set_generation_in_graph_data(struct commit *c, timestamp_t t,
-                                        void *data)
+                                        void *data UNUSED)
 {
        commit_graph_data_at(c)->generation = t;
 }
@@ -1953,35 +2076,35 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
        add_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, GRAPH_FANOUT_SIZE,
                  write_graph_chunk_fanout);
-       add_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, hashsz * ctx->commits.nr,
+       add_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, st_mult(hashsz, ctx->commits.nr),
                  write_graph_chunk_oids);
-       add_chunk(cf, GRAPH_CHUNKID_DATA, (hashsz + 16) * ctx->commits.nr,
+       add_chunk(cf, GRAPH_CHUNKID_DATA, st_mult(hashsz + 16, ctx->commits.nr),
                  write_graph_chunk_data);
 
        if (ctx->write_generation_data)
                add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
-                         sizeof(uint32_t) * ctx->commits.nr,
+                         st_mult(sizeof(uint32_t), ctx->commits.nr),
                          write_graph_chunk_generation_data);
        if (ctx->num_generation_data_overflows)
                add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
-                         sizeof(timestamp_t) * ctx->num_generation_data_overflows,
+                         st_mult(sizeof(timestamp_t), ctx->num_generation_data_overflows),
                          write_graph_chunk_generation_data_overflow);
        if (ctx->num_extra_edges)
                add_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES,
-                         4 * ctx->num_extra_edges,
+                         st_mult(4, ctx->num_extra_edges),
                          write_graph_chunk_extra_edges);
        if (ctx->changed_paths) {
                add_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
-                         sizeof(uint32_t) * ctx->commits.nr,
+                         st_mult(sizeof(uint32_t), ctx->commits.nr),
                          write_graph_chunk_bloom_indexes);
                add_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
-                         sizeof(uint32_t) * 3
-                               + ctx->total_bloom_filter_data_size,
+                         st_add(sizeof(uint32_t) * 3,
+                                ctx->total_bloom_filter_data_size),
                          write_graph_chunk_bloom_data);
        }
        if (ctx->num_commit_graphs_after > 1)
                add_chunk(cf, GRAPH_CHUNKID_BASE,
-                         hashsz * (ctx->num_commit_graphs_after - 1),
+                         st_mult(hashsz, ctx->num_commit_graphs_after - 1),
                          write_graph_chunk_base);
 
        hashwrite_be32(f, GRAPH_SIGNATURE);
@@ -1999,7 +2122,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
                            get_num_chunks(cf));
                ctx->progress = start_delayed_progress(
                        progress_title.buf,
-                       get_num_chunks(cf) * ctx->commits.nr);
+                       st_mult(get_num_chunks(cf), ctx->commits.nr));
        }
 
        write_chunkfile(cf, ctx);
@@ -2056,9 +2179,11 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
                        free(graph_name);
                }
 
+               free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
                ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));
                final_graph_name = get_split_graph_filename(ctx->odb,
                                        ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
+               free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);
                ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
 
                result = rename(ctx->graph_name, final_graph_name);
@@ -2105,11 +2230,16 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
        if (flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED &&
            flags != COMMIT_GRAPH_SPLIT_REPLACE) {
-               while (g && (g->num_commits <= size_mult * num_commits ||
+               while (g && (g->num_commits <= st_mult(size_mult, num_commits) ||
                            (max_commits && num_commits > max_commits))) {
                        if (g->odb != ctx->odb)
                                break;
 
+                       if (unsigned_add_overflows(num_commits, g->num_commits))
+                               die(_("cannot merge graphs with %"PRIuMAX", "
+                                     "%"PRIuMAX" commits"),
+                                   (uintmax_t)num_commits,
+                                   (uintmax_t)g->num_commits);
                        num_commits += g->num_commits;
                        g = g->base_graph;
 
@@ -2167,6 +2297,11 @@ static void merge_commit_graph(struct write_commit_graph_context *ctx,
        uint32_t i;
        uint32_t offset = g->num_commits_in_base;
 
+       if (unsigned_add_overflows(ctx->commits.nr, g->num_commits))
+               die(_("cannot merge graph %s, too many commits: %"PRIuMAX),
+                   oid_to_hex(&g->oid),
+                   (uintmax_t)st_add(ctx->commits.nr, g->num_commits));
+
        ALLOC_GROW(ctx->commits.list, ctx->commits.nr + g->num_commits, ctx->commits.alloc);
 
        for (i = 0; i < g->num_commits; i++) {
@@ -2437,7 +2572,7 @@ int write_commit_graph(struct object_directory *odb,
                struct commit_graph *g = ctx->r->objects->commit_graph;
                for (i = 0; i < g->num_commits; i++) {
                        struct object_id oid;
-                       oidread(&oid, g->chunk_oid_lookup + g->hash_len * i);
+                       oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i));
                        oid_array_append(&ctx->oids, &oid);
                }
        }
@@ -2497,6 +2632,7 @@ int write_commit_graph(struct object_directory *odb,
 
 cleanup:
        free(ctx->graph_name);
+       free(ctx->base_graph_name);
        free(ctx->commits.list);
        oid_array_clear(&ctx->oids);
        clear_topo_level_slab(&topo_levels);
@@ -2535,26 +2671,20 @@ static void graph_report(const char *fmt, ...)
        va_end(ap);
 }
 
-#define GENERATION_ZERO_EXISTS 1
-#define GENERATION_NUMBER_EXISTS 2
-
 static int commit_graph_checksum_valid(struct commit_graph *g)
 {
        return hashfile_checksum_valid(g->data, g->data_len);
 }
 
-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
+static int verify_one_commit_graph(struct repository *r,
+                                  struct commit_graph *g,
+                                  struct progress *progress,
+                                  uint64_t *seen)
 {
        uint32_t i, cur_fanout_pos = 0;
        struct object_id prev_oid, cur_oid;
-       int generation_zero = 0;
-       struct progress *progress = NULL;
-       int local_error = 0;
-
-       if (!g) {
-               graph_report("no commit-graph file loaded");
-               return 1;
-       }
+       struct commit *seen_gen_zero = NULL;
+       struct commit *seen_gen_non_zero = NULL;
 
        verify_commit_graph_error = verify_commit_graph_lite(g);
        if (verify_commit_graph_error)
@@ -2568,7 +2698,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
        for (i = 0; i < g->num_commits; i++) {
                struct commit *graph_commit;
 
-               oidread(&cur_oid, g->chunk_oid_lookup + g->hash_len * i);
+               oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i));
 
                if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
                        graph_report(_("commit-graph has incorrect OID order: %s then %s"),
@@ -2605,18 +2735,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
        if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
                return verify_commit_graph_error;
 
-       if (flags & COMMIT_GRAPH_WRITE_PROGRESS)
-               progress = start_progress(_("Verifying commits in commit graph"),
-                                       g->num_commits);
-
        for (i = 0; i < g->num_commits; i++) {
                struct commit *graph_commit, *odb_commit;
                struct commit_list *graph_parents, *odb_parents;
                timestamp_t max_generation = 0;
                timestamp_t generation;
 
-               display_progress(progress, i + 1);
-               oidread(&cur_oid, g->chunk_oid_lookup + g->hash_len * i);
+               display_progress(progress, ++(*seen));
+               oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i));
 
                graph_commit = lookup_commit(r, &cur_oid);
                odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));
@@ -2652,7 +2778,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                                             oid_to_hex(&graph_parents->item->object.oid),
                                             oid_to_hex(&odb_parents->item->object.oid));
 
-                       generation = commit_graph_generation(graph_parents->item);
+                       generation = commit_graph_generation_from_graph(graph_parents->item);
                        if (generation > max_generation)
                                max_generation = generation;
 
@@ -2664,16 +2790,12 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                        graph_report(_("commit-graph parent list for commit %s terminates early"),
                                     oid_to_hex(&cur_oid));
 
-               if (!commit_graph_generation(graph_commit)) {
-                       if (generation_zero == GENERATION_NUMBER_EXISTS)
-                               graph_report(_("commit-graph has generation number zero for commit %s, but non-zero elsewhere"),
-                                            oid_to_hex(&cur_oid));
-                       generation_zero = GENERATION_ZERO_EXISTS;
-               } else if (generation_zero == GENERATION_ZERO_EXISTS)
-                       graph_report(_("commit-graph has non-zero generation number for commit %s, but zero elsewhere"),
-                                    oid_to_hex(&cur_oid));
+               if (commit_graph_generation_from_graph(graph_commit))
+                       seen_gen_non_zero = graph_commit;
+               else
+                       seen_gen_zero = graph_commit;
 
-               if (generation_zero == GENERATION_ZERO_EXISTS)
+               if (seen_gen_zero)
                        continue;
 
                /*
@@ -2698,27 +2820,60 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
                                     graph_commit->date,
                                     odb_commit->date);
        }
-       stop_progress(&progress);
 
-       local_error = verify_commit_graph_error;
+       if (seen_gen_zero && seen_gen_non_zero)
+               graph_report(_("commit-graph has both zero and non-zero "
+                              "generations (e.g., commits '%s' and '%s')"),
+                            oid_to_hex(&seen_gen_zero->object.oid),
+                            oid_to_hex(&seen_gen_non_zero->object.oid));
 
-       if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW) && g->base_graph)
-               local_error |= verify_commit_graph(r, g->base_graph, flags);
+       return verify_commit_graph_error;
+}
+
+int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
+{
+       struct progress *progress = NULL;
+       int local_error = 0;
+       uint64_t seen = 0;
+
+       if (!g) {
+               graph_report("no commit-graph file loaded");
+               return 1;
+       }
+
+       if (flags & COMMIT_GRAPH_WRITE_PROGRESS) {
+               uint64_t total = g->num_commits;
+               if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))
+                       total += g->num_commits_in_base;
+
+               progress = start_progress(_("Verifying commits in commit graph"),
+                                         total);
+       }
+
+       for (; g; g = g->base_graph) {
+               local_error |= verify_one_commit_graph(r, g, progress, &seen);
+               if (flags & COMMIT_GRAPH_VERIFY_SHALLOW)
+                       break;
+       }
+
+       stop_progress(&progress);
 
        return local_error;
 }
 
 void free_commit_graph(struct commit_graph *g)
 {
-       if (!g)
-               return;
-       if (g->data) {
-               munmap((void *)g->data, g->data_len);
-               g->data = NULL;
+       while (g) {
+               struct commit_graph *next = g->base_graph;
+
+               if (g->data)
+                       munmap((void *)g->data, g->data_len);
+               free(g->filename);
+               free(g->bloom_filter_settings);
+               free(g);
+
+               g = next;
        }
-       free(g->filename);
-       free(g->bloom_filter_settings);
-       free(g);
 }
 
 void disable_commit_graph(struct repository *r)
index 83aaa1dbb929c4f16acbe8ccb2593d104af2b7f0..c6870274c5ab7e8821e65a1eb35b514c889ffa95 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef COMMIT_GRAPH_H
 #define COMMIT_GRAPH_H
 
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oidset.h"
 
 #define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
@@ -26,6 +26,7 @@ struct string_list;
 char *get_commit_graph_filename(struct object_directory *odb);
 char *get_commit_graph_chain_filename(struct object_directory *odb);
 int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);
 
 /*
  * Given a commit struct, try to fill the commit struct info, including:
@@ -93,10 +94,14 @@ struct commit_graph {
        const unsigned char *chunk_commit_data;
        const unsigned char *chunk_generation_data;
        const unsigned char *chunk_generation_data_overflow;
+       size_t chunk_generation_data_overflow_size;
        const unsigned char *chunk_extra_edges;
+       size_t chunk_extra_edges_size;
        const unsigned char *chunk_base_graphs;
+       size_t chunk_base_graphs_size;
        const unsigned char *chunk_bloom_indexes;
        const unsigned char *chunk_bloom_data;
+       size_t chunk_bloom_data_size;
 
        struct topo_level_slab *topo_levels;
        struct bloom_filter_settings *bloom_filter_settings;
@@ -105,6 +110,9 @@ struct commit_graph {
 struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
                                                 int fd, struct stat *st,
                                                 struct object_directory *odb);
+struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,
+                                                  int fd, struct stat *st,
+                                                  int *incomplete_chain);
 struct commit_graph *read_commit_graph_one(struct repository *r,
                                           struct object_directory *odb);
 
index 70bde8af05b294c86881a79b740d9fd087ebbad8..a868a575ea1cf8e7ccd331610b9d309a065ad135 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "commit.h"
 #include "commit-graph.h"
 #include "decorate.h"
@@ -174,6 +173,7 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
                        for (k = bases; k; k = k->next)
                                end = k;
                }
+               free_commit_list(ret);
                ret = new_commits;
        }
        return ret;
@@ -944,6 +944,8 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
                }
        }
 
+       clear_prio_queue(&queue);
+
        clear_commit_marks_many(nr_to, to, PARENT1);
        clear_commit_marks_many(nr_from, from, PARENT2);
 
index 0fb9316931a9da64aa9441e5bb160b98e5656faf..b3223478bc2a3ac98751e41ba133a41d3ba34bc0 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -7,7 +7,7 @@
 #include "hex.h"
 #include "repository.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pkt-line.h"
 #include "utf8.h"
 #include "diff.h"
@@ -516,7 +516,7 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
                 * The clone is shallow if nr_parent < 0, and we must
                 * not traverse its real parents even when we unhide them.
                 */
-               if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
+               if (graft && (graft->nr_parent < 0 || !grafts_keep_true_parents))
                        continue;
                new_parent = lookup_commit(r, &parent);
                if (!new_parent)
index 4c291f8a066b1b066da5084d2f67e5e9a8e0c4b9..c2afcbe6c89d9ab2f279b5ac7cb4c9a3e6ae01ea 100644 (file)
@@ -1,24 +1,24 @@
 #include "git-compat-util.h"
 #include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsm-health.h"
 #include "fsmonitor--daemon.h"
 
-int fsm_health__ctor(struct fsmonitor_daemon_state *state)
+int fsm_health__ctor(struct fsmonitor_daemon_state *state UNUSED)
 {
        return 0;
 }
 
-void fsm_health__dtor(struct fsmonitor_daemon_state *state)
+void fsm_health__dtor(struct fsmonitor_daemon_state *state UNUSED)
 {
        return;
 }
 
-void fsm_health__loop(struct fsmonitor_daemon_state *state)
+void fsm_health__loop(struct fsmonitor_daemon_state *state UNUSED)
 {
        return;
 }
 
-void fsm_health__stop_async(struct fsmonitor_daemon_state *state)
+void fsm_health__stop_async(struct fsmonitor_daemon_state *state UNUSED)
 {
 }
index fe11bdd9ce6d3bbe96f6fdec7c6b417b96cc680b..2d4e245beb18b8f3573ea33526274d3f8f45b675 100644 (file)
@@ -1,6 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsm-health.h"
 #include "fsmonitor--daemon.h"
 #include "gettext.h"
index 793073aaa721633497b5bbe71797c15c7c88f52c..6f3a95410cc1002a08b4af63bc9fff0d1e1e75ea 100644 (file)
@@ -2,9 +2,10 @@
 #include "config.h"
 #include "gettext.h"
 #include "hex.h"
+#include "path.h"
 #include "repository.h"
 #include "strbuf.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsmonitor-ipc.h"
 #include "fsmonitor-path-utils.h"
 
index 8928fa93ce223968ab59279ddac50a3dd2b15239..41984ea48e26b8c5fc9cf8ed9bc6851957a230d9 100644 (file)
@@ -6,6 +6,6 @@
 const char *fsmonitor_ipc__get_path(struct repository *r) {
        static char *ret;
        if (!ret)
-               ret = git_pathdup("fsmonitor--daemon.ipc");
+               ret = repo_git_path(r, "fsmonitor--daemon.ipc");
        return ret;
 }
index 23e24b4b374b3e2cfc8745312690629acddb042e..11b56d3ef12ffb52ef291e95e2b8e39823e77f0f 100644 (file)
 #endif
 
 #include "git-compat-util.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsm-listen.h"
 #include "fsmonitor--daemon.h"
 #include "fsmonitor-path-utils.h"
 #include "gettext.h"
 #include "string-list.h"
+#include "trace.h"
 
 struct fsm_listen_data
 {
@@ -190,12 +191,12 @@ static void my_add_path(struct fsmonitor_batch *batch, const char *path)
 }
 
 
-static void fsevent_callback(ConstFSEventStreamRef streamRef,
+static void fsevent_callback(ConstFSEventStreamRef streamRef UNUSED,
                             void *ctx,
                             size_t num_of_events,
                             void *event_paths,
                             const FSEventStreamEventFlags event_flags[],
-                            const FSEventStreamEventId event_ids[])
+                            const FSEventStreamEventId event_ids[] UNUSED)
 {
        struct fsmonitor_daemon_state *state = ctx;
        struct fsm_listen_data *data = state->listen_data;
index 677b1bbdecac2e82b03c3755af4dfa0de562f73d..90a2412284414e0675bc7603e4d13850d640a695 100644 (file)
@@ -1,6 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsm-listen.h"
 #include "fsmonitor--daemon.h"
 #include "gettext.h"
@@ -289,8 +289,7 @@ void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
        SetEvent(state->listen_data->hListener[LISTENER_SHUTDOWN]);
 }
 
-static struct one_watch *create_watch(struct fsmonitor_daemon_state *state,
-                                     const char *path)
+static struct one_watch *create_watch(const char *path)
 {
        struct one_watch *watch = NULL;
        DWORD desired_access = FILE_LIST_DIRECTORY;
@@ -361,8 +360,7 @@ static void destroy_watch(struct one_watch *watch)
        free(watch);
 }
 
-static int start_rdcw_watch(struct fsm_listen_data *data,
-                           struct one_watch *watch)
+static int start_rdcw_watch(struct one_watch *watch)
 {
        DWORD dwNotifyFilter =
                FILE_NOTIFY_CHANGE_FILE_NAME |
@@ -735,11 +733,11 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
 
        state->listen_error_code = 0;
 
-       if (start_rdcw_watch(data, data->watch_worktree) == -1)
+       if (start_rdcw_watch(data->watch_worktree) == -1)
                goto force_error_stop;
 
        if (data->watch_gitdir &&
-           start_rdcw_watch(data, data->watch_gitdir) == -1)
+           start_rdcw_watch(data->watch_gitdir) == -1)
                goto force_error_stop;
 
        for (;;) {
@@ -755,7 +753,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
                        }
                        if (result == -2) {
                                /* retryable error */
-                               if (start_rdcw_watch(data, data->watch_worktree) == -1)
+                               if (start_rdcw_watch(data->watch_worktree) == -1)
                                        goto force_error_stop;
                                continue;
                        }
@@ -763,7 +761,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
                        /* have data */
                        if (process_worktree_events(state) == LISTENER_SHUTDOWN)
                                goto force_shutdown;
-                       if (start_rdcw_watch(data, data->watch_worktree) == -1)
+                       if (start_rdcw_watch(data->watch_worktree) == -1)
                                goto force_error_stop;
                        continue;
                }
@@ -776,7 +774,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
                        }
                        if (result == -2) {
                                /* retryable error */
-                               if (start_rdcw_watch(data, data->watch_gitdir) == -1)
+                               if (start_rdcw_watch(data->watch_gitdir) == -1)
                                        goto force_error_stop;
                                continue;
                        }
@@ -784,7 +782,7 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
                        /* have data */
                        if (process_gitdir_events(state) == LISTENER_SHUTDOWN)
                                goto force_shutdown;
-                       if (start_rdcw_watch(data, data->watch_gitdir) == -1)
+                       if (start_rdcw_watch(data->watch_gitdir) == -1)
                                goto force_error_stop;
                        continue;
                }
@@ -821,16 +819,14 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
 
        data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
 
-       data->watch_worktree = create_watch(state,
-                                           state->path_worktree_watch.buf);
+       data->watch_worktree = create_watch(state->path_worktree_watch.buf);
        if (!data->watch_worktree)
                goto failed;
 
        check_for_shortnames(data->watch_worktree);
 
        if (state->nr_paths_watching > 1) {
-               data->watch_gitdir = create_watch(state,
-                                                 state->path_gitdir_watch.buf);
+               data->watch_gitdir = create_watch(state->path_gitdir_watch.buf);
                if (!data->watch_gitdir)
                        goto failed;
        }
index 45eb4a9b9e75552cf124e050b5cfdd06cda46a2d..049f97eaaf249a0206c934d8b7ae1493115246d4 100644 (file)
@@ -1,6 +1,8 @@
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
 #include "fsmonitor-path-utils.h"
 #include "gettext.h"
+#include "trace.h"
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
index 4024baafb9768f953b43c48ce247cb12ed3766c3..f4f9cc1f336720614bcbb77d1ea908419801f9ab 100644 (file)
@@ -1,7 +1,8 @@
-#include "cache.h"
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
 #include "fsmonitor-path-utils.h"
 #include "gettext.h"
+#include "trace.h"
 
 /*
  * Check remote working directory protocol.
@@ -131,7 +132,8 @@ int fsmonitor__is_fs_remote(const char *path)
 /*
  * No-op for now.
  */
-int fsmonitor__get_alias(const char *path, struct alias_info *info)
+int fsmonitor__get_alias(const char *path UNUSED,
+                        struct alias_info *info UNUSED)
 {
        return 0;
 }
@@ -139,8 +141,8 @@ int fsmonitor__get_alias(const char *path, struct alias_info *info)
 /*
  * No-op for now.
  */
-char *fsmonitor__resolve_alias(const char *path,
-       const struct alias_info *info)
+char *fsmonitor__resolve_alias(const char *path UNUSED,
+                              const struct alias_info *info UNUSED)
 {
        return NULL;
 }
index 58b623fbb9a3bf598e44d6fe377340d960e004f4..a38259063517144690122454970f399ae504708e 100644 (file)
@@ -1,6 +1,6 @@
 #include "git-compat-util.h"
 #include "config.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsmonitor-ipc.h"
 #include "fsmonitor-settings.h"
 #include "fsmonitor-path-utils.h"
index a8af31b71de05cab939c1d8223194fa91d0cbd6a..0f2aa321f6e15f729aef67d4012fea6513cacfa4 100644 (file)
@@ -1,7 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "repository.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 #include "fsmonitor-settings.h"
 #include "fsmonitor-path-utils.h"
 
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
        return FSMONITOR_REASON_OK;
 }
 
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc UNUSED)
 {
        enum fsmonitor_reason reason;
 
index d06cdc6254fbc34eabcd1130c08ae6b8f1fcae01..ec5280da160135170e2d778cfcb19cea1752c211 100644 (file)
@@ -6,7 +6,6 @@
 #include <wchar.h>
 #include "../strbuf.h"
 #include "../run-command.h"
-#include "../cache.h"
 #include "../abspath.h"
 #include "../alloc.h"
 #include "win32/lazyload.h"
@@ -244,7 +243,8 @@ static int core_restrict_inherited_handles = -1;
 static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
 static char *unset_environment_variables;
 
-int mingw_core_config(const char *var, const char *value, void *cb)
+int mingw_core_config(const char *var, const char *value,
+                     const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "core.hidedotfiles")) {
                if (value && !strcasecmp(value, "dotgitonly"))
@@ -1347,6 +1347,11 @@ static char *path_lookup(const char *cmd, int exe_only)
        return prog;
 }
 
+char *mingw_locate_in_PATH(const char *cmd)
+{
+       return path_lookup(cmd, 0);
+}
+
 static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c)
 {
        while (*s && *s != c)
index 209cf7cebadd1746c8b79e1105bac103b8a72910..6aec50e4124e145d6d43f584418288d3fc29f481 100644 (file)
@@ -11,7 +11,9 @@ typedef _sigset_t sigset_t;
 #undef _POSIX_THREAD_SAFE_FUNCTIONS
 #endif
 
-int mingw_core_config(const char *var, const char *value, void *cb);
+struct config_context;
+int mingw_core_config(const char *var, const char *value,
+                     const struct config_context *ctx, void *cb);
 #define platform_core_config mingw_core_config
 
 /*
@@ -175,6 +177,9 @@ pid_t waitpid(pid_t pid, int *status, int options);
 #define kill mingw_kill
 int mingw_kill(pid_t pid, int sig);
 
+#define locate_in_PATH mingw_locate_in_PATH
+char *mingw_locate_in_PATH(const char *cmd);
+
 #ifndef NO_OPENSSL
 #include <openssl/ssl.h>
 static inline int mingw_SSL_set_fd(SSL *ssl, int fd)
index a4d11376ba5126e3c3c6d409748a106824d089ee..0bd5c24250a4fb717f61db6e03e40326ca1fad07 100644 (file)
@@ -5,11 +5,12 @@
 
 #define PRECOMPOSE_UNICODE_C
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
 #include "path.h"
+#include "strbuf.h"
 #include "utf8.h"
 #include "precompose_utf8.h"
 
index 6adfcfd54051617fd4cbdd0e5d8a904c2a839152..a4a6f930d7b14a473d5e47a9a90b84a7557054af 100644 (file)
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "hash-ll.h"
 
 int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len)
 {
index 6adce3c650eba5b8ae4879b5c32b79c3849c3d95..8bfe51248e552e6915acec34abea31a3d3dc279e 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
 #include "gettext.h"
 #include "simple-ipc.h"
index d87e32118929742db0373fe71502bc969426c09e..0afda730f278cc776e430ca6b5f44712d5b27f7b 100644 (file)
@@ -6,7 +6,6 @@
 #include "run-command.h"
 #include "string-list.h"
 #include "hashmap.h"
-#include "wrapper.h"
 
 #if defined(HAVE_DEV_TTY) || defined(GIT_WINDOWS_NATIVE)
 
@@ -480,10 +479,13 @@ struct escape_sequence_entry {
 };
 
 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 struct hashmap_entry *he1,
+                             const struct hashmap_entry *he2,
                              const void *keydata)
 {
+       const struct escape_sequence_entry
+               *e1 = container_of(he1, const struct escape_sequence_entry, entry),
+               *e2 = container_of(he2, const struct escape_sequence_entry, entry);
        return strcmp(e1->sequence, keydata ? keydata : e2->sequence);
 }
 
@@ -497,8 +499,7 @@ static int is_known_escape_sequence(const char *sequence)
                struct strbuf buf = STRBUF_INIT;
                char *p, *eol;
 
-               hashmap_init(&sequences, (hashmap_cmp_fn)sequence_entry_cmp,
-                            NULL, 0);
+               hashmap_init(&sequences, sequence_entry_cmp, NULL, 0);
 
                strvec_pushl(&cp.args, "infocmp", "-L", "-1", NULL);
                if (pipe_command(&cp, NULL, 0, &buf, 0, NULL, 0))
diff --git a/compat/win32/headless.c b/compat/win32/headless.c
new file mode 100644 (file)
index 0000000..8b00dfe
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * headless Git - run Git without opening a console window on Windows
+ */
+
+#define STRICT
+#define WIN32_LEAN_AND_MEAN
+#define UNICODE
+#define _UNICODE
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+/*
+ * If `dir` contains the path to a Git exec directory, extend `PATH` to
+ * include the corresponding `bin/` directory (which is where all those
+ * `.dll` files needed by `git.exe` are, on Windows).
+ */
+static int extend_path(wchar_t *dir, size_t dir_len)
+{
+       const wchar_t *suffix = L"\\libexec\\git-core";
+       size_t suffix_len = wcslen(suffix);
+       wchar_t *env;
+       DWORD len;
+
+       if (dir_len < suffix_len)
+               return 0;
+
+       dir_len -= suffix_len;
+       if (memcmp(dir + dir_len, suffix, suffix_len * sizeof(wchar_t)))
+               return 0;
+
+       len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+       if (!len)
+               return 0;
+
+       env = _alloca((dir_len + 5 + len) * sizeof(wchar_t));
+       wcsncpy(env, dir, dir_len);
+       wcscpy(env + dir_len, L"\\bin;");
+       if (!GetEnvironmentVariableW(L"PATH", env + dir_len + 5, len))
+               return 0;
+
+       SetEnvironmentVariableW(L"PATH", env);
+       return 1;
+}
+
+int WINAPI wWinMain(_In_ HINSTANCE instance,
+                   _In_opt_ HINSTANCE previous_instance,
+                   _In_ LPWSTR command_line, _In_ int show)
+{
+       wchar_t git_command_line[32768];
+       size_t size = sizeof(git_command_line) / sizeof(wchar_t);
+       const wchar_t *needs_quotes = L"";
+       int slash = 0, i;
+
+       STARTUPINFO startup_info = {
+               .cb = sizeof(STARTUPINFO),
+               .dwFlags = STARTF_USESHOWWINDOW,
+               .wShowWindow = SW_HIDE,
+       };
+       PROCESS_INFORMATION process_info = { 0 };
+       DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT |
+               CREATE_NEW_CONSOLE | CREATE_NO_WINDOW;
+       DWORD exit_code;
+
+       /* First, determine the full path of argv[0] */
+       for (i = 0; _wpgmptr[i]; i++)
+               if (_wpgmptr[i] == L' ')
+                       needs_quotes = L"\"";
+               else if (_wpgmptr[i] == L'\\')
+                       slash = i;
+
+       if (slash >= size - 11)
+               return 127; /* Too long path */
+
+       /* If it is in Git's exec path, add the bin/ directory to the PATH */
+       extend_path(_wpgmptr, slash);
+
+       /* Then, add the full path of `git.exe` as argv[0] */
+       i = swprintf_s(git_command_line, size, L"%ls%.*ls\\git.exe%ls",
+                      needs_quotes, slash, _wpgmptr, needs_quotes);
+       if (i < 0)
+               return 127; /* Too long path */
+
+       if (*command_line) {
+               /* Now, append the command-line arguments */
+               i = swprintf_s(git_command_line + i, size - i,
+                              L" %ls", command_line);
+               if (i < 0)
+                       return 127;
+       }
+
+       startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+       startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+       startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+       if (!CreateProcess(NULL, /* infer argv[0] from the command line */
+                          git_command_line, /* modified command line */
+                          NULL, /* inherit process handles? */
+                          NULL, /* inherit thread handles? */
+                          FALSE, /* handles inheritable? */
+                          creation_flags,
+                          NULL, /* use this process' environment */
+                          NULL, /* use this process' working directory */
+                          &startup_info, &process_info))
+               return 129; /* could not start */
+       WaitForSingleObject(process_info.hProcess, INFINITE);
+       if (!GetExitCodeProcess(process_info.hProcess, &exit_code))
+               exit_code = 130; /* Could not determine exit code? */
+
+       CloseHandle(process_info.hProcess);
+       CloseHandle(process_info.hThread);
+
+       return (int)exit_code;
+}
index a4e33768f432d329746508853fe6021ed91f48a6..3ef0936f6ff9711caed8c22c8aebd92eb4be6e30 100644 (file)
@@ -1,10 +1,10 @@
-#include "../../cache.h"
+#include "../../git-compat-util.h"
 #include "../../json-writer.h"
 #include "../../repository.h"
 #include "../../trace2.h"
 #include "lazyload.h"
-#include <Psapi.h>
-#include <tlHelp32.h>
+#include <psapi.h>
+#include <tlhelp32.h>
 
 /*
  * An arbitrarily chosen value to limit the size of the ancestor
index b79baf83e35beb902acae4c902f619cf7eca21ef..b330c7adb4a5efc3cac898391d4c722b019d95a1 100644 (file)
--- a/config.c
+++ b/config.c
@@ -8,10 +8,10 @@
 #include "git-compat-util.h"
 #include "abspath.h"
 #include "advice.h"
-#include "alloc.h"
 #include "date.h"
 #include "branch.h"
 #include "config.h"
+#include "parse.h"
 #include "convert.h"
 #include "environment.h"
 #include "gettext.h"
 #include "repository.h"
 #include "lockfile.h"
 #include "mailmap.h"
+#include "attr.h"
 #include "exec-cmd.h"
 #include "strbuf.h"
 #include "quote.h"
 #include "hashmap.h"
 #include "string-list.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pager.h"
+#include "path.h"
 #include "utf8.h"
 #include "dir.h"
 #include "color.h"
 #include "replace-object.h"
 #include "refs.h"
 #include "setup.h"
+#include "strvec.h"
 #include "trace2.h"
+#include "wildmatch.h"
 #include "worktree.h"
 #include "ws.h"
-#include "wrapper.h"
 #include "write-or-die.h"
 
 struct config_source {
@@ -66,78 +69,6 @@ struct config_source {
 };
 #define CONFIG_SOURCE_INIT { 0 }
 
-struct config_reader {
-       /*
-        * These members record the "current" config source, which can be
-        * accessed by parsing callbacks.
-        *
-        * The "source" variable will be non-NULL only when we are actually
-        * parsing a real config source (file, blob, cmdline, etc).
-        *
-        * The "config_kvi" variable will be non-NULL only when we are feeding
-        * cached config from a configset into a callback.
-        *
-        * They cannot be non-NULL at the same time. If they are both NULL, then
-        * we aren't parsing anything (and depending on the function looking at
-        * the variables, it's either a bug for it to be called in the first
-        * place, or it's a function which can be reused for non-config
-        * purposes, and should fall back to some sane behavior).
-        */
-       struct config_source *source;
-       struct key_value_info *config_kvi;
-       /*
-        * The "scope" of the current config source being parsed (repo, global,
-        * etc). Like "source", this is only set when parsing a config source.
-        * It's not part of "source" because it transcends a single file (i.e.,
-        * a file included from .git/config is still in "repo" scope).
-        *
-        * When iterating through a configset, the equivalent value is
-        * "config_kvi.scope" (see above).
-        */
-       enum config_scope parsing_scope;
-};
-/*
- * Where possible, prefer to accept "struct config_reader" as an arg than to use
- * "the_reader". "the_reader" should only be used if that is infeasible, e.g. in
- * a public function.
- */
-static struct config_reader the_reader;
-
-static inline void config_reader_push_source(struct config_reader *reader,
-                                            struct config_source *top)
-{
-       if (reader->config_kvi)
-               BUG("source should not be set while iterating a config set");
-       top->prev = reader->source;
-       reader->source = top;
-}
-
-static inline struct config_source *config_reader_pop_source(struct config_reader *reader)
-{
-       struct config_source *ret;
-       if (!reader->source)
-               BUG("tried to pop config source, but we weren't reading config");
-       ret = reader->source;
-       reader->source = reader->source->prev;
-       return ret;
-}
-
-static inline void config_reader_set_kvi(struct config_reader *reader,
-                                        struct key_value_info *kvi)
-{
-       if (kvi && (reader->source || reader->parsing_scope))
-               BUG("kvi should not be set while parsing a config source");
-       reader->config_kvi = kvi;
-}
-
-static inline void config_reader_set_scope(struct config_reader *reader,
-                                          enum config_scope scope)
-{
-       if (scope && reader->config_kvi)
-               BUG("scope should only be set when iterating through a config source");
-       reader->parsing_scope = scope;
-}
-
 static int pack_compression_seen;
 static int zlib_compression_seen;
 
@@ -199,7 +130,7 @@ struct config_include_data {
        void *data;
        const struct config_options *opts;
        struct git_config_source *config_source;
-       struct config_reader *config_reader;
+       struct repository *repo;
 
        /*
         * All remote URLs discovered when reading all config files.
@@ -208,7 +139,8 @@ struct config_include_data {
 };
 #define CONFIG_INCLUDE_INIT { 0 }
 
-static int git_config_include(const char *var, const char *value, void *data);
+static int git_config_include(const char *var, const char *value,
+                             const struct config_context *ctx, void *data);
 
 #define MAX_INCLUDE_DEPTH 10
 static const char include_depth_advice[] = N_(
@@ -217,7 +149,8 @@ static const char include_depth_advice[] = N_(
 "from\n"
 "      %s\n"
 "This might be due to circular includes.");
-static int handle_path_include(struct config_source *cs, const char *path,
+static int handle_path_include(const struct key_value_info *kvi,
+                              const char *path,
                               struct config_include_data *inc)
 {
        int ret = 0;
@@ -239,14 +172,14 @@ static int handle_path_include(struct config_source *cs, const char *path,
        if (!is_absolute_path(path)) {
                char *slash;
 
-               if (!cs || !cs->path) {
+               if (!kvi || !kvi->path) {
                        ret = error(_("relative config includes must come from files"));
                        goto cleanup;
                }
 
-               slash = find_last_dir_sep(cs->path);
+               slash = find_last_dir_sep(kvi->path);
                if (slash)
-                       strbuf_add(&buf, cs->path, slash - cs->path + 1);
+                       strbuf_add(&buf, kvi->path, slash - kvi->path + 1);
                strbuf_addstr(&buf, path);
                path = buf.buf;
        }
@@ -254,10 +187,11 @@ static int handle_path_include(struct config_source *cs, const char *path,
        if (!access_or_die(path, R_OK, 0)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
-                           !cs ? "<unknown>" :
-                           cs->name ? cs->name :
+                           !kvi ? "<unknown>" :
+                           kvi->filename ? kvi->filename :
                            "the command line");
-               ret = git_config_from_file(git_config_include, path, inc);
+               ret = git_config_from_file_with_options(git_config_include, path, inc,
+                                                       kvi->scope, NULL);
                inc->depth--;
        }
 cleanup:
@@ -272,7 +206,7 @@ static void add_trailing_starstar_for_dir(struct strbuf *pat)
                strbuf_addstr(pat, "**");
 }
 
-static int prepare_include_condition_pattern(struct config_source *cs,
+static int prepare_include_condition_pattern(const struct key_value_info *kvi,
                                             struct strbuf *pat)
 {
        struct strbuf path = STRBUF_INIT;
@@ -289,11 +223,11 @@ static int prepare_include_condition_pattern(struct config_source *cs,
        if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) {
                const char *slash;
 
-               if (!cs || !cs->path)
+               if (!kvi || !kvi->path)
                        return error(_("relative config include "
                                       "conditionals must come from files"));
 
-               strbuf_realpath(&path, cs->path, 1);
+               strbuf_realpath(&path, kvi->path, 1);
                slash = find_last_dir_sep(path.buf);
                if (!slash)
                        BUG("how is this possible?");
@@ -308,7 +242,7 @@ static int prepare_include_condition_pattern(struct config_source *cs,
        return prefix;
 }
 
-static int include_by_gitdir(struct config_source *cs,
+static int include_by_gitdir(const struct key_value_info *kvi,
                             const struct config_options *opts,
                             const char *cond, size_t cond_len, int icase)
 {
@@ -325,7 +259,7 @@ static int include_by_gitdir(struct config_source *cs,
 
        strbuf_realpath(&text, git_dir, 1);
        strbuf_add(&pattern, cond, cond_len);
-       prefix = prepare_include_condition_pattern(cs, &pattern);
+       prefix = prepare_include_condition_pattern(kvi, &pattern);
 
 again:
        if (prefix < 0)
@@ -387,7 +321,8 @@ static int include_by_branch(const char *cond, size_t cond_len)
        return ret;
 }
 
-static int add_remote_url(const char *var, const char *value, void *data)
+static int add_remote_url(const char *var, const char *value,
+                         const struct config_context *ctx UNUSED, void *data)
 {
        struct string_list *remote_urls = data;
        const char *remote_name;
@@ -406,21 +341,17 @@ static void populate_remote_urls(struct config_include_data *inc)
 {
        struct config_options opts;
 
-       enum config_scope store_scope = inc->config_reader->parsing_scope;
-
        opts = *inc->opts;
        opts.unconditional_remote_url = 1;
 
-       config_reader_set_scope(inc->config_reader, 0);
-
        inc->remote_urls = xmalloc(sizeof(*inc->remote_urls));
        string_list_init_dup(inc->remote_urls);
-       config_with_options(add_remote_url, inc->remote_urls, inc->config_source, &opts);
-
-       config_reader_set_scope(inc->config_reader, store_scope);
+       config_with_options(add_remote_url, inc->remote_urls,
+                           inc->config_source, inc->repo, &opts);
 }
 
 static int forbid_remote_url(const char *var, const char *value UNUSED,
+                            const struct config_context *ctx UNUSED,
                             void *data UNUSED)
 {
        const char *remote_name;
@@ -464,16 +395,16 @@ static int include_by_remote_url(struct config_include_data *inc,
                                             inc->remote_urls);
 }
 
-static int include_condition_is_true(struct config_source *cs,
+static int include_condition_is_true(const struct key_value_info *kvi,
                                     struct config_include_data *inc,
                                     const char *cond, size_t cond_len)
 {
        const struct config_options *opts = inc->opts;
 
        if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len))
-               return include_by_gitdir(cs, opts, cond, cond_len, 0);
+               return include_by_gitdir(kvi, opts, cond, cond_len, 0);
        else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
-               return include_by_gitdir(cs, opts, cond, cond_len, 1);
+               return include_by_gitdir(kvi, opts, cond, cond_len, 1);
        else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
                return include_by_branch(cond, cond_len);
        else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
@@ -484,10 +415,11 @@ static int include_condition_is_true(struct config_source *cs,
        return 0;
 }
 
-static int git_config_include(const char *var, const char *value, void *data)
+static int git_config_include(const char *var, const char *value,
+                             const struct config_context *ctx,
+                             void *data)
 {
        struct config_include_data *inc = data;
-       struct config_source *cs = inc->config_reader->source;
        const char *cond, *key;
        size_t cond_len;
        int ret;
@@ -496,21 +428,21 @@ static int git_config_include(const char *var, const char *value, void *data)
         * Pass along all values, including "include" directives; this makes it
         * possible to query information on the includes themselves.
         */
-       ret = inc->fn(var, value, inc->data);
+       ret = inc->fn(var, value, ctx, inc->data);
        if (ret < 0)
                return ret;
 
        if (!strcmp(var, "include.path"))
-               ret = handle_path_include(cs, value, inc);
+               ret = handle_path_include(ctx->kvi, value, inc);
 
        if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) &&
-           cond && include_condition_is_true(cs, inc, cond, cond_len) &&
+           cond && include_condition_is_true(ctx->kvi, inc, cond, cond_len) &&
            !strcmp(key, "path")) {
                config_fn_t old_fn = inc->fn;
 
                if (inc->opts->unconditional_remote_url)
                        inc->fn = forbid_remote_url;
-               ret = handle_path_include(cs, value, inc);
+               ret = handle_path_include(ctx->kvi, value, inc);
                inc->fn = old_fn;
        }
 
@@ -668,27 +600,45 @@ out_free_ret_1:
 }
 
 static int config_parse_pair(const char *key, const char *value,
-                         config_fn_t fn, void *data)
+                            struct key_value_info *kvi,
+                            config_fn_t fn, void *data)
 {
        char *canonical_name;
        int ret;
+       struct config_context ctx = {
+               .kvi = kvi,
+       };
 
        if (!strlen(key))
                return error(_("empty config key"));
        if (git_config_parse_key(key, &canonical_name, NULL))
                return -1;
 
-       ret = (fn(canonical_name, value, data) < 0) ? -1 : 0;
+       ret = (fn(canonical_name, value, &ctx, data) < 0) ? -1 : 0;
        free(canonical_name);
        return ret;
 }
 
+
+/* for values read from `git_config_from_parameters()` */
+void kvi_from_param(struct key_value_info *out)
+{
+       out->filename = NULL;
+       out->linenr = -1;
+       out->origin_type = CONFIG_ORIGIN_CMDLINE;
+       out->scope = CONFIG_SCOPE_COMMAND;
+       out->path = NULL;
+}
+
 int git_config_parse_parameter(const char *text,
                               config_fn_t fn, void *data)
 {
        const char *value;
        struct strbuf **pair;
        int ret;
+       struct key_value_info kvi = KVI_INIT;
+
+       kvi_from_param(&kvi);
 
        pair = strbuf_split_str(text, '=', 2);
        if (!pair[0])
@@ -707,12 +657,13 @@ int git_config_parse_parameter(const char *text,
                return error(_("bogus config parameter: %s"), text);
        }
 
-       ret = config_parse_pair(pair[0]->buf, value, fn, data);
+       ret = config_parse_pair(pair[0]->buf, value, &kvi, fn, data);
        strbuf_list_free(pair);
        return ret;
 }
 
-static int parse_config_env_list(char *env, config_fn_t fn, void *data)
+static int parse_config_env_list(char *env, struct key_value_info *kvi,
+                                config_fn_t fn, void *data)
 {
        char *cur = env;
        while (cur && *cur) {
@@ -746,7 +697,7 @@ static int parse_config_env_list(char *env, config_fn_t fn, void *data)
                                             CONFIG_DATA_ENVIRONMENT);
                        }
 
-                       if (config_parse_pair(key, value, fn, data) < 0)
+                       if (config_parse_pair(key, value, kvi, fn, data) < 0)
                                return -1;
                }
                else {
@@ -770,11 +721,9 @@ int git_config_from_parameters(config_fn_t fn, void *data)
        struct strvec to_free = STRVEC_INIT;
        int ret = 0;
        char *envw = NULL;
-       struct config_source source = CONFIG_SOURCE_INIT;
-
-       source.origin_type = CONFIG_ORIGIN_CMDLINE;
-       config_reader_push_source(&the_reader, &source);
+       struct key_value_info kvi = KVI_INIT;
 
+       kvi_from_param(&kvi);
        env = getenv(CONFIG_COUNT_ENVIRONMENT);
        if (env) {
                unsigned long count;
@@ -810,7 +759,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)
                        }
                        strbuf_reset(&envvar);
 
-                       if (config_parse_pair(key, value, fn, data) < 0) {
+                       if (config_parse_pair(key, value, &kvi, fn, data) < 0) {
                                ret = -1;
                                goto out;
                        }
@@ -821,7 +770,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)
        if (env) {
                /* sq_dequote will write over it */
                envw = xstrdup(env);
-               if (parse_config_env_list(envw, fn, data) < 0) {
+               if (parse_config_env_list(envw, &kvi, fn, data) < 0) {
                        ret = -1;
                        goto out;
                }
@@ -831,7 +780,6 @@ out:
        strbuf_release(&envvar);
        strvec_clear(&to_free);
        free(envw);
-       config_reader_pop_source(&the_reader);
        return ret;
 }
 
@@ -932,12 +880,15 @@ static char *parse_value(struct config_source *cs)
        }
 }
 
-static int get_value(struct config_source *cs, config_fn_t fn, void *data,
-                    struct strbuf *name)
+static int get_value(struct config_source *cs, struct key_value_info *kvi,
+                    config_fn_t fn, void *data, struct strbuf *name)
 {
        int c;
        char *value;
        int ret;
+       struct config_context ctx = {
+               .kvi = kvi,
+       };
 
        /* Get the full name */
        for (;;) {
@@ -966,7 +917,8 @@ static int get_value(struct config_source *cs, config_fn_t fn, void *data,
         * accurate line number in error messages.
         */
        cs->linenr--;
-       ret = fn(name->buf, value, data);
+       kvi->linenr = cs->linenr;
+       ret = fn(name->buf, value, &ctx, data);
        if (ret >= 0)
                cs->linenr++;
        return ret;
@@ -1056,7 +1008,7 @@ static int do_event(struct config_source *cs, enum config_event_t type,
 
        if (data->previous_type != CONFIG_EVENT_EOF &&
            data->opts->event_fn(data->previous_type, data->previous_offset,
-                                offset, data->opts->event_fn_data) < 0)
+                                offset, cs, data->opts->event_fn_data) < 0)
                return -1;
 
        data->previous_type = type;
@@ -1065,8 +1017,20 @@ static int do_event(struct config_source *cs, enum config_event_t type,
        return 0;
 }
 
+static void kvi_from_source(struct config_source *cs,
+                           enum config_scope scope,
+                           struct key_value_info *out)
+{
+       out->filename = strintern(cs->name);
+       out->origin_type = cs->origin_type;
+       out->linenr = cs->linenr;
+       out->scope = scope;
+       out->path = cs->path;
+}
+
 static int git_parse_source(struct config_source *cs, config_fn_t fn,
-                           void *data, const struct config_options *opts)
+                           struct key_value_info *kvi, void *data,
+                           const struct config_options *opts)
 {
        int comment = 0;
        size_t baselen = 0;
@@ -1150,7 +1114,7 @@ static int git_parse_source(struct config_source *cs, config_fn_t fn,
                 */
                strbuf_setlen(var, baselen);
                strbuf_addch(var, tolower(c));
-               if (get_value(cs, fn, data, var) < 0)
+               if (get_value(cs, kvi, fn, data, var) < 0)
                        break;
        }
 
@@ -1203,223 +1167,81 @@ static int git_parse_source(struct config_source *cs, config_fn_t fn,
        return error_return;
 }
 
-static uintmax_t get_unit_factor(const char *end)
-{
-       if (!*end)
-               return 1;
-       else if (!strcasecmp(end, "k"))
-               return 1024;
-       else if (!strcasecmp(end, "m"))
-               return 1024 * 1024;
-       else if (!strcasecmp(end, "g"))
-               return 1024 * 1024 * 1024;
-       return 0;
-}
-
-static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
-{
-       if (value && *value) {
-               char *end;
-               intmax_t val;
-               intmax_t factor;
-
-               if (max < 0)
-                       BUG("max must be a positive integer");
-
-               errno = 0;
-               val = strtoimax(value, &end, 0);
-               if (errno == ERANGE)
-                       return 0;
-               if (end == value) {
-                       errno = EINVAL;
-                       return 0;
-               }
-               factor = get_unit_factor(end);
-               if (!factor) {
-                       errno = EINVAL;
-                       return 0;
-               }
-               if ((val < 0 && -max / factor > val) ||
-                   (val > 0 && max / factor < val)) {
-                       errno = ERANGE;
-                       return 0;
-               }
-               val *= factor;
-               *ret = val;
-               return 1;
-       }
-       errno = EINVAL;
-       return 0;
-}
-
-static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
-{
-       if (value && *value) {
-               char *end;
-               uintmax_t val;
-               uintmax_t factor;
-
-               /* negative values would be accepted by strtoumax */
-               if (strchr(value, '-')) {
-                       errno = EINVAL;
-                       return 0;
-               }
-               errno = 0;
-               val = strtoumax(value, &end, 0);
-               if (errno == ERANGE)
-                       return 0;
-               if (end == value) {
-                       errno = EINVAL;
-                       return 0;
-               }
-               factor = get_unit_factor(end);
-               if (!factor) {
-                       errno = EINVAL;
-                       return 0;
-               }
-               if (unsigned_mult_overflows(factor, val) ||
-                   factor * val > max) {
-                       errno = ERANGE;
-                       return 0;
-               }
-               val *= factor;
-               *ret = val;
-               return 1;
-       }
-       errno = EINVAL;
-       return 0;
-}
-
-int git_parse_int(const char *value, int *ret)
-{
-       intmax_t tmp;
-       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
-               return 0;
-       *ret = tmp;
-       return 1;
-}
-
-static int git_parse_int64(const char *value, int64_t *ret)
-{
-       intmax_t tmp;
-       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
-               return 0;
-       *ret = tmp;
-       return 1;
-}
-
-int git_parse_ulong(const char *value, unsigned long *ret)
-{
-       uintmax_t tmp;
-       if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
-               return 0;
-       *ret = tmp;
-       return 1;
-}
-
-int git_parse_ssize_t(const char *value, ssize_t *ret)
-{
-       intmax_t tmp;
-       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
-               return 0;
-       *ret = tmp;
-       return 1;
-}
-
-static int reader_config_name(struct config_reader *reader, const char **out);
-static int reader_origin_type(struct config_reader *reader,
-                             enum config_origin_type *type);
 NORETURN
-static void die_bad_number(struct config_reader *reader, const char *name,
-                          const char *value)
+static void die_bad_number(const char *name, const char *value,
+                          const struct key_value_info *kvi)
 {
        const char *error_type = (errno == ERANGE) ?
                N_("out of range") : N_("invalid unit");
        const char *bad_numeric = N_("bad numeric config value '%s' for '%s': %s");
-       const char *config_name = NULL;
-       enum config_origin_type config_origin = CONFIG_ORIGIN_UNKNOWN;
+
+       if (!kvi)
+               BUG("kvi should not be NULL");
 
        if (!value)
                value = "";
 
-       /* Ignoring the return value is okay since we handle missing values. */
-       reader_config_name(reader, &config_name);
-       reader_origin_type(reader, &config_origin);
-
-       if (!config_name)
+       if (!kvi->filename)
                die(_(bad_numeric), value, name, _(error_type));
 
-       switch (config_origin) {
+       switch (kvi->origin_type) {
        case CONFIG_ORIGIN_BLOB:
                die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
-                   value, name, config_name, _(error_type));
+                   value, name, kvi->filename, _(error_type));
        case CONFIG_ORIGIN_FILE:
                die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
-                   value, name, config_name, _(error_type));
+                   value, name, kvi->filename, _(error_type));
        case CONFIG_ORIGIN_STDIN:
                die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
                    value, name, _(error_type));
        case CONFIG_ORIGIN_SUBMODULE_BLOB:
                die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
-                   value, name, config_name, _(error_type));
+                   value, name, kvi->filename, _(error_type));
        case CONFIG_ORIGIN_CMDLINE:
                die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
-                   value, name, config_name, _(error_type));
+                   value, name, kvi->filename, _(error_type));
        default:
                die(_("bad numeric config value '%s' for '%s' in %s: %s"),
-                   value, name, config_name, _(error_type));
+                   value, name, kvi->filename, _(error_type));
        }
 }
 
-int git_config_int(const char *name, const char *value)
+int git_config_int(const char *name, const char *value,
+                  const struct key_value_info *kvi)
 {
        int ret;
        if (!git_parse_int(value, &ret))
-               die_bad_number(&the_reader, name, value);
+               die_bad_number(name, value, kvi);
        return ret;
 }
 
-int64_t git_config_int64(const char *name, const char *value)
+int64_t git_config_int64(const char *name, const char *value,
+                        const struct key_value_info *kvi)
 {
        int64_t ret;
        if (!git_parse_int64(value, &ret))
-               die_bad_number(&the_reader, name, value);
+               die_bad_number(name, value, kvi);
        return ret;
 }
 
-unsigned long git_config_ulong(const char *name, const char *value)
+unsigned long git_config_ulong(const char *name, const char *value,
+                              const struct key_value_info *kvi)
 {
        unsigned long ret;
        if (!git_parse_ulong(value, &ret))
-               die_bad_number(&the_reader, name, value);
+               die_bad_number(name, value, kvi);
        return ret;
 }
 
-ssize_t git_config_ssize_t(const char *name, const char *value)
+ssize_t git_config_ssize_t(const char *name, const char *value,
+                          const struct key_value_info *kvi)
 {
        ssize_t ret;
        if (!git_parse_ssize_t(value, &ret))
-               die_bad_number(&the_reader, name, value);
+               die_bad_number(name, value, kvi);
        return ret;
 }
 
-static int git_parse_maybe_bool_text(const char *value)
-{
-       if (!value)
-               return 1;
-       if (!*value)
-               return 0;
-       if (!strcasecmp(value, "true")
-           || !strcasecmp(value, "yes")
-           || !strcasecmp(value, "on"))
-               return 1;
-       if (!strcasecmp(value, "false")
-           || !strcasecmp(value, "no")
-           || !strcasecmp(value, "off"))
-               return 0;
-       return -1;
-}
-
 static const struct fsync_component_name {
        const char *name;
        enum fsync_component component_bits;
@@ -1494,17 +1316,8 @@ next_name:
        return (current & ~negative) | positive;
 }
 
-int git_parse_maybe_bool(const char *value)
-{
-       int v = git_parse_maybe_bool_text(value);
-       if (0 <= v)
-               return v;
-       if (git_parse_int(value, &v))
-               return !!v;
-       return -1;
-}
-
-int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
+int git_config_bool_or_int(const char *name, const char *value,
+                          const struct key_value_info *kvi, int *is_bool)
 {
        int v = git_parse_maybe_bool_text(value);
        if (0 <= v) {
@@ -1512,7 +1325,7 @@ int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
                return v;
        }
        *is_bool = 0;
-       return git_config_int(name, value);
+       return git_config_int(name, value, kvi);
 }
 
 int git_config_bool(const char *name, const char *value)
@@ -1560,7 +1373,8 @@ int git_config_color(char *dest, const char *var, const char *value)
        return 0;
 }
 
-static int git_default_core_config(const char *var, const char *value, void *cb)
+static int git_default_core_config(const char *var, const char *value,
+                                  const struct config_context *ctx, void *cb)
 {
        /* This needs a better name */
        if (!strcmp(var, "core.filemode")) {
@@ -1637,7 +1451,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
                else if (!git_parse_maybe_bool_text(value))
                        default_abbrev = the_hash_algo->hexsz;
                else {
-                       int abbrev = git_config_int(var, value);
+                       int abbrev = git_config_int(var, value, ctx->kvi);
                        if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz)
                                return error(_("abbrev length out of range: %d"), abbrev);
                        default_abbrev = abbrev;
@@ -1649,7 +1463,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
                return set_disambiguate_hint_config(var, value);
 
        if (!strcmp(var, "core.loosecompression")) {
-               int level = git_config_int(var, value);
+               int level = git_config_int(var, value, ctx->kvi);
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
@@ -1660,7 +1474,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp(var, "core.compression")) {
-               int level = git_config_int(var, value);
+               int level = git_config_int(var, value, ctx->kvi);
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
@@ -1674,7 +1488,7 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
 
        if (!strcmp(var, "core.packedgitwindowsize")) {
                int pgsz_x2 = getpagesize() * 2;
-               packed_git_window_size = git_config_ulong(var, value);
+               packed_git_window_size = git_config_ulong(var, value, ctx->kvi);
 
                /* This value must be multiple of (pagesize * 2) */
                packed_git_window_size /= pgsz_x2;
@@ -1685,17 +1499,17 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp(var, "core.bigfilethreshold")) {
-               big_file_threshold = git_config_ulong(var, value);
+               big_file_threshold = git_config_ulong(var, value, ctx->kvi);
                return 0;
        }
 
        if (!strcmp(var, "core.packedgitlimit")) {
-               packed_git_limit = git_config_ulong(var, value);
+               packed_git_limit = git_config_ulong(var, value, ctx->kvi);
                return 0;
        }
 
        if (!strcmp(var, "core.deltabasecachelimit")) {
-               delta_base_cache_limit = git_config_ulong(var, value);
+               delta_base_cache_limit = git_config_ulong(var, value, ctx->kvi);
                return 0;
        }
 
@@ -1839,13 +1653,13 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (!strcmp(var, "core.usereplacerefs")) {
-               read_replace_refs = git_config_bool(var, value);
+       if (!strcmp(var, "core.maxtreedepth")) {
+               max_allowed_tree_depth = git_config_int(var, value, ctx->kvi);
                return 0;
        }
 
        /* Add other config variables here and to Documentation/config.txt. */
-       return platform_core_config(var, value, cb);
+       return platform_core_config(var, value, ctx, cb);
 }
 
 static int git_default_sparse_config(const char *var, const char *value)
@@ -1947,15 +1761,28 @@ static int git_default_mailmap_config(const char *var, const char *value)
        return 0;
 }
 
-int git_default_config(const char *var, const char *value, void *cb)
+static int git_default_attr_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "attr.tree"))
+               return git_config_string(&git_attr_tree, var, value);
+
+       /*
+        * Add other attribute related config variables here and to
+        * Documentation/config/attr.txt.
+        */
+       return 0;
+}
+
+int git_default_config(const char *var, const char *value,
+                      const struct config_context *ctx, void *cb)
 {
        if (starts_with(var, "core."))
-               return git_default_core_config(var, value, cb);
+               return git_default_core_config(var, value, ctx, cb);
 
        if (starts_with(var, "user.") ||
            starts_with(var, "author.") ||
            starts_with(var, "committer."))
-               return git_ident_config(var, value, cb);
+               return git_ident_config(var, value, ctx, cb);
 
        if (starts_with(var, "i18n."))
                return git_default_i18n_config(var, value);
@@ -1969,6 +1796,9 @@ int git_default_config(const char *var, const char *value, void *cb)
        if (starts_with(var, "mailmap."))
                return git_default_mailmap_config(var, value);
 
+       if (starts_with(var, "attr."))
+               return git_default_attr_config(var, value);
+
        if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
                return git_default_advice_config(var, value);
 
@@ -1978,12 +1808,12 @@ int git_default_config(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp(var, "pack.packsizelimit")) {
-               pack_size_limit_cfg = git_config_ulong(var, value);
+               pack_size_limit_cfg = git_config_ulong(var, value, ctx->kvi);
                return 0;
        }
 
        if (!strcmp(var, "pack.compression")) {
-               int level = git_config_int(var, value);
+               int level = git_config_int(var, value, ctx->kvi);
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
@@ -2005,10 +1835,11 @@ int git_default_config(const char *var, const char *value, void *cb)
  * fgetc, ungetc, ftell of top need to be initialized before calling
  * this function.
  */
-static int do_config_from(struct config_reader *reader,
-                         struct config_source *top, config_fn_t fn, void *data,
+static int do_config_from(struct config_source *top, config_fn_t fn,
+                         void *data, enum config_scope scope,
                          const struct config_options *opts)
 {
+       struct key_value_info kvi = KVI_INIT;
        int ret;
 
        /* push config-file parsing state stack */
@@ -2017,23 +1848,21 @@ static int do_config_from(struct config_reader *reader,
        top->total_len = 0;
        strbuf_init(&top->value, 1024);
        strbuf_init(&top->var, 1024);
-       config_reader_push_source(reader, top);
+       kvi_from_source(top, scope, &kvi);
 
-       ret = git_parse_source(top, fn, data, opts);
+       ret = git_parse_source(top, fn, &kvi, data, opts);
 
-       /* pop config-file parsing state stack */
        strbuf_release(&top->value);
        strbuf_release(&top->var);
-       config_reader_pop_source(reader);
 
        return ret;
 }
 
-static int do_config_from_file(struct config_reader *reader,
-                              config_fn_t fn,
+static int do_config_from_file(config_fn_t fn,
                               const enum config_origin_type origin_type,
                               const char *name, const char *path, FILE *f,
-                              void *data, const struct config_options *opts)
+                              void *data, enum config_scope scope,
+                              const struct config_options *opts)
 {
        struct config_source top = CONFIG_SOURCE_INIT;
        int ret;
@@ -2048,19 +1877,20 @@ static int do_config_from_file(struct config_reader *reader,
        top.do_ftell = config_file_ftell;
 
        flockfile(f);
-       ret = do_config_from(reader, &top, fn, data, opts);
+       ret = do_config_from(&top, fn, data, scope, opts);
        funlockfile(f);
        return ret;
 }
 
-static int git_config_from_stdin(config_fn_t fn, void *data)
+static int git_config_from_stdin(config_fn_t fn, void *data,
+                                enum config_scope scope)
 {
-       return do_config_from_file(&the_reader, fn, CONFIG_ORIGIN_STDIN, "",
-                                  NULL, stdin, data, NULL);
+       return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin,
+                                  data, scope, NULL);
 }
 
 int git_config_from_file_with_options(config_fn_t fn, const char *filename,
-                                     void *data,
+                                     void *data, enum config_scope scope,
                                      const struct config_options *opts)
 {
        int ret = -1;
@@ -2070,8 +1900,8 @@ int git_config_from_file_with_options(config_fn_t fn, const char *filename,
                BUG("filename cannot be NULL");
        f = fopen_or_warn(filename, "r");
        if (f) {
-               ret = do_config_from_file(&the_reader, fn, CONFIG_ORIGIN_FILE,
-                                         filename, filename, f, data, opts);
+               ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename,
+                                         filename, f, data, scope, opts);
                fclose(f);
        }
        return ret;
@@ -2079,13 +1909,15 @@ int git_config_from_file_with_options(config_fn_t fn, const char *filename,
 
 int git_config_from_file(config_fn_t fn, const char *filename, void *data)
 {
-       return git_config_from_file_with_options(fn, filename, data, NULL);
+       return git_config_from_file_with_options(fn, filename, data,
+                                                CONFIG_SCOPE_UNKNOWN, NULL);
 }
 
 int git_config_from_mem(config_fn_t fn,
                        const enum config_origin_type origin_type,
                        const char *name, const char *buf, size_t len,
-                       void *data, const struct config_options *opts)
+                       void *data, enum config_scope scope,
+                       const struct config_options *opts)
 {
        struct config_source top = CONFIG_SOURCE_INIT;
 
@@ -2100,14 +1932,15 @@ int git_config_from_mem(config_fn_t fn,
        top.do_ungetc = config_buf_ungetc;
        top.do_ftell = config_buf_ftell;
 
-       return do_config_from(&the_reader, &top, fn, data, opts);
+       return do_config_from(&top, fn, data, scope, opts);
 }
 
 int git_config_from_blob_oid(config_fn_t fn,
                              const char *name,
                              struct repository *repo,
                              const struct object_id *oid,
-                             void *data)
+                             void *data,
+                             enum config_scope scope)
 {
        enum object_type type;
        char *buf;
@@ -2123,7 +1956,7 @@ int git_config_from_blob_oid(config_fn_t fn,
        }
 
        ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size,
-                                 data, NULL);
+                                 data, scope, NULL);
        free(buf);
 
        return ret;
@@ -2132,13 +1965,14 @@ int git_config_from_blob_oid(config_fn_t fn,
 static int git_config_from_blob_ref(config_fn_t fn,
                                    struct repository *repo,
                                    const char *name,
-                                   void *data)
+                                   void *data,
+                                   enum config_scope scope)
 {
        struct object_id oid;
 
        if (repo_get_oid(repo, name, &oid) < 0)
                return error(_("unable to resolve config blob '%s'"), name);
-       return git_config_from_blob_oid(fn, name, repo, &oid, data);
+       return git_config_from_blob_oid(fn, name, repo, &oid, data, scope);
 }
 
 char *git_system_config(void)
@@ -2164,35 +1998,13 @@ void git_global_config(char **user_out, char **xdg_out)
        *xdg_out = xdg_config;
 }
 
-/*
- * Parse environment variable 'k' as a boolean (in various
- * possible spellings); if missing, use the default value 'def'.
- */
-int git_env_bool(const char *k, int def)
-{
-       const char *v = getenv(k);
-       return v ? git_config_bool(k, v) : def;
-}
-
-/*
- * Parse environment variable 'k' as ulong with possibly a unit
- * suffix; if missing, use the default value 'val'.
- */
-unsigned long git_env_ulong(const char *k, unsigned long val)
-{
-       const char *v = getenv(k);
-       if (v && !git_parse_ulong(v, &val))
-               die(_("failed to parse %s"), k);
-       return val;
-}
-
 int git_config_system(void)
 {
        return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
-static int do_git_config_sequence(struct config_reader *reader,
-                                 const struct config_options *opts,
+static int do_git_config_sequence(const struct config_options *opts,
+                                 const struct repository *repo,
                                  config_fn_t fn, void *data)
 {
        int ret = 0;
@@ -2200,122 +2012,125 @@ static int do_git_config_sequence(struct config_reader *reader,
        char *xdg_config = NULL;
        char *user_config = NULL;
        char *repo_config;
-       enum config_scope prev_parsing_scope = reader->parsing_scope;
+       char *worktree_config;
 
-       if (opts->commondir)
+       /*
+        * Ensure that either:
+        * - the git_dir and commondir are both set, or
+        * - the git_dir and commondir are both NULL
+        */
+       if (!opts->git_dir != !opts->commondir)
+               BUG("only one of commondir and git_dir is non-NULL");
+
+       if (opts->commondir) {
                repo_config = mkpathdup("%s/config", opts->commondir);
-       else if (opts->git_dir)
-               BUG("git_dir without commondir");
-       else
+               worktree_config = mkpathdup("%s/config.worktree", opts->git_dir);
+       } else {
                repo_config = NULL;
+               worktree_config = NULL;
+       }
 
-       config_reader_set_scope(reader, CONFIG_SCOPE_SYSTEM);
        if (git_config_system() && system_config &&
            !access_or_die(system_config, R_OK,
                           opts->system_gently ? ACCESS_EACCES_OK : 0))
-               ret += git_config_from_file(fn, system_config, data);
+               ret += git_config_from_file_with_options(fn, system_config,
+                                                        data, CONFIG_SCOPE_SYSTEM,
+                                                        NULL);
 
-       config_reader_set_scope(reader, CONFIG_SCOPE_GLOBAL);
        git_global_config(&user_config, &xdg_config);
 
        if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
-               ret += git_config_from_file(fn, xdg_config, data);
+               ret += git_config_from_file_with_options(fn, xdg_config, data,
+                                                        CONFIG_SCOPE_GLOBAL, NULL);
 
        if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
-               ret += git_config_from_file(fn, user_config, data);
+               ret += git_config_from_file_with_options(fn, user_config, data,
+                                                        CONFIG_SCOPE_GLOBAL, NULL);
 
-       config_reader_set_scope(reader, CONFIG_SCOPE_LOCAL);
        if (!opts->ignore_repo && repo_config &&
            !access_or_die(repo_config, R_OK, 0))
-               ret += git_config_from_file(fn, repo_config, data);
+               ret += git_config_from_file_with_options(fn, repo_config, data,
+                                                        CONFIG_SCOPE_LOCAL, NULL);
 
-       config_reader_set_scope(reader, CONFIG_SCOPE_WORKTREE);
-       if (!opts->ignore_worktree && repository_format_worktree_config) {
-               char *path = git_pathdup("config.worktree");
-               if (!access_or_die(path, R_OK, 0))
-                       ret += git_config_from_file(fn, path, data);
-               free(path);
+       if (!opts->ignore_worktree && worktree_config &&
+           repo && repo->repository_format_worktree_config &&
+           !access_or_die(worktree_config, R_OK, 0)) {
+                       ret += git_config_from_file_with_options(fn, worktree_config, data,
+                                                                CONFIG_SCOPE_WORKTREE,
+                                                                NULL);
        }
 
-       config_reader_set_scope(reader, CONFIG_SCOPE_COMMAND);
        if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
                die(_("unable to parse command-line config"));
 
-       config_reader_set_scope(reader, prev_parsing_scope);
        free(system_config);
        free(xdg_config);
        free(user_config);
        free(repo_config);
+       free(worktree_config);
        return ret;
 }
 
 int config_with_options(config_fn_t fn, void *data,
                        struct git_config_source *config_source,
+                       struct repository *repo,
                        const struct config_options *opts)
 {
        struct config_include_data inc = CONFIG_INCLUDE_INIT;
-       enum config_scope prev_scope = the_reader.parsing_scope;
        int ret;
 
        if (opts->respect_includes) {
                inc.fn = fn;
                inc.data = data;
                inc.opts = opts;
+               inc.repo = repo;
                inc.config_source = config_source;
-               inc.config_reader = &the_reader;
                fn = git_config_include;
                data = &inc;
        }
 
-       if (config_source)
-               config_reader_set_scope(&the_reader, config_source->scope);
-
        /*
         * If we have a specific filename, use it. Otherwise, follow the
         * regular lookup sequence.
         */
        if (config_source && config_source->use_stdin) {
-               ret = git_config_from_stdin(fn, data);
+               ret = git_config_from_stdin(fn, data, config_source->scope);
        } else if (config_source && config_source->file) {
-               ret = git_config_from_file(fn, config_source->file, data);
+               ret = git_config_from_file_with_options(fn, config_source->file,
+                                                       data, config_source->scope,
+                                                       NULL);
        } else if (config_source && config_source->blob) {
-               struct repository *repo = config_source->repo ?
-                       config_source->repo : the_repository;
                ret = git_config_from_blob_ref(fn, repo, config_source->blob,
-                                               data);
+                                              data, config_source->scope);
        } else {
-               ret = do_git_config_sequence(&the_reader, opts, fn, data);
+               ret = do_git_config_sequence(opts, repo, fn, data);
        }
 
        if (inc.remote_urls) {
                string_list_clear(inc.remote_urls, 0);
                FREE_AND_NULL(inc.remote_urls);
        }
-       config_reader_set_scope(&the_reader, prev_scope);
        return ret;
 }
 
-static void configset_iter(struct config_reader *reader, struct config_set *set,
-                          config_fn_t fn, void *data)
+static void configset_iter(struct config_set *set, config_fn_t fn, void *data)
 {
        int i, value_index;
        struct string_list *values;
        struct config_set_element *entry;
        struct configset_list *list = &set->list;
+       struct config_context ctx = CONFIG_CONTEXT_INIT;
 
        for (i = 0; i < list->nr; i++) {
                entry = list->items[i].e;
                value_index = list->items[i].value_index;
                values = &entry->value_list;
 
-               config_reader_set_kvi(reader, values->items[value_index].util);
-
-               if (fn(entry->key, values->items[value_index].string, data) < 0)
+               ctx.kvi = values->items[value_index].util;
+               if (fn(entry->key, values->items[value_index].string, &ctx, data) < 0)
                        git_die_config_linenr(entry->key,
-                                             reader->config_kvi->filename,
-                                             reader->config_kvi->linenr);
-
-               config_reader_set_kvi(reader, NULL);
+                                             ctx.kvi->filename,
+                                             ctx.kvi->linenr);
        }
 }
 
@@ -2343,7 +2158,7 @@ void read_early_config(config_fn_t cb, void *data)
                opts.git_dir = gitdir.buf;
        }
 
-       config_with_options(cb, data, NULL, &opts);
+       config_with_options(cb, data, NULL, NULL, &opts);
 
        strbuf_release(&commondir);
        strbuf_release(&gitdir);
@@ -2363,7 +2178,7 @@ void read_very_early_config(config_fn_t cb, void *data)
        opts.ignore_cmdline = 1;
        opts.system_gently = 1;
 
-       config_with_options(cb, data, NULL, &opts);
+       config_with_options(cb, data, NULL, NULL, &opts);
 }
 
 RESULT_MUST_BE_USED
@@ -2391,7 +2206,7 @@ static int configset_find_element(struct config_set *set, const char *key,
        return 0;
 }
 
-static int configset_add_value(struct config_reader *reader,
+static int configset_add_value(const struct key_value_info *kvi_p,
                               struct config_set *set, const char *key,
                               const char *value)
 {
@@ -2422,19 +2237,7 @@ static int configset_add_value(struct config_reader *reader,
        l_item->e = e;
        l_item->value_index = e->value_list.nr - 1;
 
-       if (!reader->source)
-               BUG("configset_add_value has no source");
-       if (reader->source->name) {
-               kv_info->filename = strintern(reader->source->name);
-               kv_info->linenr = reader->source->linenr;
-               kv_info->origin_type = reader->source->origin_type;
-       } else {
-               /* for values read from `git_config_from_parameters()` */
-               kv_info->filename = NULL;
-               kv_info->linenr = -1;
-               kv_info->origin_type = CONFIG_ORIGIN_CMDLINE;
-       }
-       kv_info->scope = reader->parsing_scope;
+       *kv_info = *kvi_p;
        si->util = kv_info;
 
        return 0;
@@ -2482,32 +2285,26 @@ void git_configset_clear(struct config_set *set)
        set->list.items = NULL;
 }
 
-struct configset_add_data {
-       struct config_set *config_set;
-       struct config_reader *config_reader;
-};
-#define CONFIGSET_ADD_INIT { 0 }
-
-static int config_set_callback(const char *key, const char *value, void *cb)
+static int config_set_callback(const char *key, const char *value,
+                              const struct config_context *ctx,
+                              void *cb)
 {
-       struct configset_add_data *data = cb;
-       configset_add_value(data->config_reader, data->config_set, key, value);
+       struct config_set *set = cb;
+       configset_add_value(ctx->kvi, set, key, value);
        return 0;
 }
 
 int git_configset_add_file(struct config_set *set, const char *filename)
 {
-       struct configset_add_data data = CONFIGSET_ADD_INIT;
-       data.config_reader = &the_reader;
-       data.config_set = set;
-       return git_config_from_file(config_set_callback, filename, &data);
+       return git_config_from_file(config_set_callback, filename, set);
 }
 
-int git_configset_get_value(struct config_set *set, const char *key, const char **value)
+int git_configset_get_value(struct config_set *set, const char *key,
+                           const char **value, struct key_value_info *kvi)
 {
        const struct string_list *values = NULL;
        int ret;
-
+       struct string_list_item item;
        /*
         * Follows "last one wins" semantic, i.e., if there are multiple matches for the
         * queried key in the files of the configset, the value returned will be the last
@@ -2517,7 +2314,10 @@ int git_configset_get_value(struct config_set *set, const char *key, const char
                return ret;
 
        assert(values->nr > 0);
-       *value = values->items[values->nr - 1].string;
+       item = values->items[values->nr - 1];
+       *value = item.string;
+       if (kvi)
+               *kvi = *((struct key_value_info *)item.util);
        return 0;
 }
 
@@ -2570,7 +2370,7 @@ int git_configset_get(struct config_set *set, const char *key)
 int git_configset_get_string(struct config_set *set, const char *key, char **dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value))
+       if (!git_configset_get_value(set, key, &value, NULL))
                return git_config_string((const char **)dest, key, value);
        else
                return 1;
@@ -2580,7 +2380,7 @@ static int git_configset_get_string_tmp(struct config_set *set, const char *key,
                                        const char **dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value)) {
+       if (!git_configset_get_value(set, key, &value, NULL)) {
                if (!value)
                        return config_error_nonbool(key);
                *dest = value;
@@ -2593,8 +2393,10 @@ static int git_configset_get_string_tmp(struct config_set *set, const char *key,
 int git_configset_get_int(struct config_set *set, const char *key, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value)) {
-               *dest = git_config_int(key, value);
+       struct key_value_info kvi;
+
+       if (!git_configset_get_value(set, key, &value, &kvi)) {
+               *dest = git_config_int(key, value, &kvi);
                return 0;
        } else
                return 1;
@@ -2603,8 +2405,10 @@ int git_configset_get_int(struct config_set *set, const char *key, int *dest)
 int git_configset_get_ulong(struct config_set *set, const char *key, unsigned long *dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value)) {
-               *dest = git_config_ulong(key, value);
+       struct key_value_info kvi;
+
+       if (!git_configset_get_value(set, key, &value, &kvi)) {
+               *dest = git_config_ulong(key, value, &kvi);
                return 0;
        } else
                return 1;
@@ -2613,7 +2417,7 @@ int git_configset_get_ulong(struct config_set *set, const char *key, unsigned lo
 int git_configset_get_bool(struct config_set *set, const char *key, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value)) {
+       if (!git_configset_get_value(set, key, &value, NULL)) {
                *dest = git_config_bool(key, value);
                return 0;
        } else
@@ -2624,8 +2428,10 @@ int git_configset_get_bool_or_int(struct config_set *set, const char *key,
                                int *is_bool, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value)) {
-               *dest = git_config_bool_or_int(key, value, is_bool);
+       struct key_value_info kvi;
+
+       if (!git_configset_get_value(set, key, &value, &kvi)) {
+               *dest = git_config_bool_or_int(key, value, &kvi, is_bool);
                return 0;
        } else
                return 1;
@@ -2634,7 +2440,7 @@ int git_configset_get_bool_or_int(struct config_set *set, const char *key,
 int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value)) {
+       if (!git_configset_get_value(set, key, &value, NULL)) {
                *dest = git_parse_maybe_bool(value);
                if (*dest == -1)
                        return -1;
@@ -2646,7 +2452,7 @@ int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *d
 int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
 {
        const char *value;
-       if (!git_configset_get_value(set, key, &value))
+       if (!git_configset_get_value(set, key, &value, NULL))
                return git_config_pathname(dest, key, value);
        else
                return 1;
@@ -2656,7 +2462,6 @@ int git_configset_get_pathname(struct config_set *set, const char *key, const ch
 static void repo_read_config(struct repository *repo)
 {
        struct config_options opts = { 0 };
-       struct configset_add_data data = CONFIGSET_ADD_INIT;
 
        opts.respect_includes = 1;
        opts.commondir = repo->commondir;
@@ -2668,10 +2473,8 @@ static void repo_read_config(struct repository *repo)
                git_configset_clear(repo->config);
 
        git_configset_init(repo->config);
-       data.config_set = repo->config;
-       data.config_reader = &the_reader;
-
-       if (config_with_options(config_set_callback, &data, NULL, &opts) < 0)
+       if (config_with_options(config_set_callback, repo->config, NULL,
+                               repo, &opts) < 0)
                /*
                 * config_with_options() normally returns only
                 * zero, as most errors are fatal, and
@@ -2703,7 +2506,7 @@ static void repo_config_clear(struct repository *repo)
 void repo_config(struct repository *repo, config_fn_t fn, void *data)
 {
        git_config_check_init(repo);
-       configset_iter(&the_reader, repo->config, fn, data);
+       configset_iter(repo->config, fn, data);
 }
 
 int repo_config_get(struct repository *repo, const char *key)
@@ -2716,7 +2519,7 @@ int repo_config_get_value(struct repository *repo,
                          const char *key, const char **value)
 {
        git_config_check_init(repo);
-       return git_configset_get_value(repo->config, key, value);
+       return git_configset_get_value(repo->config, key, value, NULL);
 }
 
 int repo_config_get_value_multi(struct repository *repo, const char *key,
@@ -2810,19 +2613,17 @@ static void read_protected_config(void)
                .ignore_worktree = 1,
                .system_gently = 1,
        };
-       struct configset_add_data data = CONFIGSET_ADD_INIT;
 
        git_configset_init(&protected_config);
-       data.config_set = &protected_config;
-       data.config_reader = &the_reader;
-       config_with_options(config_set_callback, &data, NULL, &opts);
+       config_with_options(config_set_callback, &protected_config, NULL,
+                           NULL, &opts);
 }
 
 void git_protected_config(config_fn_t fn, void *data)
 {
        if (!protected_config.hash_initialized)
                read_protected_config();
-       configset_iter(&the_reader, &protected_config, fn, data);
+       configset_iter(&protected_config, fn, data);
 }
 
 /* Functions used historically to read configuration from 'the_repository' */
@@ -3012,7 +2813,6 @@ void git_die_config(const char *key, const char *err, ...)
  */
 
 struct config_store_data {
-       struct config_reader *config_reader;
        size_t baselen;
        char *key;
        int do_not_match;
@@ -3058,11 +2858,10 @@ static int matches(const char *key, const char *value,
                (value && !regexec(store->value_pattern, value, 0, NULL, 0));
 }
 
-static int store_aux_event(enum config_event_t type,
-                          size_t begin, size_t end, void *data)
+static int store_aux_event(enum config_event_t type, size_t begin, size_t end,
+                          struct config_source *cs, void *data)
 {
        struct config_store_data *store = data;
-       struct config_source *cs = store->config_reader->source;
 
        ALLOC_GROW(store->parsed, store->parsed_nr + 1, store->parsed_alloc);
        store->parsed[store->parsed_nr].begin = begin;
@@ -3098,7 +2897,8 @@ static int store_aux_event(enum config_event_t type,
        return 0;
 }
 
-static int store_aux(const char *key, const char *value, void *cb)
+static int store_aux(const char *key, const char *value,
+                    const struct config_context *ctx UNUSED, void *cb)
 {
        struct config_store_data *store = cb;
 
@@ -3327,7 +3127,7 @@ int repo_config_set_worktree_gently(struct repository *r,
                                    const char *key, const char *value)
 {
        /* Only use worktree-specific config if it is already enabled. */
-       if (repository_format_worktree_config) {
+       if (r->repository_format_worktree_config) {
                char *file = repo_git_path(r, "config.worktree");
                int ret = git_config_set_multivar_in_file_gently(
                                        file, key, value, NULL, 0);
@@ -3382,8 +3182,6 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
        size_t contents_sz;
        struct config_store_data store = CONFIG_STORE_INIT;
 
-       store.config_reader = &the_reader;
-
        /* parse-key returns negative; flip the sign to feed exit(3) */
        ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
        if (ret)
@@ -3472,7 +3270,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
                 */
                if (git_config_from_file_with_options(store_aux,
                                                      config_filename,
-                                                     &store, &opts)) {
+                                                     &store, CONFIG_SCOPE_UNKNOWN,
+                                                     &opts)) {
                        error(_("invalid config file %s"), config_filename);
                        ret = CONFIG_INVALID_FILE;
                        goto out_free;
@@ -3833,6 +3632,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
                                                output[0] = '\t';
                                        }
                                } else {
+                                       strbuf_release(&copystr);
                                        copystr = store_create_section(new_name, &store);
                                }
                        }
@@ -3879,6 +3679,7 @@ out_no_rollback:
        free(filename_buf);
        config_store_data_clear(&store);
        strbuf_release(&buf);
+       strbuf_release(&copystr);
        return ret;
 }
 
@@ -3952,25 +3753,8 @@ int parse_config_key(const char *var,
        return 0;
 }
 
-static int reader_origin_type(struct config_reader *reader,
-                             enum config_origin_type *type)
-{
-       if (the_reader.config_kvi)
-               *type = reader->config_kvi->origin_type;
-       else if(the_reader.source)
-               *type = reader->source->origin_type;
-       else
-               return 1;
-       return 0;
-}
-
-const char *current_config_origin_type(void)
+const char *config_origin_type_name(enum config_origin_type type)
 {
-       enum config_origin_type type = CONFIG_ORIGIN_UNKNOWN;
-
-       if (reader_origin_type(&the_reader, &type))
-               BUG("current_config_origin_type called outside config callback");
-
        switch (type) {
        case CONFIG_ORIGIN_BLOB:
                return "blob";
@@ -4007,41 +3791,6 @@ const char *config_scope_name(enum config_scope scope)
        }
 }
 
-static int reader_config_name(struct config_reader *reader, const char **out)
-{
-       if (the_reader.config_kvi)
-               *out = reader->config_kvi->filename;
-       else if (the_reader.source)
-               *out = reader->source->name;
-       else
-               return 1;
-       return 0;
-}
-
-const char *current_config_name(void)
-{
-       const char *name;
-       if (reader_config_name(&the_reader, &name))
-               BUG("current_config_name called outside config callback");
-       return name ? name : "";
-}
-
-enum config_scope current_config_scope(void)
-{
-       if (the_reader.config_kvi)
-               return the_reader.config_kvi->scope;
-       else
-               return the_reader.parsing_scope;
-}
-
-int current_config_line(void)
-{
-       if (the_reader.config_kvi)
-               return the_reader.config_kvi->linenr;
-       else
-               return the_reader.source->linenr;
-}
-
 int lookup_config(const char **mapping, int nr_mapping, const char *var)
 {
        int i;
index 247b572b37bc28e46a88118e3484795078c99b1a..14f881ecfaf6b264b6d120205ab509f2ee5930f2 100644 (file)
--- a/config.h
+++ b/config.h
@@ -3,7 +3,8 @@
 
 #include "hashmap.h"
 #include "string-list.h"
-
+#include "repository.h"
+#include "parse.h"
 
 /**
  * The config API gives callers a way to access Git configuration files
@@ -49,8 +50,6 @@ const char *config_scope_name(enum config_scope scope);
 struct git_config_source {
        unsigned int use_stdin:1;
        const char *file;
-       /* The repository if blob is not NULL; leave blank for the_repository */
-       struct repository *repo;
        const char *blob;
        enum config_scope scope;
 };
@@ -73,6 +72,7 @@ enum config_event_t {
        CONFIG_EVENT_ERROR
 };
 
+struct config_source;
 /*
  * The parser event function (if not NULL) is called with the event type and
  * the begin/end offsets of the parsed elements.
@@ -82,6 +82,7 @@ enum config_event_t {
  */
 typedef int (*config_parser_event_fn_t)(enum config_event_t type,
                                        size_t begin_offset, size_t end_offset,
+                                       struct config_source *cs,
                                        void *event_fn_data);
 
 struct config_options {
@@ -101,6 +102,10 @@ struct config_options {
 
        const char *commondir;
        const char *git_dir;
+       /*
+        * event_fn and event_fn_data are for internal use only. Handles events
+        * emitted by the config parser.
+        */
        config_parser_event_fn_t event_fn;
        void *event_fn_data;
        enum config_error_action {
@@ -111,8 +116,31 @@ struct config_options {
        } error_action;
 };
 
+/* Config source metadata for a given config key-value pair */
+struct key_value_info {
+       const char *filename;
+       int linenr;
+       enum config_origin_type origin_type;
+       enum config_scope scope;
+       const char *path;
+};
+#define KVI_INIT { \
+       .filename = NULL, \
+       .linenr = -1, \
+       .origin_type = CONFIG_ORIGIN_UNKNOWN, \
+       .scope = CONFIG_SCOPE_UNKNOWN, \
+       .path = NULL, \
+}
+
+/* Captures additional information that a config callback can use. */
+struct config_context {
+       /* Config source metadata for key and value. */
+       const struct key_value_info *kvi;
+};
+#define CONFIG_CONTEXT_INIT { 0 }
+
 /**
- * A config callback function takes three parameters:
+ * A config callback function takes four parameters:
  *
  * - the name of the parsed variable. This is in canonical "flat" form: the
  *   section, subsection, and variable segments will be separated by dots,
@@ -123,15 +151,22 @@ struct config_options {
  *   value specified, the value will be NULL (typically this means it
  *   should be interpreted as boolean true).
  *
+ * - the 'config context', that is, additional information about the config
+ *   iteration operation provided by the config machinery. For example, this
+ *   includes information about the config source being parsed (e.g. the
+ *   filename).
+ *
  * - a void pointer passed in by the caller of the config API; this can
  *   contain callback-specific data
  *
  * A config callback should return 0 for success, or -1 if the variable
  * could not be parsed properly.
  */
-typedef int (*config_fn_t)(const char *, const char *, void *);
+typedef int (*config_fn_t)(const char *, const char *,
+                          const struct config_context *, void *);
 
-int git_default_config(const char *, const char *, void *);
+int git_default_config(const char *, const char *,
+                      const struct config_context *, void *);
 
 /**
  * Read a specific file in git-config format.
@@ -142,16 +177,18 @@ int git_default_config(const char *, const char *, void *);
 int git_config_from_file(config_fn_t fn, const char *, void *);
 
 int git_config_from_file_with_options(config_fn_t fn, const char *,
-                                     void *,
+                                     void *, enum config_scope,
                                      const struct config_options *);
 int git_config_from_mem(config_fn_t fn,
                        const enum config_origin_type,
                        const char *name,
                        const char *buf, size_t len,
-                       void *data, const struct config_options *opts);
+                       void *data, enum config_scope scope,
+                       const struct config_options *opts);
 int git_config_from_blob_oid(config_fn_t fn, const char *name,
                             struct repository *repo,
-                            const struct object_id *oid, void *data);
+                            const struct object_id *oid, void *data,
+                            enum config_scope scope);
 void git_config_push_parameter(const char *text);
 void git_config_push_env(const char *spec);
 int git_config_from_parameters(config_fn_t fn, void *data);
@@ -196,6 +233,7 @@ void git_config(config_fn_t fn, void *);
  */
 int config_with_options(config_fn_t fn, void *,
                        struct git_config_source *config_source,
+                       struct repository *repo,
                        const struct config_options *opts);
 
 /**
@@ -205,36 +243,30 @@ int config_with_options(config_fn_t fn, void *,
  * The following helper functions aid in parsing string values
  */
 
-int git_parse_ssize_t(const char *, ssize_t *);
-int git_parse_ulong(const char *, unsigned long *);
-int git_parse_int(const char *value, int *ret);
-
-/**
- * Same as `git_config_bool`, except that it returns -1 on error rather
- * than dying.
- */
-int git_parse_maybe_bool(const char *);
-
 /**
  * Parse the string to an integer, including unit factors. Dies on error;
  * otherwise, returns the parsed result.
  */
-int git_config_int(const char *, const char *);
+int git_config_int(const char *, const char *, const struct key_value_info *);
 
-int64_t git_config_int64(const char *, const char *);
+int64_t git_config_int64(const char *, const char *,
+                        const struct key_value_info *);
 
 /**
  * Identical to `git_config_int`, but for unsigned longs.
  */
-unsigned long git_config_ulong(const char *, const char *);
+unsigned long git_config_ulong(const char *, const char *,
+                              const struct key_value_info *);
 
-ssize_t git_config_ssize_t(const char *, const char *);
+ssize_t git_config_ssize_t(const char *, const char *,
+                          const struct key_value_info *);
 
 /**
  * Same as `git_config_bool`, except that integers are returned as-is, and
  * an `is_bool` flag is unset.
  */
-int git_config_bool_or_int(const char *, const char *, int *);
+int git_config_bool_or_int(const char *, const char *,
+                          const struct key_value_info *, int *);
 
 /**
  * Parse a string into a boolean value, respecting keywords like "true" and
@@ -343,8 +375,6 @@ int git_config_rename_section(const char *, const char *);
 int git_config_rename_section_in_file(const char *, const char *, const char *);
 int git_config_copy_section(const char *, const char *);
 int git_config_copy_section_in_file(const char *, const char *, const char *);
-int git_env_bool(const char *, int);
-unsigned long git_env_ulong(const char *, unsigned long);
 int git_config_system(void);
 int config_error_nonbool(const char *);
 #if defined(__GNUC__)
@@ -356,10 +386,8 @@ void git_global_config(char **user, char **xdg);
 
 int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 
-enum config_scope current_config_scope(void);
-const char *current_config_origin_type(void);
-const char *current_config_name(void);
-int current_config_line(void);
+const char *config_origin_type_name(enum config_origin_type type);
+void kvi_from_param(struct key_value_info *out);
 
 /*
  * Match and parse a config key of the form:
@@ -501,7 +529,8 @@ int git_configset_get(struct config_set *cs, const char *key);
  * touching `value`. The caller should not free or modify `value`, as it
  * is owned by the cache.
  */
-int git_configset_get_value(struct config_set *cs, const char *key, const char **dest);
+int git_configset_get_value(struct config_set *cs, const char *key,
+                           const char **dest, struct key_value_info *kvi);
 
 int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
@@ -667,13 +696,6 @@ int git_config_get_expiry(const char *key, const char **output);
 /* parse either "this many days" integer, or "5.days.ago" approxidate */
 int git_config_get_expiry_in_days(const char *key, timestamp_t *, timestamp_t now);
 
-struct key_value_info {
-       const char *filename;
-       int linenr;
-       enum config_origin_type origin_type;
-       enum config_scope scope;
-};
-
 /**
  * First prints the error message specified by the caller in `err` and then
  * dies printing the line number and the file name of the highest priority
index 64c44db8058e0ca530519814bd5f4a3714d49695..3bb03f423a08102f837c52dcbe7a3b581104e0cb 100644 (file)
@@ -526,6 +526,8 @@ else
 endif
        X = .exe
 
+       EXTRA_PROGRAMS += headless-git$X
+
 compat/msvc.o: compat/msvc.c compat/mingw.c GIT-CFLAGS
 endif
 ifeq ($(uname_S),Interix)
@@ -705,6 +707,7 @@ ifeq ($(uname_S),MINGW)
        COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
                -fstack-protector-strong
        EXTLIBS += -lntdll
+       EXTRA_PROGRAMS += headless-git$X
        INSTALL = /bin/install
        INTERNAL_QSORT = YesPlease
        HAVE_LIBCHARSET_H = YesPlease
index 38ff86678a03a96dffa57507364a6f706ddb44d0..276593cd9dd935a283620f3b9d25b09987c04bf2 100644 (file)
@@ -546,6 +546,8 @@ fi
 # git-http-push are not built, and you cannot use http:// and https://
 # transports.
 
+if test -z "$NO_CURL"; then
+
 GIT_STASH_FLAGS($CURLDIR)
 
 AC_CHECK_LIB([curl], [curl_global_init],
@@ -554,6 +556,8 @@ AC_CHECK_LIB([curl], [curl_global_init],
 
 GIT_UNSTASH_FLAGS($CURLDIR)
 
+fi
+
 GIT_CONF_SUBST([NO_CURL])
 
 if test -z "$NO_CURL"; then
@@ -581,6 +585,8 @@ fi
 # Define NO_EXPAT if you do not have expat installed.  git-http-push is
 # not built, and you cannot push using http:// and https:// transports.
 
+if test -z "$NO_EXPAT"; then
+
 GIT_STASH_FLAGS($EXPATDIR)
 
 AC_CHECK_LIB([expat], [XML_ParserCreate],
@@ -589,6 +595,8 @@ AC_CHECK_LIB([expat], [XML_ParserCreate],
 
 GIT_UNSTASH_FLAGS($EXPATDIR)
 
+fi
+
 GIT_CONF_SUBST([NO_EXPAT])
 
 #
@@ -636,7 +644,6 @@ LIBS="$old_LIBS"
 GIT_UNSTASH_FLAGS($ICONVDIR)
 
 GIT_CONF_SUBST([NEEDS_LIBICONV])
-GIT_CONF_SUBST([NO_ICONV])
 
 if test -n "$NO_ICONV"; then
     NEEDS_LIBICONV=
@@ -644,6 +651,8 @@ fi
 
 fi
 
+GIT_CONF_SUBST([NO_ICONV])
+
 #
 # Define NO_DEFLATE_BOUND if deflateBound is missing from zlib.
 
index 3a0186280c439a12fa6564ff9965cf284fb214d3..0d77737a5363c39fd71376c0f483bc8808538754 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -12,6 +12,7 @@
 #include "url.h"
 #include "string-list.h"
 #include "oid-array.h"
+#include "path.h"
 #include "transport.h"
 #include "trace2.h"
 #include "strbuf.h"
@@ -964,7 +965,7 @@ static struct child_process *git_tcp_connect(int fd[2], char *host, int flags)
 static char *git_proxy_command;
 
 static int git_proxy_command_options(const char *var, const char *value,
-               void *cb)
+               const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "core.gitproxy")) {
                const char *for_pos;
@@ -1010,7 +1011,7 @@ static int git_proxy_command_options(const char *var, const char *value,
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static int git_use_proxy(const char *host)
index d672521da41d524f49556aefc29427b20836b8d2..8f89376dbcf30cd2cf69c3d2eaa446e47c9f4ae8 100644 (file)
@@ -1,7 +1,7 @@
 #include "git-compat-util.h"
 #include "gettext.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "run-command.h"
 #include "sigchain.h"
 #include "connected.h"
index 05f291c1f1d3d1018f390618816f94d0cd58951b..21d3d0e7dee46de8ee07ae69d9735b76643693db 100644 (file)
@@ -23,7 +23,7 @@ This is the same way as how I have been treating gitk, and to a
 lesser degree various foreign SCM interfaces, so you know the
 drill.
 
-I expect that things that start their life in the contrib/ area
+I expect things that start their life in the contrib/ area
 to graduate out of contrib/ once they mature, either by becoming
 projects on their own, or moving to the toplevel directory.  On
 the other hand, I expect I'll be proposing removal of disused
@@ -31,7 +31,7 @@ and inactive ones from time to time.
 
 If you have new things to add to this area, please first propose
 it on the git mailing list, and after a list discussion proves
-there are some general interests (it does not have to be a
+there is general interest (it does not have to be a
 list-wide consensus for a tool targeted to a relatively narrow
 audience -- for example I do not work with projects whose
 upstream is svn, so I have no use for git-svn myself, but it is
index 2f6e0197ffa489ccc14b0665cdf78dba43b39e3e..6b819e2fbdf357f8401a29b5f8daa29e43284cfe 100644 (file)
@@ -227,7 +227,7 @@ add_compile_definitions(GIT_HOST_CPU="${CMAKE_SYSTEM_PROCESSOR}")
 add_compile_definitions(SHA256_BLK INTERNAL_QSORT RUNTIME_PREFIX)
 add_compile_definitions(NO_OPENSSL SHA1_DC SHA1DC_NO_STANDARD_INCLUDES
                        SHA1DC_INIT_SAFE_HASH_DEFAULT=0
-                       SHA1DC_CUSTOM_INCLUDE_SHA1_C="cache.h"
+                       SHA1DC_CUSTOM_INCLUDE_SHA1_C="git-compat-util.h"
                        SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="git-compat-util.h" )
 list(APPEND compat_SOURCES sha1dc_git.c sha1dc/sha1.c sha1dc/ubc_check.c block-sha1/sha1.c sha256/block/sha256.c compat/qsort_s.c)
 
@@ -738,6 +738,15 @@ if(WIN32)
        else()
                message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
        endif()
+
+       add_executable(headless-git ${CMAKE_SOURCE_DIR}/compat/win32/headless.c)
+       if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
+               target_link_options(headless-git PUBLIC -municode -Wl,-subsystem,windows)
+       elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+               target_link_options(headless-git PUBLIC /NOLOGO /ENTRY:wWinMainCRTStartup /SUBSYSTEM:WINDOWS)
+       else()
+               message(FATAL_ERROR "Unhandled compiler: ${CMAKE_C_COMPILER_ID}")
+       endif()
 elseif(UNIX)
        target_link_libraries(common-main pthread rt)
 endif()
index 1a25789d28513bb5f9dc9b0a625d75fac6e89092..b2e68a16715e3987f7bb05d69cad39e6b457a30c 100644 (file)
@@ -76,7 +76,7 @@ sub createProject {
 
     my $libs_release = "\n    ";
     my $libs_debug = "\n    ";
-    if (!$static_library) {
+    if (!$static_library && $name ne 'headless-git') {
       $libs_release = join(";", sort(grep /^(?!libgit\.lib|xdiff\/lib\.lib|vcs-svn\/lib\.lib|reftable\/libreftable\.lib)/, @{$$build_structure{"$prefix${name}_LIBS"}}));
       $libs_debug = $libs_release;
       $libs_debug =~ s/zlib\.lib/zlibd\.lib/g;
@@ -230,7 +230,7 @@ EOM
     print F << "EOM";
   </ItemGroup>
 EOM
-    if (!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') {
+    if ((!$static_library || $target =~ 'vcs-svn' || $target =~ 'xdiff') && !($name =~ /headless-git/)) {
       my $uuid_libgit = $$build_structure{"LIBS_libgit_GUID"};
       my $uuid_libreftable = $$build_structure{"LIBS_reftable/libreftable_GUID"};
       my $uuid_xdiff_lib = $$build_structure{"LIBS_xdiff/lib_GUID"};
index ed6c45988a38b0f45a2b67a15cb18a221ad911c7..069be7e4befcd793430b338f930d103e41c4802a 100755 (executable)
@@ -371,6 +371,7 @@ sub handleLinkLine
 #    exit(1);
     foreach (@objfiles) {
         my $sourcefile = $_;
+        $sourcefile =~ s/^headless-git\.o$/compat\/win32\/headless.c/;
         $sourcefile =~ s/\.o$/.c/;
         push(@sources, $sourcefile);
         push(@cflags, @{$compile_options{"${sourcefile}_CFLAGS"}});
index d1daa1f62639a1bbd37e4aedf6f51c1d8d831b63..055ad0e06a70e2a23c88c1cf34782d679d42426a 100644 (file)
@@ -1,7 +1,9 @@
-This directory provides examples of Coccinelle (http://coccinelle.lip6.fr/)
-semantic patches that might be useful to developers.
+= coccinelle
 
-There are two types of semantic patches:
+This directory provides Coccinelle (http://coccinelle.lip6.fr/) semantic patches
+that might be useful to developers.
+
+==  Types of semantic patches
 
  * Using the semantic transformation to check for bad patterns in the code;
    The target 'make coccicheck' is designed to check for these patterns and
@@ -42,7 +44,7 @@ There are two types of semantic patches:
    This allows to expose plans of pending large scale refactorings without
    impacting the bad pattern checks.
 
-Git-specific tips & things to know about how we run "spatch":
+== Git-specific tips & things to know about how we run "spatch":
 
  * The "make coccicheck" will piggy-back on
    "COMPUTE_HEADER_DEPENDENCIES". If you've built a given object file
@@ -90,3 +92,33 @@ Git-specific tips & things to know about how we run "spatch":
 
    The absolute times will differ for you, but the relative speedup
    from caching should be on that order.
+
+== Authoring and reviewing coccinelle changes
+
+* When a .cocci is made, both the Git changes and .cocci file should be
+  reviewed. When reviewing such a change, do your best to understand the .cocci
+  changes (e.g. by asking the author to explain the change) and be explicit
+  about your understanding of the changes. This helps us decide whether input
+  from coccinelle experts is needed or not. If you aren't sure of the cocci
+  changes, indicate what changes you actively endorse and leave an Acked-by
+  (instead of Reviewed-by).
+
+* Authors should consider that reviewers may not be coccinelle experts, thus the
+  the .cocci changes may not be self-evident. A plain text description of the
+  changes is strongly encouraged, especially when using more esoteric features
+  of the language.
+
+* .cocci rules should target only the problem it is trying to solve; "collateral
+  damage" is not allowed. Reviewers should look out and flag overly-broad rules.
+
+* Consider the cost-benefit ratio of .cocci changes. In particular, consider the
+  effect on the runtime of "make coccicheck", and how often your .cocci check
+  will catch something valuable. As a rule of thumb, rules that can bail early
+  if a file doesn't have a particular token will have a small impact on runtime,
+  and vice-versa.
+
+* .cocci files used for refactoring should be temporarily kept in-tree to aid
+  the refactoring of out-of-tree code (e.g. in-flight topics). Periodically
+  evaluate the cost-benefit ratio to determine when the file should be removed.
+  For example, consider how many out-of-tree users are left and how much this
+  slows down "make coccicheck".
diff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/contrib/coccinelle/config_fn_ctx.pending.cocci
new file mode 100644 (file)
index 0000000..6d3d100
--- /dev/null
@@ -0,0 +1,144 @@
+@ get_fn @
+identifier fn, R;
+@@
+(
+(
+git_config_from_file
+|
+git_config_from_file_with_options
+|
+git_config_from_mem
+|
+git_config_from_blob_oid
+|
+read_early_config
+|
+read_very_early_config
+|
+config_with_options
+|
+git_config
+|
+git_protected_config
+|
+config_from_gitmodules
+)
+  (fn, ...)
+|
+repo_config(R, fn, ...)
+)
+
+@ extends get_fn @
+identifier C1, C2, D;
+@@
+int fn(const char *C1, const char *C2,
++ const struct config_context *ctx,
+  void *D);
+
+@ extends get_fn @
+@@
+int fn(const char *, const char *,
++ const struct config_context *,
+  void *);
+
+@ extends get_fn @
+// Don't change fns that look like callback fns but aren't
+identifier fn2 != tar_filter_config && != git_diff_heuristic_config &&
+  != git_default_submodule_config && != git_color_config &&
+  != bundle_list_update && != parse_object_filter_config;
+identifier C1, C2, D1, D2, S;
+attribute name UNUSED;
+@@
+int fn(const char *C1, const char *C2,
++ const struct config_context *ctx,
+  void *D1) {
+<+...
+(
+fn2(C1, C2
++ , ctx
+, D2);
+|
+if(fn2(C1, C2
++ , ctx
+, D2) < 0) { ... }
+|
+return fn2(C1, C2
++ , ctx
+, D2);
+|
+S = fn2(C1, C2
++ , ctx
+, D2);
+)
+...+>
+  }
+
+@ extends get_fn@
+identifier C1, C2, D;
+attribute name UNUSED;
+@@
+int fn(const char *C1, const char *C2,
++ const struct config_context *ctx UNUSED,
+  void *D) {...}
+
+
+// The previous rules don't catch all callbacks, especially if they're defined
+// in a separate file from the git_config() call. Fix these manually.
+@@
+identifier C1, C2, D;
+attribute name UNUSED;
+@@
+int
+(
+git_ident_config
+|
+urlmatch_collect_fn
+|
+write_one_config
+|
+forbid_remote_url
+|
+credential_config_callback
+)
+  (const char *C1, const char *C2,
++ const struct config_context *ctx UNUSED,
+  void *D) {...}
+
+@@
+identifier C1, C2, D, D2, S, fn2;
+@@
+int
+(
+http_options
+|
+git_status_config
+|
+git_commit_config
+|
+git_default_core_config
+|
+grep_config
+)
+  (const char *C1, const char *C2,
++ const struct config_context *ctx,
+  void *D) {
+<+...
+(
+fn2(C1, C2
++ , ctx
+, D2);
+|
+if(fn2(C1, C2
++ , ctx
+, D2) < 0) { ... }
+|
+return fn2(C1, C2
++ , ctx
+, D2);
+|
+S = fn2(C1, C2
++ , ctx
+, D2);
+)
+...+>
+  }
diff --git a/contrib/coccinelle/git_config_number.cocci b/contrib/coccinelle/git_config_number.cocci
new file mode 100644 (file)
index 0000000..7b57dce
--- /dev/null
@@ -0,0 +1,27 @@
+@@
+identifier C1, C2, C3;
+@@
+(
+(
+git_config_int
+|
+git_config_int64
+|
+git_config_ulong
+|
+git_config_ssize_t
+)
+  (C1, C2
++ , ctx->kvi
+  )
+|
+(
+git_configset_get_value
+|
+git_config_bool_or_int
+)
+  (C1, C2
++ , ctx->kvi
+ , C3
+  )
+)
index dc95c34cc853557efd2a59a33825f834e8d934cf..13a39ebd2e73f9b34de743b797577a5e8e98cbae 100644 (file)
@@ -28,6 +28,8 @@
 # completion style.  For example '!f() { : git commit ; ... }; f' will
 # tell the completion to use commit completion.  This also works with aliases
 # of form "!sh -c '...'".  For example, "!sh -c ': git commit ; ... '".
+# Note that "git" is optional --- '!f() { : commit; ...}; f' would complete
+# just like the 'git commit' command.
 #
 # If you have a command that is not part of git, but you would still
 # like completion, you can use __git_complete:
@@ -767,7 +769,7 @@ __git_refs ()
                        track=""
                        ;;
                *)
-                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
+                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD REVERT_HEAD BISECT_HEAD AUTO_MERGE; do
                                case "$i" in
                                $match*|$umatch*)
                                        if [ -e "$dir/$i" ]; then
@@ -1182,7 +1184,7 @@ __git_aliased_command ()
                        :)      : skip null command ;;
                        \'*)    : skip opening quote after sh -c ;;
                        *)
-                               cur="$word"
+                               cur="${word%;}"
                                break
                        esac
                done
@@ -1607,7 +1609,7 @@ _git_checkout ()
 
                if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
                        __git_complete_refs --mode="refs"
-               elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+               elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
                        __git_complete_refs --mode="remote-heads"
                else
                        __git_complete_refs $dwim_opt --mode="refs"
@@ -1677,6 +1679,11 @@ _git_clone ()
 
 __git_untracked_file_modes="all no normal"
 
+__git_trailer_tokens ()
+{
+       __git config --name-only --get-regexp '^trailer\..*\.key$' | cut -d. -f 2- | rev | cut -d. -f2- | rev
+}
+
 _git_commit ()
 {
        case "$prev" in
@@ -1701,6 +1708,10 @@ _git_commit ()
                __gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
                return
                ;;
+       --trailer=*)
+               __gitcomp_nl "$(__git_trailer_tokens)" "" "${cur##--trailer=}" ":"
+               return
+               ;;
        --*)
                __gitcomp_builtin commit
                return
@@ -1733,32 +1744,44 @@ __git_color_moved_opts="no default plain blocks zebra dimmed-zebra"
 __git_color_moved_ws_opts="no ignore-space-at-eol ignore-space-change
                        ignore-all-space allow-indentation-change"
 
+__git_ws_error_highlight_opts="context old new all default"
+
+# Options for the diff machinery (diff, log, show, stash, range-diff, ...)
 __git_diff_common_options="--stat --numstat --shortstat --summary
                        --patch-with-stat --name-only --name-status --color
                        --no-color --color-words --no-renames --check
                        --color-moved --color-moved= --no-color-moved
                        --color-moved-ws= --no-color-moved-ws
                        --full-index --binary --abbrev --diff-filter=
+                       --find-copies --find-object --find-renames
+                       --no-relative --relative
                        --find-copies-harder --ignore-cr-at-eol
                        --text --ignore-space-at-eol --ignore-space-change
                        --ignore-all-space --ignore-blank-lines --exit-code
-                       --quiet --ext-diff --no-ext-diff
+                       --quiet --ext-diff --no-ext-diff --unified=
                        --no-prefix --src-prefix= --dst-prefix=
-                       --inter-hunk-context=
+                       --inter-hunk-context= --function-context
                        --patience --histogram --minimal
                        --raw --word-diff --word-diff-regex=
                        --dirstat --dirstat= --dirstat-by-file
                        --dirstat-by-file= --cumulative
-                       --diff-algorithm=
+                       --diff-algorithm= --default-prefix
                        --submodule --submodule= --ignore-submodules
                        --indent-heuristic --no-indent-heuristic
-                       --textconv --no-textconv
-                       --patch --no-patch
-                       --anchored=
+                       --textconv --no-textconv --break-rewrites
+                       --patch --no-patch --cc --combined-all-paths
+                       --anchored= --compact-summary --ignore-matching-lines=
+                       --irreversible-delete --line-prefix --no-stat
+                       --output= --output-indicator-context=
+                       --output-indicator-new= --output-indicator-old=
+                       --ws-error-highlight=
+                       --pickaxe-all --pickaxe-regex
 "
 
-__git_diff_difftool_options="--cached --staged --pickaxe-all --pickaxe-regex
-                       --base --ours --theirs --no-index --relative --merge-base
+# Options for diff/difftool
+__git_diff_difftool_options="--cached --staged
+                       --base --ours --theirs --no-index --merge-base
+                       --ita-invisible-in-index --ita-visible-in-index
                        $__git_diff_common_options"
 
 _git_diff ()
@@ -1782,6 +1805,10 @@ _git_diff ()
                __gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
                return
                ;;
+       --ws-error-highlight=*)
+               __gitcomp "$__git_ws_error_highlight_opts" "" "${cur##--ws-error-highlight=}"
+               return
+               ;;
        --*)
                __gitcomp "$__git_diff_difftool_options"
                return
@@ -2024,6 +2051,12 @@ __git_log_shortlog_options="
        --author= --committer= --grep=
        --all-match --invert-grep
 "
+# Options accepted by log and show
+__git_log_show_options="
+       --diff-merges --diff-merges= --no-diff-merges --dd --remerge-diff
+"
+
+__git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-combined cc remerge r"
 
 __git_log_pretty_formats="oneline short medium full fuller reference email raw format: tformat: mboxrd"
 __git_log_date_formats="relative iso8601 iso8601-strict rfc2822 short local default human raw unix auto: format:"
@@ -2072,15 +2105,24 @@ _git_log ()
                __gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
                return
                ;;
+       --ws-error-highlight=*)
+               __gitcomp "$__git_ws_error_highlight_opts" "" "${cur##--ws-error-highlight=}"
+               return
+               ;;
        --no-walk=*)
                __gitcomp "sorted unsorted" "" "${cur##--no-walk=}"
                return
                ;;
+       --diff-merges=*)
+                __gitcomp "$__git_diff_merges_opts" "" "${cur##--diff-merges=}"
+                return
+                ;;
        --*)
                __gitcomp "
                        $__git_log_common_options
                        $__git_log_shortlog_options
                        $__git_log_gitk_options
+                       $__git_log_show_options
                        --root --topo-order --date-order --reverse
                        --follow --full-diff
                        --abbrev-commit --no-abbrev-commit --abbrev=
@@ -2097,7 +2139,6 @@ _git_log ()
                        --expand-tabs --expand-tabs= --no-expand-tabs
                        $merge
                        $__git_diff_common_options
-                       --pickaxe-all --pickaxe-regex
                        "
                return
                ;;
@@ -2484,7 +2525,7 @@ _git_switch ()
 
                if [ -n "$(__git_find_on_cmdline "-c -C -d --detach")" ]; then
                        __git_complete_refs --mode="refs"
-               elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+               elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
                        __git_complete_refs --mode="remote-heads"
                else
                        __git_complete_refs $dwim_opt --mode="heads"
@@ -2992,10 +3033,19 @@ _git_show ()
                __gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
                return
                ;;
+       --ws-error-highlight=*)
+               __gitcomp "$__git_ws_error_highlight_opts" "" "${cur##--ws-error-highlight=}"
+               return
+               ;;
+       --diff-merges=*)
+                __gitcomp "$__git_diff_merges_opts" "" "${cur##--diff-merges=}"
+                return
+                ;;
        --*)
                __gitcomp "--pretty= --format= --abbrev-commit --no-abbrev-commit
                        --oneline --show-signature
                        --expand-tabs --expand-tabs= --no-expand-tabs
+                       $__git_log_show_options
                        $__git_diff_common_options
                        "
                return
index ef681f29d5ba12dd5c6f7f11baa42cb1e6aab7d5..215a81d8bae59ca2364eb762c72089ff8b6b51d7 100644 (file)
@@ -39,6 +39,8 @@ struct credential {
        char *path;
        char *username;
        char *password;
+       char *password_expiry_utc;
+       char *oauth_refresh_token;
 };
 
 #define CREDENTIAL_INIT { 0 }
@@ -52,8 +54,29 @@ struct credential_operation {
 
 #define CREDENTIAL_OP_END { NULL, NULL }
 
+static void credential_clear(struct credential *c);
+
 /* ----------------- Secret Service functions ----------------- */
 
+static const SecretSchema schema = {
+       "org.git.Password",
+       /* Ignore schema name during search for backwards compatibility */
+       SECRET_SCHEMA_DONT_MATCH_NAME,
+       {
+               /*
+                * libsecret assumes attribute values are non-confidential and
+                * unchanging, so we can't include oauth_refresh_token or
+                * password_expiry_utc.
+                */
+               {  "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
+               {  "object", SECRET_SCHEMA_ATTRIBUTE_STRING },
+               {  "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING },
+               {  "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+               {  "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
+               {  NULL, 0 },
+       }
+};
+
 static char *make_label(struct credential *c)
 {
        if (c->port)
@@ -101,7 +124,7 @@ static int keyring_get(struct credential *c)
 
        attributes = make_attr_list(c);
        items = secret_service_search_sync(service,
-                                          SECRET_SCHEMA_COMPAT_NETWORK,
+                                          &schema,
                                           attributes,
                                           SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
                                           NULL,
@@ -117,6 +140,7 @@ static int keyring_get(struct credential *c)
                SecretItem *item;
                SecretValue *secret;
                const char *s;
+               gchar **parts;
 
                item = items->data;
                secret = secret_item_get_secret(item);
@@ -130,8 +154,27 @@ static int keyring_get(struct credential *c)
 
                s = secret_value_get_text(secret);
                if (s) {
-                       g_free(c->password);
-                       c->password = g_strdup(s);
+                       /*
+                        * Passwords and other attributes encoded in following format:
+                        *   hunter2
+                        *   password_expiry_utc=1684189401
+                        *   oauth_refresh_token=xyzzy
+                        */
+                       parts = g_strsplit(s, "\n", 0);
+                       if (g_strv_length(parts) >= 1) {
+                               g_free(c->password);
+                               c->password = g_strdup(parts[0]);
+                       }
+                       for (int i = 1; i < g_strv_length(parts); i++) {
+                               if (g_str_has_prefix(parts[i], "password_expiry_utc=")) {
+                                       g_free(c->password_expiry_utc);
+                                       c->password_expiry_utc = g_strdup(&parts[i][20]);
+                               } else if (g_str_has_prefix(parts[i], "oauth_refresh_token=")) {
+                                       g_free(c->oauth_refresh_token);
+                                       c->oauth_refresh_token = g_strdup(&parts[i][20]);
+                               }
+                       }
+                       g_strfreev(parts);
                }
 
                g_hash_table_unref(attributes);
@@ -148,6 +191,7 @@ static int keyring_store(struct credential *c)
        char *label = NULL;
        GHashTable *attributes = NULL;
        GError *error = NULL;
+       GString *secret = NULL;
 
        /*
         * Sanity check that what we are storing is actually sensible.
@@ -162,13 +206,23 @@ static int keyring_store(struct credential *c)
 
        label = make_label(c);
        attributes = make_attr_list(c);
-       secret_password_storev_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+       secret = g_string_new(c->password);
+       if (c->password_expiry_utc) {
+               g_string_append_printf(secret, "\npassword_expiry_utc=%s",
+                       c->password_expiry_utc);
+       }
+       if (c->oauth_refresh_token) {
+               g_string_append_printf(secret, "\noauth_refresh_token=%s",
+                       c->oauth_refresh_token);
+       }
+       secret_password_storev_sync(&schema,
                                    attributes,
                                    NULL,
                                    label,
-                                   c->password,
+                                   secret->str,
                                    NULL,
                                    &error);
+       g_string_free(secret, TRUE);
        g_free(label);
        g_hash_table_unref(attributes);
 
@@ -185,6 +239,7 @@ static int keyring_erase(struct credential *c)
 {
        GHashTable *attributes = NULL;
        GError *error = NULL;
+       struct credential existing = CREDENTIAL_INIT;
 
        /*
         * Sanity check that we actually have something to match
@@ -197,8 +252,22 @@ static int keyring_erase(struct credential *c)
        if (!c->protocol && !c->host && !c->path && !c->username)
                return EXIT_FAILURE;
 
+       if (c->password) {
+               existing.host = g_strdup(c->host);
+               existing.path = g_strdup(c->path);
+               existing.port = c->port;
+               existing.protocol = g_strdup(c->protocol);
+               existing.username = g_strdup(c->username);
+               keyring_get(&existing);
+               if (existing.password && strcmp(c->password, existing.password)) {
+                       credential_clear(&existing);
+                       return EXIT_SUCCESS;
+               }
+               credential_clear(&existing);
+       }
+
        attributes = make_attr_list(c);
-       secret_password_clearv_sync(SECRET_SCHEMA_COMPAT_NETWORK,
+       secret_password_clearv_sync(&schema,
                                    attributes,
                                    NULL,
                                    &error);
@@ -238,6 +307,8 @@ static void credential_clear(struct credential *c)
        g_free(c->path);
        g_free(c->username);
        g_free(c->password);
+       g_free(c->password_expiry_utc);
+       g_free(c->oauth_refresh_token);
 
        credential_init(c);
 }
@@ -284,11 +355,19 @@ static int credential_read(struct credential *c)
                } else if (!strcmp(key, "username")) {
                        g_free(c->username);
                        c->username = g_strdup(value);
+               } else if (!strcmp(key, "password_expiry_utc")) {
+                       g_free(c->password_expiry_utc);
+                       c->password_expiry_utc = g_strdup(value);
                } else if (!strcmp(key, "password")) {
                        g_free(c->password);
                        c->password = g_strdup(value);
                        while (*value)
                                *value++ = '\0';
+               } else if (!strcmp(key, "oauth_refresh_token")) {
+                       g_free(c->oauth_refresh_token);
+                       c->oauth_refresh_token = g_strdup(value);
+                       while (*value)
+                               *value++ = '\0';
                }
                /*
                 * Ignore other lines; we don't know what they mean, but
@@ -314,6 +393,10 @@ static void credential_write(const struct credential *c)
        /* only write username/password, if set */
        credential_write_item(stdout, "username", c->username);
        credential_write_item(stdout, "password", c->password);
+       credential_write_item(stdout, "password_expiry_utc",
+               c->password_expiry_utc);
+       credential_write_item(stdout, "oauth_refresh_token",
+               c->oauth_refresh_token);
 }
 
 static void usage(const char *name)
index 96f10613aee29b7c360b25308927564df1551388..4cd56c42e24469a48a40e7b02de4b4921ff8662c 100644 (file)
@@ -109,7 +109,18 @@ static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
        return match_part_with_last(ptarget, want, delim, 1);
 }
 
-static int match_cred(const CREDENTIALW *cred)
+static int match_cred_password(const CREDENTIALW *cred) {
+       int ret;
+       WCHAR *cred_password = xmalloc(cred->CredentialBlobSize);
+       wcsncpy_s(cred_password, cred->CredentialBlobSize,
+               (LPCWSTR)cred->CredentialBlob,
+               cred->CredentialBlobSize / sizeof(WCHAR));
+       ret = !wcscmp(cred_password, password);
+       free(cred_password);
+       return ret;
+}
+
+static int match_cred(const CREDENTIALW *cred, int match_password)
 {
        LPCWSTR target = cred->TargetName;
        if (wusername && wcscmp(wusername, cred->UserName ? cred->UserName : L""))
@@ -119,7 +130,8 @@ static int match_cred(const CREDENTIALW *cred)
                match_part(&target, protocol, L"://") &&
                match_part_last(&target, wusername, L"@") &&
                match_part(&target, host, L"/") &&
-               match_part(&target, path, L"");
+               match_part(&target, path, L"") &&
+               (!match_password || match_cred_password(cred));
 }
 
 static void get_credential(void)
@@ -134,7 +146,7 @@ static void get_credential(void)
 
        /* search for the first credential that matches username */
        for (i = 0; i < num_creds; ++i)
-               if (match_cred(creds[i])) {
+               if (match_cred(creds[i], 0)) {
                        write_item("username", creds[i]->UserName,
                                creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
                        write_item("password",
@@ -196,7 +208,7 @@ static void erase_credential(void)
                return;
 
        for (i = 0; i < num_creds; ++i) {
-               if (match_cred(creds[i]))
+               if (match_cred(creds[i], password != NULL))
                        CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);
        }
 
index 40c4b0d111071676c278651f49669036e90f079a..47e0c557e63f1b236a3ad763e03ac086f1842d23 100755 (executable)
@@ -9,7 +9,7 @@ The <mode> parameter is one of:
 
 diff: elements are diff hunks. Arguments are given to diff.
 
-merge: elements are merge conflicts. Arguments are ignored.
+merge: elements are merge conflicts. Arguments are given to ls-files -u.
 
 grep: elements are grep hits. Arguments are given to git grep or, if
       configured, to the command in `jump.grepCmd`.
index 7db4c45676d304869bba126bd57e7f553aec2008..e0c5d3b0de63483113edbcc09003e70aaa0a3d2d 100755 (executable)
@@ -33,19 +33,19 @@ git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
 git subtree push  --prefix=<prefix> <repository> <refspec>
 --
-h,help        show the help
-q,quiet       quiet
-d,debug       show debug messages
+h,help!       show the help
+q,quiet!      quiet
+d,debug!      show debug messages
 P,prefix=     the name of the subdir to split out
  options for 'split' (also: 'push')
 annotate=     add a prefix to commit message of new commits
-b,branch    create a new branch from the split subtree
+b,branch!=    create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
  options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
 squash        merge subtree changes as a single commit
-m,message   use the given message as the commit message for the merge commit
+m,message!=   use the given message as the commit message for the merge commit
 "
 
 indent=0
index 341c169eca7e6c0f02ac43f0e1844605abddf24d..49a21dd7c9c553f80a905ca8333b93fbe05fcc67 100755 (executable)
@@ -71,7 +71,7 @@ test_expect_success 'shows short help text for -h' '
        test_expect_code 129 git subtree -h >out 2>err &&
        test_must_be_empty err &&
        grep -e "^ *or: git subtree pull" out &&
-       grep -e --annotate out
+       grep -F -e "--[no-]annotate" out
 '
 
 #
index 9ee79fe4699ef1c4cc1d070f82153aaf8b17aa88..a8870baff36a4a3042baf31c730793b45f6b6442 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1,21 +1,21 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "advice.h"
 #include "config.h"
 #include "convert.h"
 #include "copy.h"
 #include "gettext.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "attr.h"
 #include "run-command.h"
 #include "quote.h"
+#include "read-cache-ll.h"
 #include "sigchain.h"
 #include "pkt-line.h"
 #include "sub-process.h"
 #include "trace.h"
 #include "utf8.h"
-#include "ll-merge.h"
-#include "wrapper.h"
+#include "merge-ll.h"
 
 /*
  * convert.c - convert a file when checking it out and checking it in.
@@ -633,23 +633,21 @@ static int filter_buffer_or_fd(int in UNUSED, int out, void *data)
         */
        struct child_process child_process = CHILD_PROCESS_INIT;
        struct filter_params *params = (struct filter_params *)data;
+       const char *format = params->cmd;
        int write_err, status;
 
        /* apply % substitution to cmd */
        struct strbuf cmd = STRBUF_INIT;
-       struct strbuf path = STRBUF_INIT;
-       struct strbuf_expand_dict_entry dict[] = {
-               { "f", NULL, },
-               { NULL, NULL, },
-       };
-
-       /* quote the path to preserve spaces, etc. */
-       sq_quote_buf(&path, params->path);
-       dict[0].value = path.buf;
 
-       /* expand all %f with the quoted path */
-       strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
-       strbuf_release(&path);
+       /* expand all %f with the quoted path; quote to preserve space, etc. */
+       while (strbuf_expand_step(&cmd, &format)) {
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(&cmd, '%');
+               else if (skip_prefix(format, "f", &format))
+                       sq_quote_buf(&cmd, params->path);
+               else
+                       strbuf_addch(&cmd, '%');
+       }
 
        strvec_push(&child_process.args, cmd.buf);
        child_process.use_shell = 1;
@@ -1015,7 +1013,9 @@ 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 UNUSED)
+static int read_convert_config(const char *var, const char *value,
+                              const struct config_context *ctx UNUSED,
+                              void *cb UNUSED)
 {
        const char *key, *name;
        size_t namelen;
diff --git a/copy.c b/copy.c
index 882c79cffb0d38434dde66a307b32b460440f875..23d84c6c1db554bcc7a33804d58821dfb3fb7634 100644 (file)
--- a/copy.c
+++ b/copy.c
@@ -1,7 +1,6 @@
 #include "git-compat-util.h"
 #include "copy.h"
 #include "path.h"
-#include "wrapper.h"
 
 int copy_fd(int ifd, int ofd)
 {
index 023b59d5711cf2fede0aa0408b47a1a6f64df059..18098bd35ebab9683ae0046c1712b111eaeb3fe1 100644 (file)
@@ -33,13 +33,14 @@ void credential_clear(struct credential *c)
 }
 
 int credential_match(const struct credential *want,
-                    const struct credential *have)
+                    const struct credential *have, int match_password)
 {
 #define CHECK(x) (!want->x || (have->x && !strcmp(want->x, have->x)))
        return CHECK(protocol) &&
               CHECK(host) &&
               CHECK(path) &&
-              CHECK(username);
+              CHECK(username) &&
+              (!match_password || CHECK(password));
 #undef CHECK
 }
 
@@ -48,6 +49,7 @@ static int credential_from_potentially_partial_url(struct credential *c,
                                                   const char *url);
 
 static int credential_config_callback(const char *var, const char *value,
+                                     const struct config_context *ctx UNUSED,
                                      void *data)
 {
        struct credential *c = data;
@@ -86,8 +88,8 @@ static int proto_is_http(const char *s)
 static void credential_describe(struct credential *c, struct strbuf *out);
 static void credential_format(struct credential *c, struct strbuf *out);
 
-static int select_all(const struct urlmatch_item *a,
-                     const struct urlmatch_item *b)
+static int select_all(const struct urlmatch_item *a UNUSED,
+                     const struct urlmatch_item *b UNUSED)
 {
        return 0;
 }
@@ -102,7 +104,7 @@ static int match_partial_url(const char *url, void *cb)
                warning(_("skipping credential lookup for key: credential.%s"),
                        url);
        else
-               matches = credential_match(&want, c);
+               matches = credential_match(&want, c, 0);
        credential_clear(&want);
 
        return matches;
index b8e2936d1dcb978d67fb6660c6ee288d9a26dfc5..acc41adf5481a21148a6b4797f9a8267feb5d8b6 100644 (file)
@@ -211,6 +211,6 @@ void credential_from_url(struct credential *, const char *url);
 int credential_from_url_gently(struct credential *, const char *url, int quiet);
 
 int credential_match(const struct credential *want,
-                    const struct credential *have);
+                    const struct credential *have, int match_password);
 
 #endif /* CREDENTIAL_H */
index daf9b06dfff60efb47a603c4e8aa410848933e56..870748e01695f865e1e4d587cdb38f769367a5c6 100644 (file)
@@ -11,7 +11,6 @@
 #include "progress.h"
 #include "csum-file.h"
 #include "hash.h"
-#include "wrapper.h"
 
 static void verify_buffer_or_die(struct hashfile *f,
                                 const void *buf,
@@ -208,7 +207,7 @@ int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint
            lseek(f->fd, offset, SEEK_SET) != offset)
                return -1;
        f->total = offset;
-       f->ctx = checkpoint->ctx;
+       the_hash_algo->clone_fn(&f->ctx, &checkpoint->ctx);
        f->offset = 0; /* hashflush() was called in checkpoint */
        return 0;
 }
diff --git a/ctype.c b/ctype.c
index fc0225cebd1a4b43654772270826e06fd941a128..345174555077984f695dba702593e08fbed95031 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -28,39 +28,3 @@ const unsigned char sane_ctype[256] = {
        A, A, A, A, A, A, A, A, A, A, A, R, R, U, P, X,         /* 112..127 */
        /* Nothing in the 128.. range */
 };
-
-/* For case-insensitive kwset */
-const unsigned char tolower_trans_tbl[256] = {
-       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-        ' ',  '!',  '"',  '#',  '$',  '%',  '&', 0x27,
-        '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
-        '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
-        '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
-        '@',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
-        'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
-        'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
-        'x',  'y',  'z',  '[', 0x5c,  ']',  '^',  '_',
-        '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
-        'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
-        'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
-        'x',  'y',  'z',  '{',  '|',  '}',  '~', 0x7f,
-       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
-       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
-       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
-       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
-       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
-       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
-       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
-       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
-       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
-       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-};
index 7139cc201d7560967352c701ed258c859567c26d..17d331b2f38465e295c019e534eff371ef3e6e49 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "path.h"
@@ -10,7 +9,6 @@
 #include "setup.h"
 #include "strbuf.h"
 #include "string-list.h"
-#include "wrapper.h"
 
 #ifdef NO_INITGROUPS
 #define initgroups(x, y) (0) /* nothing */
@@ -144,42 +142,6 @@ static void NORETURN daemon_die(const char *err, va_list params)
        exit(1);
 }
 
-struct expand_path_context {
-       const char *directory;
-       struct hostinfo *hostinfo;
-};
-
-static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
-{
-       struct expand_path_context *context = ctx;
-       struct hostinfo *hi = context->hostinfo;
-
-       switch (placeholder[0]) {
-       case 'H':
-               strbuf_addbuf(sb, &hi->hostname);
-               return 1;
-       case 'C':
-               if (placeholder[1] == 'H') {
-                       strbuf_addstr(sb, get_canon_hostname(hi));
-                       return 2;
-               }
-               break;
-       case 'I':
-               if (placeholder[1] == 'P') {
-                       strbuf_addstr(sb, get_ip_address(hi));
-                       return 2;
-               }
-               break;
-       case 'P':
-               strbuf_addbuf(sb, &hi->tcp_port);
-               return 1;
-       case 'D':
-               strbuf_addstr(sb, context->directory);
-               return 1;
-       }
-       return 0;
-}
-
 static const char *path_ok(const char *directory, struct hostinfo *hi)
 {
        static char rpath[PATH_MAX];
@@ -223,10 +185,7 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
        }
        else if (interpolated_path && hi->saw_extended_args) {
                struct strbuf expanded_path = STRBUF_INIT;
-               struct expand_path_context context;
-
-               context.directory = directory;
-               context.hostinfo = hi;
+               const char *format = interpolated_path;
 
                if (*dir != '/') {
                        /* Allow only absolute */
@@ -234,8 +193,24 @@ static const char *path_ok(const char *directory, struct hostinfo *hi)
                        return NULL;
                }
 
-               strbuf_expand(&expanded_path, interpolated_path,
-                             expand_path, &context);
+               while (strbuf_expand_step(&expanded_path, &format)) {
+                       if (skip_prefix(format, "%", &format))
+                               strbuf_addch(&expanded_path, '%');
+                       else if (skip_prefix(format, "H", &format))
+                               strbuf_addbuf(&expanded_path, &hi->hostname);
+                       else if (skip_prefix(format, "CH", &format))
+                               strbuf_addstr(&expanded_path,
+                                             get_canon_hostname(hi));
+                       else if (skip_prefix(format, "IP", &format))
+                               strbuf_addstr(&expanded_path,
+                                             get_ip_address(hi));
+                       else if (skip_prefix(format, "P", &format))
+                               strbuf_addbuf(&expanded_path, &hi->tcp_port);
+                       else if (skip_prefix(format, "D", &format))
+                               strbuf_addstr(&expanded_path, directory);
+                       else
+                               strbuf_addch(&expanded_path, '%');
+               }
 
                rlen = strlcpy(interp_path, expanded_path.buf,
                               sizeof(interp_path));
@@ -1268,19 +1243,20 @@ static int serve(struct string_list *listen_addr, int listen_port,
 int cmd_main(int argc, const char **argv)
 {
        int listen_port = 0;
-       struct string_list listen_addr = STRING_LIST_INIT_NODUP;
+       struct string_list listen_addr = STRING_LIST_INIT_DUP;
        int serve_mode = 0, inetd_mode = 0;
        const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
        int detach = 0;
        struct credentials *cred = NULL;
        int i;
+       int ret;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                const char *v;
 
                if (skip_prefix(arg, "--listen=", &v)) {
-                       string_list_append(&listen_addr, xstrdup_tolower(v));
+                       string_list_append_nodup(&listen_addr, xstrdup_tolower(v));
                        continue;
                }
                if (skip_prefix(arg, "--port=", &v)) {
@@ -1462,22 +1438,26 @@ int cmd_main(int argc, const char **argv)
                        die_errno("failed to redirect stderr to /dev/null");
        }
 
-       if (inetd_mode || serve_mode)
-               return execute();
+       if (inetd_mode || serve_mode) {
+               ret = execute();
+       } else {
+               if (detach) {
+                       if (daemonize())
+                               die("--detach not supported on this platform");
+               }
 
-       if (detach) {
-               if (daemonize())
-                       die("--detach not supported on this platform");
-       }
+               if (pid_file)
+                       write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
 
-       if (pid_file)
-               write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
+               /* prepare argv for serving-processes */
+               strvec_push(&cld_argv, argv[0]); /* git-daemon */
+               strvec_push(&cld_argv, "--serve");
+               for (i = 1; i < argc; ++i)
+                       strvec_push(&cld_argv, argv[i]);
 
-       /* prepare argv for serving-processes */
-       strvec_push(&cld_argv, argv[0]); /* git-daemon */
-       strvec_push(&cld_argv, "--serve");
-       for (i = 1; i < argc; ++i)
-               strvec_push(&cld_argv, argv[i]);
+               ret = serve(&listen_addr, listen_port, cred);
+       }
 
-       return serve(&listen_addr, listen_port, cred);
+       string_list_clear(&listen_addr, 0);
+       return ret;
 }
index 71e79daa8259684f836f0addade83d644af91601..69aeb142b45e9fee08d61dace73f6dc2bce1c2d0 100644 (file)
@@ -3,7 +3,6 @@
  * data.
  */
 #include "git-compat-util.h"
-#include "hashmap.h"
 #include "object.h"
 #include "decorate.h"
 
@@ -82,3 +81,18 @@ void *lookup_decoration(struct decoration *n, const struct object *obj)
                        j = 0;
        }
 }
+
+void clear_decoration(struct decoration *n, void (*free_cb)(void *))
+{
+       if (free_cb) {
+               unsigned int i;
+               for (i = 0; i < n->size; i++) {
+                       void *d = n->entries[i].decoration;
+                       if (d)
+                               free_cb(d);
+               }
+       }
+
+       FREE_AND_NULL(n->entries);
+       n->size = n->nr = 0;
+}
index ee43dee1f008882094ca9c85f6b28b86ec88fdf6..cdeb17c9df2eb680d85e73e8ed2f48b52f44569f 100644 (file)
@@ -58,4 +58,14 @@ void *add_decoration(struct decoration *n, const struct object *obj, void *decor
  */
 void *lookup_decoration(struct decoration *n, const struct object *obj);
 
+/*
+ * Clear all decoration entries, releasing any memory used by the structure.
+ * If free_cb is not NULL, it is called for every decoration value currently
+ * stored.
+ *
+ * After clearing, the decoration struct can be used again. The "name" field is
+ * retained.
+ */
+void clear_decoration(struct decoration *n, void (*free_cb)(void *));
+
 #endif
index c824a5f6a42e56c04a46c8189d4fc1675fd172ea..5de5759f3f13da13465ec6c9bfa6abeb44ceaee3 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "attr.h"
 #include "object.h"
 #include "blob.h"
@@ -341,7 +340,9 @@ static void free_remote_islands(kh_str_t *remote_islands)
        kh_destroy_str(remote_islands);
 }
 
-static int island_config_callback(const char *k, const char *v, void *cb)
+static int island_config_callback(const char *k, const char *v,
+                                 const struct config_context *ctx UNUSED,
+                                 void *cb)
 {
        struct island_load_data *ild = cb;
 
index c8c7ebcfa392f674286a39a5d37a1bba292d10a3..4d096c857f1e669a44bc2e43375889ce2952083c 100644 (file)
@@ -7,7 +7,7 @@
 #include "gettext.h"
 #include "hex.h"
 #include "strvec.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
 #include "parse-options.h"
 #include "write-or-die.h"
@@ -71,42 +71,6 @@ static int dir_file_stats(struct object_directory *object_dir, void *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);
@@ -117,7 +81,7 @@ static int count_files(struct strbuf *path)
                return 0;
 
        while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
-               if (get_dtype(e, path) == DT_REG)
+               if (get_dtype(e, path, 0) == DT_REG)
                        count++;
 
        closedir(dir);
@@ -146,7 +110,7 @@ static void loose_objs_stats(struct strbuf *buf, const char *path)
        base_path_len = count_path.len;
 
        while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
-               if (get_dtype(e, &count_path) == DT_DIR &&
+               if (get_dtype(e, &count_path, 0) == DT_DIR &&
                    strlen(e->d_name) == 2 &&
                    !hex_to_bytes(&c, e->d_name, 1)) {
                        strbuf_setlen(&count_path, base_path_len);
@@ -191,7 +155,7 @@ static int add_directory_to_archiver(struct strvec *archiver_args,
 
                strbuf_add_absolute_path(&abspath, at_root ? "." : path);
                strbuf_addch(&abspath, '/');
-               dtype = get_dtype(e, &abspath);
+               dtype = get_dtype(e, &abspath, 0);
 
                strbuf_setlen(&buf, len);
                strbuf_addstr(&buf, e->d_name);
index 60e979dc1bdf1633ed8a62dee944c663f30fbe8b..0e9ec4f68afb01f23d9b9a0142d2ffb2cd1cc79b 100644 (file)
@@ -1,18 +1,21 @@
 /*
  * Copyright (C) 2005 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "quote.h"
 #include "commit.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "object-name.h"
+#include "read-cache.h"
 #include "revision.h"
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "refs.h"
+#include "repository.h"
 #include "submodule.h"
 #include "symlinks.h"
 #include "trace.h"
  * exists for ce that is a submodule -- it is a submodule that is not
  * checked out).  Return negative for an error.
  */
-static int check_removed(const struct index_state *istate, const struct cache_entry *ce, struct stat *st)
+static int check_removed(const struct cache_entry *ce, struct stat *st)
 {
-       assert(is_fsmonitor_refreshed(istate));
-       if (!(ce->ce_flags & CE_FSMONITOR_VALID) && lstat(ce->name, st) < 0) {
+       if (lstat(ce->name, st) < 0) {
                if (!is_missing_file_error(errno))
                        return -1;
                return 1;
        }
+
        if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
                return 1;
        if (S_ISDIR(st->st_mode)) {
@@ -93,7 +96,7 @@ static int match_stat_with_submodule(struct diff_options *diffopt,
        return changed;
 }
 
-int run_diff_files(struct rev_info *revs, unsigned int option)
+void run_diff_files(struct rev_info *revs, unsigned int option)
 {
        int entries, i;
        int diff_unmerged_stage = revs->max_count;
@@ -146,7 +149,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        memset(&(dpath->parent[0]), 0,
                               sizeof(struct combine_diff_parent)*5);
 
-                       changed = check_removed(istate, ce, &st);
+                       changed = check_removed(ce, &st);
                        if (!changed)
                                wt_mode = ce_mode_from_stat(ce, st.st_mode);
                        else {
@@ -226,7 +229,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                } else {
                        struct stat st;
 
-                       changed = check_removed(istate, ce, &st);
+                       changed = check_removed(ce, &st);
                        if (changed) {
                                if (changed < 0) {
                                        perror(ce->name);
@@ -269,7 +272,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        trace_performance_since(start, "diff-files");
-       return 0;
 }
 
 /*
@@ -301,7 +303,7 @@ static int get_stat_data(const struct index_state *istate,
        if (!cached && !ce_uptodate(ce)) {
                int changed;
                struct stat st;
-               changed = check_removed(istate, ce, &st);
+               changed = check_removed(ce, &st);
                if (changed < 0)
                        return -1;
                else if (changed) {
@@ -569,8 +571,6 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
                struct object *obj = revs->pending.objects[i].item;
                if (obj->flags)
                        die(_("--merge-base does not work with ranges"));
-               if (obj->type != OBJ_COMMIT)
-                       die(_("--merge-base only works with commits"));
        }
 
        /*
@@ -603,7 +603,7 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb)
        free_commit_list(merge_bases);
 }
 
-int run_diff_index(struct rev_info *revs, unsigned int option)
+void run_diff_index(struct rev_info *revs, unsigned int option)
 {
        struct object_array_entry *ent;
        int cached = !!(option & DIFF_INDEX_CACHED);
@@ -637,7 +637,6 @@ int run_diff_index(struct rev_info *revs, unsigned int option)
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        trace_performance_leave("diff-index");
-       return 0;
 }
 
 int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
@@ -669,10 +668,17 @@ int index_differs_from(struct repository *r,
        setup_revisions(0, NULL, &rev, &opt);
        rev.diffopt.flags.quick = 1;
        rev.diffopt.flags.exit_with_status = 1;
-       if (flags)
+       if (flags) {
                diff_flags_or(&rev.diffopt.flags, flags);
+               /*
+                * Now that flags are merged, honor override_submodule_config
+                * and ignore_submodules from passed flags.
+                */
+               if (flags->override_submodule_config)
+                       rev.diffopt.flags.ignore_submodules = flags->ignore_submodules;
+       }
        rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
-       run_diff_index(&rev, 1);
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
        has_changes = rev.diffopt.flags.has_changes;
        release_revisions(&rev);
        return (has_changes != 0);
index ec97616db1dfaa0673945bb08a9f364b2d570db1..45507588a2797b8d3618e3a19a2854d12051157b 100644 (file)
@@ -131,6 +131,9 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
        } else if (!strcmp(arg, "--cc")) {
                set_dense_combined(revs);
                revs->merges_imply_patch = 1;
+       } else if (!strcmp(arg, "--dd")) {
+               set_first_parent(revs);
+               revs->merges_imply_patch = 1;
        } else if (!strcmp(arg, "--remerge-diff")) {
                set_remerge_diff(revs);
                revs->merges_imply_patch = 1;
index 4296940f907530ef420a9bc6ba085f2dd1f693a9..e7041b89e38887e04237a00f84366781dbabf739 100644 (file)
@@ -41,42 +41,81 @@ static int read_directory_contents(const char *path, struct string_list *list)
  */
 static const char file_from_standard_input[] = "-";
 
-static int get_mode(const char *path, int *mode)
+/*
+ * For paths given on the command-line we treat "-" as stdin and named
+ * pipes and symbolic links to named pipes specially.
+ */
+enum special {
+       SPECIAL_NONE,
+       SPECIAL_STDIN,
+       SPECIAL_PIPE,
+};
+
+static int get_mode(const char *path, int *mode, enum special *special)
 {
        struct stat st;
 
-       if (!path || !strcmp(path, "/dev/null"))
+       if (!path || !strcmp(path, "/dev/null")) {
                *mode = 0;
 #ifdef GIT_WINDOWS_NATIVE
-       else if (!strcasecmp(path, "nul"))
+       } else if (!strcasecmp(path, "nul")) {
                *mode = 0;
 #endif
-       else if (path == file_from_standard_input)
+       } else if (path == file_from_standard_input) {
                *mode = create_ce_mode(0666);
-       else if (lstat(path, &st))
+               *special = SPECIAL_STDIN;
+       } else if (lstat(path, &st)) {
                return error("Could not access '%s'", path);
-       else
+       } else {
                *mode = st.st_mode;
+       }
+       /*
+        * For paths on the command-line treat named pipes and symbolic
+        * links that resolve to a named pipe specially.
+        */
+       if (special &&
+           (S_ISFIFO(*mode) ||
+            (S_ISLNK(*mode) && !stat(path, &st) && S_ISFIFO(st.st_mode)))) {
+               *mode = create_ce_mode(0666);
+               *special = SPECIAL_PIPE;
+       }
+
        return 0;
 }
 
-static int populate_from_stdin(struct diff_filespec *s)
+static void populate_common(struct diff_filespec *s, struct strbuf *buf)
 {
-       struct strbuf buf = STRBUF_INIT;
        size_t size = 0;
 
-       if (strbuf_read(&buf, 0, 0) < 0)
-               return error_errno("error while reading from stdin");
-
        s->should_munmap = 0;
-       s->data = strbuf_detach(&buf, &size);
+       s->data = strbuf_detach(buf, &size);
        s->size = size;
        s->should_free = 1;
        s->is_stdin = 1;
-       return 0;
 }
 
-static struct diff_filespec *noindex_filespec(const char *name, int mode)
+static void populate_from_pipe(struct diff_filespec *s)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int fd = xopen(s->path, O_RDONLY);
+
+       if (strbuf_read(&buf, fd, 0) < 0)
+               die_errno("error while reading from '%s'", s->path);
+       close(fd);
+       populate_common(s, &buf);
+}
+
+static void populate_from_stdin(struct diff_filespec *s)
+{
+       struct strbuf buf = STRBUF_INIT;
+
+       if (strbuf_read(&buf, 0, 0) < 0)
+               die_errno("error while reading from stdin");
+       populate_common(s, &buf);
+}
+
+static struct diff_filespec *noindex_filespec(const char *name, int mode,
+                                             enum special special)
 {
        struct diff_filespec *s;
 
@@ -84,17 +123,22 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode)
                name = "/dev/null";
        s = alloc_filespec(name);
        fill_filespec(s, null_oid(), 0, mode);
-       if (name == file_from_standard_input)
+       if (special == SPECIAL_STDIN)
                populate_from_stdin(s);
+       else if (special == SPECIAL_PIPE)
+               populate_from_pipe(s);
        return s;
 }
 
 static int queue_diff(struct diff_options *o,
-                     const char *name1, const char *name2)
+                     const char *name1, const char *name2, int recursing)
 {
        int mode1 = 0, mode2 = 0;
+       enum special special1 = SPECIAL_NONE, special2 = SPECIAL_NONE;
 
-       if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
+       /* Paths can only be special if we're not recursing. */
+       if (get_mode(name1, &mode1, recursing ? NULL : &special1) ||
+           get_mode(name2, &mode2, recursing ? NULL : &special2))
                return -1;
 
        if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) {
@@ -102,14 +146,14 @@ static int queue_diff(struct diff_options *o,
 
                if (S_ISDIR(mode1)) {
                        /* 2 is file that is created */
-                       d1 = noindex_filespec(NULL, 0);
-                       d2 = noindex_filespec(name2, mode2);
+                       d1 = noindex_filespec(NULL, 0, SPECIAL_NONE);
+                       d2 = noindex_filespec(name2, mode2, special2);
                        name2 = NULL;
                        mode2 = 0;
                } else {
                        /* 1 is file that is deleted */
-                       d1 = noindex_filespec(name1, mode1);
-                       d2 = noindex_filespec(NULL, 0);
+                       d1 = noindex_filespec(name1, mode1, special1);
+                       d2 = noindex_filespec(NULL, 0, SPECIAL_NONE);
                        name1 = NULL;
                        mode1 = 0;
                }
@@ -174,7 +218,7 @@ static int queue_diff(struct diff_options *o,
                                n2 = buffer2.buf;
                        }
 
-                       ret = queue_diff(o, n1, n2);
+                       ret = queue_diff(o, n1, n2, 1);
                }
                string_list_clear(&p1, 0);
                string_list_clear(&p2, 0);
@@ -188,10 +232,11 @@ static int queue_diff(struct diff_options *o,
                if (o->flags.reverse_diff) {
                        SWAP(mode1, mode2);
                        SWAP(name1, name2);
+                       SWAP(special1, special2);
                }
 
-               d1 = noindex_filespec(name1, mode1);
-               d2 = noindex_filespec(name2, mode2);
+               d1 = noindex_filespec(name1, mode1, special1);
+               d2 = noindex_filespec(name2, mode2, special2);
                diff_queue(&diff_queued_diff, d1, d2);
                return 0;
        }
@@ -216,13 +261,27 @@ static void append_basename(struct strbuf *path, const char *dir, const char *fi
  */
 static void fixup_paths(const char **path, struct strbuf *replacement)
 {
-       unsigned int isdir0, isdir1;
+       struct stat st;
+       unsigned int isdir0 = 0, isdir1 = 0;
+       unsigned int ispipe0 = 0, ispipe1 = 0;
+
+       if (path[0] != file_from_standard_input && !stat(path[0], &st)) {
+               isdir0 = S_ISDIR(st.st_mode);
+               ispipe0 = S_ISFIFO(st.st_mode);
+       }
+
+       if (path[1] != file_from_standard_input && !stat(path[1], &st)) {
+               isdir1 = S_ISDIR(st.st_mode);
+               ispipe1 = S_ISFIFO(st.st_mode);
+       }
+
+       if ((path[0] == file_from_standard_input && isdir1) ||
+           (isdir0 && path[1] == file_from_standard_input))
+               die(_("cannot compare stdin to a directory"));
+
+       if ((isdir0 && ispipe1) || (ispipe0 && isdir1))
+               die(_("cannot compare a named pipe to a directory"));
 
-       if (path[0] == file_from_standard_input ||
-           path[1] == file_from_standard_input)
-               return;
-       isdir0 = is_directory(path[0]);
-       isdir1 = is_directory(path[1]);
        if (isdir0 == isdir1)
                return;
        if (isdir0) {
@@ -296,7 +355,7 @@ int diff_no_index(struct rev_info *revs,
        setup_diff_pager(&revs->diffopt);
        revs->diffopt.flags.exit_with_status = 1;
 
-       if (queue_diff(&revs->diffopt, paths[0], paths[1]))
+       if (queue_diff(&revs->diffopt, paths[0], paths[1], 0))
                goto out;
        diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
        diffcore_std(&revs->diffopt);
@@ -306,7 +365,7 @@ int diff_no_index(struct rev_info *revs,
         * The return code for --no-index imitates diff(1):
         * 0 = no changes, 1 = changes, else error
         */
-       ret = diff_result_code(&revs->diffopt, 0);
+       ret = diff_result_code(&revs->diffopt);
 
 out:
        for (i = 0; i < ARRAY_SIZE(to_free); i++)
diff --git a/diff.c b/diff.c
index 3c88c37908d6b13665ff7cd88abd46141485c891..2c602df10a372c7e99402ca5a2dc9cf7aa673c09 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1,9 +1,8 @@
 /*
  * Copyright (C) 2005 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "base85.h"
 #include "config.h"
 #include "convert.h"
 #include "attr.h"
 #include "run-command.h"
 #include "utf8.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "userdiff.h"
 #include "submodule-config.h"
 #include "submodule.h"
 #include "hashmap.h"
 #include "mem-pool.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "string-list.h"
 #include "strvec.h"
 #include "graph.h"
 #include "dir.h"
 #include "object-file.h"
 #include "object-name.h"
+#include "read-cache-ll.h"
 #include "setup.h"
 #include "strmap.h"
 #include "ws.h"
-#include "wrapper.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -66,6 +65,7 @@ int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
 static int diff_relative;
+static int diff_stat_name_width;
 static int diff_stat_graph_width;
 static int diff_dirstat_permille_default = 30;
 static struct diff_options default_diff_options;
@@ -357,7 +357,8 @@ static unsigned parse_color_moved_ws(const char *arg)
        return ret;
 }
 
-int git_diff_ui_config(const char *var, const char *value, void *cb)
+int git_diff_ui_config(const char *var, const char *value,
+                      const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                diff_use_color_default = git_config_colorbool(var, value);
@@ -378,13 +379,14 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                return 0;
        }
        if (!strcmp(var, "diff.context")) {
-               diff_context_default = git_config_int(var, value);
+               diff_context_default = git_config_int(var, value, ctx->kvi);
                if (diff_context_default < 0)
                        return -1;
                return 0;
        }
        if (!strcmp(var, "diff.interhunkcontext")) {
-               diff_interhunk_context_default = git_config_int(var, value);
+               diff_interhunk_context_default = git_config_int(var, value,
+                                                               ctx->kvi);
                if (diff_interhunk_context_default < 0)
                        return -1;
                return 0;
@@ -409,8 +411,12 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_relative = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "diff.statnamewidth")) {
+               diff_stat_name_width = git_config_int(var, value, ctx->kvi);
+               return 0;
+       }
        if (!strcmp(var, "diff.statgraphwidth")) {
-               diff_stat_graph_width = git_config_int(var, value);
+               diff_stat_graph_width = git_config_int(var, value, ctx->kvi);
                return 0;
        }
        if (!strcmp(var, "diff.external"))
@@ -440,15 +446,16 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
        if (git_color_config(var, value, cb) < 0)
                return -1;
 
-       return git_diff_basic_config(var, value, cb);
+       return git_diff_basic_config(var, value, ctx, cb);
 }
 
-int git_diff_basic_config(const char *var, const char *value, void *cb)
+int git_diff_basic_config(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb)
 {
        const char *name;
 
        if (!strcmp(var, "diff.renamelimit")) {
-               diff_rename_limit_default = git_config_int(var, value);
+               diff_rename_limit_default = git_config_int(var, value, ctx->kvi);
                return 0;
        }
 
@@ -495,7 +502,7 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
        if (git_diff_heuristic_config(var, value, cb) < 0)
                return -1;
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static char *quote_two(const char *one, const char *two)
@@ -2702,12 +2709,14 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
        number_width = decimal_width(max_change) > number_width ?
                decimal_width(max_change) : number_width;
 
+       if (options->stat_name_width == -1)
+               options->stat_name_width = diff_stat_name_width;
        if (options->stat_graph_width == -1)
                options->stat_graph_width = diff_stat_graph_width;
 
        /*
-        * Guarantee 3/8*16==6 for the graph part
-        * and 5/8*16==10 for the filename part
+        * Guarantee 3/8*16 == 6 for the graph part
+        * and 5/8*16 == 10 for the filename part
         */
        if (width < 16 + 6 + number_width)
                width = 16 + 6 + number_width;
@@ -3561,18 +3570,21 @@ static void builtin_diff(const char *name_a,
                strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, meta, two->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
+               o->found_changes = 1;
                must_show_header = 1;
        }
        else if (lbl[1][0] == '/') {
                strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, meta, one->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
+               o->found_changes = 1;
                must_show_header = 1;
        }
        else {
                if (one->mode != two->mode) {
                        strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, meta, one->mode, reset);
                        strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, meta, two->mode, reset);
+                       o->found_changes = 1;
                        must_show_header = 1;
                }
                if (xfrm_msg)
@@ -4751,6 +4763,31 @@ unsigned diff_filter_bit(char status)
        return filter_bit[(int) status];
 }
 
+int diff_check_follow_pathspec(struct pathspec *ps, int die_on_error)
+{
+       unsigned forbidden_magic;
+
+       if (ps->nr != 1) {
+               if (die_on_error)
+                       die(_("--follow requires exactly one pathspec"));
+               return 0;
+       }
+
+       forbidden_magic = ps->items[0].magic & ~(PATHSPEC_FROMTOP |
+                                                PATHSPEC_LITERAL);
+       if (forbidden_magic) {
+               if (die_on_error) {
+                       struct strbuf sb = STRBUF_INIT;
+                       pathspec_magic_names(forbidden_magic, &sb);
+                       die(_("pathspec magic not supported by --follow: %s"),
+                           sb.buf);
+               }
+               return 0;
+       }
+
+       return 1;
+}
+
 void diff_setup_done(struct diff_options *options)
 {
        unsigned check_mask = DIFF_FORMAT_NAME |
@@ -4805,6 +4842,10 @@ void diff_setup_done(struct diff_options *options)
        else
                options->prefix_length = 0;
 
+       /*
+        * --name-only, --name-status, --checkdiff, and -s
+        * turn other output format off.
+        */
        if (options->output_format & (DIFF_FORMAT_NAME |
                                      DIFF_FORMAT_NAME_STATUS |
                                      DIFF_FORMAT_CHECKDIFF |
@@ -4858,8 +4899,8 @@ void diff_setup_done(struct diff_options *options)
 
        options->diff_path_counter = 0;
 
-       if (options->flags.follow_renames && options->pathspec.nr != 1)
-               die(_("--follow requires exactly one pathspec"));
+       if (options->flags.follow_renames)
+               diff_check_follow_pathspec(&options->pathspec, 1);
 
        if (!options->use_color || external_diff())
                options->color_moved = 0;
@@ -4936,6 +4977,7 @@ static int diff_opt_stat(const struct option *opt, const char *value, int unset)
        } else
                BUG("%s should not get here", opt->long_name);
 
+       options->output_format &= ~DIFF_FORMAT_NO_OUTPUT;
        options->output_format |= DIFF_FORMAT_DIFFSTAT;
        options->stat_name_width = name_width;
        options->stat_graph_width = graph_width;
@@ -4955,6 +4997,7 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params)
         * The caller knows a dirstat-related option is given from the command
         * line; allow it to say "return this_function();"
         */
+       options->output_format &= ~DIFF_FORMAT_NO_OUTPUT;
        options->output_format |= DIFF_FORMAT_DIRSTAT;
        return 1;
 }
@@ -5154,6 +5197,7 @@ static int diff_opt_compact_summary(const struct option *opt,
                options->flags.stat_with_summary = 0;
        } else {
                options->flags.stat_with_summary = 1;
+               options->output_format &= ~DIFF_FORMAT_NO_OUTPUT;
                options->output_format |= DIFF_FORMAT_DIFFSTAT;
        }
        return 0;
@@ -5491,6 +5535,10 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns
        return 0;
 }
 
+/*
+ * Consider adding new flags to __git_diff_common_options
+ * in contrib/completion/git-completion.bash
+ */
 struct option *add_diff_options(const struct option *opts,
                                struct diff_options *options)
 {
@@ -5499,9 +5547,8 @@ struct option *add_diff_options(const struct option *opts,
                OPT_BITOP('p', "patch", &options->output_format,
                          N_("generate patch"),
                          DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT),
-               OPT_BIT_F('s', "no-patch", &options->output_format,
-                         N_("suppress diff output"),
-                         DIFF_FORMAT_NO_OUTPUT, PARSE_OPT_NONEG),
+               OPT_SET_INT('s', "no-patch", &options->output_format,
+                           N_("suppress diff output"), DIFF_FORMAT_NO_OUTPUT),
                OPT_BITOP('u', NULL, &options->output_format,
                          N_("generate patch"),
                          DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT),
@@ -5510,9 +5557,9 @@ struct option *add_diff_options(const struct option *opts,
                               PARSE_OPT_NONEG | PARSE_OPT_OPTARG, diff_opt_unified),
                OPT_BOOL('W', "function-context", &options->flags.funccontext,
                         N_("generate diffs with <n> lines context")),
-               OPT_BIT_F(0, "raw", &options->output_format,
+               OPT_BITOP(0, "raw", &options->output_format,
                          N_("generate the diff in raw format"),
-                         DIFF_FORMAT_RAW, PARSE_OPT_NONEG),
+                         DIFF_FORMAT_RAW, DIFF_FORMAT_NO_OUTPUT),
                OPT_BITOP(0, "patch-with-raw", &options->output_format,
                          N_("synonym for '-p --raw'"),
                          DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW,
@@ -5521,12 +5568,12 @@ struct option *add_diff_options(const struct option *opts,
                          N_("synonym for '-p --stat'"),
                          DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT,
                          DIFF_FORMAT_NO_OUTPUT),
-               OPT_BIT_F(0, "numstat", &options->output_format,
+               OPT_BITOP(0, "numstat", &options->output_format,
                          N_("machine friendly --stat"),
-                         DIFF_FORMAT_NUMSTAT, PARSE_OPT_NONEG),
-               OPT_BIT_F(0, "shortstat", &options->output_format,
+                         DIFF_FORMAT_NUMSTAT, DIFF_FORMAT_NO_OUTPUT),
+               OPT_BITOP(0, "shortstat", &options->output_format,
                          N_("output only the last line of --stat"),
-                         DIFF_FORMAT_SHORTSTAT, PARSE_OPT_NONEG),
+                         DIFF_FORMAT_SHORTSTAT, DIFF_FORMAT_NO_OUTPUT),
                OPT_CALLBACK_F('X', "dirstat", options, N_("<param1,param2>..."),
                               N_("output the distribution of relative amount of changes for each sub-directory"),
                               PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
@@ -5542,9 +5589,9 @@ struct option *add_diff_options(const struct option *opts,
                OPT_BIT_F(0, "check", &options->output_format,
                          N_("warn if changes introduce conflict markers or whitespace errors"),
                          DIFF_FORMAT_CHECKDIFF, PARSE_OPT_NONEG),
-               OPT_BIT_F(0, "summary", &options->output_format,
+               OPT_BITOP(0, "summary", &options->output_format,
                          N_("condensed summary such as creations, renames and mode changes"),
-                         DIFF_FORMAT_SUMMARY, PARSE_OPT_NONEG),
+                         DIFF_FORMAT_SUMMARY, DIFF_FORMAT_NO_OUTPUT),
                OPT_BIT_F(0, "name-only", &options->output_format,
                          N_("show only names of changed files"),
                          DIFF_FORMAT_NAME, PARSE_OPT_NONEG),
@@ -6173,6 +6220,8 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
                fprintf(opt->file, "%s", diff_line_prefix(opt));
                write_name_quoted(name_a, opt->file, opt->line_termination);
        }
+
+       opt->found_changes = 1;
 }
 
 static void show_file_mode_name(struct diff_options *opt, const char *newdelete, struct diff_filespec *fs)
@@ -6651,6 +6700,21 @@ void diff_flush(struct diff_options *options)
                separator++;
        }
 
+       if (output_format & DIFF_FORMAT_PATCH) {
+               if (separator) {
+                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0);
+                       if (options->stat_sep)
+                               /* attach patch instead of inline */
+                               emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP,
+                                                NULL, 0, 0);
+               }
+
+               diff_flush_patch_all_file_pairs(options);
+       }
+
+       if (output_format & DIFF_FORMAT_CALLBACK)
+               options->format_callback(q, options, options->format_callback_data);
+
        if (output_format & DIFF_FORMAT_NO_OUTPUT &&
            options->flags.exit_with_status &&
            options->flags.diff_from_contents) {
@@ -6672,21 +6736,6 @@ void diff_flush(struct diff_options *options)
                }
        }
 
-       if (output_format & DIFF_FORMAT_PATCH) {
-               if (separator) {
-                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0);
-                       if (options->stat_sep)
-                               /* attach patch instead of inline */
-                               emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP,
-                                                NULL, 0, 0);
-               }
-
-               diff_flush_patch_all_file_pairs(options);
-       }
-
-       if (output_format & DIFF_FORMAT_CALLBACK)
-               options->format_callback(q, options, options->format_callback_data);
-
 free_queue:
        diff_free_queue(q);
        DIFF_QUEUE_CLEAR(q);
@@ -6887,6 +6936,13 @@ void diff_queued_diff_prefetch(void *repository)
        oid_array_clear(&to_fetch);
 }
 
+void init_diffstat_widths(struct diff_options *options)
+{
+       options->stat_width = -1;        /* use full terminal width */
+       options->stat_name_width = -1;   /* respect diff.statNameWidth config */
+       options->stat_graph_width = -1;  /* respect diff.statGraphWidth config */
+}
+
 void diffcore_std(struct diff_options *options)
 {
        int output_formats_to_prefetch = DIFF_FORMAT_DIFFSTAT |
@@ -6940,16 +6996,14 @@ void diffcore_std(struct diff_options *options)
        options->found_follow = 0;
 }
 
-int diff_result_code(struct diff_options *opt, int status)
+int diff_result_code(struct diff_options *opt)
 {
        int result = 0;
 
        diff_warn_rename_limit("diff.renameLimit",
                               opt->needed_rename_limit,
                               opt->degraded_cc_to_c);
-       if (!opt->flags.exit_with_status &&
-           !(opt->output_format & DIFF_FORMAT_CHECKDIFF))
-               return status;
+
        if (opt->flags.exit_with_status &&
            opt->flags.has_changes)
                result |= 01;
@@ -6996,6 +7050,7 @@ void compute_diffstat(struct diff_options *options,
                if (check_pair_status(p))
                        diff_flush_stat(p, options, diffstat);
        }
+       options->found_changes = !!diffstat->nr;
 }
 
 void diff_addremove(struct diff_options *options,
diff --git a/diff.h b/diff.h
index 3a7a9e8b888743fb9d0c99040b9b76cb94901615..66bd8aeb2936fbe9d6610f7dc1202e31e1450ebb 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -4,10 +4,12 @@
 #ifndef DIFF_H
 #define DIFF_H
 
+#include "hash-ll.h"
 #include "pathspec.h"
-#include "oidset.h"
 #include "strbuf.h"
 
+struct oidset;
+
 /**
  * The diff API is for programs that compare two sets of files (e.g. two trees,
  * one tree and the index) and present the found difference in various ways.
@@ -531,14 +533,24 @@ void free_diffstat_info(struct diffstat_t *diffstat);
 int parse_long_opt(const char *opt, const char **argv,
                   const char **optarg);
 
-int git_diff_basic_config(const char *var, const char *value, void *cb);
+struct config_context;
+int git_diff_basic_config(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb);
 int git_diff_heuristic_config(const char *var, const char *value, void *cb);
 void init_diff_ui_defaults(void);
-int git_diff_ui_config(const char *var, const char *value, void *cb);
+int git_diff_ui_config(const char *var, const char *value,
+                      const struct config_context *ctx, void *cb);
 void repo_diff_setup(struct repository *, struct diff_options *);
 struct option *add_diff_options(const struct option *, struct diff_options *);
 int diff_opt_parse(struct diff_options *, const char **, int, const char *);
 void diff_setup_done(struct diff_options *);
+
+/*
+ * Returns true if the pathspec can work with --follow mode. If die_on_error is
+ * set, die() with a specific error message rather than returning false.
+ */
+int diff_check_follow_pathspec(struct pathspec *ps, int die_on_error);
+
 int git_config_rename(const char *var, const char *value);
 
 #define DIFF_DETECT_RENAME     1
@@ -561,6 +573,7 @@ int git_config_rename(const char *var, const char *value);
 
 #define DIFF_PICKAXE_IGNORE_CASE       32
 
+void init_diffstat_widths(struct diff_options *);
 void diffcore_std(struct diff_options *);
 void diffcore_fix_diff_index(void);
 
@@ -625,17 +638,17 @@ void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb);
 #define DIFF_SILENT_ON_REMOVED 01
 /* report racily-clean paths as modified */
 #define DIFF_RACY_IS_MODIFIED 02
-int run_diff_files(struct rev_info *revs, unsigned int option);
+void run_diff_files(struct rev_info *revs, unsigned int option);
 
 #define DIFF_INDEX_CACHED 01
 #define DIFF_INDEX_MERGE_BASE 02
-int run_diff_index(struct rev_info *revs, unsigned int option);
+void run_diff_index(struct rev_info *revs, unsigned int option);
 
 int do_diff_cache(const struct object_id *, struct diff_options *);
 int diff_flush_patch_id(struct diff_options *, struct object_id *, int);
 void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx);
 
-int diff_result_code(struct diff_options *, int);
+int diff_result_code(struct diff_options *);
 
 int diff_no_index(struct rev_info *,
                  int implicit_no_index, int, const char **);
@@ -694,4 +707,6 @@ void print_stat_summary(FILE *fp, int files,
                        int insertions, int deletions);
 void setup_diff_pager(struct diff_options *);
 
+extern int diff_auto_refresh_index;
+
 #endif /* DIFF_H */
index 5462420bbbecceedd2366fc5506d4218230181c4..f57ece2757d46ea6dee3af34a476c5fdd9908b0d 100644 (file)
@@ -1,9 +1,11 @@
 /*
  * Copyright (C) 2005 Junio C Hamano
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "hash.h"
+#include "object.h"
 #include "promisor-remote.h"
 
 static int should_break(struct repository *r,
index 57ccab284645693322301e59b07f6fceb62d6224..e7d20ebd2d1b45b073ac2825b9371986d305ee29 100644 (file)
@@ -5,6 +5,7 @@
 #include "gettext.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "wildmatch.h"
 
 static char **order;
 static int order_cnt;
index 13c98a7b5e7751c8db6a9d78575a9b76e0313f92..b195fa4eb3c045c030a47c84edcaa702e447c8f8 100644 (file)
@@ -7,6 +7,7 @@
 #include "diffcore.h"
 #include "xdiff-interface.h"
 #include "kwset.h"
+#include "oidset.h"
 #include "pretty.h"
 #include "quote.h"
 
index 8e2e7a3ad738468b1738661ab00627a05d6dd129..5a6e2bcac7147e487624c1bf53e1572a54b0d93d 100644 (file)
@@ -3,10 +3,9 @@
  * Copyright (C) 2005 Junio C Hamano
  */
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "diff.h"
 #include "diffcore.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "hashmap.h"
 #include "mem-pool.h"
 #include "oid-array.h"
index fb7c47f0e8a9516d17ded95d70e3dabaa61264bb..278b04243a3f40e63df433eea9549f90aed1c34d 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "dir.h"
 #include "iterator.h"
 #include "dir-iterator.h"
diff --git a/dir.c b/dir.c
index a7469df3ac7f95109c48ced53259aac021e14b8b..16fdb03f2a51c9505b3cc9da2d9a908f3e4ae119 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -7,14 +7,15 @@
  */
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "convert.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
+#include "name-hash.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "attr.h"
 #include "refs.h"
 #include "wildmatch.h"
 #include "utf8.h"
 #include "varint.h"
 #include "ewah/ewok.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
+#include "read-cache-ll.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "submodule-config.h"
 #include "symlinks.h"
 #include "trace2.h"
 #include "tree.h"
-#include "wrapper.h"
 
 /*
  * Tells read_directory_recursive how a file or directory should be treated.
@@ -374,7 +376,7 @@ static int match_pathspec_item(struct index_state *istate,
                return 0;
 
        if (item->attr_match_nr &&
-           !match_pathspec_attrs(istate, name, namelen, item))
+           !match_pathspec_attrs(istate, name - prefix, namelen + prefix, item))
                return 0;
 
        /* If the match was just the prefix, we matched */
@@ -2233,6 +2235,39 @@ static int get_index_dtype(struct index_state *istate,
        return DT_UNKNOWN;
 }
 
+unsigned char get_dtype(struct dirent *e, struct strbuf *path,
+                       int follow_symlink)
+{
+       struct stat st;
+       unsigned char dtype = DTYPE(e);
+       size_t base_path_len;
+
+       if (dtype != DT_UNKNOWN && !(follow_symlink && dtype == DT_LNK))
+               return dtype;
+
+       /*
+        * d_type unknown or unfollowed symlink, try to fall back on [l]stat
+        * results. If [l]stat fails, explicitly set DT_UNKNOWN.
+        */
+       base_path_len = path->len;
+       strbuf_addstr(path, e->d_name);
+       if ((follow_symlink && stat(path->buf, &st)) ||
+           (!follow_symlink && 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 resolve_dtype(int dtype, struct index_state *istate,
                         const char *path, int len)
 {
diff --git a/dir.h b/dir.h
index 79b85a01ee40b551268c8ad7bc675fffa66c7f51..98aa85fcc0ee357a2df50014008c3e5ec12acb25 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -1,11 +1,14 @@
 #ifndef DIR_H
 #define DIR_H
 
+#include "hash-ll.h"
 #include "hashmap.h"
 #include "pathspec.h"
 #include "statinfo.h"
 #include "strbuf.h"
 
+struct repository;
+
 /**
  * The directory listing API is used to enumerate paths in the work tree,
  * optionally taking `.git/info/exclude` and `.gitignore` files per directory
@@ -40,6 +43,8 @@
  *
  */
 
+struct repository;
+
 struct dir_entry {
        unsigned int len;
        char name[FLEX_ARRAY]; /* more */
@@ -358,6 +363,22 @@ struct dir_struct {
 
 struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp);
 
+/*
+ * Get the d_type of a dirent. If the d_type is unknown, derive it from
+ * stat.st_mode using the path to the dirent's containing directory (path) and
+ * the name of the dirent itself.
+ *
+ * If 'follow_symlink' is 1, this function will attempt to follow DT_LNK types
+ * using 'stat'. Links are *not* followed recursively, so a symlink pointing
+ * to another symlink will still resolve to 'DT_LNK'.
+ *
+ * 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.
+ */
+unsigned char get_dtype(struct dirent *e, struct strbuf *path,
+                       int follow_symlink);
+
 /*Count the number of slashes for string s*/
 int count_slashes(const char *s);
 
@@ -641,18 +662,4 @@ static inline int starts_with_dot_dot_slash_native(const char *const path)
        return path_match_flags(path, what | PATH_MATCH_NATIVE);
 }
 
-#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
-#define DTYPE(de)      ((de)->d_type)
-#else
-#undef DT_UNKNOWN
-#undef DT_DIR
-#undef DT_REG
-#undef DT_LNK
-#define DT_UNKNOWN     0
-#define DT_DIR         1
-#define DT_REG         2
-#define DT_LNK         3
-#define DTYPE(de)      DT_UNKNOWN
-#endif
-
 #endif
index 38c5dbbb79b96ca15431141bf70b84799149eb40..b67b802ddf8493ea25ccbb1fc5c046240bfe917d 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -11,7 +11,6 @@
 #include "strvec.h"
 #include "run-command.h"
 #include "sigchain.h"
-#include "wrapper.h"
 
 #ifndef DEFAULT_EDITOR
 #define DEFAULT_EDITOR "vi"
diff --git a/entry.c b/entry.c
index 91a540bd29fac2320ab214020cdcc58fee0412b4..076e97eb89ce15e312b6ff08eebd3c1389245997 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,10 +1,12 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "blob.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
+#include "name-hash.h"
+#include "sparse-index.h"
 #include "streaming.h"
 #include "submodule.h"
 #include "symlinks.h"
@@ -12,7 +14,6 @@
 #include "fsmonitor.h"
 #include "entry.h"
 #include "parallel-checkout.h"
-#include "wrapper.h"
 
 static void create_directories(const char *path, int path_len,
                               const struct checkout *state)
@@ -580,3 +581,8 @@ void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
                return;
        schedule_dir_for_removal(ce->name, ce_namelen(ce));
 }
+
+int remove_or_warn(unsigned int mode, const char *file)
+{
+       return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
+}
diff --git a/entry.h b/entry.h
index 7329f918a97ee3f80aeeaff07e4236143fcf3cbf..ca3ed35bc08654ee47bc6c9331c1fad2804bfd32 100644 (file)
--- a/entry.h
+++ b/entry.h
@@ -62,4 +62,10 @@ int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st)
 void update_ce_after_write(const struct checkout *state, struct cache_entry *ce,
                           struct stat *st);
 
+/*
+ * Calls the correct function out of {unlink,rmdir}_or_warn based on
+ * the supplied file mode.
+ */
+int remove_or_warn(unsigned int mode, const char *path);
+
 #endif /* ENTRY_H */
index 28d18eaca8ee0a1edd33f1faebae9f8c19fbba4c..bb3c2a96a33445c6fddb41e5ac02df2b3a88c442 100644 (file)
 #include "commit.h"
 #include "strvec.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "replace-object.h"
 #include "tmp-objdir.h"
 #include "chdir-notify.h"
 #include "setup.h"
 #include "shallow.h"
 #include "trace.h"
-#include "wrapper.h"
 #include "write-or-die.h"
 
 int trust_executable_bit = 1;
@@ -42,7 +42,6 @@ int is_bare_repository_cfg = -1; /* unspecified */
 int warn_ambiguous_refs = 1;
 int warn_on_object_refname_ambiguity = 1;
 int repository_format_precious_objects;
-int repository_format_worktree_config;
 const char *git_commit_encoding;
 const char *git_log_output_encoding;
 char *apply_default_whitespace;
@@ -63,7 +62,6 @@ const char *editor_program;
 const char *askpass_program;
 const char *excludes_file;
 enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
-int read_replace_refs = 1;
 enum eol core_eol = EOL_UNSET;
 int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
 char *check_roundtrip_encoding = "SHIFT-JIS";
@@ -75,7 +73,7 @@ enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
 #endif
 enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 char *notes_ref_name;
-int grafts_replace_parents = 1;
+int grafts_keep_true_parents;
 int core_apply_sparse_checkout;
 int core_sparse_checkout_cone;
 int sparse_expect_files_outside_of_patterns;
@@ -83,6 +81,7 @@ int merge_log_config = -1;
 int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
 unsigned long pack_size_limit_cfg;
 enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
+int max_allowed_tree_depth = 2048;
 
 #ifndef PROTECT_HFS_DEFAULT
 #define PROTECT_HFS_DEFAULT 0
@@ -110,7 +109,7 @@ char *git_work_tree_cfg;
 static char *git_namespace;
 
 /*
- * Repository-local GIT_* environment variables; see cache.h for details.
+ * Repository-local GIT_* environment variables; see environment.h for details.
  */
 const char * const local_repo_env[] = {
        ALTERNATE_DB_ENVIRONMENT,
@@ -184,7 +183,7 @@ void setup_git_env(const char *git_dir)
        strvec_clear(&to_free);
 
        if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
-               read_replace_refs = 0;
+               disable_replace_refs();
        replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
        git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
                                                          : "refs/replace/");
index 30cb7e0fa34d35ef074167b2e7e012a887504c0c..e5351c9dd95ea6e7afe77b1db466d6ab30310491 100644 (file)
@@ -1,9 +1,8 @@
 #ifndef ENVIRONMENT_H
 #define ENVIRONMENT_H
 
-#include "strvec.h"
-
 struct repository;
+struct strvec;
 
 /*
  * The character that begins a commented line in user-editable file
@@ -133,6 +132,7 @@ extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
 extern unsigned long big_file_threshold;
 extern unsigned long pack_size_limit_cfg;
+extern int max_allowed_tree_depth;
 
 /*
  * Accessors for the core.sharedrepository config which lazy-load the value
@@ -194,10 +194,9 @@ extern enum object_creation_mode object_creation_mode;
 
 extern char *notes_ref_name;
 
-extern int grafts_replace_parents;
+extern int grafts_keep_true_parents;
 
 extern int repository_format_precious_objects;
-extern int repository_format_worktree_config;
 
 /*
  * Create a temporary file rooted in the object database directory, or
index 12d6aa398e907f83eeaee9e9635ccbf11220ce35..7b525b1ecd896e02dfa71cdf3aab75496d998fac 100644 (file)
@@ -17,7 +17,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "ewok.h"
 
 #define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))
index c6d4ffc87cacaaaefb3edf4f81f62f7481b4b742..8785cbc54a821cd2cb89ba0226a29a233d8c19ff 100644 (file)
@@ -17,7 +17,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "ewok.h"
 #include "ewok_rlw.h"
 
index 1e34e48c0e467a96e806ce62bec682fb83979625..1d597e84ea7f4c3c8296cbf527bf0c5514037e99 100644 (file)
@@ -1,10 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
 #include "environment.h"
 #include "exec-cmd.h"
 #include "gettext.h"
 #include "path.h"
 #include "quote.h"
+#include "run-command.h"
 #include "strvec.h"
 #include "trace.h"
 #include "trace2.h"
index 0f71054fbaefbdbfdc7878a2f1be06bb9c3f24e7..26999e3b6591313a18df430170aaf935d2e24c14 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "repository.h"
 #include "config.h"
 #include "date.h"
@@ -24,7 +23,8 @@
 #include "oid-array.h"
 #include "oidset.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "connected.h"
 #include "fetch-negotiator.h"
 #include "fsck.h"
@@ -33,7 +33,6 @@
 #include "commit-graph.h"
 #include "sigchain.h"
 #include "mergesort.h"
-#include "wrapper.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -1860,7 +1859,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        return ref;
 }
 
-static int fetch_pack_config_cb(const char *var, const char *value, void *cb)
+static int fetch_pack_config_cb(const char *var, const char *value,
+                               const struct config_context *ctx, void *cb)
 {
        if (strcmp(var, "fetch.fsck.skiplist") == 0) {
                const char *path;
@@ -1882,7 +1882,7 @@ static int fetch_pack_config_cb(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 static void fetch_pack_config(void)
@@ -1911,10 +1911,10 @@ static void fetch_pack_setup(void)
        if (did_setup)
                return;
        fetch_pack_config();
-       if (0 <= transfer_unpack_limit)
-               unpack_limit = transfer_unpack_limit;
-       else if (0 <= fetch_unpack_limit)
+       if (0 <= fetch_unpack_limit)
                unpack_limit = fetch_unpack_limit;
+       else if (0 <= transfer_unpack_limit)
+               unpack_limit = transfer_unpack_limit;
        did_setup = 1;
 }
 
index 5af0d4715ba22f2f1629880ec530a0752398e716..66e47449a092d67b66a172a0e325593d5e494efa 100644 (file)
@@ -1,10 +1,9 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "refs.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "diff.h"
 #include "diff-merges.h"
 #include "hex.h"
 #include "fmt-merge-msg.h"
 #include "commit-reach.h"
 #include "gpg-interface.h"
+#include "wildmatch.h"
 
 static int use_branch_desc;
 static int suppress_dest_pattern_seen;
 static struct string_list suppress_dest_patterns = STRING_LIST_INIT_DUP;
 
-int fmt_merge_msg_config(const char *key, const char *value, void *cb)
+int fmt_merge_msg_config(const char *key, const char *value,
+                        const struct config_context *ctx, void *cb)
 {
        if (!strcmp(key, "merge.log") || !strcmp(key, "merge.summary")) {
                int is_bool;
-               merge_log_config = git_config_bool_or_int(key, value, &is_bool);
+               merge_log_config = git_config_bool_or_int(key, value, ctx->kvi, &is_bool);
                if (!is_bool && merge_log_config < 0)
                        return error("%s: negative length %s", key, value);
                if (is_bool && merge_log_config)
@@ -40,7 +41,7 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
                        string_list_append(&suppress_dest_patterns, value);
                suppress_dest_pattern_seen = 1;
        } else {
-               return git_default_config(key, value, cb);
+               return git_default_config(key, value, ctx, cb);
        }
        return 0;
 }
@@ -508,7 +509,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
        strbuf_complete_line(tagbuf);
        if (sig->len) {
                strbuf_addch(tagbuf, '\n');
-               strbuf_add_commented_lines(tagbuf, sig->buf, sig->len);
+               strbuf_add_commented_lines(tagbuf, sig->buf, sig->len,
+                                          comment_line_char);
        }
 }
 
@@ -554,7 +556,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
                                strbuf_addch(&tagline, '\n');
                                strbuf_add_commented_lines(&tagline,
                                                origins.items[first_tag].string,
-                                               strlen(origins.items[first_tag].string));
+                                               strlen(origins.items[first_tag].string),
+                                               comment_line_char);
                                strbuf_insert(&tagbuf, 0, tagline.buf,
                                              tagline.len);
                                strbuf_release(&tagline);
@@ -562,7 +565,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
                        strbuf_addch(&tagbuf, '\n');
                        strbuf_add_commented_lines(&tagbuf,
                                        origins.items[i].string,
-                                       strlen(origins.items[i].string));
+                                       strlen(origins.items[i].string),
+                                       comment_line_char);
                        fmt_tag_signature(&tagbuf, &sig, buf, len);
                }
                strbuf_release(&payload);
index 99054042dc5e574b2ef1c00394331955239e0324..73ca3e44652204867457092954d6f9d9ff04ad95 100644 (file)
@@ -13,7 +13,8 @@ struct fmt_merge_msg_opts {
 };
 
 extern int merge_log_config;
-int fmt_merge_msg_config(const char *key, const char *value, void *cb);
+int fmt_merge_msg_config(const char *key, const char *value,
+                        const struct config_context *ctx, void *cb);
 int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                  struct fmt_merge_msg_opts *);
 
diff --git a/fsck.c b/fsck.c
index 3261ef9ec28928974c6b555c05752511e63e484a..6a0bbc50877710ff22db33adec48f4a469143c37 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -1,8 +1,9 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "date.h"
+#include "dir.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
 #include "object.h"
 #include "attr.h"
@@ -23,6 +24,8 @@
 #include "credential.h"
 #include "help.h"
 
+static ssize_t max_tree_entry_len = 4096;
+
 #define STR(x) #x
 #define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
 static struct {
@@ -153,15 +156,29 @@ void fsck_set_msg_type(struct fsck_options *options,
                       const char *msg_id_str, const char *msg_type_str)
 {
        int msg_id = parse_msg_id(msg_id_str);
-       enum fsck_msg_type msg_type = parse_msg_type(msg_type_str);
+       char *to_free = NULL;
+       enum fsck_msg_type msg_type;
 
        if (msg_id < 0)
                die("Unhandled message id: %s", msg_id_str);
 
+       if (msg_id == FSCK_MSG_LARGE_PATHNAME) {
+               const char *colon = strchr(msg_type_str, ':');
+               if (colon) {
+                       msg_type_str = to_free =
+                               xmemdupz(msg_type_str, colon - msg_type_str);
+                       colon++;
+                       if (!git_parse_ssize_t(colon, &max_tree_entry_len))
+                               die("unable to parse max tree entry len: %s", colon);
+               }
+       }
+       msg_type = parse_msg_type(msg_type_str);
+
        if (msg_type != FSCK_ERROR && msg_id_info[msg_id].msg_type == FSCK_FATAL)
                die("Cannot demote %s to %s", msg_id_str, msg_type_str);
 
        fsck_set_msg_type_from_ids(options, msg_id, msg_type);
+       free(to_free);
 }
 
 void fsck_set_msg_types(struct fsck_options *options, const char *values)
@@ -577,6 +594,7 @@ static int fsck_tree(const struct object_id *tree_oid,
        int has_bad_modes = 0;
        int has_dup_entries = 0;
        int not_properly_sorted = 0;
+       int has_large_name = 0;
        struct tree_desc desc;
        unsigned o_mode;
        const char *o_name;
@@ -606,6 +624,7 @@ static int fsck_tree(const struct object_id *tree_oid,
                has_dotdot |= !strcmp(name, "..");
                has_dotgit |= is_hfs_dotgit(name) || is_ntfs_dotgit(name);
                has_zero_pad |= *(char *)desc.buffer == '0';
+               has_large_name |= tree_entry_len(&desc.entry) > max_tree_entry_len;
 
                if (is_hfs_dotgitmodules(name) || is_ntfs_dotgitmodules(name)) {
                        if (!S_ISLNK(mode))
@@ -748,6 +767,10 @@ static int fsck_tree(const struct object_id *tree_oid,
                retval += report(options, tree_oid, OBJ_TREE,
                                 FSCK_MSG_TREE_NOT_SORTED,
                                 "not properly sorted");
+       if (has_large_name)
+               retval += report(options, tree_oid, OBJ_TREE,
+                                FSCK_MSG_LARGE_PATHNAME,
+                                "contains excessively large pathname");
        return retval;
 }
 
@@ -1163,7 +1186,9 @@ struct fsck_gitmodules_data {
        int ret;
 };
 
-static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
+static int fsck_gitmodules_fn(const char *var, const char *value,
+                             const struct config_context *ctx UNUSED,
+                             void *vdata)
 {
        struct fsck_gitmodules_data *data = vdata;
        const char *subsection, *key;
@@ -1236,7 +1261,8 @@ static int fsck_blob(const struct object_id *oid, const char *buf,
                data.ret = 0;
                config_opts.error_action = CONFIG_ERROR_SILENT;
                if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
-                                       ".gitmodules", buf, size, &data, &config_opts))
+                                       ".gitmodules", buf, size, &data,
+                                       CONFIG_SCOPE_UNKNOWN, &config_opts))
                        data.ret |= report(options, oid, OBJ_BLOB,
                                        FSCK_MSG_GITMODULES_PARSE,
                                        "could not parse gitmodules blob");
@@ -1305,9 +1331,9 @@ int fsck_buffer(const struct object_id *oid, enum object_type type,
 
 int fsck_error_function(struct fsck_options *o,
                        const struct object_id *oid,
-                       enum object_type object_type,
+                       enum object_type object_type UNUSED,
                        enum fsck_msg_type msg_type,
-                       enum fsck_msg_id msg_id,
+                       enum fsck_msg_id msg_id UNUSED,
                        const char *message)
 {
        if (msg_type == FSCK_WARN) {
@@ -1373,7 +1399,8 @@ int fsck_finish(struct fsck_options *options)
        return ret;
 }
 
-int git_fsck_config(const char *var, const char *value, void *cb)
+int git_fsck_config(const char *var, const char *value,
+                   const struct config_context *ctx, void *cb)
 {
        struct fsck_options *options = cb;
        if (strcmp(var, "fsck.skiplist") == 0) {
@@ -1394,7 +1421,7 @@ int git_fsck_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
 
 /*
diff --git a/fsck.h b/fsck.h
index e17730e9da94053f39f1610e8cd81ab80bbf8a9f..e3adf9d91159878ae09b35a9fe12370fdbf85f98 100644 (file)
--- a/fsck.h
+++ b/fsck.h
@@ -73,6 +73,7 @@ enum fsck_msg_type {
        FUNC(NULL_SHA1, WARN) \
        FUNC(ZERO_PADDED_FILEMODE, WARN) \
        FUNC(NUL_IN_COMMIT, WARN) \
+       FUNC(LARGE_PATHNAME, WARN) \
        /* infos (reported as warnings, but ignored by default) */ \
        FUNC(BAD_FILEMODE, INFO) \
        FUNC(GITMODULES_PARSE, INFO) \
@@ -233,10 +234,12 @@ void fsck_put_object_name(struct fsck_options *options,
 const char *fsck_describe_object(struct fsck_options *options,
                                 const struct object_id *oid);
 
+struct key_value_info;
 /*
  * git_config() callback for use by fsck-y tools that want to support
  * fsck.<msg> fsck.skipList etc.
  */
-int git_fsck_config(const char *var, const char *value, void *cb);
+int git_fsck_config(const char *var, const char *value,
+                   const struct config_context *ctx, void *cb);
 
 #endif
index 70d776c54f6d142c2efd931cec140afaa91479f4..673f80d2aad0d4a2e0dff1f7f114f2fc7b5b653c 100644 (file)
@@ -99,7 +99,7 @@ struct fsmonitor_daemon_state {
  * to only mean an external GITDIR referenced by a ".git" file.
  *
  * The platform FS event backends will receive watch-specific
- * relative paths (except for those OS's that always emit absolute
+ * relative paths (except for those OSes that always emit absolute
  * paths).  We use the following enum and routines to classify each
  * path so that we know how to handle it.  There is a slight asymmetry
  * here because ".git/" is inside the working directory and the
index 6a6a89764a6e5c3d9059bbfeb8580df43a33e93a..153918cf768c48f4b9cad799cd728c45a152a8ad 100644 (file)
@@ -1,5 +1,5 @@
-#include "cache.h"
-#include "fsmonitor.h"
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
 #include "gettext.h"
 #include "simple-ipc.h"
 #include "fsmonitor-ipc.h"
@@ -20,7 +20,7 @@ int fsmonitor_ipc__is_supported(void)
        return 0;
 }
 
-const char *fsmonitor_ipc__get_path(struct repository *r)
+const char *fsmonitor_ipc__get_path(struct repository *r UNUSED)
 {
        return NULL;
 }
@@ -30,14 +30,14 @@ enum ipc_active_state fsmonitor_ipc__get_state(void)
        return IPC_STATE__OTHER_ERROR;
 }
 
-int fsmonitor_ipc__send_query(const char *since_token,
-                             struct strbuf *answer)
+int fsmonitor_ipc__send_query(const char *since_token UNUSED,
+                             struct strbuf *answer UNUSED)
 {
        return -1;
 }
 
-int fsmonitor_ipc__send_command(const char *command,
-                               struct strbuf *answer)
+int fsmonitor_ipc__send_command(const char *command UNUSED,
+                               struct strbuf *answer UNUSED)
 {
        return -1;
 }
diff --git a/fsmonitor-ll.h b/fsmonitor-ll.h
new file mode 100644 (file)
index 0000000..0504ca0
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef FSMONITOR_LL_H
+#define FSMONITOR_LL_H
+
+struct index_state;
+struct strbuf;
+
+extern struct trace_key trace_fsmonitor;
+
+/*
+ * Read the fsmonitor index extension and (if configured) restore the
+ * CE_FSMONITOR_VALID state.
+ */
+int read_fsmonitor_extension(struct index_state *istate, const void *data, unsigned long sz);
+
+/*
+ * Fill the fsmonitor_dirty ewah bits with their state from the index,
+ * before it is split during writing.
+ */
+void fill_fsmonitor_bitmap(struct index_state *istate);
+
+/*
+ * Write the CE_FSMONITOR_VALID state into the fsmonitor index
+ * extension.  Reads from the fsmonitor_dirty ewah in the index.
+ */
+void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate);
+
+/*
+ * Add/remove the fsmonitor index extension
+ */
+void add_fsmonitor(struct index_state *istate);
+void remove_fsmonitor(struct index_state *istate);
+
+/*
+ * Add/remove the fsmonitor index extension as necessary based on the current
+ * core.fsmonitor setting.
+ */
+void tweak_fsmonitor(struct index_state *istate);
+
+/*
+ * Run the configured fsmonitor integration script and clear the
+ * CE_FSMONITOR_VALID bit for any files returned as dirty.  Also invalidate
+ * any corresponding untracked cache directory structures. Optimized to only
+ * run the first time it is called.
+ */
+void refresh_fsmonitor(struct index_state *istate);
+
+/*
+ * Does the received result contain the "trivial" response?
+ */
+int fsmonitor_is_trivial_response(const struct strbuf *query_result);
+
+#endif /* FSMONITOR_LL_H */
index b62acf44aee2b9c029fac4389f6af7e4c4df6dab..a6a9e6bc199ec2ea0b608212da2f5b4a6edd94ed 100644 (file)
@@ -62,7 +62,8 @@ static enum fsmonitor_reason check_remote(struct repository *r)
 }
 #endif
 
-static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r,
+                                                   int ipc MAYBE_UNUSED)
 {
        if (!r->worktree) {
                /*
index 28c083d4d8417404bcf4efca872ac1106cf4a925..f670c50937898342f693708c706a0db270be3a6d 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "dir.h"
 #include "environment.h"
index c67e0ebc09bd52bc9cb0b65d054b1d9ef83003e1..5195a8624db82b27f8fbb533675b35e841a2a44b 100644 (file)
@@ -1,56 +1,13 @@
 #ifndef FSMONITOR_H
 #define FSMONITOR_H
 
-#include "cache.h"
+#include "fsmonitor-ll.h"
 #include "dir.h"
 #include "fsmonitor-settings.h"
+#include "object.h"
+#include "read-cache-ll.h"
 #include "trace.h"
 
-extern struct trace_key trace_fsmonitor;
-
-/*
- * Read the fsmonitor index extension and (if configured) restore the
- * CE_FSMONITOR_VALID state.
- */
-int read_fsmonitor_extension(struct index_state *istate, const void *data, unsigned long sz);
-
-/*
- * Fill the fsmonitor_dirty ewah bits with their state from the index,
- * before it is split during writing.
- */
-void fill_fsmonitor_bitmap(struct index_state *istate);
-
-/*
- * Write the CE_FSMONITOR_VALID state into the fsmonitor index
- * extension.  Reads from the fsmonitor_dirty ewah in the index.
- */
-void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate);
-
-/*
- * Add/remove the fsmonitor index extension
- */
-void add_fsmonitor(struct index_state *istate);
-void remove_fsmonitor(struct index_state *istate);
-
-/*
- * Add/remove the fsmonitor index extension as necessary based on the current
- * core.fsmonitor setting.
- */
-void tweak_fsmonitor(struct index_state *istate);
-
-/*
- * Run the configured fsmonitor integration script and clear the
- * CE_FSMONITOR_VALID bit for any files returned as dirty.  Also invalidate
- * any corresponding untracked cache directory structures. Optimized to only
- * run the first time it is called.
- */
-void refresh_fsmonitor(struct index_state *istate);
-
-/*
- * Does the received result contain the "trivial" response?
- */
-int fsmonitor_is_trivial_response(const struct strbuf *query_result);
-
 /*
  * Check if refresh_fsmonitor has been called at least once.
  * refresh_fsmonitor is idempotent. Returns true if fsmonitor is
index 5b2b99c17c564c5a5904442416e5d7d13f7b0568..3e7a59b5ff108dddce111cb372b6c846c093b4be 100644 (file)
@@ -422,6 +422,10 @@ char *gitdirname(char *);
 #define PATH_MAX 4096
 #endif
 
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
 typedef uintmax_t timestamp_t;
 #define PRItime PRIuMAX
 #define parse_timestamp strtoumax
@@ -440,8 +444,10 @@ typedef uintmax_t timestamp_t;
 #endif
 
 #ifndef platform_core_config
+struct config_context;
 static inline int noop_core_config(const char *var UNUSED,
                                   const char *value UNUSED,
+                                  const struct config_context *ctx UNUSED,
                                   void *cb UNUSED)
 {
        return 0;
@@ -625,9 +631,7 @@ static inline int git_has_dir_sep(const char *path)
 
 #include "compat/bswap.h"
 
-#include "wildmatch.h"
-
-struct strbuf;
+#include "wrapper.h"
 
 /* General helper functions */
 NORETURN void usage(const char *err);
@@ -679,9 +683,6 @@ void set_warn_routine(report_fn routine);
 report_fn get_warn_routine(void);
 void set_die_is_recursing_routine(int (*routine)(void));
 
-int starts_with(const char *str, const char *prefix);
-int istarts_with(const char *str, const char *prefix);
-
 /*
  * If the string "str" begins with the string found in "prefix", return 1.
  * The "out" parameter is set to "str + strlen(prefix)" (i.e., to the point in
@@ -710,29 +711,6 @@ static inline int skip_prefix(const char *str, const char *prefix,
        return 0;
 }
 
-/*
- * If the string "str" is the same as the string in "prefix", then the "arg"
- * parameter is set to the "def" parameter and 1 is returned.
- * If the string "str" begins with the string found in "prefix" and then a
- * "=" sign, then the "arg" parameter is set to "str + strlen(prefix) + 1"
- * (i.e., to the point in the string right after the prefix and the "=" sign),
- * and 1 is returned.
- *
- * Otherwise, return 0 and leave "arg" untouched.
- *
- * When we accept both a "--key" and a "--key=<val>" option, this function
- * can be used instead of !strcmp(arg, "--key") and then
- * skip_prefix(arg, "--key=", &arg) to parse such an option.
- */
-int skip_to_optional_arg_default(const char *str, const char *prefix,
-                                const char **arg, const char *def);
-
-static inline int skip_to_optional_arg(const char *str, const char *prefix,
-                                      const char **arg)
-{
-       return skip_to_optional_arg_default(str, prefix, arg, "");
-}
-
 /*
  * Like skip_prefix, but promises never to read past "len" bytes of the input
  * buffer, and returns the remaining number of bytes in "out" via "outlen".
@@ -777,12 +755,6 @@ static inline int strip_suffix(const char *str, const char *suffix, size_t *len)
        return strip_suffix_mem(str, len, suffix);
 }
 
-static inline int ends_with(const char *str, const char *suffix)
-{
-       size_t len;
-       return strip_suffix(str, suffix, &len);
-}
-
 #define SWAP(a, b) do {                                                \
        void *_swap_a_ptr = &(a);                               \
        void *_swap_b_ptr = &(b);                               \
@@ -1079,36 +1051,6 @@ static inline int cast_size_t_to_int(size_t a)
 # define xalloca(size)      (xmalloc(size))
 # define xalloca_free(p)    (free(p))
 #endif
-char *xstrdup(const char *str);
-void *xmalloc(size_t size);
-void *xmallocz(size_t size);
-void *xmallocz_gently(size_t size);
-void *xmemdupz(const void *data, size_t len);
-char *xstrndup(const char *str, size_t len);
-void *xrealloc(void *ptr, size_t size);
-void *xcalloc(size_t nmemb, size_t size);
-void xsetenv(const char *name, const char *value, int overwrite);
-void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
-const char *mmap_os_err(void);
-void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset);
-int xopen(const char *path, int flags, ...);
-ssize_t xread(int fd, void *buf, size_t len);
-ssize_t xwrite(int fd, const void *buf, size_t len);
-ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
-int xdup(int fd);
-FILE *xfopen(const char *path, const char *mode);
-FILE *xfdopen(int fd, const char *mode);
-int xmkstemp(char *temp_filename);
-int xmkstemp_mode(char *temp_filename, int mode);
-char *xgetcwd(void);
-FILE *fopen_for_writing(const char *path);
-FILE *fopen_or_warn(const char *path, const char *mode);
-
-/*
- * Like strncmp, but only return zero if s is NUL-terminated and exactly len
- * characters long.  If it is not, consider it greater than t.
- */
-int xstrncmpz(const char *s, const char *t, size_t len);
 
 /*
  * FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
@@ -1198,6 +1140,81 @@ static inline void move_array(void *dst, const void *src, size_t n, size_t size)
 #define FLEXPTR_ALLOC_STR(x, ptrname, str) \
        FLEXPTR_ALLOC_MEM((x), ptrname, (str), strlen(str))
 
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/**
+ * Dynamically growing an array using realloc() is error prone and boring.
+ *
+ * Define your array with:
+ *
+ * - a pointer (`item`) that points at the array, initialized to `NULL`
+ *   (although please name the variable based on its contents, not on its
+ *   type);
+ *
+ * - an integer variable (`alloc`) that keeps track of how big the current
+ *   allocation is, initialized to `0`;
+ *
+ * - another integer variable (`nr`) to keep track of how many elements the
+ *   array currently has, initialized to `0`.
+ *
+ * Then before adding `n`th element to the item, call `ALLOC_GROW(item, n,
+ * alloc)`.  This ensures that the array can hold at least `n` elements by
+ * calling `realloc(3)` and adjusting `alloc` variable.
+ *
+ * ------------
+ * sometype *item;
+ * size_t nr;
+ * size_t alloc
+ *
+ * for (i = 0; i < nr; i++)
+ *     if (we like item[i] already)
+ *             return;
+ *
+ * // we did not like any existing one, so add one
+ * ALLOC_GROW(item, nr + 1, alloc);
+ * item[nr++] = value you like;
+ * ------------
+ *
+ * You are responsible for updating the `nr` variable.
+ *
+ * If you need to specify the number of elements to allocate explicitly
+ * then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
+ *
+ * Consider using ALLOC_GROW_BY instead of ALLOC_GROW as it has some
+ * added niceties.
+ *
+ * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+       do { \
+               if ((nr) > alloc) { \
+                       if (alloc_nr(alloc) < (nr)) \
+                               alloc = (nr); \
+                       else \
+                               alloc = alloc_nr(alloc); \
+                       REALLOC_ARRAY(x, alloc); \
+               } \
+       } while (0)
+
+/*
+ * Similar to ALLOC_GROW but handles updating of the nr value and
+ * zeroing the bytes of the newly-grown array elements.
+ *
+ * DO NOT USE any expression with side-effect for any of the
+ * arguments.
+ */
+#define ALLOC_GROW_BY(x, nr, increase, alloc) \
+       do { \
+               if (increase) { \
+                       size_t new_nr = nr + (increase); \
+                       if (new_nr < nr) \
+                               BUG("negative growth in ALLOC_GROW_BY"); \
+                       ALLOC_GROW(x, new_nr, alloc); \
+                       memset((x) + nr, 0, sizeof(*(x)) * (increase)); \
+                       nr = new_nr; \
+               } \
+       } while (0)
+
 static inline char *xstrdup_or_null(const char *str)
 {
        return str ? xstrdup(str) : NULL;
@@ -1210,79 +1227,11 @@ static inline size_t xsize_t(off_t len)
        return (size_t) len;
 }
 
-__attribute__((format (printf, 3, 4)))
-int xsnprintf(char *dst, size_t max, const char *fmt, ...);
-
 #ifndef HOST_NAME_MAX
 #define HOST_NAME_MAX 256
 #endif
 
-int xgethostname(char *buf, size_t len);
-
-/* in ctype.c, for kwset users */
-extern const unsigned char tolower_trans_tbl[256];
-
-/* Sane ctype - no locale, and works with signed chars */
-#undef isascii
-#undef isspace
-#undef isdigit
-#undef isalpha
-#undef isalnum
-#undef isprint
-#undef islower
-#undef isupper
-#undef tolower
-#undef toupper
-#undef iscntrl
-#undef ispunct
-#undef isxdigit
-
-extern const unsigned char sane_ctype[256];
-extern const signed char hexval_table[256];
-#define GIT_SPACE 0x01
-#define GIT_DIGIT 0x02
-#define GIT_ALPHA 0x04
-#define GIT_GLOB_SPECIAL 0x08
-#define GIT_REGEX_SPECIAL 0x10
-#define GIT_PATHSPEC_MAGIC 0x20
-#define GIT_CNTRL 0x40
-#define GIT_PUNCT 0x80
-#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
-#define isascii(x) (((x) & ~0x7f) == 0)
-#define isspace(x) sane_istest(x,GIT_SPACE)
-#define isdigit(x) sane_istest(x,GIT_DIGIT)
-#define isalpha(x) sane_istest(x,GIT_ALPHA)
-#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
-#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e)
-#define islower(x) sane_iscase(x, 1)
-#define isupper(x) sane_iscase(x, 0)
-#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
-#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
-#define iscntrl(x) (sane_istest(x,GIT_CNTRL))
-#define ispunct(x) sane_istest(x, GIT_PUNCT | GIT_REGEX_SPECIAL | \
-               GIT_GLOB_SPECIAL | GIT_PATHSPEC_MAGIC)
-#define isxdigit(x) (hexval_table[(unsigned char)(x)] != -1)
-#define tolower(x) sane_case((unsigned char)(x), 0x20)
-#define toupper(x) sane_case((unsigned char)(x), 0)
-#define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC)
-
-static inline int sane_case(int x, int high)
-{
-       if (sane_istest(x, GIT_ALPHA))
-               x = (x & ~0x20) | high;
-       return x;
-}
-
-static inline int sane_iscase(int x, int is_lower)
-{
-       if (!sane_istest(x, GIT_ALPHA))
-               return 0;
-
-       if (is_lower)
-               return (x & 0x20) != 0;
-       else
-               return (x & 0x20) == 0;
-}
+#include "sane-ctype.h"
 
 /*
  * Like skip_prefix, but compare case-insensitively. Note that the comparison
@@ -1459,72 +1408,6 @@ void bug_fl(const char *file, int line, const char *fmt, ...);
 #endif
 #endif
 
-enum fsync_action {
-       FSYNC_WRITEOUT_ONLY,
-       FSYNC_HARDWARE_FLUSH
-};
-
-/*
- * Issues an fsync against the specified file according to the specified mode.
- *
- * FSYNC_WRITEOUT_ONLY attempts to use interfaces available on some operating
- * systems to flush the OS cache without issuing a flush command to the storage
- * controller. If those interfaces are unavailable, the function fails with
- * ENOSYS.
- *
- * FSYNC_HARDWARE_FLUSH does an OS writeout and hardware flush to ensure that
- * changes are durable. It is not expected to fail.
- */
-int git_fsync(int fd, enum fsync_action action);
-
-/*
- * Writes out trace statistics for fsync using the trace2 API.
- */
-void trace_git_fsync_stats(void);
-
-/*
- * Preserves errno, prints a message, but gives no warning for ENOENT.
- * Returns 0 on success, which includes trying to unlink an object that does
- * not exist.
- */
-int unlink_or_warn(const char *path);
- /*
-  * Tries to unlink file.  Returns 0 if unlink succeeded
-  * or the file already didn't exist.  Returns -1 and
-  * appends a message to err suitable for
-  * 'error("%s", err->buf)' on error.
-  */
-int unlink_or_msg(const char *file, struct strbuf *err);
-/*
- * Preserves errno, prints a message, but gives no warning for ENOENT.
- * Returns 0 on success, which includes trying to remove a directory that does
- * not exist.
- */
-int rmdir_or_warn(const char *path);
-/*
- * Calls the correct function out of {unlink,rmdir}_or_warn based on
- * the supplied file mode.
- */
-int remove_or_warn(unsigned int mode, const char *path);
-
-/*
- * Call access(2), but warn for any error except "missing file"
- * (ENOENT or ENOTDIR).
- */
-#define ACCESS_EACCES_OK (1U << 0)
-int access_or_warn(const char *path, int mode, unsigned flag);
-int access_or_die(const char *path, int mode, unsigned flag);
-
-/* Warn on an inaccessible file if errno indicates this is an error */
-int warn_on_fopen_errors(const char *path);
-
-/*
- * Open with O_NOFOLLOW, or equivalent. Note that the fallback equivalent
- * may be racy. Do not use this as protection against an attacker who can
- * simultaneously create paths.
- */
-int open_nofollow(const char *path, int flags);
-
 #ifndef SHELL_PATH
 # define SHELL_PATH "/bin/sh"
 #endif
@@ -1664,13 +1547,4 @@ static inline void *container_of_or_null_offset(void *ptr, size_t offset)
        ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr))
 #endif /* !__GNUC__ */
 
-void sleep_millisec(int millisec);
-
-/*
- * Generate len bytes from the system cryptographically secure PRNG.
- * Returns 0 on success and -1 on error, setting errno.  The inability to
- * satisfy the full request is an error.
- */
-int csprng_bytes(void *buf, size_t len);
-
 #endif
index a0d5a4b28e171542a0bfca2a3e833607aa47d409..3f80435436c11d2f36ee626450ae72697570ca8e 100644 (file)
@@ -138,25 +138,10 @@ GITGUI_SCRIPT   := $$0
 GITGUI_RELATIVE :=
 GITGUI_MACOSXAPP :=
 
-ifeq ($(uname_O),Cygwin)
-       GITGUI_SCRIPT := `cygpath --windows --absolute "$(GITGUI_SCRIPT)"`
-
-       # Is this a Cygwin Tcl/Tk binary?  If so it knows how to do
-       # POSIX path translation just like cygpath does and we must
-       # keep libdir in POSIX format so Cygwin packages of git-gui
-       # work no matter where the user installs them.
-       #
-       ifeq ($(shell echo 'puts [file normalize /]' | '$(TCL_PATH_SQ)'),$(shell cygpath --mixed --absolute /))
-               gg_libdir_sed_in := $(gg_libdir)
-       else
-               gg_libdir_sed_in := $(shell cygpath --windows --absolute "$(gg_libdir)")
-       endif
-else
-       ifeq ($(exedir),$(gg_libdir))
-               GITGUI_RELATIVE := 1
-       endif
-       gg_libdir_sed_in := $(gg_libdir)
+ifeq ($(exedir),$(gg_libdir))
+       GITGUI_RELATIVE := 1
 endif
+gg_libdir_sed_in := $(gg_libdir)
 ifeq ($(uname_S),Darwin)
        ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y)
                GITGUI_MACOSXAPP := YesPlease
index 5ce2122fbc618384f66f4e1f08f98bca047db1c0..b460b649a8ccfec587dab03fb3c516007ab1a060 100644 (file)
@@ -88,7 +88,7 @@ that you first use `git-format-patch` to generate the emails, audit them, and
 then send them via `git-send-email`.
 
 A pretty good guide to configuring and using `git-send-email` can be found
-[here](https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/)
+[here](https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/).
 
 ### Using your email client
 
index 201524c34edac053f908c927a00270a7b1fdc09a..3e5907a4609b1510aef71ab54f56a82eeb36e071 100755 (executable)
@@ -44,6 +44,132 @@ if {[catch {package require Tcl 8.5} err]
 
 catch {rename send {}} ; # What an evil concept...
 
+######################################################################
+##
+## Enabling platform-specific code paths
+
+proc is_MacOSX {} {
+       if {[tk windowingsystem] eq {aqua}} {
+               return 1
+       }
+       return 0
+}
+
+proc is_Windows {} {
+       if {$::tcl_platform(platform) eq {windows}} {
+               return 1
+       }
+       return 0
+}
+
+set _iscygwin {}
+proc is_Cygwin {} {
+       global _iscygwin
+       if {$_iscygwin eq {}} {
+               if {[string match "CYGWIN_*" $::tcl_platform(os)]} {
+                       set _iscygwin 1
+               } else {
+                       set _iscygwin 0
+               }
+       }
+       return $_iscygwin
+}
+
+######################################################################
+##
+## PATH lookup
+
+set _search_path {}
+proc _which {what args} {
+       global env _search_exe _search_path
+
+       if {$_search_path eq {}} {
+               if {[is_Windows]} {
+                       set gitguidir [file dirname [info script]]
+                       regsub -all ";" $gitguidir "\\;" gitguidir
+                       set env(PATH) "$gitguidir;$env(PATH)"
+                       set _search_path [split $env(PATH) {;}]
+                       # Skip empty `PATH` elements
+                       set _search_path [lsearch -all -inline -not -exact \
+                               $_search_path ""]
+                       set _search_exe .exe
+               } else {
+                       set _search_path [split $env(PATH) :]
+                       set _search_exe {}
+               }
+       }
+
+       if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
+               set suffix {}
+       } else {
+               set suffix $_search_exe
+       }
+
+       foreach p $_search_path {
+               set p [file join $p $what$suffix]
+               if {[file exists $p]} {
+                       return [file normalize $p]
+               }
+       }
+       return {}
+}
+
+proc sanitize_command_line {command_line from_index} {
+       set i $from_index
+       while {$i < [llength $command_line]} {
+               set cmd [lindex $command_line $i]
+               if {[llength [file split $cmd]] < 2} {
+                       set fullpath [_which $cmd]
+                       if {$fullpath eq ""} {
+                               throw {NOT-FOUND} "$cmd not found in PATH"
+                       }
+                       lset command_line $i $fullpath
+               }
+
+               # handle piped commands, e.g. `exec A | B`
+               for {incr i} {$i < [llength $command_line]} {incr i} {
+                       if {[lindex $command_line $i] eq "|"} {
+                               incr i
+                               break
+                       }
+               }
+       }
+       return $command_line
+}
+
+# Override `exec` to avoid unsafe PATH lookup
+
+rename exec real_exec
+
+proc exec {args} {
+       # skip options
+       for {set i 0} {$i < [llength $args]} {incr i} {
+               set arg [lindex $args $i]
+               if {$arg eq "--"} {
+                       incr i
+                       break
+               }
+               if {[string range $arg 0 0] ne "-"} {
+                       break
+               }
+       }
+       set args [sanitize_command_line $args $i]
+       uplevel 1 real_exec $args
+}
+
+# Override `open` to avoid unsafe PATH lookup
+
+rename open real_open
+
+proc open {args} {
+       set arg0 [lindex $args 0]
+       if {[string range $arg0 0 0] eq "|"} {
+               set command_line [string trim [string range $arg0 1 end]]
+               lset args 0 "| [sanitize_command_line $command_line 0]"
+       }
+       uplevel 1 real_open $args
+}
+
 ######################################################################
 ##
 ## locate our library
@@ -163,8 +289,6 @@ set _isbare {}
 set _gitexec {}
 set _githtmldir {}
 set _reponame {}
-set _iscygwin {}
-set _search_path {}
 set _shellpath {@@SHELL_PATH@@}
 
 set _trace [lsearch -exact $argv --trace]
@@ -211,14 +335,7 @@ proc gitexec {args} {
                if {[catch {set _gitexec [git --exec-path]} err]} {
                        error "Git not installed?\n\n$err"
                }
-               if {[is_Cygwin]} {
-                       set _gitexec [exec cygpath \
-                               --windows \
-                               --absolute \
-                               $_gitexec]
-               } else {
-                       set _gitexec [file normalize $_gitexec]
-               }
+               set _gitexec [file normalize $_gitexec]
        }
        if {$args eq {}} {
                return $_gitexec
@@ -233,14 +350,7 @@ proc githtmldir {args} {
                        # Git not installed or option not yet supported
                        return {}
                }
-               if {[is_Cygwin]} {
-                       set _githtmldir [exec cygpath \
-                               --windows \
-                               --absolute \
-                               $_githtmldir]
-               } else {
-                       set _githtmldir [file normalize $_githtmldir]
-               }
+               set _githtmldir [file normalize $_githtmldir]
        }
        if {$args eq {}} {
                return $_githtmldir
@@ -252,40 +362,6 @@ proc reponame {} {
        return $::_reponame
 }
 
-proc is_MacOSX {} {
-       if {[tk windowingsystem] eq {aqua}} {
-               return 1
-       }
-       return 0
-}
-
-proc is_Windows {} {
-       if {$::tcl_platform(platform) eq {windows}} {
-               return 1
-       }
-       return 0
-}
-
-proc is_Cygwin {} {
-       global _iscygwin
-       if {$_iscygwin eq {}} {
-               if {$::tcl_platform(platform) eq {windows}} {
-                       if {[catch {set p [exec cygpath --windir]} err]} {
-                               set _iscygwin 0
-                       } else {
-                               set _iscygwin 1
-                               # Handle MSys2 which is only cygwin when MSYSTEM is MSYS.
-                               if {[info exists ::env(MSYSTEM)] && $::env(MSYSTEM) ne "MSYS"} {
-                                       set _iscygwin 0
-                               }
-                       }
-               } else {
-                       set _iscygwin 0
-               }
-       }
-       return $_iscygwin
-}
-
 proc is_enabled {option} {
        global enabled_options
        if {[catch {set on $enabled_options($option)}]} {return 0}
@@ -448,44 +524,6 @@ proc _git_cmd {name} {
        return $v
 }
 
-proc _which {what args} {
-       global env _search_exe _search_path
-
-       if {$_search_path eq {}} {
-               if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} {
-                       set _search_path [split [exec cygpath \
-                               --windows \
-                               --path \
-                               --absolute \
-                               $env(PATH)] {;}]
-                       set _search_exe .exe
-               } elseif {[is_Windows]} {
-                       set gitguidir [file dirname [info script]]
-                       regsub -all ";" $gitguidir "\\;" gitguidir
-                       set env(PATH) "$gitguidir;$env(PATH)"
-                       set _search_path [split $env(PATH) {;}]
-                       set _search_exe .exe
-               } else {
-                       set _search_path [split $env(PATH) :]
-                       set _search_exe {}
-               }
-       }
-
-       if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
-               set suffix {}
-       } else {
-               set suffix $_search_exe
-       }
-
-       foreach p $_search_path {
-               set p [file join $p $what$suffix]
-               if {[file exists $p]} {
-                       return [file normalize $p]
-               }
-       }
-       return {}
-}
-
 # Test a file for a hashbang to identify executable scripts on Windows.
 proc is_shellscript {filename} {
        if {![file exists $filename]} {return 0}
@@ -623,31 +661,8 @@ proc git_write {args} {
 }
 
 proc githook_read {hook_name args} {
-       set pchook [gitdir hooks $hook_name]
-       lappend args 2>@1
-
-       # On Windows [file executable] might lie so we need to ask
-       # the shell if the hook is executable.  Yes that's annoying.
-       #
-       if {[is_Windows]} {
-               upvar #0 _sh interp
-               if {![info exists interp]} {
-                       set interp [_which sh]
-               }
-               if {$interp eq {}} {
-                       error "hook execution requires sh (not in PATH)"
-               }
-
-               set scr {if test -x "$1";then exec "$@";fi}
-               set sh_c [list $interp -c $scr $interp $pchook]
-               return [_open_stdout_stderr [concat $sh_c $args]]
-       }
-
-       if {[file executable $pchook]} {
-               return [_open_stdout_stderr [concat [list $pchook] $args]]
-       }
-
-       return {}
+       set cmd [concat git hook run --ignore-missing $hook_name -- $args 2>@1]
+       return [_open_stdout_stderr $cmd]
 }
 
 proc kill_file_process {fd} {
@@ -1259,9 +1274,6 @@ if {$_gitdir eq "."} {
        set _gitdir [pwd]
 }
 
-if {![file isdirectory $_gitdir] && [is_Cygwin]} {
-       catch {set _gitdir [exec cygpath --windows $_gitdir]}
-}
 if {![file isdirectory $_gitdir]} {
        catch {wm withdraw .}
        error_popup [strcat [mc "Git directory not found:"] "\n\n$_gitdir"]
@@ -1273,11 +1285,7 @@ apply_config
 
 # v1.7.0 introduced --show-toplevel to return the canonical work-tree
 if {[package vcompare $_git_version 1.7.0] >= 0} {
-       if { [is_Cygwin] } {
-               catch {set _gitworktree [exec cygpath --windows [git rev-parse --show-toplevel]]}
-       } else {
-               set _gitworktree [git rev-parse --show-toplevel]
-       }
+       set _gitworktree [git rev-parse --show-toplevel]
 } else {
        # try to set work tree from environment, core.worktree or use
        # cdup to obtain a relative path to the top of the worktree. If
@@ -1502,24 +1510,8 @@ proc rescan {after {honor_trustmtime 1}} {
        }
 }
 
-if {[is_Cygwin]} {
-       set is_git_info_exclude {}
-       proc have_info_exclude {} {
-               global is_git_info_exclude
-
-               if {$is_git_info_exclude eq {}} {
-                       if {[catch {exec test -f [gitdir info exclude]}]} {
-                               set is_git_info_exclude 0
-                       } else {
-                               set is_git_info_exclude 1
-                       }
-               }
-               return $is_git_info_exclude
-       }
-} else {
-       proc have_info_exclude {} {
-               return [file readable [gitdir info exclude]]
-       }
+proc have_info_exclude {} {
+       return [file readable [gitdir info exclude]]
 }
 
 proc rescan_stage2 {fd after} {
@@ -2259,7 +2251,9 @@ proc do_git_gui {} {
 
 # Get the system-specific explorer app/command.
 proc get_explorer {} {
-       if {[is_Cygwin] || [is_Windows]} {
+       if {[is_Cygwin]} {
+               set explorer "/bin/cygstart.exe --explore"
+       } elseif {[is_Windows]} {
                set explorer "explorer.exe"
        } elseif {[is_MacOSX]} {
                set explorer "open"
@@ -3053,10 +3047,6 @@ if {[is_MacOSX]} {
 set doc_path [githtmldir]
 if {$doc_path ne {}} {
        set doc_path [file join $doc_path index.html]
-
-       if {[is_Cygwin]} {
-               set doc_path [exec cygpath --mixed $doc_path]
-       }
 }
 
 if {[file isfile $doc_path]} {
@@ -4028,60 +4018,6 @@ set file_lists($ui_workdir) [list]
 wm title . "[appname] ([reponame]) [file normalize $_gitworktree]"
 focus -force $ui_comm
 
-# -- Warn the user about environmental problems.  Cygwin's Tcl
-#    does *not* pass its env array onto any processes it spawns.
-#    This means that git processes get none of our environment.
-#
-if {[is_Cygwin]} {
-       set ignored_env 0
-       set suggest_user {}
-       set msg [mc "Possible environment issues exist.
-
-The following environment variables are probably
-going to be ignored by any Git subprocess run
-by %s:
-
-" [appname]]
-       foreach name [array names env] {
-               switch -regexp -- $name {
-               {^GIT_INDEX_FILE$} -
-               {^GIT_OBJECT_DIRECTORY$} -
-               {^GIT_ALTERNATE_OBJECT_DIRECTORIES$} -
-               {^GIT_DIFF_OPTS$} -
-               {^GIT_EXTERNAL_DIFF$} -
-               {^GIT_PAGER$} -
-               {^GIT_TRACE$} -
-               {^GIT_CONFIG$} -
-               {^GIT_(AUTHOR|COMMITTER)_DATE$} {
-                       append msg " - $name\n"
-                       incr ignored_env
-               }
-               {^GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL)$} {
-                       append msg " - $name\n"
-                       incr ignored_env
-                       set suggest_user $name
-               }
-               }
-       }
-       if {$ignored_env > 0} {
-               append msg [mc "
-This is due to a known issue with the
-Tcl binary distributed by Cygwin."]
-
-               if {$suggest_user ne {}} {
-                       append msg [mc "
-
-A good replacement for %s
-is placing values for the user.name and
-user.email settings into your personal
-~/.gitconfig file.
-" $suggest_user]
-               }
-               warn_popup $msg
-       }
-       unset ignored_env msg suggest_user name
-}
-
 # -- Only initialize complex UI if we are going to stay running.
 #
 if {[is_enabled transport]} {
index af1fee7c751dc635bcc9c621161dc3558f297cb8..d23abedcb36fd93ab3f12694d607bf354d6cf208 100644 (file)
@@ -174,9 +174,6 @@ constructor pick {} {
                        -foreground blue \
                        -underline 1
                set home $::env(HOME)
-               if {[is_Cygwin]} {
-                       set home [exec cygpath --windows --absolute $home]
-               }
                set home "[file normalize $home]/"
                set hlen [string length $home]
                foreach p $sorted_recent {
@@ -374,18 +371,6 @@ proc _objdir {path} {
                return $objdir
        }
 
-       if {[is_Cygwin]} {
-               set objdir [file join $path .git objects.lnk]
-               if {[file isfile $objdir]} {
-                       return [win32_read_lnk $objdir]
-               }
-
-               set objdir [file join $path objects.lnk]
-               if {[file isfile $objdir]} {
-                       return [win32_read_lnk $objdir]
-               }
-       }
-
        return {}
 }
 
@@ -623,12 +608,6 @@ method _do_clone2 {} {
        }
 
        set giturl $origin_url
-       if {[is_Cygwin] && [file isdirectory $giturl]} {
-               set giturl [exec cygpath --unix --absolute $giturl]
-               if {$clone_type eq {shared}} {
-                       set objdir [exec cygpath --unix --absolute $objdir]
-               }
-       }
 
        if {[file exists $local_path]} {
                error_popup [mc "Location %s already exists." $local_path]
@@ -668,11 +647,7 @@ method _do_clone2 {} {
                                fconfigure $f_cp -translation binary -encoding binary
                                cd $objdir
                                while {[gets $f_in line] >= 0} {
-                                       if {[is_Cygwin]} {
-                                               puts $f_cp [exec cygpath --unix --absolute $line]
-                                       } else {
-                                               puts $f_cp [file normalize $line]
-                                       }
+                                       puts $f_cp [file normalize $line]
                                }
                                close $f_in
                                close $f_cp
index 97d1d7aa02686606912dd5ff7b512343083a17c0..674a41f5e0c868b70d84202381fec8b5919f962f 100644 (file)
@@ -27,13 +27,10 @@ proc do_windows_shortcut {} {
 }
 
 proc do_cygwin_shortcut {} {
-       global argv0 _gitworktree
+       global argv0 _gitworktree oguilib
 
        if {[catch {
                set desktop [exec cygpath \
-                       --windows \
-                       --absolute \
-                       --long-name \
                        --desktop]
                }]} {
                        set desktop .
@@ -48,19 +45,19 @@ proc do_cygwin_shortcut {} {
                        set fn ${fn}.lnk
                }
                if {[catch {
-                               set sh [exec cygpath \
-                                       --windows \
-                                       --absolute \
-                                       /bin/sh.exe]
-                               set me [exec cygpath \
-                                       --unix \
-                                       --absolute \
-                                       $argv0]
-                               win32_create_lnk $fn [list \
-                                       $sh -c \
-                                       "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \
-                                       ] \
-                                       [file normalize $_gitworktree]
+                               set repodir [file normalize $_gitworktree]
+                               set shargs {-c \
+                                       "CHERE_INVOKING=1 \
+                                       source /etc/profile; \
+                                       git gui"}
+                               exec /bin/mkshortcut.exe \
+                                       --arguments $shargs \
+                                       --desc "git-gui on $repodir" \
+                                       --icon $oguilib/git-gui.ico \
+                                       --name $fn \
+                                       --show min \
+                                       --workingdir $repodir \
+                                       /bin/sh.exe
                        } err]} {
                        error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"]
                }
index d26a980e5acb66eda31d32e075d90736bcac4e3a..0eb3bb4c47dcf12a9f1d98e1b76a3681197ac52e 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -1522,6 +1522,10 @@ class LargeFileSystem(object):
            file is stored in the large file system and handles all necessary
            steps.
            """
+        # symlinks aren't processed by smudge/clean filters
+        if git_mode == "120000":
+            return (git_mode, contents)
+
         if self.exceedsLargeFileThreshold(relPath, contents) or self.hasLargeFileExtension(relPath):
             contentTempFile = self.generateTempFile(contents)
             pointer_git_mode, contents, localLargeFile = self.generatePointer(contentTempFile)
index 76b28ed76454fe02996c8748dfef481be0875186..cacdbd6bb2e41823994071fc936148dab806f7c2 100755 (executable)
@@ -26,18 +26,6 @@ use Git::I18N;
 
 Getopt::Long::Configure qw/ pass_through /;
 
-package FakeTerm;
-sub new {
-       my ($class, $reason) = @_;
-       return bless \$reason, shift;
-}
-sub readline {
-       my $self = shift;
-       die "Cannot use readline on FakeTerm: $$self";
-}
-package main;
-
-
 sub usage {
        print <<EOT;
 git send-email' [<options>] <file|directory>
@@ -849,6 +837,9 @@ if ($compose) {
        my $tpl_subject = $initial_subject || '';
        my $tpl_in_reply_to = $initial_in_reply_to || '';
        my $tpl_reply_to = $reply_to || '';
+       my $tpl_to = join(',', @initial_to);
+       my $tpl_cc = join(',', @initial_cc);
+       my $tpl_bcc = join(', ', @initial_bcc);
 
        print $c <<EOT1, Git::prefix_lines("GIT: ", __(<<EOT2)), <<EOT3;
 From $tpl_sender # This line is ignored.
@@ -860,6 +851,9 @@ for the patch you are writing.
 Clear the body content if you don't wish to send a summary.
 EOT2
 From: $tpl_sender
+To: $tpl_to
+Cc: $tpl_cc
+Bcc: $tpl_bcc
 Reply-To: $tpl_reply_to
 Subject: $tpl_subject
 In-Reply-To: $tpl_in_reply_to
@@ -876,88 +870,82 @@ EOT3
                do_edit($compose_filename);
        }
 
+       open my $c2, ">", $compose_filename . ".final"
+               or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
+
        open $c, "<", $compose_filename
                or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
 
+       my $need_8bit_cte = file_has_nonascii($compose_filename);
+       my $in_body = 0;
+       my $summary_empty = 1;
        if (!defined $compose_encoding) {
                $compose_encoding = "UTF-8";
        }
-
-       my %parsed_email;
-       while (my $line = <$c>) {
-               next if $line =~ m/^GIT:/;
-               parse_header_line($line, \%parsed_email);
-               if ($line =~ /^$/) {
-                       $parsed_email{'body'} = filter_body($c);
+       while(<$c>) {
+               next if m/^GIT:/;
+               if ($in_body) {
+                       $summary_empty = 0 unless (/^\n$/);
+               } elsif (/^\n$/) {
+                       $in_body = 1;
+                       if ($need_8bit_cte) {
+                               print $c2 "MIME-Version: 1.0\n",
+                                        "Content-Type: text/plain; ",
+                                          "charset=$compose_encoding\n",
+                                        "Content-Transfer-Encoding: 8bit\n";
+                       }
+               } elsif (/^MIME-Version:/i) {
+                       $need_8bit_cte = 0;
+               } elsif (/^Subject:\s*(.+)\s*$/i) {
+                       $initial_subject = $1;
+                       my $subject = $initial_subject;
+                       $_ = "Subject: " .
+                               quote_subject($subject, $compose_encoding) .
+                               "\n";
+               } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
+                       $initial_in_reply_to = $1;
+                       next;
+               } elsif (/^Reply-To:\s*(.+)\s*$/i) {
+                       $reply_to = $1;
+               } elsif (/^From:\s*(.+)\s*$/i) {
+                       $sender = $1;
+                       next;
+               } elsif (/^To:\s*(.+)\s*$/i) {
+                       @initial_to = parse_address_line($1);
+                       next;
+               } elsif (/^Cc:\s*(.+)\s*$/i) {
+                       @initial_cc = parse_address_line($1);
+                       next;
+               } elsif (/^Bcc:/i) {
+                       @initial_bcc = parse_address_line($1);
+                       next;
                }
+               print $c2 $_;
        }
        close $c;
+       close $c2;
 
-       open my $c2, ">", $compose_filename . ".final"
-       or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
-
-
-       if ($parsed_email{'From'}) {
-               $sender = delete($parsed_email{'From'});
-       }
-       if ($parsed_email{'In-Reply-To'}) {
-               $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
-       }
-       if ($parsed_email{'Reply-To'}) {
-               $reply_to = delete($parsed_email{'Reply-To'});
-       }
-       if ($parsed_email{'Subject'}) {
-               $initial_subject = delete($parsed_email{'Subject'});
-               print $c2 "Subject: " .
-                       quote_subject($initial_subject, $compose_encoding) .
-                       "\n";
-       }
-
-       if ($parsed_email{'MIME-Version'}) {
-               print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
-                               "Content-Type: $parsed_email{'Content-Type'};\n",
-                               "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
-               delete($parsed_email{'MIME-Version'});
-               delete($parsed_email{'Content-Type'});
-               delete($parsed_email{'Content-Transfer-Encoding'});
-       } elsif (file_has_nonascii($compose_filename)) {
-               my $content_type = (delete($parsed_email{'Content-Type'}) or
-                       "text/plain; charset=$compose_encoding");
-               print $c2 "MIME-Version: 1.0\n",
-                       "Content-Type: $content_type\n",
-                       "Content-Transfer-Encoding: 8bit\n";
-       }
-       # Preserve unknown headers
-       foreach my $key (keys %parsed_email) {
-               next if $key eq 'body';
-               print $c2 "$key: $parsed_email{$key}";
-       }
-
-       if ($parsed_email{'body'}) {
-               print $c2 "\n$parsed_email{'body'}\n";
-               delete($parsed_email{'body'});
-       } else {
+       if ($summary_empty) {
                print __("Summary email is empty, skipping it\n");
                $compose = -1;
        }
-
-       close $c2;
-
 } elsif ($annotate) {
        do_edit(@files);
 }
 
-sub term {
-       my $term = eval {
+{
+       # Only instantiate one $term per program run, since some
+       # Term::ReadLine providers refuse to create a second instance.
+       my $term;
+       sub term {
                require Term::ReadLine;
-               $ENV{"GIT_SEND_EMAIL_NOTTY"}
-                       ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
-                       : Term::ReadLine->new('git-send-email');
-       };
-       if ($@) {
-               $term = FakeTerm->new("$@: going non-interactive");
+               if (!defined $term) {
+                       $term = $ENV{"GIT_SEND_EMAIL_NOTTY"}
+                               ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
+                               : Term::ReadLine->new('git-send-email');
+               }
+               return $term;
        }
-       return $term;
 }
 
 sub ask {
@@ -995,32 +983,6 @@ sub ask {
        return;
 }
 
-sub parse_header_line {
-       my $lines = shift;
-       my $parsed_line = shift;
-       my $addr_pat = join "|", qw(To Cc Bcc);
-
-       foreach (split(/\n/, $lines)) {
-               if (/^($addr_pat):\s*(.+)$/i) {
-                       $parsed_line->{$1} = [ parse_address_line($2) ];
-               } elsif (/^([^:]*):\s*(.+)\s*$/i) {
-                       $parsed_line->{$1} = $2;
-               }
-       }
-}
-
-sub filter_body {
-       my $c = shift;
-       my $body = "";
-       while (my $body_line = <$c>) {
-               if ($body_line !~ m/^GIT:/) {
-                       $body .= $body_line;
-               }
-       }
-       return $body;
-}
-
-
 my %broken_encoding;
 
 sub file_declares_8bit_cte {
@@ -1152,10 +1114,10 @@ sub extract_valid_address {
 
 sub extract_valid_address_or_die {
        my $address = shift;
-       $address = extract_valid_address($address);
+       my $valid_address = extract_valid_address($address);
        die sprintf(__("error: unable to extract a valid address from: %s\n"), $address)
-               if !$address;
-       return $address;
+               if !$valid_address;
+       return $valid_address;
 }
 
 sub validate_address {
index be987e316f92acda1ff83c880ead3c6848db487c..4e8878f0357ce0d98ae0675b0cabf5c6efb098b2 100755 (executable)
@@ -297,28 +297,12 @@ my %cmd = (
                {} ],
 );
 
-package FakeTerm;
-sub new {
-       my ($class, $reason) = @_;
-       return bless \$reason, shift;
-}
-sub readline {
-       my $self = shift;
-       die "Cannot use readline on FakeTerm: $$self";
-}
-package main;
-
 my $term;
 sub term_init {
-       $term = eval {
-               require Term::ReadLine;
-               $ENV{"GIT_SVN_NOTTY"}
+       require Term::ReadLine;
+       $term = $ENV{"GIT_SVN_NOTTY"}
                        ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
                        : new Term::ReadLine 'git-svn';
-       };
-       if ($@) {
-               $term = new FakeTerm "$@: going non-interactive";
-       }
 }
 
 my $cmd;
diff --git a/git.c b/git.c
index 2f42da20f4e0dfbf021c2e5da40d4adcbde5d642..c67e44dd82d2e4fc01fb841c8f863282607f6ac7 100644 (file)
--- a/git.c
+++ b/git.c
@@ -5,6 +5,7 @@
 #include "gettext.h"
 #include "help.h"
 #include "pager.h"
+#include "read-cache-ll.h"
 #include "run-command.h"
 #include "alias.h"
 #include "replace-object.h"
@@ -186,7 +187,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--no-replace-objects")) {
-                       read_replace_refs = 0;
+                       disable_replace_refs();
                        setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
                        if (envchanged)
                                *envchanged = 1;
index 19a3471a0b55a5b5f92d0756cd4c1419d2b2e344..48f43c5a21d34569bdc966eefd652da38003d157 100644 (file)
 #include "sigchain.h"
 #include "tempfile.h"
 #include "alias.h"
-#include "wrapper.h"
+#include "environment.h"
 
-static int git_gpg_config(const char *, const char *, void *);
+static int git_gpg_config(const char *, const char *,
+                         const struct config_context *, void *);
 
 static void gpg_interface_lazy_init(void)
 {
@@ -586,8 +587,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
                }
        }
 
-       strbuf_stripspace(&ssh_keygen_out, 0);
-       strbuf_stripspace(&ssh_keygen_err, 0);
+       strbuf_stripspace(&ssh_keygen_out, '\0');
+       strbuf_stripspace(&ssh_keygen_err, '\0');
        /* Add stderr outputs to show the user actual ssh-keygen errors */
        strbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);
        strbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);
@@ -720,7 +721,9 @@ void set_signing_key(const char *key)
        configured_signing_key = xstrdup(key);
 }
 
-static int git_gpg_config(const char *var, const char *value, void *cb UNUSED)
+static int git_gpg_config(const char *var, const char *value,
+                         const struct config_context *ctx UNUSED,
+                         void *cb UNUSED)
 {
        struct gpg_format *fmt = NULL;
        char *fmtname = NULL;
diff --git a/graph.c b/graph.c
index 2a9dc430fae105c8d6fb5a8763320ae40fb1e5c8..1ca34770ee8139f25e0a2476c5aa3cd8b06fb89c 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -339,7 +339,6 @@ void graph_setup_line_prefix(struct diff_options *diffopt)
                diffopt->output_prefix = diff_output_prefix_callback;
 }
 
-
 struct git_graph *graph_init(struct rev_info *opt)
 {
        struct git_graph *graph = xmalloc(sizeof(struct git_graph));
diff --git a/grep.c b/grep.c
index f00986c451a99502a9dbe5bc1feeca6c486f0065..fc2d0c837a378d6a14da32fad69c0f3620447a21 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -3,7 +3,7 @@
 #include "gettext.h"
 #include "grep.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pretty.h"
 #include "userdiff.h"
 #include "xdiff-interface.h"
 #include "commit.h"
 #include "quote.h"
 #include "help.h"
-#include "wrapper.h"
 
 static int grep_source_load(struct grep_source *gs);
 static int grep_source_is_binary(struct grep_source *gs,
                                 struct index_state *istate);
 
-static void std_output(struct grep_opt *opt, const void *buf, size_t size)
+static void std_output(struct grep_opt *opt UNUSED, const void *buf, size_t size)
 {
        fwrite(buf, size, 1, stdout);
 }
@@ -56,7 +55,8 @@ define_list_config_array_extra(color_grep_slots, {"match"});
  * Read the configuration file once and store it in
  * the grep_defaults template.
  */
-int grep_config(const char *var, const char *value, void *cb)
+int grep_config(const char *var, const char *value,
+               const struct config_context *ctx, void *cb)
 {
        struct grep_opt *opt = cb;
        const char *slot;
@@ -91,9 +91,9 @@ int grep_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "color.grep"))
                opt->color = git_config_colorbool(var, value);
        if (!strcmp(var, "color.grep.match")) {
-               if (grep_config("color.grep.matchcontext", value, cb) < 0)
+               if (grep_config("color.grep.matchcontext", value, ctx, cb) < 0)
                        return -1;
-               if (grep_config("color.grep.matchselected", value, cb) < 0)
+               if (grep_config("color.grep.matchselected", value, ctx, cb) < 0)
                        return -1;
        } else if (skip_prefix(var, "color.grep.", &slot)) {
                int i = LOOKUP_CONFIG(color_grep_slots, slot);
@@ -452,18 +452,20 @@ static void free_pcre2_pattern(struct grep_pat *p)
        pcre2_general_context_free(p->pcre2_general_context);
 }
 #else /* !USE_LIBPCRE2 */
-static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
+static void compile_pcre2_pattern(struct grep_pat *p UNUSED,
+                                 const struct grep_opt *opt UNUSED)
 {
        die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
 }
 
-static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
-               regmatch_t *match, int eflags)
+static int pcre2match(struct grep_pat *p UNUSED, const char *line UNUSED,
+                     const char *eol UNUSED, regmatch_t *match UNUSED,
+                     int eflags UNUSED)
 {
        return 1;
 }
 
-static void free_pcre2_pattern(struct grep_pat *p)
+static void free_pcre2_pattern(struct grep_pat *p UNUSED)
 {
 }
 
diff --git a/grep.h b/grep.h
index c59592e3bdba5205befb38b5a19881ba3c6c9ce2..926c0875c42f63f961447a30f95c39d7ae031999 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -202,7 +202,9 @@ struct grep_opt {
        .output = std_output, \
 }
 
-int grep_config(const char *var, const char *value, void *);
+struct config_context;
+int grep_config(const char *var, const char *value,
+               const struct config_context *ctx, void *data);
 void grep_init(struct grep_opt *, struct repository *repo);
 
 void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
index 80509251370523029710e2e691b832e601be939f..10d84cc208886187d044b0b69fbfc397f4d28864 100644 (file)
--- a/hash-ll.h
+++ b/hash-ll.h
@@ -4,7 +4,11 @@
 #if defined(SHA1_APPLE)
 #include <CommonCrypto/CommonDigest.h>
 #elif defined(SHA1_OPENSSL)
-#include <openssl/sha.h>
+#  include <openssl/sha.h>
+#  if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
+#    define SHA1_NEEDS_CLONE_HELPER
+#    include "sha1/openssl.h"
+#  endif
 #elif defined(SHA1_DC)
 #include "sha1dc_git.h"
 #else /* SHA1_BLK */
 #define SHA256_NEEDS_CLONE_HELPER
 #include "sha256/gcrypt.h"
 #elif defined(SHA256_OPENSSL)
-#include <openssl/sha.h>
+#  include <openssl/sha.h>
+#  if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
+#    define SHA256_NEEDS_CLONE_HELPER
+#    include "sha256/openssl.h"
+#  endif
 #else
 #include "sha256/block/sha256.h"
 #endif
 #define git_SHA1_Update                platform_SHA1_Update
 #define git_SHA1_Final         platform_SHA1_Final
 
+#ifdef platform_SHA1_Clone
+#define git_SHA1_Clone platform_SHA1_Clone
+#endif
+
 #ifndef platform_SHA256_CTX
 #define platform_SHA256_CTX    SHA256_CTX
 #define platform_SHA256_Init   SHA256_Init
 #define git_SHA1_Update                git_SHA1_Update_Chunked
 #endif
 
+#ifndef SHA1_NEEDS_CLONE_HELPER
 static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
 {
        memcpy(dst, src, sizeof(*dst));
 }
+#endif
 
 #ifndef SHA256_NEEDS_CLONE_HELPER
 static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
@@ -270,6 +284,25 @@ static inline void oid_set_algo(struct object_id *oid, const struct git_hash_alg
        oid->algo = hash_algo_by_ptr(algop);
 }
 
+/*
+ * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code
+ * for use in hash tables. Cryptographic hashes are supposed to have
+ * uniform distribution, so in contrast to `memhash()`, this just copies
+ * the first `sizeof(int)` bytes without shuffling any bits. Note that
+ * the results will be different on big-endian and little-endian
+ * platforms, so they should not be stored or transferred over the net.
+ */
+static inline unsigned int oidhash(const struct object_id *oid)
+{
+       /*
+        * Equivalent to 'return *(unsigned int *)oid->hash;', but safe on
+        * platforms that don't support unaligned reads.
+        */
+       unsigned int hash;
+       memcpy(&hash, oid->hash, sizeof(hash));
+       return hash;
+}
+
 const char *empty_tree_oid_hex(void);
 const char *empty_blob_oid_hex(void);
 
index bb54dfde9c77c8b88dc902e071f09ab3b6ddd31b..9f0f95e2b9e0c44e79bfe6ee3ec43b61e7991f4a 100644 (file)
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "hash.h"
 #include "hash-lookup.h"
+#include "read-cache-ll.h"
 
 static uint32_t take2(const struct object_id *oid, size_t ofs)
 {
index 2695f3d3a6e68c779625113ad6fe76f9dc2baccb..c8216e47bb21171a59cdcc1f17b600ae60699dfa 100644 (file)
--- a/hashmap.h
+++ b/hashmap.h
@@ -1,8 +1,6 @@
 #ifndef HASHMAP_H
 #define HASHMAP_H
 
-#include "hash-ll.h"
-
 /*
  * Generic implementation of hash-based key-value mappings.
  *
@@ -120,25 +118,6 @@ unsigned int memhash(const void *buf, size_t len);
 unsigned int memihash(const void *buf, size_t len);
 unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len);
 
-/*
- * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code
- * for use in hash tables. Cryptographic hashes are supposed to have
- * uniform distribution, so in contrast to `memhash()`, this just copies
- * the first `sizeof(int)` bytes without shuffling any bits. Note that
- * the results will be different on big-endian and little-endian
- * platforms, so they should not be stored or transferred over the net.
- */
-static inline unsigned int oidhash(const struct object_id *oid)
-{
-       /*
-        * Equivalent to 'return *(unsigned int *)oid->hash;', but safe on
-        * platforms that don't support unaligned reads.
-        */
-       unsigned int hash;
-       memcpy(&hash, oid->hash, sizeof(hash));
-       return hash;
-}
-
 /*
  * struct hashmap_entry is an opaque structure representing an entry in the
  * hash table.
diff --git a/help.c b/help.c
index 5d7637dce92867c1c0bee7f6f6b904852d237222..6d2ebfbd2a45f134bc45c039cb4cf26b402b8f6c 100644 (file)
--- a/help.c
+++ b/help.c
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "builtin.h"
 #include "exec-cmd.h"
@@ -309,7 +308,8 @@ void load_command_list(const char *prefix,
        exclude_cmds(other_cmds, main_cmds);
 }
 
-static int get_colopts(const char *var, const char *value, void *data)
+static int get_colopts(const char *var, const char *value,
+                      const struct config_context *ctx UNUSED, void *data)
 {
        unsigned int *colopts = data;
 
@@ -459,7 +459,8 @@ void list_developer_interfaces_help(void)
        putchar('\n');
 }
 
-static int get_alias(const char *var, const char *value, void *data)
+static int get_alias(const char *var, const char *value,
+                    const struct config_context *ctx UNUSED, void *data)
 {
        struct string_list *list = data;
 
@@ -543,6 +544,7 @@ static struct cmdnames aliases;
 #define AUTOCORRECT_IMMEDIATELY (-1)
 
 static int git_unknown_cmd_config(const char *var, const char *value,
+                                 const struct config_context *ctx,
                                  void *cb UNUSED)
 {
        const char *p;
@@ -557,7 +559,7 @@ static int git_unknown_cmd_config(const char *var, const char *value,
                } else if (!strcmp(value, "prompt")) {
                        autocorrect = AUTOCORRECT_PROMPT;
                } else {
-                       int v = git_config_int(var, value);
+                       int v = git_config_int(var, value, ctx->kvi);
                        autocorrect = (v < 0)
                                ? AUTOCORRECT_IMMEDIATELY : v;
                }
diff --git a/hex-ll.c b/hex-ll.c
new file mode 100644 (file)
index 0000000..4d7ece1
--- /dev/null
+++ b/hex-ll.c
@@ -0,0 +1,49 @@
+#include "git-compat-util.h"
+#include "hex-ll.h"
+
+const signed char hexval_table[256] = {
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 00-07 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 08-0f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 10-17 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 18-1f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 20-27 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 28-2f */
+         0,  1,  2,  3,  4,  5,  6,  7,                /* 30-37 */
+         8,  9, -1, -1, -1, -1, -1, -1,                /* 38-3f */
+        -1, 10, 11, 12, 13, 14, 15, -1,                /* 40-47 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 48-4f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 50-57 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 58-5f */
+        -1, 10, 11, 12, 13, 14, 15, -1,                /* 60-67 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 68-67 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 70-77 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 78-7f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 80-87 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 88-8f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 90-97 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* 98-9f */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* a0-a7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* a8-af */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* b0-b7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* b8-bf */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* c0-c7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* c8-cf */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* d0-d7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* d8-df */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* e0-e7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* e8-ef */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* f0-f7 */
+        -1, -1, -1, -1, -1, -1, -1, -1,                /* f8-ff */
+};
+
+int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
+{
+       for (; len; len--, hex += 2) {
+               unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+
+               if (val & ~0xff)
+                       return -1;
+               *binary++ = val;
+       }
+       return 0;
+}
diff --git a/hex-ll.h b/hex-ll.h
new file mode 100644 (file)
index 0000000..a381fa8
--- /dev/null
+++ b/hex-ll.h
@@ -0,0 +1,27 @@
+#ifndef HEX_LL_H
+#define HEX_LL_H
+
+extern const signed char hexval_table[256];
+static inline unsigned int hexval(unsigned char c)
+{
+       return hexval_table[c];
+}
+
+/*
+ * Convert two consecutive hexadecimal digits into a char.  Return a
+ * negative value on error.  Don't run over the end of short strings.
+ */
+static inline int hex2chr(const char *s)
+{
+       unsigned int val = hexval(s[0]);
+       return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
+}
+
+/*
+ * Read `len` pairs of hexadecimal digits from `hex` and write the
+ * values to `binary` as `len` bytes. Return 0 on success, or -1 if
+ * the input does not consist of hex digits).
+ */
+int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
+
+#endif
diff --git a/hex.c b/hex.c
index 7bb440e7940212809006b21da96971b7dcda936e..d42262bdca71a8703ce191393f0217f0c589a75e 100644 (file)
--- a/hex.c
+++ b/hex.c
@@ -2,53 +2,6 @@
 #include "hash.h"
 #include "hex.h"
 
-const signed char hexval_table[256] = {
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 00-07 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 08-0f */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 10-17 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 18-1f */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 20-27 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 28-2f */
-         0,  1,  2,  3,  4,  5,  6,  7,                /* 30-37 */
-         8,  9, -1, -1, -1, -1, -1, -1,                /* 38-3f */
-        -1, 10, 11, 12, 13, 14, 15, -1,                /* 40-47 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 48-4f */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 50-57 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 58-5f */
-        -1, 10, 11, 12, 13, 14, 15, -1,                /* 60-67 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 68-67 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 70-77 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 78-7f */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 80-87 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 88-8f */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 90-97 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* 98-9f */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* a0-a7 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* a8-af */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* b0-b7 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* b8-bf */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* c0-c7 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* c8-cf */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* d0-d7 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* d8-df */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* e0-e7 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* e8-ef */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* f0-f7 */
-        -1, -1, -1, -1, -1, -1, -1, -1,                /* f8-ff */
-};
-
-int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
-{
-       for (; len; len--, hex += 2) {
-               unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
-
-               if (val & ~0xff)
-                       return -1;
-               *binary++ = val;
-       }
-       return 0;
-}
-
 static int get_hash_hex_algop(const char *hex, unsigned char *hash,
                              const struct git_hash_algo *algop)
 {
@@ -63,7 +16,7 @@ static int get_hash_hex_algop(const char *hex, unsigned char *hash,
        return 0;
 }
 
-int get_sha1_hex(const char *hex, unsigned char *sha1)
+int get_hash_hex(const char *hex, unsigned char *sha1)
 {
        return get_hash_hex_algop(hex, sha1, the_hash_algo);
 }
diff --git a/hex.h b/hex.h
index 7df4b3c460e52a444ac681f88937116ab38a3660..e0b83f776f1a8cc62ab1694be4faf579051396b4 100644 (file)
--- a/hex.h
+++ b/hex.h
@@ -2,43 +2,23 @@
 #define HEX_H
 
 #include "hash-ll.h"
-
-extern const signed char hexval_table[256];
-static inline unsigned int hexval(unsigned char c)
-{
-       return hexval_table[c];
-}
-
-/*
- * Convert two consecutive hexadecimal digits into a char.  Return a
- * negative value on error.  Don't run over the end of short strings.
- */
-static inline int hex2chr(const char *s)
-{
-       unsigned int val = hexval(s[0]);
-       return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
-}
+#include "hex-ll.h"
 
 /*
- * Try to read a SHA1 in hexadecimal format from the 40 characters
- * starting at hex.  Write the 20-byte result to sha1 in binary form.
+ * Try to read a hash (specified by the_hash_algo) in hexadecimal
+ * format from the 40 (or whatever length the hash algorithm uses)
+ * characters starting at hex.  Write the 20-byte (or the length of
+ * the hash) result to hash in binary form.
  * Return 0 on success.  Reading stops if a NUL is encountered in the
  * input, so it is safe to pass this function an arbitrary
  * null-terminated string.
  */
-int get_sha1_hex(const char *hex, unsigned char *sha1);
-int get_oid_hex(const char *hex, struct object_id *sha1);
+int get_hash_hex(const char *hex, unsigned char *hash);
+int get_oid_hex(const char *hex, struct object_id *oid);
 
 /* Like get_oid_hex, but for an arbitrary hash algorithm. */
 int get_oid_hex_algop(const char *hex, struct object_id *oid, const struct git_hash_algo *algop);
 
-/*
- * Read `len` pairs of hexadecimal digits from `hex` and write the
- * values to `binary` as `len` bytes. Return 0 on success, or -1 if
- * the input does not consist of hex digits).
- */
-int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
-
 /*
  * Convert a binary hash in "unsigned char []" or an object name in
  * "struct object_id *" to its hex equivalent. The `_r` variant is reentrant,
diff --git a/hook.c b/hook.c
index 3ca5e60895d65f01a87ebd2e055e5fe2dc41436c..f6306d72b31879705977a023a7865c3f1677404c 100644 (file)
--- a/hook.c
+++ b/hook.c
@@ -1,4 +1,5 @@
 #include "git-compat-util.h"
+#include "abspath.h"
 #include "advice.h"
 #include "gettext.h"
 #include "hook.h"
index ac146d85c54efddf1f7cf01b61aa13ec3b3470e3..ff07b87e6461446610c35708a39f22a5e5b36aff 100644 (file)
@@ -1,9 +1,9 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "git-zlib.h"
 #include "hex.h"
+#include "path.h"
 #include "repository.h"
 #include "refs.h"
 #include "pkt-line.h"
 #include "url.h"
 #include "strvec.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "protocol.h"
 #include "date.h"
-#include "wrapper.h"
 #include "write-or-die.h"
 
 static const char content_type[] = "Content-Type";
@@ -559,7 +558,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
 
        } else {
                select_getanyfile(hdr);
-               for_each_namespaced_ref(show_text_ref, &buf);
+               for_each_namespaced_ref(NULL, show_text_ref, &buf);
                send_strbuf(hdr, "text/plain", &buf);
        }
        strbuf_release(&buf);
index 29cf9db34e35fed836fd7d4b4096a0050630d8a9..a704f490fdb2c2144b47a5629ed9ee0643ab0d83 100644 (file)
@@ -18,7 +18,7 @@
 #include "tree.h"
 #include "tree-walk.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit-reach.h"
 
 #ifdef EXPAT_NEEDS_XMLPARSE_H
@@ -783,7 +783,7 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
 static void one_remote_ref(const char *refname);
 
 static void
-xml_start_tag(void *userData, const char *name, const char **atts)
+xml_start_tag(void *userData, const char *name, const char **atts UNUSED)
 {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
        const char *c = strchr(name, ':');
index bba306b2d5e18b94aaa41e8fdce30321034feaea..78d99f7c4b002cb95196800a62a1de8fbcce6cea 100644 (file)
@@ -7,7 +7,7 @@
 #include "list.h"
 #include "transport.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 struct alt_base {
        char *base;
diff --git a/http.c b/http.c
index b71bb1e3addfa4a1f73a432c2f86fc3abfbf86d9..8f71bf00d8998af44e177a86d73dbc86872c9726 100644 (file)
--- a/http.c
+++ b/http.c
@@ -18,7 +18,7 @@
 #include "protocol.h"
 #include "string-list.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
 static int trace_curl_data = 1;
@@ -196,7 +196,7 @@ static inline int is_hdr_continuation(const char *ptr, const size_t size)
        return size && (*ptr == ' ' || *ptr == '\t');
 }
 
-static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p)
+static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p UNUSED)
 {
        size_t size = eltsize * nmemb;
        struct strvec *values = &http_auth.wwwauth_headers;
@@ -295,7 +295,8 @@ exit:
        return size;
 }
 
-size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
+size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
+                  void *data UNUSED)
 {
        return nmemb;
 }
@@ -363,7 +364,8 @@ static void process_curl_messages(void)
        }
 }
 
-static int http_options(const char *var, const char *value, void *cb)
+static int http_options(const char *var, const char *value,
+                       const struct config_context *ctx, void *data)
 {
        if (!strcmp("http.version", var)) {
                return git_config_string(&curl_http_version, var, value);
@@ -413,21 +415,21 @@ static int http_options(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp("http.minsessions", var)) {
-               min_curl_sessions = git_config_int(var, value);
+               min_curl_sessions = git_config_int(var, value, ctx->kvi);
                if (min_curl_sessions > 1)
                        min_curl_sessions = 1;
                return 0;
        }
        if (!strcmp("http.maxrequests", var)) {
-               max_requests = git_config_int(var, value);
+               max_requests = git_config_int(var, value, ctx->kvi);
                return 0;
        }
        if (!strcmp("http.lowspeedlimit", var)) {
-               curl_low_speed_limit = (long)git_config_int(var, value);
+               curl_low_speed_limit = (long)git_config_int(var, value, ctx->kvi);
                return 0;
        }
        if (!strcmp("http.lowspeedtime", var)) {
-               curl_low_speed_time = (long)git_config_int(var, value);
+               curl_low_speed_time = (long)git_config_int(var, value, ctx->kvi);
                return 0;
        }
 
@@ -463,7 +465,7 @@ static int http_options(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp("http.postbuffer", var)) {
-               http_post_buffer = git_config_ssize_t(var, value);
+               http_post_buffer = git_config_ssize_t(var, value, ctx->kvi);
                if (http_post_buffer < 0)
                        warning(_("negative value for http.postBuffer; defaulting to %d"), LARGE_PACKET_MAX);
                if (http_post_buffer < LARGE_PACKET_MAX)
@@ -534,7 +536,7 @@ static int http_options(const char *var, const char *value, void *cb)
        }
 
        /* Fall back on the default ones */
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, data);
 }
 
 static int curl_empty_auth_enabled(void)
@@ -736,18 +738,43 @@ static int redact_sensitive_header(struct strbuf *header, size_t offset)
        return ret;
 }
 
+static int match_curl_h2_trace(const char *line, const char **out)
+{
+       const char *p;
+
+       /*
+        * curl prior to 8.1.0 gives us:
+        *
+        *     h2h3 [<header-name>: <header-val>]
+        *
+        * Starting in 8.1.0, the first token became just "h2".
+        */
+       if (skip_iprefix(line, "h2h3 [", out) ||
+           skip_iprefix(line, "h2 [", out))
+               return 1;
+
+       /*
+        * curl 8.3.0 uses:
+        *   [HTTP/2] [<stream-id>] [<header-name>: <header-val>]
+        * where <stream-id> is numeric.
+        */
+       if (skip_iprefix(line, "[HTTP/2] [", &p)) {
+               while (isdigit(*p))
+                       p++;
+               if (skip_prefix(p, "] [", out))
+                       return 1;
+       }
+
+       return 0;
+}
+
 /* Redact headers in info */
 static void redact_sensitive_info_header(struct strbuf *header)
 {
        const char *sensitive_header;
 
-       /*
-        * curl's h2h3 prints headers in info, e.g.:
-        *   h2h3 [<header-name>: <header-val>]
-        */
        if (trace_curl_redact &&
-           (skip_iprefix(header->buf, "h2h3 [", &sensitive_header) ||
-            skip_iprefix(header->buf, "h2 [", &sensitive_header))) {
+           match_curl_h2_trace(header->buf, &sensitive_header)) {
                if (redact_sensitive_header(header, sensitive_header - header->buf)) {
                        /* redaction ate our closing bracket */
                        strbuf_addch(header, ']');
@@ -820,7 +847,9 @@ static void curl_dump_info(char *data, size_t size)
        strbuf_release(&buf);
 }
 
-static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
+static int curl_trace(CURL *handle UNUSED, curl_infotype type,
+                     char *data, size_t size,
+                     void *userp UNUSED)
 {
        const char *text;
        enum { NO_FILTER = 0, DO_FILTER = 1 };
diff --git a/ident.c b/ident.c
index 8fad92d7007e2101d630680f4aecd9626c97d6bd..cc7afdbf8197e981e02b6257a4618197063db69f 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -203,7 +203,6 @@ void reset_ident_date(void)
 static int crud(unsigned char c)
 {
        return  c <= 32  ||
-               c == '.' ||
                c == ',' ||
                c == ':' ||
                c == ';' ||
@@ -671,7 +670,9 @@ static int set_ident(const char *var, const char *value)
        return 0;
 }
 
-int git_ident_config(const char *var, const char *value, void *data UNUSED)
+int git_ident_config(const char *var, const char *value,
+                    const struct config_context *ctx UNUSED,
+                    void *data UNUSED)
 {
        if (!strcmp(var, "user.useconfigonly")) {
                ident_use_config_only = git_config_bool(var, value);
diff --git a/ident.h b/ident.h
index 96a64896a0167381228af77cbfec4cb56c428ec7..6a79febba15feabb8418ee6441a47553e616c6ec 100644 (file)
--- a/ident.h
+++ b/ident.h
@@ -62,6 +62,8 @@ const char *fmt_name(enum want_ident);
 int committer_ident_sufficiently_given(void);
 int author_ident_sufficiently_given(void);
 
-int git_ident_config(const char *, const char *, void *);
+struct config_context;
+int git_ident_config(const char *, const char *, const struct config_context *,
+                    void *);
 
 #endif
index 7f5426177a16e6c098f3197777fa14df0c5b8b27..996651e4f80abd5fa2daf570f9d981934d328aeb 100644 (file)
@@ -30,7 +30,6 @@
 #include "parse-options.h"
 #include "setup.h"
 #include "strbuf.h"
-#include "wrapper.h"
 #if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
 typedef void *SSL;
 #endif
@@ -137,12 +136,10 @@ struct imap_store {
 };
 
 struct imap_cmd_cb {
-       int (*cont)(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt);
-       void (*done)(struct imap_store *ctx, struct imap_cmd *cmd, int response);
+       int (*cont)(struct imap_store *ctx, const char *prompt);
        void *ctx;
        char *data;
        int dlen;
-       int uid;
 };
 
 struct imap_cmd {
@@ -209,10 +206,14 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
                else
                        fprintf(stderr, "%s: unexpected EOF\n", func);
        }
+       /* mark as used to appease -Wunused-parameter with NO_OPENSSL */
+       (void)sock;
 }
 
 #ifdef NO_OPENSSL
-static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+static int ssl_socket_connect(struct imap_socket *sock UNUSED,
+                             int use_tls_only UNUSED,
+                             int verify UNUSED)
 {
        fprintf(stderr, "SSL requested but SSL support not compiled in\n");
        return -1;
@@ -786,7 +787,7 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
                                if (n != (int)cmdp->cb.dlen)
                                        return RESP_BAD;
                        } else if (cmdp->cb.cont) {
-                               if (cmdp->cb.cont(ctx, cmdp, cmd))
+                               if (cmdp->cb.cont(ctx, cmd))
                                        return RESP_BAD;
                        } else {
                                fprintf(stderr, "IMAP error: unexpected command continuation request\n");
@@ -828,8 +829,6 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
                        }
                        if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp)
                                resp = resp2;
-                       if (cmdp->cb.done)
-                               cmdp->cb.done(ctx, cmdp, resp);
                        free(cmdp->cb.data);
                        free(cmdp->cmd);
                        free(cmdp);
@@ -909,7 +908,9 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)
 
 #else
 
-static char *cram(const char *challenge_64, const char *user, const char *pass)
+static char *cram(const char *challenge_64 UNUSED,
+                 const char *user UNUSED,
+                 const char *pass UNUSED)
 {
        die("If you want to use CRAM-MD5 authenticate method, "
            "you have to build git-imap-send with OpenSSL library.");
@@ -917,7 +918,7 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)
 
 #endif
 
-static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt)
+static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
 {
        int ret;
        char *response;
@@ -1323,7 +1324,8 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
        return 1;
 }
 
-static int git_imap_config(const char *var, const char *val, void *cb)
+static int git_imap_config(const char *var, const char *val,
+                          const struct config_context *ctx, void *cb)
 {
 
        if (!strcmp("imap.sslverify", var))
@@ -1341,7 +1343,7 @@ static int git_imap_config(const char *var, const char *val, void *cb)
        else if (!strcmp("imap.authmethod", var))
                return git_config_string(&server.auth_method, var, val);
        else if (!strcmp("imap.port", var))
-               server.port = git_config_int(var, val);
+               server.port = git_config_int(var, val, ctx->kvi);
        else if (!strcmp("imap.host", var)) {
                if (!val) {
                        git_die_config("imap.host", "Missing value for 'imap.host'");
@@ -1357,7 +1359,7 @@ static int git_imap_config(const char *var, const char *val, void *cb)
                        server.host = xstrdup(val);
                }
        } else
-               return git_default_config(var, val, cb);
+               return git_default_config(var, val, ctx, cb);
 
        return 0;
 }
@@ -1415,16 +1417,16 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
        if (!curl)
                die("curl_easy_init failed");
 
-       server_fill_credential(&server, cred);
-       curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
-       curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
+       server_fill_credential(srvc, cred);
+       curl_easy_setopt(curl, CURLOPT_USERNAME, srvc->user);
+       curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
 
-       strbuf_addstr(&path, server.use_ssl ? "imaps://" : "imap://");
-       strbuf_addstr(&path, server.host);
+       strbuf_addstr(&path, srvc->use_ssl ? "imaps://" : "imap://");
+       strbuf_addstr(&path, srvc->host);
        if (!path.len || path.buf[path.len - 1] != '/')
                strbuf_addch(&path, '/');
 
-       uri_encoded_folder = curl_easy_escape(curl, server.folder, 0);
+       uri_encoded_folder = curl_easy_escape(curl, srvc->folder, 0);
        if (!uri_encoded_folder)
                die("failed to encode server folder");
        strbuf_addstr(&path, uri_encoded_folder);
@@ -1432,25 +1434,25 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
 
        curl_easy_setopt(curl, CURLOPT_URL, path.buf);
        strbuf_release(&path);
-       curl_easy_setopt(curl, CURLOPT_PORT, server.port);
+       curl_easy_setopt(curl, CURLOPT_PORT, srvc->port);
 
-       if (server.auth_method) {
+       if (srvc->auth_method) {
 #ifndef GIT_CURL_HAVE_CURLOPT_LOGIN_OPTIONS
                warning("No LOGIN_OPTIONS support in this cURL version");
 #else
                struct strbuf auth = STRBUF_INIT;
                strbuf_addstr(&auth, "AUTH=");
-               strbuf_addstr(&auth, server.auth_method);
+               strbuf_addstr(&auth, srvc->auth_method);
                curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
                strbuf_release(&auth);
 #endif
        }
 
-       if (!server.use_ssl)
+       if (!srvc->use_ssl)
                curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
 
-       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);
-       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);
+       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, srvc->ssl_verify);
+       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, srvc->ssl_verify);
 
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
 
diff --git a/khash.h b/khash.h
index 56241e6a5c9a4c88a4201f082c2040035e60ed95..ff8816317785862662b1eeb2fe5036b801be1773 100644 (file)
--- a/khash.h
+++ b/khash.h
@@ -26,7 +26,6 @@
 #ifndef __AC_KHASH_H
 #define __AC_KHASH_H
 
-#include "hashmap.h"
 #include "hash.h"
 
 #define AC_VERSION_KHASH_H "0.2.8"
@@ -62,7 +61,7 @@ static inline khint_t __ac_X31_hash_string(const char *s)
 static const double __ac_HASH_UPPER = 0.77;
 
 #define __KHASH_TYPE(name, khkey_t, khval_t) \
-       typedef struct { \
+       typedef struct kh_##name { \
                khint_t n_buckets, size, n_occupied, upper_bound; \
                khint32_t *flags; \
                khkey_t *keys; \
diff --git a/kwset.c b/kwset.c
index 4b14d4f86b8d1965023a49586fdd56631631cb8e..bbfcf815a567b053bd0206ddb7bb38d138731bd1 100644 (file)
--- a/kwset.c
+++ b/kwset.c
@@ -49,6 +49,42 @@ static void *obstack_chunk_alloc(long size)
 
 #define U(c) ((unsigned char) (c))
 
+/* For case-insensitive kwset */
+const unsigned char tolower_trans_tbl[256] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+        ' ',  '!',  '"',  '#',  '$',  '%',  '&', 0x27,
+        '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
+        '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
+        '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
+        '@',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
+        'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+        'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
+        'x',  'y',  'z',  '[', 0x5c,  ']',  '^',  '_',
+        '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
+        'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+        'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
+        'x',  'y',  'z',  '{',  '|',  '}',  '~', 0x7f,
+       0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+       0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+       0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+       0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+       0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+};
+
 /* Balanced tree of edges and labels leaving a given trie node. */
 struct tree
 {
diff --git a/kwset.h b/kwset.h
index f50ecae573b9ff77e0169fa93e733e68ef9fa300..d42a793a301cb6d7ba758a5d592516cdf9d8444f 100644 (file)
--- a/kwset.h
+++ b/kwset.h
@@ -26,6 +26,8 @@
    The author may be reached (Email) at the address mike@ai.mit.edu,
    or (US mail) as Mike Haertel c/o Free Software Foundation. */
 
+extern const unsigned char tolower_trans_tbl[256];
+
 struct kwsmatch
 {
   int index;                   /* Index number of matching keyword. */
index 6a7ac312a43f4a7c6b24f213d2e1d583d0e8b64f..24a1ecb67799c23570ef485bc382b4bbdf2779d2 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "line-range.h"
 #include "hex.h"
 #include "tag.h"
@@ -8,6 +7,7 @@
 #include "diff.h"
 #include "commit.h"
 #include "decorate.h"
+#include "repository.h"
 #include "revision.h"
 #include "xdiff-interface.h"
 #include "strbuf.h"
@@ -1327,3 +1327,13 @@ int line_log_filter(struct rev_info *rev)
 
        return 0;
 }
+
+static void free_void_line_log_data(void *data)
+{
+       free_line_log_data(data);
+}
+
+void line_log_free(struct rev_info *rev)
+{
+       clear_decoration(&rev->line_log_data, free_void_line_log_data);
+}
index adff361b1bc93905641341df88a7cfcbfb6c118d..4291da8d79235d1f477742a11a5fdb67a4346e2e 100644 (file)
@@ -60,4 +60,6 @@ int line_log_process_ranges_arbitrary_commit(struct rev_info *rev,
 
 int line_log_print(struct rev_info *rev, struct commit *commit);
 
+void line_log_free(struct rev_info *rev);
+
 #endif /* LINE_LOG_H */
index 2a3b7881af2bf5960dfbd41934aa3c66ad2a90eb..8a08b7af49c1ff7750296508102bf67807027bea 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "commit.h"
 #include "config.h"
 #include "gettext.h"
index f6206125868eb06cc448182418c23b3e4c9e95a6..55fab8563d20a5a7ada0e9fd1215303808c5853d 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "gettext.h"
 #include "object.h"
-#include "string-list.h"
 #include "strbuf.h"
 
 struct option;
index 5d270ce59877e297298258e89762a75146518edd..9327ccd5057cb6fffc9fcd9a92f2939a50b50253 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "dir.h"
 #include "gettext.h"
 #include "hex.h"
@@ -16,7 +15,7 @@
 #include "oidmap.h"
 #include "oidset.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 /* Remember to update object flag allocation in object.h */
 /*
index eecca721ac0826ef09071e6c3119a231d693771a..c25c72b32c323c18da214fb7c0f5935556bb97a4 100644 (file)
@@ -12,8 +12,9 @@
 #include "list-objects-filter.h"
 #include "list-objects-filter-options.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "trace.h"
+#include "environment.h"
 
 struct traversal_context {
        struct rev_info *revs;
@@ -21,6 +22,7 @@ struct traversal_context {
        show_commit_fn show_commit;
        void *show_data;
        struct filter *filter;
+       int depth;
 };
 
 static void show_commit(struct traversal_context *ctx,
@@ -102,7 +104,7 @@ static void process_tree_contents(struct traversal_context *ctx,
        while (tree_entry(&desc, &entry)) {
                if (match != all_entries_interesting) {
                        match = tree_entry_interesting(ctx->revs->repo->index,
-                                                      &entry, base, 0,
+                                                      &entry, base,
                                                       &ctx->revs->diffopt.pathspec);
                        if (match == all_entries_not_interesting)
                                break;
@@ -118,7 +120,9 @@ static void process_tree_contents(struct traversal_context *ctx,
                                    entry.path, oid_to_hex(&tree->object.oid));
                        }
                        t->object.flags |= NOT_USER_GIVEN;
+                       ctx->depth++;
                        process_tree(ctx, t, base, entry.path);
+                       ctx->depth--;
                }
                else if (S_ISGITLINK(entry.mode))
                        ; /* ignore gitlink */
@@ -156,6 +160,9 @@ static void process_tree(struct traversal_context *ctx,
            !revs->include_check_obj(&tree->object, revs->include_check_data))
                return;
 
+       if (ctx->depth > max_allowed_tree_depth)
+               die("exceeded maximum allowed tree depth");
+
        failed_parse = parse_tree_gently(tree, 1);
        if (failed_parse) {
                if (revs->ignore_missing_links)
@@ -349,6 +356,7 @@ static void traverse_non_commits(struct traversal_context *ctx,
                if (!path)
                        path = "";
                if (obj->type == OBJ_TREE) {
+                       ctx->depth = 0;
                        process_tree(ctx, (struct tree *)obj, base, path);
                        continue;
                }
index f4b22a60cc53c7b0d723de1fce1a00282ddd41ff..504da6b519edff523bd542d07684a4c27a6c10bb 100644 (file)
@@ -5,7 +5,7 @@
 #include "environment.h"
 #include "hex.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "repository.h"
 #include "tmp-objdir.h"
 #include "commit.h"
@@ -16,6 +16,7 @@
 #include "reflog-walk.h"
 #include "refs.h"
 #include "replace-object.h"
+#include "revision.h"
 #include "string-list.h"
 #include "color.h"
 #include "gpg-interface.h"
@@ -25,6 +26,7 @@
 #include "range-diff.h"
 #include "strmap.h"
 #include "tree.h"
+#include "wildmatch.h"
 #include "write-or-die.h"
 
 static struct decoration name_decoration = { "object names" };
@@ -156,7 +158,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
 
        if (starts_with(refname, git_replace_ref_base)) {
                struct object_id original_oid;
-               if (!read_replace_refs)
+               if (!replace_refs_enabled(the_repository))
                        return 0;
                if (get_oid_hex(refname + strlen(git_replace_ref_base),
                                &original_oid)) {
@@ -301,26 +303,43 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio
 
 /*
  * The caller makes sure there is no funny color before calling.
- * format_decorations_extended makes sure the same after return.
+ * format_decorations ensures the same after return.
  */
-void format_decorations_extended(struct strbuf *sb,
+void format_decorations(struct strbuf *sb,
                        const struct commit *commit,
                        int use_color,
-                       const char *prefix,
-                       const char *separator,
-                       const char *suffix)
+                       const struct decoration_options *opts)
 {
        const struct name_decoration *decoration;
        const struct name_decoration *current_and_HEAD;
-       const char *color_commit =
-               diff_get_color(use_color, DIFF_COMMIT);
-       const char *color_reset =
-               decorate_get_color(use_color, DECORATION_NONE);
+       const char *color_commit, *color_reset;
+
+       const char *prefix = " (";
+       const char *suffix = ")";
+       const char *separator = ", ";
+       const char *pointer = " -> ";
+       const char *tag = "tag: ";
 
        decoration = get_name_decoration(&commit->object);
        if (!decoration)
                return;
 
+       if (opts) {
+               if (opts->prefix)
+                       prefix = opts->prefix;
+               if (opts->suffix)
+                       suffix = opts->suffix;
+               if (opts->separator)
+                       separator = opts->separator;
+               if (opts->pointer)
+                       pointer = opts->pointer;
+               if (opts->tag)
+                       tag = opts->tag;
+       }
+
+       color_commit = diff_get_color(use_color, DIFF_COMMIT);
+       color_reset = decorate_get_color(use_color, DECORATION_NONE);
+
        current_and_HEAD = current_pointed_by_HEAD(decoration);
        while (decoration) {
                /*
@@ -329,31 +348,44 @@ void format_decorations_extended(struct strbuf *sb,
                 * appeared, skipping the entry for current.
                 */
                if (decoration != current_and_HEAD) {
-                       strbuf_addstr(sb, color_commit);
-                       strbuf_addstr(sb, prefix);
-                       strbuf_addstr(sb, color_reset);
-                       strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
-                       if (decoration->type == DECORATION_REF_TAG)
-                               strbuf_addstr(sb, "tag: ");
+                       const char *color =
+                               decorate_get_color(use_color, decoration->type);
+
+                       if (*prefix) {
+                               strbuf_addstr(sb, color_commit);
+                               strbuf_addstr(sb, prefix);
+                               strbuf_addstr(sb, color_reset);
+                       }
 
+                       if (*tag && decoration->type == DECORATION_REF_TAG) {
+                               strbuf_addstr(sb, color);
+                               strbuf_addstr(sb, tag);
+                               strbuf_addstr(sb, color_reset);
+                       }
+
+                       strbuf_addstr(sb, color);
                        show_name(sb, decoration);
+                       strbuf_addstr(sb, color_reset);
 
                        if (current_and_HEAD &&
                            decoration->type == DECORATION_REF_HEAD) {
-                               strbuf_addstr(sb, " -> ");
+                               strbuf_addstr(sb, color_commit);
+                               strbuf_addstr(sb, pointer);
                                strbuf_addstr(sb, color_reset);
                                strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
                                show_name(sb, current_and_HEAD);
+                               strbuf_addstr(sb, color_reset);
                        }
-                       strbuf_addstr(sb, color_reset);
 
                        prefix = separator;
                }
                decoration = decoration->next;
        }
-       strbuf_addstr(sb, color_commit);
-       strbuf_addstr(sb, suffix);
-       strbuf_addstr(sb, color_reset);
+       if (*suffix) {
+               strbuf_addstr(sb, color_commit);
+               strbuf_addstr(sb, suffix);
+               strbuf_addstr(sb, color_reset);
+       }
 }
 
 void show_decorations(struct rev_info *opt, struct commit *commit)
@@ -368,7 +400,7 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
        }
        if (!opt->show_decorations)
                return;
-       format_decorations(&sb, commit, opt->diffopt.use_color);
+       format_decorations(&sb, commit, opt->diffopt.use_color, NULL);
        fputs(sb.buf, opt->diffopt.file);
        strbuf_release(&sb);
 }
index e7e4641cf83c5b7cfd4457b54a88115723ac979d..41c776fea52e6867800caf2eb919379fc6e54218 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef LOG_TREE_H
 #define LOG_TREE_H
 
-#include "revision.h"
+struct rev_info;
 
 struct log_info {
        struct commit *commit, *parent;
@@ -13,17 +13,20 @@ struct decoration_filter {
        struct string_list *exclude_ref_config_pattern;
 };
 
+struct decoration_options {
+       char *prefix;
+       char *suffix;
+       char *separator;
+       char *pointer;
+       char *tag;
+};
+
 int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);
 int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 void show_log(struct rev_info *opt);
-void format_decorations_extended(struct strbuf *sb, const struct commit *commit,
-                            int use_color,
-                            const char *prefix,
-                            const char *separator,
-                            const char *suffix);
-#define format_decorations(strbuf, commit, color) \
-                            format_decorations_extended((strbuf), (commit), (color), " (", ", ", ")")
+void format_decorations(struct strbuf *sb, const struct commit *commit,
+                       int use_color, const struct decoration_options *opts);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                             const char **extra_headers_p,
index f385938b64c6f9758a440195449a8fdca54ad0ef..0e49b932c308b24a5654910d5e0197cf1388162e 100644 (file)
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -72,7 +72,7 @@ struct ls_refs_data {
        unsigned symrefs;
        struct strvec prefixes;
        struct strbuf buf;
-       struct string_list hidden_refs;
+       struct strvec hidden_refs;
        unsigned unborn : 1;
 };
 
@@ -137,6 +137,7 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
 }
 
 static int ls_refs_config(const char *var, const char *value,
+                         const struct config_context *ctx UNUSED,
                          void *cb_data)
 {
        struct ls_refs_data *data = cb_data;
@@ -155,7 +156,7 @@ int ls_refs(struct repository *r, struct packet_reader *request)
        memset(&data, 0, sizeof(data));
        strvec_init(&data.prefixes);
        strbuf_init(&data.buf, 0);
-       string_list_init_dup(&data.hidden_refs);
+       strvec_init(&data.hidden_refs);
 
        git_config(ls_refs_config, &data);
 
@@ -193,11 +194,12 @@ int ls_refs(struct repository *r, struct packet_reader *request)
                strvec_push(&data.prefixes, "");
        refs_for_each_fullref_in_prefixes(get_main_ref_store(r),
                                          get_git_namespace(), data.prefixes.v,
+                                         hidden_refs_to_excludes(&data.hidden_refs),
                                          send_ref, &data);
        packet_fflush(stdout);
        strvec_clear(&data.prefixes);
        strbuf_release(&data.buf);
-       string_list_clear(&data.hidden_refs, 0);
+       strvec_clear(&data.hidden_refs);
        return 0;
 }
 
index 2aeb20e5e6268ebbd14a1a4538bfe8842e1b11ec..a07d2da16dedb2779a9797cfa185ec29d9321491 100644 (file)
@@ -1,7 +1,7 @@
 #include "git-compat-util.h"
 #include "config.h"
 #include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
 #include "utf8.h"
 #include "strbuf.h"
 #include "mailinfo.h"
@@ -1241,12 +1241,13 @@ int mailinfo_parse_quoted_cr_action(const char *actionstr, int *action)
        return 0;
 }
 
-static int git_mailinfo_config(const char *var, const char *value, void *mi_)
+static int git_mailinfo_config(const char *var, const char *value,
+                              const struct config_context *ctx, void *mi_)
 {
        struct mailinfo *mi = mi_;
 
        if (!starts_with(var, "mailinfo."))
-               return git_default_config(var, value, NULL);
+               return git_default_config(var, value, ctx, NULL);
        if (!strcmp(var, "mailinfo.scissors")) {
                mi->use_scissors = git_config_bool(var, value);
                return 0;
index 5dc5223c430949030d0ceb5aa8a29c6d7e6c02aa..3d6a5e9400f4c8195d0f58ab58f3f9a4dfa0acba 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -3,7 +3,7 @@
 #include "string-list.h"
 #include "mailmap.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "setup.h"
 
 const char *git_mailmap_file;
index 6bc8eb76477b75e3b8ed32a1f9770e27f235e80f..0885ac681cd5055f80fb5088b04c92eed8e7f291 100644 (file)
@@ -1,9 +1,10 @@
 #include "git-compat-util.h"
 #include "hex.h"
 #include "match-trees.h"
+#include "strbuf.h"
 #include "tree.h"
 #include "tree-walk.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 static int score_missing(unsigned mode)
 {
index 5632ff6abb68146b3d6db6a96009a2454f4f339b..9293cbf75c8ab737a2cf7267d3e31ffd93a48dc8 100644 (file)
@@ -1,10 +1,10 @@
 #include "git-compat-util.h"
 #include "run-command.h"
 #include "xdiff-interface.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "blob.h"
 #include "merge-blobs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
 {
similarity index 92%
rename from ll-merge.c
rename to merge-ll.c
index 07ec16e8e5bb59f091a1c41df123abce3cefe337..8fcf2d3710ed1a87bd851abe04dd22a32fafdf84 100644 (file)
 #include "attr.h"
 #include "xdiff-interface.h"
 #include "run-command.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "quote.h"
 #include "strbuf.h"
-#include "wrapper.h"
 
 struct ll_merge_driver;
 
@@ -192,24 +191,15 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
                        const struct ll_merge_options *opts,
                        int marker_size)
 {
-       char temp[4][50];
+       char temp[3][50];
        struct strbuf cmd = STRBUF_INIT;
-       struct strbuf_expand_dict_entry dict[6];
-       struct strbuf path_sq = STRBUF_INIT;
+       const char *format = fn->cmdline;
        struct child_process child = CHILD_PROCESS_INIT;
        int status, fd, i;
        struct stat st;
        enum ll_merge_result ret;
        assert(opts);
 
-       sq_quote_buf(&path_sq, path);
-       dict[0].placeholder = "O"; dict[0].value = temp[0];
-       dict[1].placeholder = "A"; dict[1].value = temp[1];
-       dict[2].placeholder = "B"; dict[2].value = temp[2];
-       dict[3].placeholder = "L"; dict[3].value = temp[3];
-       dict[4].placeholder = "P"; dict[4].value = path_sq.buf;
-       dict[5].placeholder = NULL; dict[5].value = NULL;
-
        if (!fn->cmdline)
                die("custom merge driver %s lacks command line.", fn->name);
 
@@ -218,9 +208,23 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
        create_temp(orig, temp[0], sizeof(temp[0]));
        create_temp(src1, temp[1], sizeof(temp[1]));
        create_temp(src2, temp[2], sizeof(temp[2]));
-       xsnprintf(temp[3], sizeof(temp[3]), "%d", marker_size);
 
-       strbuf_expand(&cmd, fn->cmdline, strbuf_expand_dict_cb, &dict);
+       while (strbuf_expand_step(&cmd, &format)) {
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(&cmd, '%');
+               else if (skip_prefix(format, "O", &format))
+                       strbuf_addstr(&cmd, temp[0]);
+               else if (skip_prefix(format, "A", &format))
+                       strbuf_addstr(&cmd, temp[1]);
+               else if (skip_prefix(format, "B", &format))
+                       strbuf_addstr(&cmd, temp[2]);
+               else if (skip_prefix(format, "L", &format))
+                       strbuf_addf(&cmd, "%d", marker_size);
+               else if (skip_prefix(format, "P", &format))
+                       sq_quote_buf(&cmd, path);
+               else
+                       strbuf_addch(&cmd, '%');
+       }
 
        child.use_shell = 1;
        strvec_push(&child.args, cmd.buf);
@@ -242,8 +246,13 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
        for (i = 0; i < 3; i++)
                unlink_or_warn(temp[i]);
        strbuf_release(&cmd);
-       strbuf_release(&path_sq);
-       ret = (status > 0) ? LL_MERGE_CONFLICT : status;
+       if (!status)
+               ret = LL_MERGE_OK;
+       else if (status <= 128)
+               ret = LL_MERGE_CONFLICT;
+       else
+               /* died due to a signal: WTERMSIG(status) + 128 */
+               ret = LL_MERGE_ERROR;
        return ret;
 }
 
@@ -254,6 +263,7 @@ 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,
+                            const struct config_context *ctx UNUSED,
                             void *cb UNUSED)
 {
        struct ll_merge_driver *fn;
similarity index 100%
rename from ll-merge.h
rename to merge-ll.h
index a5507533009abca90617b388f93a7e335049eb16..4acedf3c3386d7c9c2e57eebabddb1fe9ec27331 100644 (file)
@@ -1,8 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "gettext.h"
 #include "hash.h"
 #include "merge-ort.h"
 #include "merge-ort-wrappers.h"
+#include "read-cache-ll.h"
 #include "tree.h"
 
 #include "commit.h"
index a50b095c470ef520f1b1b769ff40488edeb2e496..6491070d965835f9202b68fbdae72cb6cd6c987f 100644 (file)
@@ -14,7 +14,7 @@
  * "cale", "peedy", or "ins" instead of "ort"?)
  */
 
-#include "cache.h"
+#include "git-compat-util.h"
 #include "merge-ort.h"
 
 #include "alloc.h"
 #include "gettext.h"
 #include "hex.h"
 #include "entry.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "match-trees.h"
 #include "mem-pool.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oid-array.h"
+#include "path.h"
 #include "promisor-remote.h"
+#include "read-cache-ll.h"
 #include "revision.h"
+#include "sparse-index.h"
 #include "strmap.h"
 #include "submodule-config.h"
 #include "submodule.h"
@@ -718,23 +721,6 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
        renames->callback_data_nr = renames->callback_data_alloc = 0;
 }
 
-__attribute__((format (printf, 2, 3)))
-static int err(struct merge_options *opt, const char *err, ...)
-{
-       va_list params;
-       struct strbuf sb = STRBUF_INIT;
-
-       strbuf_addstr(&sb, "error: ");
-       va_start(params, err);
-       strbuf_vaddf(&sb, err, params);
-       va_end(params);
-
-       error("%s", sb.buf);
-       strbuf_release(&sb);
-
-       return -1;
-}
-
 static void format_commit(struct strbuf *sb,
                          int indent,
                          struct repository *repo,
@@ -1916,6 +1902,7 @@ static void initialize_attr_index(struct merge_options *opt)
        struct index_state *attr_index = &opt->priv->attr_index;
        struct cache_entry *ce;
 
+       attr_index->repo = opt->repo;
        attr_index->initialized = 1;
 
        if (!opt->renormalize)
@@ -2050,7 +2037,7 @@ static int handle_content_merge(struct merge_options *opt,
         * the three blobs to merge on various sides of history.
         *
         * extra_marker_size is the amount to extend conflict markers in
-        * ll_merge; this is neeed if we have content merges of content
+        * ll_merge; this is needed if we have content merges of content
         * merges, which happens for example with rename/rename(2to1) and
         * rename/add conflicts.
         */
@@ -2119,13 +2106,12 @@ static int handle_content_merge(struct merge_options *opt,
                                          &result_buf);
 
                if ((merge_status < 0) || !result_buf.ptr)
-                       ret = err(opt, _("Failed to execute internal merge"));
+                       ret = error(_("failed to execute internal merge"));
 
                if (!ret &&
                    write_object_file(result_buf.ptr, result_buf.size,
                                      OBJ_BLOB, &result->oid))
-                       ret = err(opt, _("Unable to add %s to database"),
-                                 path);
+                       ret = error(_("unable to add %s to database"), path);
 
                free(result_buf.ptr);
                if (ret)
@@ -3339,10 +3325,7 @@ static int collect_renames(struct merge_options *opt,
        return clean;
 }
 
-static int detect_and_process_renames(struct merge_options *opt,
-                                     struct tree *merge_base,
-                                     struct tree *side1,
-                                     struct tree *side2)
+static int detect_and_process_renames(struct merge_options *opt)
 {
        struct diff_queue_struct combined = { 0 };
        struct rename_info *renames = &opt->priv->renames;
@@ -3506,8 +3489,7 @@ static int sort_dirs_next_to_their_children(const char *one, const char *two)
                return c1 - c2;
 }
 
-static int read_oid_strbuf(struct merge_options *opt,
-                          const struct object_id *oid,
+static int read_oid_strbuf(const struct object_id *oid,
                           struct strbuf *dst)
 {
        void *buf;
@@ -3515,10 +3497,10 @@ static int read_oid_strbuf(struct merge_options *opt,
        unsigned long size;
        buf = repo_read_object_file(the_repository, oid, &type, &size);
        if (!buf)
-               return err(opt, _("cannot read object %s"), oid_to_hex(oid));
+               return error(_("cannot read object %s"), oid_to_hex(oid));
        if (type != OBJ_BLOB) {
                free(buf);
-               return err(opt, _("object %s is not a blob"), oid_to_hex(oid));
+               return error(_("object %s is not a blob"), oid_to_hex(oid));
        }
        strbuf_attach(dst, buf, size, size + 1);
        return 0;
@@ -3542,8 +3524,8 @@ static int blob_unchanged(struct merge_options *opt,
        if (oideq(&base->oid, &side->oid))
                return 1;
 
-       if (read_oid_strbuf(opt, &base->oid, &basebuf) ||
-           read_oid_strbuf(opt, &side->oid, &sidebuf))
+       if (read_oid_strbuf(&base->oid, &basebuf) ||
+           read_oid_strbuf(&side->oid, &sidebuf))
                goto error_return;
        /*
         * Note: binary | is used so that both renormalizations are
@@ -4899,8 +4881,7 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
        trace2_region_leave("merge", "allocate/init", opt->repo);
 }
 
-static void merge_check_renames_reusable(struct merge_options *opt,
-                                        struct merge_result *result,
+static void merge_check_renames_reusable(struct merge_result *result,
                                         struct tree *merge_base,
                                         struct tree *side1,
                                         struct tree *side2)
@@ -4970,7 +4951,7 @@ redo:
                 * TRANSLATORS: The %s arguments are: 1) tree hash of a merge
                 * base, and 2-3) the trees for the two trees we're merging.
                 */
-               err(opt, _("collecting merge info failed for trees %s, %s, %s"),
+               error(_("collecting merge info failed for trees %s, %s, %s"),
                    oid_to_hex(&merge_base->object.oid),
                    oid_to_hex(&side1->object.oid),
                    oid_to_hex(&side2->object.oid));
@@ -4980,8 +4961,7 @@ redo:
        trace2_region_leave("merge", "collect_merge_info", opt->repo);
 
        trace2_region_enter("merge", "renames", opt->repo);
-       result->clean = detect_and_process_renames(opt, merge_base,
-                                                  side1, side2);
+       result->clean = detect_and_process_renames(opt);
        trace2_region_leave("merge", "renames", opt->repo);
        if (opt->priv->renames.redo_after_renames == 2) {
                trace2_region_enter("merge", "reset_maps", opt->repo);
@@ -5103,7 +5083,7 @@ void merge_incore_nonrecursive(struct merge_options *opt,
 
        trace2_region_enter("merge", "merge_start", opt->repo);
        assert(opt->ancestor != NULL);
-       merge_check_renames_reusable(opt, result, merge_base, side1, side2);
+       merge_check_renames_reusable(result, merge_base, side1, side2);
        merge_start(opt, result);
        /*
         * Record the trees used in this merge, so if there's a next merge in
index 8e87b6386d9f7aee03ba63ee005122eb5d2556b7..e3beb0801b115691d84b5da3403bc52abcb97336 100644 (file)
@@ -3,7 +3,7 @@
  * Fredrik Kuivinen.
  * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "merge-recursive.h"
 
 #include "advice.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "lockfile.h"
 #include "match-trees.h"
+#include "name-hash.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
 #include "revision.h"
+#include "sparse-index.h"
 #include "string-list.h"
 #include "submodule-config.h"
 #include "submodule.h"
@@ -35,7 +38,6 @@
 #include "tag.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
-#include "wrapper.h"
 #include "xdiff-interface.h"
 
 struct merge_options_internal {
@@ -1381,12 +1383,12 @@ static int merge_mode_and_contents(struct merge_options *opt,
                                                  extra_marker_size);
 
                        if ((merge_status < 0) || !result_buf.ptr)
-                               ret = err(opt, _("Failed to execute internal merge"));
+                               ret = err(opt, _("failed to execute internal merge"));
 
                        if (!ret &&
                            write_object_file(result_buf.ptr, result_buf.size,
                                              OBJ_BLOB, &result->blob.oid))
-                               ret = err(opt, _("Unable to add %s to database"),
+                               ret = err(opt, _("unable to add %s to database"),
                                          a->path);
 
                        free(result_buf.ptr);
@@ -3910,6 +3912,22 @@ void init_merge_options(struct merge_options *opt,
                opt->buffer_output = 0;
 }
 
+/*
+ * For now, members of merge_options do not need deep copying, but
+ * it may change in the future, in which case we would need to update
+ * this, and also make a matching change to clear_merge_options() to
+ * release the resources held by a copied instance.
+ */
+void copy_merge_options(struct merge_options *dst, struct merge_options *src)
+{
+       *dst = *src;
+}
+
+void clear_merge_options(struct merge_options *opt UNUSED)
+{
+       ; /* no-op as our copy is shallow right now */
+}
+
 int parse_merge_opt(struct merge_options *opt, const char *s)
 {
        const char *arg;
index b88000e3c25277d07d20b7ba29755b9670cd28ff..3d3b3e3c295deb0dc8470958d01f8ed1e6ef0611 100644 (file)
@@ -55,6 +55,9 @@ struct merge_options {
 
 void init_merge_options(struct merge_options *opt, struct repository *repo);
 
+void copy_merge_options(struct merge_options *dst, struct merge_options *src);
+void clear_merge_options(struct merge_options *opt);
+
 /* parse the option in s and update the relevant field of opt */
 int parse_merge_opt(struct merge_options *opt, const char *s);
 
diff --git a/merge.c b/merge.c
index 10aaec3a6c1afca8fef4e3aac3dcd0d1cd2b9f63..b60925459c292bbb4a9daae46534edfbb3eca756 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -1,10 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "lockfile.h"
+#include "merge.h"
 #include "commit.h"
+#include "repository.h"
 #include "run-command.h"
 #include "resolve-undo.h"
 #include "tree.h"
diff --git a/merge.h b/merge.h
new file mode 100644 (file)
index 0000000..21ac7ef
--- /dev/null
+++ b/merge.h
@@ -0,0 +1,17 @@
+#ifndef MERGE_H
+#define MERGE_H
+
+struct commit_list;
+struct object_id;
+struct repository;
+
+int try_merge_command(struct repository *r,
+               const char *strategy, size_t xopts_nr,
+               const char **xopts, struct commit_list *common,
+               const char *head_arg, struct commit_list *remotes);
+int checkout_fast_forward(struct repository *r,
+                         const struct object_id *from,
+                         const struct object_id *to,
+                         int overwrite_ignore);
+
+#endif /* MERGE_H */
diff --git a/midx.c b/midx.c
index b500174d1f3d1a895463a13fb59850eb2f1b88f5..2f3863c936a4c1c9035f90ae28b73887cf8f24b2 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "csum-file.h"
 #include "dir.h"
@@ -9,7 +8,7 @@
 #include "lockfile.h"
 #include "packfile.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "hash-lookup.h"
 #include "midx.h"
 #include "progress.h"
@@ -72,6 +71,33 @@ static int midx_read_oid_fanout(const unsigned char *chunk_start,
                error(_("multi-pack-index OID fanout is of the wrong size"));
                return 1;
        }
+       m->num_objects = ntohl(m->chunk_oid_fanout[255]);
+       return 0;
+}
+
+static int midx_read_oid_lookup(const unsigned char *chunk_start,
+                               size_t chunk_size, void *data)
+{
+       struct multi_pack_index *m = data;
+       m->chunk_oid_lookup = chunk_start;
+
+       if (chunk_size != st_mult(m->hash_len, m->num_objects)) {
+               error(_("multi-pack-index OID lookup chunk is the wrong size"));
+               return 1;
+       }
+       return 0;
+}
+
+static int midx_read_object_offsets(const unsigned char *chunk_start,
+                                   size_t chunk_size, void *data)
+{
+       struct multi_pack_index *m = data;
+       m->chunk_object_offsets = chunk_start;
+
+       if (chunk_size != st_mult(m->num_objects, MIDX_CHUNK_OFFSET_WIDTH)) {
+               error(_("multi-pack-index object offset chunk is the wrong size"));
+               return 1;
+       }
        return 0;
 }
 
@@ -141,33 +167,41 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
        cf = init_chunkfile(NULL);
 
        if (read_table_of_contents(cf, m->data, midx_size,
-                                  MIDX_HEADER_SIZE, m->num_chunks))
+                                  MIDX_HEADER_SIZE, m->num_chunks,
+                                  MIDX_CHUNK_ALIGNMENT))
                goto cleanup_fail;
 
-       if (pair_chunk(cf, MIDX_CHUNKID_PACKNAMES, &m->chunk_pack_names) == CHUNK_NOT_FOUND)
-               die(_("multi-pack-index missing required pack-name chunk"));
-       if (read_chunk(cf, MIDX_CHUNKID_OIDFANOUT, midx_read_oid_fanout, m) == CHUNK_NOT_FOUND)
-               die(_("multi-pack-index missing required OID fanout chunk"));
-       if (pair_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, &m->chunk_oid_lookup) == CHUNK_NOT_FOUND)
-               die(_("multi-pack-index missing required OID lookup chunk"));
-       if (pair_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, &m->chunk_object_offsets) == CHUNK_NOT_FOUND)
-               die(_("multi-pack-index missing required object offsets chunk"));
+       if (pair_chunk(cf, MIDX_CHUNKID_PACKNAMES, &m->chunk_pack_names, &m->chunk_pack_names_len))
+               die(_("multi-pack-index required pack-name chunk missing or corrupted"));
+       if (read_chunk(cf, MIDX_CHUNKID_OIDFANOUT, midx_read_oid_fanout, m))
+               die(_("multi-pack-index required OID fanout chunk missing or corrupted"));
+       if (read_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, midx_read_oid_lookup, m))
+               die(_("multi-pack-index required OID lookup chunk missing or corrupted"));
+       if (read_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, midx_read_object_offsets, m))
+               die(_("multi-pack-index required object offsets chunk missing or corrupted"));
 
-       pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets);
+       pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets,
+                  &m->chunk_large_offsets_len);
 
        if (git_env_bool("GIT_TEST_MIDX_READ_RIDX", 1))
-               pair_chunk(cf, MIDX_CHUNKID_REVINDEX, &m->chunk_revindex);
-
-       m->num_objects = ntohl(m->chunk_oid_fanout[255]);
+               pair_chunk(cf, MIDX_CHUNKID_REVINDEX, &m->chunk_revindex,
+                          &m->chunk_revindex_len);
 
        CALLOC_ARRAY(m->pack_names, m->num_packs);
        CALLOC_ARRAY(m->packs, m->num_packs);
 
        cur_pack_name = (const char *)m->chunk_pack_names;
        for (i = 0; i < m->num_packs; i++) {
+               const char *end;
+               size_t avail = m->chunk_pack_names_len -
+                               (cur_pack_name - (const char *)m->chunk_pack_names);
+
                m->pack_names[i] = cur_pack_name;
 
-               cur_pack_name += strlen(cur_pack_name) + 1;
+               end = memchr(cur_pack_name, '\0', avail);
+               if (!end)
+                       die(_("multi-pack-index pack-name chunk is too short"));
+               cur_pack_name = end + 1;
 
                if (i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0)
                        die(_("multi-pack-index pack names out of order: '%s' before '%s'"),
@@ -254,7 +288,7 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid,
        if (n >= m->num_objects)
                return NULL;
 
-       oidread(oid, m->chunk_oid_lookup + m->hash_len * n);
+       oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n));
        return oid;
 }
 
@@ -271,6 +305,8 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
                        die(_("multi-pack-index stores a 64-bit offset, but off_t is too small"));
 
                offset32 ^= MIDX_LARGE_OFFSET_NEEDED;
+               if (offset32 >= m->chunk_large_offsets_len / sizeof(uint64_t))
+                       die(_("multi-pack-index large offset out of bounds"));
                return get_be64(m->chunk_large_offsets + sizeof(uint64_t) * offset32);
        }
 
@@ -445,14 +481,14 @@ static int idx_or_pack_name_cmp(const void *_va, const void *_vb)
 
 struct write_midx_context {
        struct pack_info *info;
-       uint32_t nr;
-       uint32_t alloc;
+       size_t nr;
+       size_t alloc;
        struct multi_pack_index *m;
        struct progress *progress;
        unsigned pack_paths_checked;
 
        struct pack_midx_entry *entries;
-       uint32_t entries_nr;
+       size_t entries_nr;
 
        uint32_t *pack_perm;
        uint32_t *pack_order;
@@ -584,12 +620,14 @@ static void fill_pack_entry(uint32_t pack_int_id,
 
 struct midx_fanout {
        struct pack_midx_entry *entries;
-       uint32_t nr;
-       uint32_t alloc;
+       size_t nr, alloc;
 };
 
-static void midx_fanout_grow(struct midx_fanout *fanout, uint32_t nr)
+static void midx_fanout_grow(struct midx_fanout *fanout, size_t nr)
 {
+       if (nr < fanout->nr)
+               BUG("negative growth in midx_fanout_grow() (%"PRIuMAX" < %"PRIuMAX")",
+                   (uintmax_t)nr, (uintmax_t)fanout->nr);
        ALLOC_GROW(fanout->entries, nr, fanout->alloc);
 }
 
@@ -668,17 +706,18 @@ static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
 static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
                                                  struct pack_info *info,
                                                  uint32_t nr_packs,
-                                                 uint32_t *nr_objects,
+                                                 size_t *nr_objects,
                                                  int preferred_pack)
 {
        uint32_t cur_fanout, cur_pack, cur_object;
-       uint32_t alloc_objects, total_objects = 0;
+       size_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;
 
        for (cur_pack = start_pack; cur_pack < nr_packs; cur_pack++)
-               total_objects += info[cur_pack].p->num_objects;
+               total_objects = st_add(total_objects,
+                                      info[cur_pack].p->num_objects);
 
        /*
         * As we de-duplicate by fanout value, we expect the fanout
@@ -721,7 +760,8 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
                                                &fanout.entries[cur_object].oid))
                                continue;
 
-                       ALLOC_GROW(deduplicated_entries, *nr_objects + 1, alloc_objects);
+                       ALLOC_GROW(deduplicated_entries, st_add(*nr_objects, 1),
+                                  alloc_objects);
                        memcpy(&deduplicated_entries[*nr_objects],
                               &fanout.entries[cur_object],
                               sizeof(struct pack_midx_entry));
@@ -1496,21 +1536,22 @@ static int write_midx_internal(const char *object_dir,
        add_chunk(cf, MIDX_CHUNKID_OIDFANOUT, MIDX_CHUNK_FANOUT_SIZE,
                  write_midx_oid_fanout);
        add_chunk(cf, MIDX_CHUNKID_OIDLOOKUP,
-                 (size_t)ctx.entries_nr * the_hash_algo->rawsz,
+                 st_mult(ctx.entries_nr, the_hash_algo->rawsz),
                  write_midx_oid_lookup);
        add_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS,
-                 (size_t)ctx.entries_nr * MIDX_CHUNK_OFFSET_WIDTH,
+                 st_mult(ctx.entries_nr, MIDX_CHUNK_OFFSET_WIDTH),
                  write_midx_object_offsets);
 
        if (ctx.large_offsets_needed)
                add_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS,
-                       (size_t)ctx.num_large_offsets * MIDX_CHUNK_LARGE_OFFSET_WIDTH,
+                       st_mult(ctx.num_large_offsets,
+                               MIDX_CHUNK_LARGE_OFFSET_WIDTH),
                        write_midx_large_offsets);
 
        if (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
                ctx.pack_order = midx_pack_order(&ctx);
                add_chunk(cf, MIDX_CHUNKID_REVINDEX,
-                         ctx.entries_nr * sizeof(uint32_t),
+                         st_mult(ctx.entries_nr, sizeof(uint32_t)),
                          write_midx_revindex);
        }
 
@@ -1988,8 +2029,8 @@ static int fill_included_packs_batch(struct repository *r,
                if (open_pack_index(p) || !p->num_objects)
                        continue;
 
-               expected_size = (size_t)(p->pack_size
-                                        * pack_info[i].referenced_objects);
+               expected_size = st_mult(p->pack_size,
+                                       pack_info[i].referenced_objects);
                expected_size /= p->num_objects;
 
                if (expected_size >= batch_size)
diff --git a/midx.h b/midx.h
index 5578cd7b835e2b396e502e8abaf4560ab765c850..a5d98919c857b812789f44d86fb6ad13fb7e0560 100644 (file)
--- a/midx.h
+++ b/midx.h
@@ -32,11 +32,14 @@ struct multi_pack_index {
        int local;
 
        const unsigned char *chunk_pack_names;
+       size_t chunk_pack_names_len;
        const uint32_t *chunk_oid_fanout;
        const unsigned char *chunk_oid_lookup;
        const unsigned char *chunk_object_offsets;
        const unsigned char *chunk_large_offsets;
+       size_t chunk_large_offsets_len;
        const unsigned char *chunk_revindex;
+       size_t chunk_revindex_len;
 
        const char **pack_names;
        struct packed_git **packs;
index fb13716e4303ebc7c96caa49934ca67f61ae772e..251f036eef6983a66ac13013e5bee3ef770e8f9f 100644 (file)
@@ -5,9 +5,12 @@
  *
  * Copyright (C) 2008 Linus Torvalds
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "environment.h"
 #include "gettext.h"
+#include "name-hash.h"
+#include "object.h"
+#include "read-cache-ll.h"
 #include "thread-utils.h"
 #include "trace.h"
 #include "trace2.h"
diff --git a/name-hash.h b/name-hash.h
new file mode 100644 (file)
index 0000000..b1b4b0f
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef NAME_HASH_H
+#define NAME_HASH_H
+
+struct cache_entry;
+struct index_state;
+
+int index_dir_exists(struct index_state *istate, const char *name, int namelen);
+void adjust_dirname_case(struct index_state *istate, char *name);
+struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
+
+int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
+void add_name_hash(struct index_state *istate, struct cache_entry *ce);
+void remove_name_hash(struct index_state *istate, struct cache_entry *ce);
+void free_name_hash(struct index_state *istate);
+
+#endif /* NAME_HASH_H */
index 7b729376867afee47c76aaf74901aa19f3615804..de39028ab7f88058c87f735a79185da2f3b5e749 100644 (file)
@@ -3,22 +3,24 @@
 #include "../commit.h"
 #include "../fetch-negotiator.h"
 
-static void known_common(struct fetch_negotiator *n, struct commit *c)
+static void known_common(struct fetch_negotiator *n UNUSED,
+                        struct commit *c UNUSED)
 {
        /* do nothing */
 }
 
-static void add_tip(struct fetch_negotiator *n, struct commit *c)
+static void add_tip(struct fetch_negotiator *n UNUSED,
+                   struct commit *c UNUSED)
 {
        /* do nothing */
 }
 
-static const struct object_id *next(struct fetch_negotiator *n)
+static const struct object_id *next(struct fetch_negotiator *n UNUSED)
 {
        return NULL;
 }
 
-static int ack(struct fetch_negotiator *n, struct commit *c)
+static int ack(struct fetch_negotiator *n UNUSED, struct commit *c UNUSED)
 {
        /*
         * This negotiator does not emit any commits, so there is no commit to
@@ -28,7 +30,7 @@ static int ack(struct fetch_negotiator *n, struct commit *c)
        return 0;
 }
 
-static void release(struct fetch_negotiator *n)
+static void release(struct fetch_negotiator *n UNUSED)
 {
        /* nothing to release */
 }
index 14288caf98f83ca27759e6061080fd9cf791e017..0e1d5b1ac7a48d9bda8f76091a55be7c527e68cc 100644 (file)
@@ -1,10 +1,11 @@
 #include "git-compat-util.h"
 #include "notes-cache.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pretty.h"
 #include "repository.h"
 #include "commit.h"
 #include "refs.h"
+#include "strbuf.h"
 
 static int notes_cache_match_validity(struct repository *r,
                                      const char *ref,
index 233e49e31950ac95d38418e41f5d6cae19e79e3c..8799b522a55f31869dcc8cbfd7229cc8db65af4c 100644 (file)
@@ -5,13 +5,14 @@
 #include "refs.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "hex.h"
 #include "xdiff-interface.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "dir.h"
 #include "notes.h"
 #include "notes-merge.h"
@@ -19,7 +20,6 @@
 #include "trace.h"
 #include "notes-utils.h"
 #include "commit-reach.h"
-#include "wrapper.h"
 
 struct notes_merge_pair {
        struct object_id obj, base, local, remote;
index 4a793eb347f74bf031b69d9315d2c678793e4935..97c031c26ec7c7c2fdade8478fa039d470820bad 100644 (file)
@@ -94,7 +94,9 @@ static combine_notes_fn parse_combine_notes_fn(const char *v)
                return NULL;
 }
 
-static int notes_rewrite_config(const char *k, const char *v, void *cb)
+static int notes_rewrite_config(const char *k, const char *v,
+                               const struct config_context *ctx UNUSED,
+                               void *cb)
 {
        struct notes_rewrite_cfg *c = cb;
        if (starts_with(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) {
diff --git a/notes.c b/notes.c
index f51a2d3630e4336b0f8fd264e5f637e2f2a105c1..1ef2a331ce9302e58cb2078e58b7b40a94972b3e 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -4,7 +4,7 @@
 #include "hex.h"
 #include "notes.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "tree.h"
 #include "utf8.h"
@@ -974,7 +974,9 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
        free(globs_copy);
 }
 
-static int notes_display_config(const char *k, const char *v, void *cb)
+static int notes_display_config(const char *k, const char *v,
+                               const struct config_context *ctx UNUSED,
+                               void *cb)
 {
        int *load_refs = cb;
 
diff --git a/notes.h b/notes.h
index c1682c39a97bf6d84940b64b353286dfb91282a3..064fd7143aad33424714de671f08238bdd463190 100644 (file)
--- a/notes.h
+++ b/notes.h
@@ -256,7 +256,17 @@ void free_notes(struct notes_tree *t);
 struct string_list;
 
 struct display_notes_opt {
+       /*
+        * Less than `0` is "unset", which means that the default notes
+        * are shown iff no other notes are given. Otherwise,
+        * treat it like a boolean.
+        */
        int use_default_notes;
+
+       /*
+        * A list of globs (in the same style as notes.displayRef) where
+        * notes should be loaded from.
+        */
        struct string_list extra_notes_refs;
 };
 
@@ -283,14 +293,7 @@ void disable_display_notes(struct display_notes_opt *opt, int *show_notes);
 /*
  * Load the notes machinery for displaying several notes trees.
  *
- * If 'opt' is not NULL, then it specifies additional settings for the
- * displaying:
- *
- * - suppress_default_notes indicates that the notes from
- *   core.notesRef and notes.displayRef should not be loaded.
- *
- * - extra_notes_refs may contain a list of globs (in the same style
- *   as notes.displayRef) where notes should be loaded from.
+ * 'opt' may be NULL.
  */
 void load_display_notes(struct display_notes_opt *opt);
 
index 7c1af5c8db89e6eeb364186c1d4985face1c174c..7c7afe5793641c06b10dee6f1f6735a1a476c7d9 100644 (file)
@@ -8,7 +8,6 @@
  */
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "convert.h"
 #include "environment.h"
 #include "object-file.h"
 #include "object-store.h"
 #include "oidtree.h"
+#include "path.h"
 #include "promisor-remote.h"
 #include "setup.h"
 #include "submodule.h"
 #include "fsck.h"
-#include "wrapper.h"
 
 /* The maximum size for an object header. */
 #define MAX_HEADER_LEN 32
@@ -2307,11 +2306,11 @@ int repo_has_object_file(struct repository *r,
  * report the minimal fsck error here, and rely on the caller to
  * give more context.
  */
-static int hash_format_check_report(struct fsck_options *opts,
-                                    const struct object_id *oid,
-                                    enum object_type object_type,
-                                    enum fsck_msg_type msg_type,
-                                    enum fsck_msg_id msg_id,
+static int hash_format_check_report(struct fsck_options *opts UNUSED,
+                                    const struct object_id *oid UNUSED,
+                                    enum object_type object_type UNUSED,
+                                    enum fsck_msg_type msg_type UNUSED,
+                                    enum fsck_msg_id msg_id UNUSED,
                                     const char *message)
 {
        error(_("object fails fsck: %s"), message);
@@ -2447,11 +2446,11 @@ static int index_core(struct index_state *istate,
  * binary blobs, they generally do not want to get any conversion, and
  * callers should avoid this code path when filters are requested.
  */
-static int index_stream(struct object_id *oid, int fd, size_t size,
-                       enum object_type type, const char *path,
-                       unsigned flags)
+static int index_blob_stream(struct object_id *oid, int fd, size_t size,
+                            const char *path,
+                            unsigned flags)
 {
-       return index_bulk_checkin(oid, fd, size, type, path, flags);
+       return index_blob_bulk_checkin(oid, fd, size, path, flags);
 }
 
 int index_fd(struct index_state *istate, struct object_id *oid,
@@ -2473,8 +2472,8 @@ int index_fd(struct index_state *istate, struct object_id *oid,
                ret = index_core(istate, oid, fd, xsize_t(st->st_size),
                                 type, path, flags);
        else
-               ret = index_stream(oid, fd, xsize_t(st->st_size), type, path,
-                                  flags);
+               ret = index_blob_stream(oid, fd, xsize_t(st->st_size), path,
+                                       flags);
        close(fd);
        return ret;
 }
index 6fc3fa595b87d348dbab071b0d60db02ad4e75fe..0bfa29dbbfe9b489e454c03b419092294427425d 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "object-name.h"
 #include "advice.h"
 #include "config.h"
@@ -17,7 +17,8 @@
 #include "oidtree.h"
 #include "packfile.h"
 #include "pretty.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 #include "submodule.h"
@@ -768,6 +769,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)
                find_abbrev_len_for_pack(p, mad);
 }
 
+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
+                                  const struct object_id *oid, int abbrev_len)
+{
+       int r;
+       strbuf_grow(sb, GIT_MAX_HEXSZ + 1);
+       r = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);
+       strbuf_setlen(sb, sb->len + r);
+}
+
+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
+                             int abbrev_len)
+{
+       strbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);
+}
+
 int repo_find_unique_abbrev_r(struct repository *r, char *hex,
                              const struct object_id *oid, int len)
 {
index 1d63698f42b7b5f247381ea2dd1bb8448cfc44d3..9ae52230714876b719dd3d48755ad3885030d07a 100644 (file)
@@ -40,6 +40,15 @@ struct object_context {
 const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);
 int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);
 
+/**
+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to
+ * the strbuf `sb`.
+ */
+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
+                                  const struct object_id *oid, int abbrev_len);
+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
+                             int abbrev_len);
+
 int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);
 __attribute__((format (printf, 2, 3)))
 int get_oidf(struct object_id *oid, const char *fmt, ...);
diff --git a/object-store-ll.h b/object-store-ll.h
new file mode 100644 (file)
index 0000000..26a3895
--- /dev/null
@@ -0,0 +1,533 @@
+#ifndef OBJECT_STORE_LL_H
+#define OBJECT_STORE_LL_H
+
+#include "hashmap.h"
+#include "object.h"
+#include "list.h"
+#include "thread-utils.h"
+#include "oidset.h"
+
+struct oidmap;
+struct oidtree;
+struct strbuf;
+
+struct object_directory {
+       struct object_directory *next;
+
+       /*
+        * Used to store the results of readdir(3) calls when we are OK
+        * sacrificing accuracy due to races for speed. That includes
+        * object existence with OBJECT_INFO_QUICK, as well as
+        * our search for unique abbreviated hashes. Don't use it for tasks
+        * requiring greater accuracy!
+        *
+        * Be sure to call odb_load_loose_cache() before using.
+        */
+       uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
+       struct oidtree *loose_objects_cache;
+
+       /*
+        * This is a temporary object store created by the tmp_objdir
+        * facility. Disable ref updates since the objects in the store
+        * might be discarded on rollback.
+        */
+       int disable_ref_updates;
+
+       /*
+        * This object store is ephemeral, so there is no need to fsync.
+        */
+       int will_destroy;
+
+       /*
+        * Path to the alternative object store. If this is a relative path,
+        * it is relative to the current working directory.
+        */
+       char *path;
+};
+
+struct input_stream {
+       const void *(*read)(struct input_stream *, unsigned long *len);
+       void *data;
+       int is_finished;
+};
+
+void prepare_alt_odb(struct repository *r);
+int has_alt_odb(struct repository *r);
+char *compute_alternate_path(const char *path, struct strbuf *err);
+struct object_directory *find_odb(struct repository *r, const char *obj_dir);
+typedef int alt_odb_fn(struct object_directory *, void *);
+int foreach_alt_odb(alt_odb_fn, void*);
+typedef void alternate_ref_fn(const struct object_id *oid, void *);
+void for_each_alternate_ref(alternate_ref_fn, void *);
+
+/*
+ * Add the directory to the on-disk alternates file; the new entry will also
+ * take effect in the current process.
+ */
+void add_to_alternates_file(const char *dir);
+
+/*
+ * Add the directory to the in-memory list of alternates (along with any
+ * recursive alternates it points to), but do not modify the on-disk alternates
+ * file.
+ */
+void add_to_alternates_memory(const char *dir);
+
+/*
+ * Replace the current writable object directory with the specified temporary
+ * object directory; returns the former primary object directory.
+ */
+struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy);
+
+/*
+ * Restore a previous ODB replaced by set_temporary_main_odb.
+ */
+void restore_primary_odb(struct object_directory *restore_odb, const char *old_path);
+
+/*
+ * Populate and return the loose object cache array corresponding to the
+ * given object ID.
+ */
+struct oidtree *odb_loose_cache(struct object_directory *odb,
+                                 const struct object_id *oid);
+
+/* Empty the loose object cache for the specified object directory. */
+void odb_clear_loose_cache(struct object_directory *odb);
+
+/* Clear and free the specified object directory */
+void free_object_directory(struct object_directory *odb);
+
+struct packed_git {
+       struct hashmap_entry packmap_ent;
+       struct packed_git *next;
+       struct list_head mru;
+       struct pack_window *windows;
+       off_t pack_size;
+       const void *index_data;
+       size_t index_size;
+       uint32_t num_objects;
+       size_t crc_offset;
+       struct oidset bad_objects;
+       int index_version;
+       time_t mtime;
+       int pack_fd;
+       int index;              /* for builtin/pack-objects.c */
+       unsigned pack_local:1,
+                pack_keep:1,
+                pack_keep_in_core:1,
+                freshened:1,
+                do_not_close:1,
+                pack_promisor:1,
+                multi_pack_index:1,
+                is_cruft:1;
+       unsigned char hash[GIT_MAX_RAWSZ];
+       struct revindex_entry *revindex;
+       const uint32_t *revindex_data;
+       const uint32_t *revindex_map;
+       size_t revindex_size;
+       /*
+        * mtimes_map points at the beginning of the memory mapped region of
+        * this pack's corresponding .mtimes file, and mtimes_size is the size
+        * of that .mtimes file
+        */
+       const uint32_t *mtimes_map;
+       size_t mtimes_size;
+       /* something like ".git/objects/pack/xxxxx.pack" */
+       char pack_name[FLEX_ARRAY]; /* more */
+};
+
+struct multi_pack_index;
+
+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)
+{
+       const char *key = keydata;
+       const struct packed_git *pg1, *pg2;
+
+       pg1 = container_of(entry, const struct packed_git, packmap_ent);
+       pg2 = container_of(entry2, const struct packed_git, packmap_ent);
+
+       return strcmp(pg1->pack_name, key ? key : pg2->pack_name);
+}
+
+struct raw_object_store {
+       /*
+        * Set of all object directories; the main directory is first (and
+        * cannot be NULL after initialization). Subsequent directories are
+        * alternates.
+        */
+       struct object_directory *odb;
+       struct object_directory **odb_tail;
+       struct kh_odb_path_map *odb_by_path;
+
+       int loaded_alternates;
+
+       /*
+        * A list of alternate object directories loaded from the environment;
+        * this should not generally need to be accessed directly, but will
+        * populate the "odb" list when prepare_alt_odb() is run.
+        */
+       char *alternate_db;
+
+       /*
+        * Objects that should be substituted by other objects
+        * (see git-replace(1)).
+        */
+       struct oidmap *replace_map;
+       unsigned replace_map_initialized : 1;
+       pthread_mutex_t replace_mutex; /* protect object replace functions */
+
+       struct commit_graph *commit_graph;
+       unsigned commit_graph_attempted : 1; /* if loading has been attempted */
+
+       /*
+        * private data
+        *
+        * should only be accessed directly by packfile.c and midx.c
+        */
+       struct multi_pack_index *multi_pack_index;
+
+       /*
+        * private data
+        *
+        * should only be accessed directly by packfile.c
+        */
+
+       struct packed_git *packed_git;
+       /* A most-recently-used ordered version of the packed_git list. */
+       struct list_head packed_git_mru;
+
+       struct {
+               struct packed_git **packs;
+               unsigned flags;
+       } kept_pack_cache;
+
+       /*
+        * A map of packfiles to packed_git structs for tracking which
+        * packs have been loaded already.
+        */
+       struct hashmap pack_map;
+
+       /*
+        * A fast, rough count of the number of objects in the repository.
+        * These two fields are not meant for direct access. Use
+        * repo_approximate_object_count() instead.
+        */
+       unsigned long approximate_object_count;
+       unsigned approximate_object_count_valid : 1;
+
+       /*
+        * Whether packed_git has already been populated with this repository's
+        * packs.
+        */
+       unsigned packed_git_initialized : 1;
+};
+
+struct raw_object_store *raw_object_store_new(void);
+void raw_object_store_clear(struct raw_object_store *o);
+
+/*
+ * Put in `buf` the name of the file in the local object database that
+ * would be used to store a loose object with the specified oid.
+ */
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+                             const struct object_id *oid);
+
+void *map_loose_object(struct repository *r, const struct object_id *oid,
+                      unsigned long *size);
+
+void *repo_read_object_file(struct repository *r,
+                           const struct object_id *oid,
+                           enum object_type *type,
+                           unsigned long *size);
+
+/* Read and unpack an object file into memory, write memory to an object file */
+int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
+
+void hash_object_file(const struct git_hash_algo *algo, const void *buf,
+                     unsigned long len, enum object_type type,
+                     struct object_id *oid);
+
+int write_object_file_flags(const void *buf, unsigned long len,
+                           enum object_type type, struct object_id *oid,
+                           unsigned flags);
+static inline int write_object_file(const void *buf, unsigned long len,
+                                   enum object_type type, struct object_id *oid)
+{
+       return write_object_file_flags(buf, len, type, oid, 0);
+}
+
+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
+ * to disk.
+ *
+ * Callers are responsible for calling write_object_file to record the
+ * object in persistent storage before writing any other new objects
+ * that reference it.
+ */
+int pretend_object_file(void *, unsigned long, enum object_type,
+                       struct object_id *oid);
+
+int force_object_loose(const struct object_id *oid, time_t mtime);
+
+struct object_info {
+       /* Request */
+       enum object_type *typep;
+       unsigned long *sizep;
+       off_t *disk_sizep;
+       struct object_id *delta_base_oid;
+       struct strbuf *type_name;
+       void **contentp;
+
+       /* Response */
+       enum {
+               OI_CACHED,
+               OI_LOOSE,
+               OI_PACKED,
+               OI_DBCACHED
+       } whence;
+       union {
+               /*
+                * struct {
+                *      ... Nothing to expose in this case
+                * } cached;
+                * struct {
+                *      ... Nothing to expose in this case
+                * } loose;
+                */
+               struct {
+                       struct packed_git *pack;
+                       off_t offset;
+                       unsigned int is_delta;
+               } packed;
+       } u;
+};
+
+/*
+ * Initializer for a "struct object_info" that wants no items. You may
+ * also memset() the memory to all-zeroes.
+ */
+#define OBJECT_INFO_INIT { 0 }
+
+/* Invoke lookup_replace_object() on the given hash */
+#define OBJECT_INFO_LOOKUP_REPLACE 1
+/* Allow reading from a loose object file of unknown/bogus type */
+#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
+/* Do not retry packed storage after checking packed and loose storage */
+#define OBJECT_INFO_QUICK 8
+/*
+ * Do not attempt to fetch the object if missing (even if fetch_is_missing is
+ * nonzero).
+ */
+#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
+/*
+ * This is meant for bulk prefetching of missing blobs in a partial
+ * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
+ */
+#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
+
+/* Die if object corruption (not just an object being missing) was detected. */
+#define OBJECT_INFO_DIE_IF_CORRUPT 32
+
+int oid_object_info_extended(struct repository *r,
+                            const struct object_id *,
+                            struct object_info *, unsigned flags);
+
+/*
+ * Open the loose object at path, check its hash, and return the contents,
+ * use the "oi" argument to assert things about the object, or e.g. populate its
+ * type, and size. If the object is a blob, then "contents" may return NULL,
+ * to allow streaming of large blobs.
+ *
+ * Returns 0 on success, negative on error (details may be written to stderr).
+ */
+int read_loose_object(const char *path,
+                     const struct object_id *expected_oid,
+                     struct object_id *real_oid,
+                     void **contents,
+                     struct object_info *oi);
+
+/* Retry packed storage after checking packed and loose storage */
+#define HAS_OBJECT_RECHECK_PACKED 1
+
+/*
+ * Returns 1 if the object exists. This function will not lazily fetch objects
+ * in a partial clone.
+ */
+int has_object(struct repository *r, const struct object_id *oid,
+              unsigned flags);
+
+/*
+ * These macros and functions are deprecated. If checking existence for an
+ * object that is likely to be missing and/or whose absence is relatively
+ * inconsequential (or is consequential but the caller is prepared to handle
+ * it), use has_object(), which has better defaults (no lazy fetch in a partial
+ * clone and no rechecking of packed storage). In the unlikely event that a
+ * caller needs to assert existence of an object that it fully expects to
+ * exist, and wants to trigger a lazy fetch in a partial clone, use
+ * oid_object_info_extended() with a NULL struct object_info.
+ *
+ * These functions can be removed once all callers have migrated to
+ * has_object() and/or oid_object_info_extended().
+ */
+int repo_has_object_file(struct repository *r, const struct object_id *oid);
+int repo_has_object_file_with_flags(struct repository *r,
+                                   const struct object_id *oid, int flags);
+
+/*
+ * Return true iff an alternate object database has a loose object
+ * with the specified name.  This function does not respect replace
+ * references.
+ */
+int has_loose_object_nonlocal(const struct object_id *);
+
+int has_loose_object(const struct object_id *);
+
+/**
+ * format_object_header() is a thin wrapper around s xsnprintf() that
+ * writes the initial "<type> <obj-len>" part of the loose object
+ * header. It returns the size that snprintf() returns + 1.
+ */
+int format_object_header(char *str, size_t size, enum object_type type,
+                        size_t objsize);
+
+void assert_oid_type(const struct object_id *oid, enum object_type expect);
+
+/*
+ * Enabling the object read lock allows multiple threads to safely call the
+ * following functions in parallel: repo_read_object_file(),
+ * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
+ *
+ * obj_read_lock() and obj_read_unlock() may also be used to protect other
+ * section which cannot execute in parallel with object reading. Since the used
+ * lock is a recursive mutex, these sections can even contain calls to object
+ * reading functions. However, beware that in these cases zlib inflation won't
+ * be performed in parallel, losing performance.
+ *
+ * TODO: oid_object_info_extended()'s call stack has a recursive behavior. If
+ * any of its callees end up calling it, this recursive call won't benefit from
+ * parallel inflation.
+ */
+void enable_obj_read_lock(void);
+void disable_obj_read_lock(void);
+
+extern int obj_read_use_lock;
+extern pthread_mutex_t obj_read_mutex;
+
+static inline void obj_read_lock(void)
+{
+       if(obj_read_use_lock)
+               pthread_mutex_lock(&obj_read_mutex);
+}
+
+static inline void obj_read_unlock(void)
+{
+       if(obj_read_use_lock)
+               pthread_mutex_unlock(&obj_read_mutex);
+}
+
+/*
+ * Iterate over the files in the loose-object parts of the object
+ * directory "path", triggering the following callbacks:
+ *
+ *  - loose_object is called for each loose object we find.
+ *
+ *  - loose_cruft is called for any files that do not appear to be
+ *    loose objects. Note that we only look in the loose object
+ *    directories "objects/[0-9a-f]{2}/", so we will not report
+ *    "objects/foobar" as cruft.
+ *
+ *  - loose_subdir is called for each top-level hashed subdirectory
+ *    of the object directory (e.g., "$OBJDIR/f0"). It is called
+ *    after the objects in the directory are processed.
+ *
+ * Any callback that is NULL will be ignored. Callbacks returning non-zero
+ * will end the iteration.
+ *
+ * In the "buf" variant, "path" is a strbuf which will also be used as a
+ * scratch buffer, but restored to its original contents before
+ * the function returns.
+ */
+typedef int each_loose_object_fn(const struct object_id *oid,
+                                const char *path,
+                                void *data);
+typedef int each_loose_cruft_fn(const char *basename,
+                               const char *path,
+                               void *data);
+typedef int each_loose_subdir_fn(unsigned int nr,
+                                const char *path,
+                                void *data);
+int for_each_file_in_obj_subdir(unsigned int subdir_nr,
+                               struct strbuf *path,
+                               each_loose_object_fn obj_cb,
+                               each_loose_cruft_fn cruft_cb,
+                               each_loose_subdir_fn subdir_cb,
+                               void *data);
+int for_each_loose_file_in_objdir(const char *path,
+                                 each_loose_object_fn obj_cb,
+                                 each_loose_cruft_fn cruft_cb,
+                                 each_loose_subdir_fn subdir_cb,
+                                 void *data);
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
+                                     each_loose_object_fn obj_cb,
+                                     each_loose_cruft_fn cruft_cb,
+                                     each_loose_subdir_fn subdir_cb,
+                                     void *data);
+
+/* Flags for for_each_*_object() below. */
+enum for_each_object_flags {
+       /* Iterate only over local objects, not alternates. */
+       FOR_EACH_OBJECT_LOCAL_ONLY = (1<<0),
+
+       /* Only iterate over packs obtained from the promisor remote. */
+       FOR_EACH_OBJECT_PROMISOR_ONLY = (1<<1),
+
+       /*
+        * Visit objects within a pack in packfile order rather than .idx order
+        */
+       FOR_EACH_OBJECT_PACK_ORDER = (1<<2),
+
+       /* Only iterate over packs that are not marked as kept in-core. */
+       FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS = (1<<3),
+
+       /* Only iterate over packs that do not have .keep files. */
+       FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
+};
+
+/*
+ * Iterate over all accessible loose objects without respect to
+ * reachability. By default, this includes both local and alternate objects.
+ * The order in which objects are visited is unspecified.
+ *
+ * Any flags specific to packs are ignored.
+ */
+int for_each_loose_object(each_loose_object_fn, void *,
+                         enum for_each_object_flags flags);
+
+/*
+ * Iterate over all accessible packed objects without respect to reachability.
+ * By default, this includes both local and alternate packs.
+ *
+ * Note that some objects may appear twice if they are found in multiple packs.
+ * Each pack is visited in an unspecified order. By default, objects within a
+ * pack are visited in pack-idx order (i.e., sorted by oid).
+ */
+typedef int each_packed_object_fn(const struct object_id *oid,
+                                 struct packed_git *pack,
+                                 uint32_t pos,
+                                 void *data);
+int for_each_object_in_pack(struct packed_git *p,
+                           each_packed_object_fn, void *data,
+                           enum for_each_object_flags flags);
+int for_each_packed_object(each_packed_object_fn, void *,
+                          enum for_each_object_flags flags);
+
+#endif /* OBJECT_STORE_LL_H */
index 12415e5ea739d74df5f351ab5da41bcd862827aa..1b3e3d7d0145be18b523ea836aaac3e84c06af4e 100644 (file)
 #ifndef OBJECT_STORE_H
 #define OBJECT_STORE_H
 
-#include "object.h"
-#include "list.h"
-#include "thread-utils.h"
 #include "khash.h"
 #include "dir.h"
-#include "oidset.h"
-
-struct oidmap;
-struct oidtree;
-struct strbuf;
-
-struct object_directory {
-       struct object_directory *next;
-
-       /*
-        * Used to store the results of readdir(3) calls when we are OK
-        * sacrificing accuracy due to races for speed. That includes
-        * object existence with OBJECT_INFO_QUICK, as well as
-        * our search for unique abbreviated hashes. Don't use it for tasks
-        * requiring greater accuracy!
-        *
-        * Be sure to call odb_load_loose_cache() before using.
-        */
-       uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
-       struct oidtree *loose_objects_cache;
-
-       /*
-        * This is a temporary object store created by the tmp_objdir
-        * facility. Disable ref updates since the objects in the store
-        * might be discarded on rollback.
-        */
-       int disable_ref_updates;
-
-       /*
-        * This object store is ephemeral, so there is no need to fsync.
-        */
-       int will_destroy;
-
-       /*
-        * Path to the alternative object store. If this is a relative path,
-        * it is relative to the current working directory.
-        */
-       char *path;
-};
-
-struct input_stream {
-       const void *(*read)(struct input_stream *, unsigned long *len);
-       void *data;
-       int is_finished;
-};
+#include "object-store-ll.h"
 
 KHASH_INIT(odb_path_map, const char * /* key: odb_path */,
        struct object_directory *, 1, fspathhash, fspatheq)
 
-void prepare_alt_odb(struct repository *r);
-int has_alt_odb(struct repository *r);
-char *compute_alternate_path(const char *path, struct strbuf *err);
-struct object_directory *find_odb(struct repository *r, const char *obj_dir);
-typedef int alt_odb_fn(struct object_directory *, void *);
-int foreach_alt_odb(alt_odb_fn, void*);
-typedef void alternate_ref_fn(const struct object_id *oid, void *);
-void for_each_alternate_ref(alternate_ref_fn, void *);
-
-/*
- * Add the directory to the on-disk alternates file; the new entry will also
- * take effect in the current process.
- */
-void add_to_alternates_file(const char *dir);
-
-/*
- * Add the directory to the in-memory list of alternates (along with any
- * recursive alternates it points to), but do not modify the on-disk alternates
- * file.
- */
-void add_to_alternates_memory(const char *dir);
-
-/*
- * Replace the current writable object directory with the specified temporary
- * object directory; returns the former primary object directory.
- */
-struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy);
-
-/*
- * Restore a previous ODB replaced by set_temporary_main_odb.
- */
-void restore_primary_odb(struct object_directory *restore_odb, const char *old_path);
-
-/*
- * Populate and return the loose object cache array corresponding to the
- * given object ID.
- */
-struct oidtree *odb_loose_cache(struct object_directory *odb,
-                                 const struct object_id *oid);
-
-/* Empty the loose object cache for the specified object directory. */
-void odb_clear_loose_cache(struct object_directory *odb);
-
-/* Clear and free the specified object directory */
-void free_object_directory(struct object_directory *odb);
-
-struct packed_git {
-       struct hashmap_entry packmap_ent;
-       struct packed_git *next;
-       struct list_head mru;
-       struct pack_window *windows;
-       off_t pack_size;
-       const void *index_data;
-       size_t index_size;
-       uint32_t num_objects;
-       uint32_t crc_offset;
-       struct oidset bad_objects;
-       int index_version;
-       time_t mtime;
-       int pack_fd;
-       int index;              /* for builtin/pack-objects.c */
-       unsigned pack_local:1,
-                pack_keep:1,
-                pack_keep_in_core:1,
-                freshened:1,
-                do_not_close:1,
-                pack_promisor:1,
-                multi_pack_index:1,
-                is_cruft:1;
-       unsigned char hash[GIT_MAX_RAWSZ];
-       struct revindex_entry *revindex;
-       const uint32_t *revindex_data;
-       const uint32_t *revindex_map;
-       size_t revindex_size;
-       /*
-        * mtimes_map points at the beginning of the memory mapped region of
-        * this pack's corresponding .mtimes file, and mtimes_size is the size
-        * of that .mtimes file
-        */
-       const uint32_t *mtimes_map;
-       size_t mtimes_size;
-       /* something like ".git/objects/pack/xxxxx.pack" */
-       char pack_name[FLEX_ARRAY]; /* more */
-};
-
-struct multi_pack_index;
-
-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)
-{
-       const char *key = keydata;
-       const struct packed_git *pg1, *pg2;
-
-       pg1 = container_of(entry, const struct packed_git, packmap_ent);
-       pg2 = container_of(entry2, const struct packed_git, packmap_ent);
-
-       return strcmp(pg1->pack_name, key ? key : pg2->pack_name);
-}
-
-struct raw_object_store {
-       /*
-        * Set of all object directories; the main directory is first (and
-        * cannot be NULL after initialization). Subsequent directories are
-        * alternates.
-        */
-       struct object_directory *odb;
-       struct object_directory **odb_tail;
-       kh_odb_path_map_t *odb_by_path;
-
-       int loaded_alternates;
-
-       /*
-        * A list of alternate object directories loaded from the environment;
-        * this should not generally need to be accessed directly, but will
-        * populate the "odb" list when prepare_alt_odb() is run.
-        */
-       char *alternate_db;
-
-       /*
-        * Objects that should be substituted by other objects
-        * (see git-replace(1)).
-        */
-       struct oidmap *replace_map;
-       unsigned replace_map_initialized : 1;
-       pthread_mutex_t replace_mutex; /* protect object replace functions */
-
-       struct commit_graph *commit_graph;
-       unsigned commit_graph_attempted : 1; /* if loading has been attempted */
-
-       /*
-        * private data
-        *
-        * should only be accessed directly by packfile.c and midx.c
-        */
-       struct multi_pack_index *multi_pack_index;
-
-       /*
-        * private data
-        *
-        * should only be accessed directly by packfile.c
-        */
-
-       struct packed_git *packed_git;
-       /* A most-recently-used ordered version of the packed_git list. */
-       struct list_head packed_git_mru;
-
-       struct {
-               struct packed_git **packs;
-               unsigned flags;
-       } kept_pack_cache;
-
-       /*
-        * A map of packfiles to packed_git structs for tracking which
-        * packs have been loaded already.
-        */
-       struct hashmap pack_map;
-
-       /*
-        * A fast, rough count of the number of objects in the repository.
-        * These two fields are not meant for direct access. Use
-        * repo_approximate_object_count() instead.
-        */
-       unsigned long approximate_object_count;
-       unsigned approximate_object_count_valid : 1;
-
-       /*
-        * Whether packed_git has already been populated with this repository's
-        * packs.
-        */
-       unsigned packed_git_initialized : 1;
-};
-
-struct raw_object_store *raw_object_store_new(void);
-void raw_object_store_clear(struct raw_object_store *o);
-
-/*
- * Put in `buf` the name of the file in the local object database that
- * would be used to store a loose object with the specified oid.
- */
-const char *loose_object_path(struct repository *r, struct strbuf *buf,
-                             const struct object_id *oid);
-
-void *map_loose_object(struct repository *r, const struct object_id *oid,
-                      unsigned long *size);
-
-void *repo_read_object_file(struct repository *r,
-                           const struct object_id *oid,
-                           enum object_type *type,
-                           unsigned long *size);
-
-/* Read and unpack an object file into memory, write memory to an object file */
-int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
-
-void hash_object_file(const struct git_hash_algo *algo, const void *buf,
-                     unsigned long len, enum object_type type,
-                     struct object_id *oid);
-
-int write_object_file_flags(const void *buf, unsigned long len,
-                           enum object_type type, struct object_id *oid,
-                           unsigned flags);
-static inline int write_object_file(const void *buf, unsigned long len,
-                                   enum object_type type, struct object_id *oid)
-{
-       return write_object_file_flags(buf, len, type, oid, 0);
-}
-
-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
- * to disk.
- *
- * Callers are responsible for calling write_object_file to record the
- * object in persistent storage before writing any other new objects
- * that reference it.
- */
-int pretend_object_file(void *, unsigned long, enum object_type,
-                       struct object_id *oid);
-
-int force_object_loose(const struct object_id *oid, time_t mtime);
-
-struct object_info {
-       /* Request */
-       enum object_type *typep;
-       unsigned long *sizep;
-       off_t *disk_sizep;
-       struct object_id *delta_base_oid;
-       struct strbuf *type_name;
-       void **contentp;
-
-       /* Response */
-       enum {
-               OI_CACHED,
-               OI_LOOSE,
-               OI_PACKED,
-               OI_DBCACHED
-       } whence;
-       union {
-               /*
-                * struct {
-                *      ... Nothing to expose in this case
-                * } cached;
-                * struct {
-                *      ... Nothing to expose in this case
-                * } loose;
-                */
-               struct {
-                       struct packed_git *pack;
-                       off_t offset;
-                       unsigned int is_delta;
-               } packed;
-       } u;
-};
-
-/*
- * Initializer for a "struct object_info" that wants no items. You may
- * also memset() the memory to all-zeroes.
- */
-#define OBJECT_INFO_INIT { 0 }
-
-/* Invoke lookup_replace_object() on the given hash */
-#define OBJECT_INFO_LOOKUP_REPLACE 1
-/* Allow reading from a loose object file of unknown/bogus type */
-#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
-/* Do not retry packed storage after checking packed and loose storage */
-#define OBJECT_INFO_QUICK 8
-/*
- * Do not attempt to fetch the object if missing (even if fetch_is_missing is
- * nonzero).
- */
-#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
-/*
- * This is meant for bulk prefetching of missing blobs in a partial
- * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
- */
-#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
-
-/* Die if object corruption (not just an object being missing) was detected. */
-#define OBJECT_INFO_DIE_IF_CORRUPT 32
-
-int oid_object_info_extended(struct repository *r,
-                            const struct object_id *,
-                            struct object_info *, unsigned flags);
-
-/*
- * Open the loose object at path, check its hash, and return the contents,
- * use the "oi" argument to assert things about the object, or e.g. populate its
- * type, and size. If the object is a blob, then "contents" may return NULL,
- * to allow streaming of large blobs.
- *
- * Returns 0 on success, negative on error (details may be written to stderr).
- */
-int read_loose_object(const char *path,
-                     const struct object_id *expected_oid,
-                     struct object_id *real_oid,
-                     void **contents,
-                     struct object_info *oi);
-
-/* Retry packed storage after checking packed and loose storage */
-#define HAS_OBJECT_RECHECK_PACKED 1
-
-/*
- * Returns 1 if the object exists. This function will not lazily fetch objects
- * in a partial clone.
- */
-int has_object(struct repository *r, const struct object_id *oid,
-              unsigned flags);
-
-/*
- * These macros and functions are deprecated. If checking existence for an
- * object that is likely to be missing and/or whose absence is relatively
- * inconsequential (or is consequential but the caller is prepared to handle
- * it), use has_object(), which has better defaults (no lazy fetch in a partial
- * clone and no rechecking of packed storage). In the unlikely event that a
- * caller needs to assert existence of an object that it fully expects to
- * exist, and wants to trigger a lazy fetch in a partial clone, use
- * oid_object_info_extended() with a NULL struct object_info.
- *
- * These functions can be removed once all callers have migrated to
- * has_object() and/or oid_object_info_extended().
- */
-int repo_has_object_file(struct repository *r, const struct object_id *oid);
-int repo_has_object_file_with_flags(struct repository *r,
-                                   const struct object_id *oid, int flags);
-
-/*
- * Return true iff an alternate object database has a loose object
- * with the specified name.  This function does not respect replace
- * references.
- */
-int has_loose_object_nonlocal(const struct object_id *);
-
-int has_loose_object(const struct object_id *);
-
-/**
- * format_object_header() is a thin wrapper around s xsnprintf() that
- * writes the initial "<type> <obj-len>" part of the loose object
- * header. It returns the size that snprintf() returns + 1.
- */
-int format_object_header(char *str, size_t size, enum object_type type,
-                        size_t objsize);
-
-void assert_oid_type(const struct object_id *oid, enum object_type expect);
-
-/*
- * Enabling the object read lock allows multiple threads to safely call the
- * following functions in parallel: repo_read_object_file(),
- * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
- *
- * obj_read_lock() and obj_read_unlock() may also be used to protect other
- * section which cannot execute in parallel with object reading. Since the used
- * lock is a recursive mutex, these sections can even contain calls to object
- * reading functions. However, beware that in these cases zlib inflation won't
- * be performed in parallel, losing performance.
- *
- * TODO: oid_object_info_extended()'s call stack has a recursive behavior. If
- * any of its callees end up calling it, this recursive call won't benefit from
- * parallel inflation.
- */
-void enable_obj_read_lock(void);
-void disable_obj_read_lock(void);
-
-extern int obj_read_use_lock;
-extern pthread_mutex_t obj_read_mutex;
-
-static inline void obj_read_lock(void)
-{
-       if(obj_read_use_lock)
-               pthread_mutex_lock(&obj_read_mutex);
-}
-
-static inline void obj_read_unlock(void)
-{
-       if(obj_read_use_lock)
-               pthread_mutex_unlock(&obj_read_mutex);
-}
-
-/*
- * Iterate over the files in the loose-object parts of the object
- * directory "path", triggering the following callbacks:
- *
- *  - loose_object is called for each loose object we find.
- *
- *  - loose_cruft is called for any files that do not appear to be
- *    loose objects. Note that we only look in the loose object
- *    directories "objects/[0-9a-f]{2}/", so we will not report
- *    "objects/foobar" as cruft.
- *
- *  - loose_subdir is called for each top-level hashed subdirectory
- *    of the object directory (e.g., "$OBJDIR/f0"). It is called
- *    after the objects in the directory are processed.
- *
- * Any callback that is NULL will be ignored. Callbacks returning non-zero
- * will end the iteration.
- *
- * In the "buf" variant, "path" is a strbuf which will also be used as a
- * scratch buffer, but restored to its original contents before
- * the function returns.
- */
-typedef int each_loose_object_fn(const struct object_id *oid,
-                                const char *path,
-                                void *data);
-typedef int each_loose_cruft_fn(const char *basename,
-                               const char *path,
-                               void *data);
-typedef int each_loose_subdir_fn(unsigned int nr,
-                                const char *path,
-                                void *data);
-int for_each_file_in_obj_subdir(unsigned int subdir_nr,
-                               struct strbuf *path,
-                               each_loose_object_fn obj_cb,
-                               each_loose_cruft_fn cruft_cb,
-                               each_loose_subdir_fn subdir_cb,
-                               void *data);
-int for_each_loose_file_in_objdir(const char *path,
-                                 each_loose_object_fn obj_cb,
-                                 each_loose_cruft_fn cruft_cb,
-                                 each_loose_subdir_fn subdir_cb,
-                                 void *data);
-int for_each_loose_file_in_objdir_buf(struct strbuf *path,
-                                     each_loose_object_fn obj_cb,
-                                     each_loose_cruft_fn cruft_cb,
-                                     each_loose_subdir_fn subdir_cb,
-                                     void *data);
-
-/* Flags for for_each_*_object() below. */
-enum for_each_object_flags {
-       /* Iterate only over local objects, not alternates. */
-       FOR_EACH_OBJECT_LOCAL_ONLY = (1<<0),
-
-       /* Only iterate over packs obtained from the promisor remote. */
-       FOR_EACH_OBJECT_PROMISOR_ONLY = (1<<1),
-
-       /*
-        * Visit objects within a pack in packfile order rather than .idx order
-        */
-       FOR_EACH_OBJECT_PACK_ORDER = (1<<2),
-
-       /* Only iterate over packs that are not marked as kept in-core. */
-       FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS = (1<<3),
-
-       /* Only iterate over packs that do not have .keep files. */
-       FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS = (1<<4),
-};
-
-/*
- * Iterate over all accessible loose objects without respect to
- * reachability. By default, this includes both local and alternate objects.
- * The order in which objects are visited is unspecified.
- *
- * Any flags specific to packs are ignored.
- */
-int for_each_loose_object(each_loose_object_fn, void *,
-                         enum for_each_object_flags flags);
-
-/*
- * Iterate over all accessible packed objects without respect to reachability.
- * By default, this includes both local and alternate packs.
- *
- * Note that some objects may appear twice if they are found in multiple packs.
- * Each pack is visited in an unspecified order. By default, objects within a
- * pack are visited in pack-idx order (i.e., sorted by oid).
- */
-typedef int each_packed_object_fn(const struct object_id *oid,
-                                 struct packed_git *pack,
-                                 uint32_t pos,
-                                 void *data);
-int for_each_object_in_pack(struct packed_git *p,
-                           each_packed_object_fn, void *data,
-                           enum for_each_object_flags flags);
-int for_each_packed_object(each_packed_object_fn, void *,
-                          enum for_each_object_flags flags);
-
 #endif /* OBJECT_STORE_H */
index 6d4ef1524defed90be95ee17372e37ed099cd27e..2c61e4c86217e633d2e28acd0b3ae654584ede7d 100644 (file)
--- a/object.c
+++ b/object.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object.h"
@@ -6,6 +6,7 @@
 #include "object-file.h"
 #include "object-store.h"
 #include "blob.h"
+#include "statinfo.h"
 #include "tree.h"
 #include "commit.h"
 #include "tag.h"
@@ -356,6 +357,12 @@ void object_list_free(struct object_list **list)
  */
 static char object_array_slopbuf[1];
 
+void object_array_init(struct object_array *array)
+{
+       struct object_array blank = OBJECT_ARRAY_INIT;
+       memcpy(array, &blank, sizeof(*array));
+}
+
 void add_object_array_with_path(struct object *obj, const char *name,
                                struct object_array *array,
                                unsigned mode, const char *path)
index 5871615feea44d30c0fac060feca052933b3d5d0..114d45954d082229ed747dee16f2510387145771 100644 (file)
--- a/object.h
+++ b/object.h
@@ -58,6 +58,8 @@ struct object_array {
 
 #define OBJECT_ARRAY_INIT { 0 }
 
+void object_array_init(struct object_array *array);
+
 /*
  * object flag allocation:
  * revision.h:               0---------10         15             23------27
index e8228c777b1619d6bd1baaac0e24f14124d3e4d3..8e4717746c3183bd47c3c746c747efd83c61168c 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "oid-array.h"
 #include "hash-lookup.h"
 
index c1642927fa614764312b0ebccd05a77d12a07388..05c673eb7c1163d912dd7e54466ae9931be5426b 100644 (file)
--- a/oidmap.h
+++ b/oidmap.h
@@ -1,6 +1,7 @@
 #ifndef OIDMAP_H
 #define OIDMAP_H
 
+#include "hash-ll.h"
 #include "hashmap.h"
 
 /*
index 7d57b7b19e364706f037ccb44388e00e901b1583..daef175dc71d6c7d55fc89ef1e286334afbe00b7 100644 (file)
--- a/oidtree.c
+++ b/oidtree.c
@@ -4,7 +4,6 @@
  */
 #include "git-compat-util.h"
 #include "oidtree.h"
-#include "alloc.h"
 #include "hash.h"
 
 struct oidtree_iter_data {
index 609a343ee3ea41e6c4f18f0d07a104922dc952f2..3e190214d1487e4bd1f04315698e0f041402648e 100644 (file)
@@ -1,5 +1,5 @@
 #include "git-compat-util.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
index cdffe2ce47d44546aecbf5b569d6400fcf300563..f4ecdf8b0e3581cb6d92d0b88832c37adf749dc1 100644 (file)
@@ -1,9 +1,8 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "tag.h"
 #include "diff.h"
@@ -15,6 +14,7 @@
 #include "pack-bitmap.h"
 #include "hash-lookup.h"
 #include "pack-objects.h"
+#include "path.h"
 #include "commit-reach.h"
 #include "prio-queue.h"
 #include "trace2.h"
@@ -413,15 +413,19 @@ static int fill_bitmap_commit(struct bb_commit *ent,
 
                if (old_bitmap && mapping) {
                        struct ewah_bitmap *old = bitmap_for_commit(old_bitmap, c);
+                       struct bitmap *remapped = bitmap_new();
                        /*
                         * If this commit has an old bitmap, then translate that
                         * bitmap and add its bits to this one. No need to walk
                         * parents or the tree for this commit.
                         */
-                       if (old && !rebuild_bitmap(mapping, old, ent->bitmap)) {
+                       if (old && !rebuild_bitmap(mapping, old, remapped)) {
+                               bitmap_or(ent->bitmap, remapped);
+                               bitmap_free(remapped);
                                reused_bitmaps_nr++;
                                continue;
                        }
+                       bitmap_free(remapped);
                }
 
                /*
index 999f962602da7d1aae2e90cb620c0ffb42a7f510..ca8319b87c66f75941b43ab029d69e6eda19e3be 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "commit.h"
 #include "gettext.h"
 #include "hex.h"
@@ -17,7 +16,7 @@
 #include "repository.h"
 #include "trace2.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "list-objects-filter-options.h"
 #include "midx.h"
 #include "config.h"
@@ -387,9 +386,11 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
        }
 
        for (i = 0; i < bitmap_git->midx->num_packs; i++) {
-               if (prepare_midx_pack(the_repository, bitmap_git->midx, i))
-                       die(_("could not open pack %s"),
-                           bitmap_git->midx->pack_names[i]);
+               if (prepare_midx_pack(the_repository, bitmap_git->midx, i)) {
+                       warning(_("could not open pack %s"),
+                               bitmap_git->midx->pack_names[i]);
+                       goto cleanup;
+               }
        }
 
        preferred = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)];
@@ -1043,6 +1044,161 @@ static int add_commit_to_bitmap(struct bitmap_index *bitmap_git,
        return 1;
 }
 
+static struct bitmap *fill_in_bitmap(struct bitmap_index *bitmap_git,
+                                    struct rev_info *revs,
+                                    struct bitmap *base,
+                                    struct bitmap *seen)
+{
+       struct include_data incdata;
+       struct bitmap_show_data show_data;
+
+       if (!base)
+               base = bitmap_new();
+
+       incdata.bitmap_git = bitmap_git;
+       incdata.base = base;
+       incdata.seen = seen;
+
+       revs->include_check = should_include;
+       revs->include_check_obj = should_include_obj;
+       revs->include_check_data = &incdata;
+
+       if (prepare_revision_walk(revs))
+               die(_("revision walk setup failed"));
+
+       show_data.bitmap_git = bitmap_git;
+       show_data.base = base;
+
+       traverse_commit_list(revs, show_commit, show_object, &show_data);
+
+       revs->include_check = NULL;
+       revs->include_check_obj = NULL;
+       revs->include_check_data = NULL;
+
+       return base;
+}
+
+struct bitmap_boundary_cb {
+       struct bitmap_index *bitmap_git;
+       struct bitmap *base;
+
+       struct object_array boundary;
+};
+
+static void show_boundary_commit(struct commit *commit, void *_data)
+{
+       struct bitmap_boundary_cb *data = _data;
+
+       if (commit->object.flags & BOUNDARY)
+               add_object_array(&commit->object, "", &data->boundary);
+
+       if (commit->object.flags & UNINTERESTING) {
+               if (bitmap_walk_contains(data->bitmap_git, data->base,
+                                        &commit->object.oid))
+                       return;
+
+               add_commit_to_bitmap(data->bitmap_git, &data->base, commit);
+       }
+}
+
+static void show_boundary_object(struct object *object UNUSED,
+                                const char *name UNUSED,
+                                void *data UNUSED)
+{
+       BUG("should not be called");
+}
+
+static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git,
+                                           struct rev_info *revs,
+                                           struct object_list *roots)
+{
+       struct bitmap_boundary_cb cb;
+       struct object_list *root;
+       unsigned int i;
+       unsigned int tmp_blobs, tmp_trees, tmp_tags;
+       int any_missing = 0;
+
+       cb.bitmap_git = bitmap_git;
+       cb.base = bitmap_new();
+       object_array_init(&cb.boundary);
+
+       revs->ignore_missing_links = 1;
+
+       /*
+        * OR in any existing reachability bitmaps among `roots` into
+        * `cb.base`.
+        */
+       for (root = roots; root; root = root->next) {
+               struct object *object = root->item;
+               if (object->type != OBJ_COMMIT ||
+                   bitmap_walk_contains(bitmap_git, cb.base, &object->oid))
+                       continue;
+
+               if (add_commit_to_bitmap(bitmap_git, &cb.base,
+                                        (struct commit *)object))
+                       continue;
+
+               any_missing = 1;
+       }
+
+       if (!any_missing)
+               goto cleanup;
+
+       tmp_blobs = revs->blob_objects;
+       tmp_trees = revs->tree_objects;
+       tmp_tags = revs->blob_objects;
+       revs->blob_objects = 0;
+       revs->tree_objects = 0;
+       revs->tag_objects = 0;
+
+       /*
+        * We didn't have complete coverage of the roots. First setup a
+        * revision walk to (a) OR in any bitmaps that are UNINTERESTING
+        * between the tips and boundary, and (b) record the boundary.
+        */
+       trace2_region_enter("pack-bitmap", "boundary-prepare", the_repository);
+       if (prepare_revision_walk(revs))
+               die("revision walk setup failed");
+       trace2_region_leave("pack-bitmap", "boundary-prepare", the_repository);
+
+       trace2_region_enter("pack-bitmap", "boundary-traverse", the_repository);
+       revs->boundary = 1;
+       traverse_commit_list_filtered(revs,
+                                     show_boundary_commit,
+                                     show_boundary_object,
+                                     &cb, NULL);
+       revs->boundary = 0;
+       trace2_region_leave("pack-bitmap", "boundary-traverse", the_repository);
+
+       revs->blob_objects = tmp_blobs;
+       revs->tree_objects = tmp_trees;
+       revs->tag_objects = tmp_tags;
+
+       reset_revision_walk();
+       clear_object_flags(UNINTERESTING);
+
+       /*
+        * Then add the boundary commit(s) as fill-in traversal tips.
+        */
+       trace2_region_enter("pack-bitmap", "boundary-fill-in", the_repository);
+       for (i = 0; i < cb.boundary.nr; i++) {
+               struct object *obj = cb.boundary.objects[i].item;
+               if (bitmap_walk_contains(bitmap_git, cb.base, &obj->oid))
+                       obj->flags |= SEEN;
+               else
+                       add_pending_object(revs, obj, "");
+       }
+       if (revs->pending.nr)
+               cb.base = fill_in_bitmap(bitmap_git, revs, cb.base, NULL);
+       trace2_region_leave("pack-bitmap", "boundary-fill-in", the_repository);
+
+cleanup:
+       object_array_clear(&cb.boundary);
+       revs->ignore_missing_links = 0;
+
+       return cb.base;
+}
+
 static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
                                   struct rev_info *revs,
                                   struct object_list *roots,
@@ -1109,33 +1265,19 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
        }
 
        if (needs_walk) {
-               struct include_data incdata;
-               struct bitmap_show_data show_data;
-
-               if (!base)
-                       base = bitmap_new();
-
-               incdata.bitmap_git = bitmap_git;
-               incdata.base = base;
-               incdata.seen = seen;
-
-               revs->include_check = should_include;
-               revs->include_check_obj = should_include_obj;
-               revs->include_check_data = &incdata;
-
-               if (prepare_revision_walk(revs))
-                       die(_("revision walk setup failed"));
-
-               show_data.bitmap_git = bitmap_git;
-               show_data.base = base;
-
-               traverse_commit_list(revs,
-                                    show_commit, show_object,
-                                    &show_data);
-
-               revs->include_check = NULL;
-               revs->include_check_obj = NULL;
-               revs->include_check_data = NULL;
+               /*
+                * This fill-in traversal may walk over some objects
+                * again, since we have already traversed in order to
+                * find the boundary.
+                *
+                * But this extra walk should be extremely cheap, since
+                * all commit objects are loaded into memory, and
+                * because we skip walking to parents that are
+                * UNINTERESTING, since it will be marked in the haves
+                * bitmap already (or it has an on-disk bitmap, since
+                * OR-ing it in covers all of its ancestors).
+                */
+               base = fill_in_bitmap(bitmap_git, revs, base, seen);
        }
 
        return base;
@@ -1152,7 +1294,7 @@ static void show_extended_objects(struct bitmap_index *bitmap_git,
        for (i = 0; i < eindex->count; ++i) {
                struct object *obj;
 
-               if (!bitmap_get(objects, bitmap_num_objects(bitmap_git) + i))
+               if (!bitmap_get(objects, st_add(bitmap_num_objects(bitmap_git), i)))
                        continue;
 
                obj = eindex->objects[i];
@@ -1331,7 +1473,7 @@ static void filter_bitmap_exclude_type(struct bitmap_index *bitmap_git,
         * them individually.
         */
        for (i = 0; i < eindex->count; i++) {
-               uint32_t pos = i + bitmap_num_objects(bitmap_git);
+               size_t pos = st_add(i, bitmap_num_objects(bitmap_git));
                if (eindex->objects[i]->type == type &&
                    bitmap_get(to_filter, pos) &&
                    !bitmap_get(tips, pos))
@@ -1422,7 +1564,7 @@ static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
        }
 
        for (i = 0; i < eindex->count; i++) {
-               uint32_t pos = i + bitmap_num_objects(bitmap_git);
+               size_t pos = st_add(i, bitmap_num_objects(bitmap_git));
                if (eindex->objects[i]->type == OBJ_BLOB &&
                    bitmap_get(to_filter, pos) &&
                    !bitmap_get(tips, pos) &&
@@ -1528,6 +1670,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
                                         int filter_provided_objects)
 {
        unsigned int i;
+       int use_boundary_traversal;
 
        struct object_list *wants = NULL;
        struct object_list *haves = NULL;
@@ -1578,13 +1721,21 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
                        object_list_insert(object, &wants);
        }
 
-       /*
-        * if we have a HAVES list, but none of those haves is contained
-        * in the packfile that has a bitmap, we don't have anything to
-        * optimize here
-        */
-       if (haves && !in_bitmapped_pack(bitmap_git, haves))
-               goto cleanup;
+       use_boundary_traversal = git_env_bool(GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL, -1);
+       if (use_boundary_traversal < 0) {
+               prepare_repo_settings(revs->repo);
+               use_boundary_traversal = revs->repo->settings.pack_use_bitmap_boundary_traversal;
+       }
+
+       if (!use_boundary_traversal) {
+               /*
+                * if we have a HAVES list, but none of those haves is contained
+                * in the packfile that has a bitmap, we don't have anything to
+                * optimize here
+                */
+               if (haves && !in_bitmapped_pack(bitmap_git, haves))
+                       goto cleanup;
+       }
 
        /* if we don't want anything, we're done here */
        if (!wants)
@@ -1598,18 +1749,32 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
        if (load_bitmap(revs->repo, bitmap_git) < 0)
                goto cleanup;
 
-       object_array_clear(&revs->pending);
+       if (!use_boundary_traversal)
+               object_array_clear(&revs->pending);
 
        if (haves) {
-               revs->ignore_missing_links = 1;
-               haves_bitmap = find_objects(bitmap_git, revs, haves, NULL);
-               reset_revision_walk();
-               revs->ignore_missing_links = 0;
+               if (use_boundary_traversal) {
+                       trace2_region_enter("pack-bitmap", "haves/boundary", the_repository);
+                       haves_bitmap = find_boundary_objects(bitmap_git, revs, haves);
+                       trace2_region_leave("pack-bitmap", "haves/boundary", the_repository);
+               } else {
+                       trace2_region_enter("pack-bitmap", "haves/classic", the_repository);
+                       revs->ignore_missing_links = 1;
+                       haves_bitmap = find_objects(bitmap_git, revs, haves, NULL);
+                       reset_revision_walk();
+                       revs->ignore_missing_links = 0;
+                       trace2_region_leave("pack-bitmap", "haves/classic", the_repository);
+               }
 
                if (!haves_bitmap)
                        BUG("failed to perform bitmap walk");
        }
 
+       if (use_boundary_traversal) {
+               object_array_clear(&revs->pending);
+               reset_revision_walk();
+       }
+
        wants_bitmap = find_objects(bitmap_git, revs, wants, haves_bitmap);
 
        if (!wants_bitmap)
@@ -1873,7 +2038,8 @@ static uint32_t count_object_type(struct bitmap_index *bitmap_git,
 
        for (i = 0; i < eindex->count; ++i) {
                if (eindex->objects[i]->type == type &&
-                       bitmap_get(objects, bitmap_num_objects(bitmap_git) + i))
+                   bitmap_get(objects,
+                              st_add(bitmap_num_objects(bitmap_git), i)))
                        count++;
        }
 
@@ -2287,7 +2453,8 @@ static off_t get_disk_usage_for_extended(struct bitmap_index *bitmap_git)
        for (i = 0; i < eindex->count; i++) {
                struct object *obj = eindex->objects[i];
 
-               if (!bitmap_get(result, bitmap_num_objects(bitmap_git) + i))
+               if (!bitmap_get(result,
+                               st_add(bitmap_num_objects(bitmap_git), i)))
                        continue;
 
                if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
index 84591f041bf5e0842ec55894f43e73619e9ada85..5273a6a019708c8295be8e4fa5ca11db342f3a40 100644 (file)
@@ -62,6 +62,10 @@ void traverse_bitmap_commit_list(struct bitmap_index *,
 void test_bitmap_walk(struct rev_info *revs);
 int test_bitmap_commits(struct repository *r);
 int test_bitmap_hashes(struct repository *r);
+
+#define GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL \
+       "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL"
+
 struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
                                         int filter_provided_objects);
 uint32_t midx_preferred_pack(struct bitmap_index *bitmap_git);
index 049f2f0bfc03f2c08a4e24fa6be767f01fe8145d..977f619618e0a9b97044f0b07e5617d3b3e1839b 100644 (file)
@@ -7,7 +7,7 @@
 #include "progress.h"
 #include "packfile.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 struct idx_entry {
        off_t                offset;
index 020a37f8fe3a837de959ceade8dca86849253593..cdf30b8d2b0e809db7ee7e219b39863fad702bd4 100644 (file)
@@ -2,8 +2,9 @@
 #include "gettext.h"
 #include "pack-mtimes.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
+#include "strbuf.h"
 
 static char *pack_mtimes_filename(struct packed_git *p)
 {
index ccab09fe654391ef8da95c4f4ecf0bf55d5f3df7..f403ca6986a9d4c68715c1e1b24462d462fb8aa9 100644 (file)
@@ -1,10 +1,9 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "object.h"
 #include "pack.h"
 #include "pack-objects.h"
 #include "packfile.h"
-#include "config.h"
+#include "parse.h"
 
 static uint32_t locate_object_entry_hash(struct packing_data *pdata,
                                         const struct object_id *oid,
index 579476687c4f7123c7861cde595a1ce94f87ae1f..0d78db40cb2f11fcbc4b3c2bbb2d23624ef3f22e 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef PACK_OBJECTS_H
 #define PACK_OBJECTS_H
 
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "thread-utils.h"
 #include "pack.h"
 
index 1f51b712e879e401e9b308d993a2b810460f01e3..acf1dd9786cd3c2a0cb410804721488b6d1d92b4 100644 (file)
@@ -2,10 +2,11 @@
 #include "gettext.h"
 #include "pack-revindex.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
+#include "strbuf.h"
 #include "trace2.h"
-#include "config.h"
+#include "parse.h"
 #include "midx.h"
 #include "csum-file.h"
 
@@ -342,6 +343,17 @@ int verify_pack_revindex(struct packed_git *p)
        return res;
 }
 
+static int can_use_midx_ridx_chunk(struct multi_pack_index *m)
+{
+       if (!m->chunk_revindex)
+               return 0;
+       if (m->chunk_revindex_len != st_mult(sizeof(uint32_t), m->num_objects)) {
+               error(_("multi-pack-index reverse-index chunk is the wrong size"));
+               return 0;
+       }
+       return 1;
+}
+
 int load_midx_revindex(struct multi_pack_index *m)
 {
        struct strbuf revindex_name = STRBUF_INIT;
@@ -350,7 +362,7 @@ int load_midx_revindex(struct multi_pack_index *m)
        if (m->revindex_data)
                return 0;
 
-       if (m->chunk_revindex) {
+       if (can_use_midx_ridx_chunk(m)) {
                /*
                 * If the MIDX `m` has a `RIDX` chunk, then use its contents for
                 * the reverse index instead of trying to load a separate `.rev`
index 3b3ce89de6e9c2f13b81ca6b67c9a3b02cee54e3..b19ddf15b284868acd7ad9123aed8fba10d08d30 100644 (file)
@@ -10,7 +10,8 @@
 #include "oidmap.h"
 #include "pack-objects.h"
 #include "pack-revindex.h"
-#include "wrapper.h"
+#include "path.h"
+#include "strbuf.h"
 
 void reset_pack_idx_option(struct pack_idx_option *opts)
 {
index fd083c86e00c1dbb1de6ba994f2df50e15797002..9cc0a2e37a83dd38c2fe1b26d34cfb5fea983bc7 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "tree-walk.h"
 #include "tree.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "midx.h"
 #include "commit-graph.h"
 #include "pack-revindex.h"
 #include "promisor-remote.h"
-#include "wrapper.h"
 
 char *odb_pack_name(struct strbuf *buf,
                    const unsigned char *hash,
@@ -186,7 +184,7 @@ int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
                     */
                    (sizeof(off_t) <= 4))
                        return error("pack too large for current definition of off_t in %s", path);
-               p->crc_offset = 8 + 4 * 256 + nr * hashsz;
+               p->crc_offset = st_add(8 + 4 * 256, st_mult(nr, hashsz));
        }
 
        p->index_version = version;
@@ -381,7 +379,7 @@ void close_object_store(struct raw_object_store *o)
 
 void unlink_pack_path(const char *pack_name, int force_delete)
 {
-       static const char *exts[] = {".pack", ".idx", ".rev", ".keep", ".bitmap", ".promisor", ".mtimes"};
+       static const char *exts[] = {".idx", ".pack", ".rev", ".keep", ".bitmap", ".promisor", ".mtimes"};
        int i;
        struct strbuf buf = STRBUF_INIT;
        size_t plen;
@@ -753,7 +751,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
        p->pack_local = local;
        p->mtime = st.st_mtime;
        if (path_len < the_hash_algo->hexsz ||
-           get_sha1_hex(path + path_len - the_hash_algo->hexsz, p->hash))
+           get_hash_hex(path + path_len - the_hash_algo->hexsz, p->hash))
                hashclr(p->hash);
        return p;
 }
@@ -1920,10 +1918,10 @@ int nth_packed_object_id(struct object_id *oid,
                return -1;
        index += 4 * 256;
        if (p->index_version == 1) {
-               oidread(oid, index + (hashsz + 4) * n + 4);
+               oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4));
        } else {
                index += 8;
-               oidread(oid, index + hashsz * n);
+               oidread(oid, index + st_mult(hashsz, n));
        }
        return 0;
 }
@@ -1948,14 +1946,15 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
        const unsigned int hashsz = the_hash_algo->rawsz;
        index += 4 * 256;
        if (p->index_version == 1) {
-               return ntohl(*((uint32_t *)(index + (hashsz + 4) * (size_t)n)));
+               return ntohl(*((uint32_t *)(index + st_mult(hashsz + 4, n))));
        } else {
                uint32_t off;
-               index += 8 + (size_t)p->num_objects * (hashsz + 4);
-               off = ntohl(*((uint32_t *)(index + 4 * n)));
+               index += st_add(8, st_mult(p->num_objects, hashsz + 4));
+               off = ntohl(*((uint32_t *)(index + st_mult(4, n))));
                if (!(off & 0x80000000))
                        return off;
-               index += (size_t)p->num_objects * 4 + (off & 0x7fffffff) * 8;
+               index += st_add(st_mult(p->num_objects, 4),
+                               st_mult(off & 0x7fffffff, 8));
                check_pack_index_ptr(p, index);
                return get_be64(index);
        }
diff --git a/pager.c b/pager.c
index 63055d0873f01c01809927ecd56d09a10f500fbe..b8822a9381e49487ecb9bf37f1a42f1414eb8ff3 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -43,6 +43,7 @@ static void wait_for_pager_signal(int signo)
 }
 
 static int core_pager_config(const char *var, const char *value,
+                            const struct config_context *ctx UNUSED,
                             void *data UNUSED)
 {
        if (!strcmp(var, "core.pager"))
@@ -228,7 +229,9 @@ struct pager_command_config_data {
        char *value;
 };
 
-static int pager_command_config(const char *var, const char *value, void *vdata)
+static int pager_command_config(const char *var, const char *value,
+                               const struct config_context *ctx UNUSED,
+                               void *vdata)
 {
        struct pager_command_config_data *data = vdata;
        const char *cmd;
index 69d569f3525630723978a1cce358b9a6a3f42115..b5a714c7111bda0d179077ef1614bbe5ce1570b5 100644 (file)
@@ -1,5 +1,4 @@
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "entry.h"
 #include "gettext.h"
@@ -8,13 +7,13 @@
 #include "parallel-checkout.h"
 #include "pkt-line.h"
 #include "progress.h"
+#include "read-cache-ll.h"
 #include "run-command.h"
 #include "sigchain.h"
 #include "streaming.h"
 #include "symlinks.h"
 #include "thread-utils.h"
 #include "trace2.h"
-#include "wrapper.h"
 
 struct pc_worker {
        struct child_process cp;
index a24521dee0fca3de6284a9c59cd3bd8cefdb4942..bdc7fae49719dfef060739854ae7491045afb6f2 100644 (file)
@@ -227,7 +227,9 @@ int parse_opt_strvec(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
-int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
+int parse_opt_noop_cb(const struct option *opt UNUSED,
+                     const char *arg UNUSED,
+                     int unset UNUSED)
 {
        return 0;
 }
index f8a155ee13b9599e2de3f973d9f9744c9c045893..e0c94b0546b5487c5b324c4c2b76d668289e8b10 100644 (file)
@@ -1,11 +1,12 @@
 #include "git-compat-util.h"
 #include "parse-options.h"
 #include "abspath.h"
-#include "config.h"
+#include "parse.h"
 #include "commit.h"
 #include "color.h"
 #include "gettext.h"
 #include "strbuf.h"
+#include "string-list.h"
 #include "utf8.h"
 
 static int disallow_abbreviated_options;
@@ -69,42 +70,10 @@ static void fix_filename(const char *prefix, char **file)
                *file = prefix_filename_except_for_dash(prefix, *file);
 }
 
-static enum parse_opt_result opt_command_mode_error(
-       const struct option *opt,
-       const struct option *all_opts,
-       enum opt_parsed flags)
-{
-       const struct option *that;
-       struct strbuf that_name = STRBUF_INIT;
-
-       /*
-        * Find the other option that was used to set the variable
-        * already, and report that this is not compatible with it.
-        */
-       for (that = all_opts; that->type != OPTION_END; that++) {
-               if (that == opt ||
-                   !(that->flags & PARSE_OPT_CMDMODE) ||
-                   that->value != opt->value ||
-                   that->defval != *(int *)opt->value)
-                       continue;
-
-               if (that->long_name)
-                       strbuf_addf(&that_name, "--%s", that->long_name);
-               else
-                       strbuf_addf(&that_name, "-%c", that->short_name);
-               error(_("%s is incompatible with %s"),
-                     optname(opt, flags), that_name.buf);
-               strbuf_release(&that_name);
-               return PARSE_OPT_ERROR;
-       }
-       return error(_("%s : incompatible with something else"),
-                    optname(opt, flags));
-}
-
-static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
-                                      const struct option *opt,
-                                      const struct option *all_opts,
-                                      enum opt_parsed flags)
+static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
+                                         const struct option *opt,
+                                         enum opt_parsed flags,
+                                         const char **argp)
 {
        const char *s, *arg;
        const int unset = flags & OPT_UNSET;
@@ -117,14 +86,6 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
        if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG))
                return error(_("%s takes no value"), optname(opt, flags));
 
-       /*
-        * Giving the same mode option twice, although unnecessary,
-        * is not a grave error, so let it pass.
-        */
-       if ((opt->flags & PARSE_OPT_CMDMODE) &&
-           *(int *)opt->value && *(int *)opt->value != opt->defval)
-               return opt_command_mode_error(opt, all_opts, flags);
-
        switch (opt->type) {
        case OPTION_LOWLEVEL_CALLBACK:
                return opt->ll_callback(p, opt, NULL, unset);
@@ -199,6 +160,8 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
                        p_unset = 0;
                        p_arg = arg;
                }
+               if (opt->flags & PARSE_OPT_CMDMODE)
+                       *argp = p_arg;
                if (opt->callback)
                        return (*opt->callback)(opt, p_arg, p_unset) ? (-1) : 0;
                else
@@ -246,16 +209,91 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
        }
 }
 
+struct parse_opt_cmdmode_list {
+       int value, *value_ptr;
+       const struct option *opt;
+       const char *arg;
+       enum opt_parsed flags;
+       struct parse_opt_cmdmode_list *next;
+};
+
+static void build_cmdmode_list(struct parse_opt_ctx_t *ctx,
+                              const struct option *opts)
+{
+       ctx->cmdmode_list = NULL;
+
+       for (; opts->type != OPTION_END; opts++) {
+               struct parse_opt_cmdmode_list *elem = ctx->cmdmode_list;
+               int *value_ptr = opts->value;
+
+               if (!(opts->flags & PARSE_OPT_CMDMODE) || !value_ptr)
+                       continue;
+
+               while (elem && elem->value_ptr != value_ptr)
+                       elem = elem->next;
+               if (elem)
+                       continue;
+
+               CALLOC_ARRAY(elem, 1);
+               elem->value_ptr = value_ptr;
+               elem->value = *value_ptr;
+               elem->next = ctx->cmdmode_list;
+               ctx->cmdmode_list = elem;
+       }
+}
+
+static char *optnamearg(const struct option *opt, const char *arg,
+                       enum opt_parsed flags)
+{
+       if (flags & OPT_SHORT)
+               return xstrfmt("-%c%s", opt->short_name, arg ? arg : "");
+       return xstrfmt("--%s%s%s%s", flags & OPT_UNSET ? "no-" : "",
+                      opt->long_name, arg ? "=" : "", arg ? arg : "");
+}
+
+static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
+                                      const struct option *opt,
+                                      enum opt_parsed flags)
+{
+       const char *arg = NULL;
+       enum parse_opt_result result = do_get_value(p, opt, flags, &arg);
+       struct parse_opt_cmdmode_list *elem = p->cmdmode_list;
+       char *opt_name, *other_opt_name;
+
+       for (; elem; elem = elem->next) {
+               if (*elem->value_ptr == elem->value)
+                       continue;
+
+               if (elem->opt &&
+                   (elem->opt->flags | opt->flags) & PARSE_OPT_CMDMODE)
+                       break;
+
+               elem->opt = opt;
+               elem->arg = arg;
+               elem->flags = flags;
+               elem->value = *elem->value_ptr;
+       }
+
+       if (result || !elem)
+               return result;
+
+       opt_name = optnamearg(opt, arg, flags);
+       other_opt_name = optnamearg(elem->opt, elem->arg, elem->flags);
+       error(_("%s is incompatible with %s"), opt_name, other_opt_name);
+       free(opt_name);
+       free(other_opt_name);
+       return -1;
+}
+
 static enum parse_opt_result parse_short_opt(struct parse_opt_ctx_t *p,
                                             const struct option *options)
 {
-       const struct option *all_opts = options;
        const struct option *numopt = NULL;
 
        for (; options->type != OPTION_END; options++) {
                if (options->short_name == *p->opt) {
                        p->opt = p->opt[1] ? p->opt + 1 : NULL;
-                       return get_value(p, options, all_opts, OPT_SHORT);
+                       return get_value(p, options, OPT_SHORT);
                }
 
                /*
@@ -317,7 +355,6 @@ static enum parse_opt_result parse_long_opt(
        struct parse_opt_ctx_t *p, const char *arg,
        const struct option *options)
 {
-       const struct option *all_opts = options;
        const char *arg_end = strchrnul(arg, '=');
        const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
        enum opt_parsed abbrev_flags = OPT_LONG, ambiguous_flags = OPT_LONG;
@@ -386,7 +423,7 @@ is_abbreviated:
                                continue;
                        p->opt = rest + 1;
                }
-               return get_value(p, options, all_opts, flags ^ opt_flags);
+               return get_value(p, options, flags ^ opt_flags);
        }
 
        if (disallow_abbreviated_options && (ambiguous_option || abbrev_option))
@@ -404,7 +441,7 @@ is_abbreviated:
                return PARSE_OPT_HELP;
        }
        if (abbrev_option)
-               return get_value(p, abbrev_option, all_opts, abbrev_flags);
+               return get_value(p, abbrev_option, abbrev_flags);
        return PARSE_OPT_UNKNOWN;
 }
 
@@ -412,13 +449,11 @@ static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p,
                                              const char *arg,
                                              const struct option *options)
 {
-       const struct option *all_opts = options;
-
        for (; options->type != OPTION_END; options++) {
                if (!(options->flags & PARSE_OPT_NODASH))
                        continue;
                if (options->short_name == arg[0] && arg[1] == '\0')
-                       return get_value(p, options, all_opts, OPT_SHORT);
+                       return get_value(p, options, OPT_SHORT);
        }
        return PARSE_OPT_ERROR;
 }
@@ -480,6 +515,9 @@ static void parse_options_check(const struct option *opts)
                     opts->long_name))
                        optbug(opts, "uses feature "
                               "not supported for dashless options");
+               if (opts->type == OPTION_SET_INT && !opts->defval &&
+                   opts->long_name && !(opts->flags & PARSE_OPT_NONEG))
+                       optbug(opts, "OPTION_SET_INT 0 should not be negatable");
                switch (opts->type) {
                case OPTION_COUNTUP:
                case OPTION_BIT:
@@ -570,6 +608,7 @@ static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
            (flags & PARSE_OPT_KEEP_ARGV0))
                BUG("Can't keep argv0 if you don't have it");
        parse_options_check(options);
+       build_cmdmode_list(ctx, options);
 }
 
 void parse_options_start(struct parse_opt_ctx_t *ctx,
@@ -1002,6 +1041,11 @@ int parse_options(int argc, const char **argv,
        precompose_argv_prefix(argc, argv, NULL);
        free_preprocessed_options(real_options);
        free(ctx.alias_groups);
+       for (struct parse_opt_cmdmode_list *elem = ctx.cmdmode_list; elem;) {
+               struct parse_opt_cmdmode_list *next = elem->next;
+               free(elem);
+               elem = next;
+       }
        return parse_options_end(&ctx);
 }
 
@@ -1020,14 +1064,37 @@ static int usage_argh(const struct option *opts, FILE *outfile)
        return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
 }
 
-#define USAGE_OPTS_WIDTH 24
-#define USAGE_GAP         2
+static int usage_indent(FILE *outfile)
+{
+       return fprintf(outfile, "    ");
+}
+
+#define USAGE_OPTS_WIDTH 26
+
+static void usage_padding(FILE *outfile, size_t pos)
+{
+       if (pos < USAGE_OPTS_WIDTH)
+               fprintf(outfile, "%*s", USAGE_OPTS_WIDTH - (int)pos, "");
+       else
+               fprintf(outfile, "\n%*s", USAGE_OPTS_WIDTH, "");
+}
+
+static const struct option *find_option_by_long_name(const struct option *opts,
+                                                    const char *long_name)
+{
+       for (; opts->type != OPTION_END; opts++) {
+               if (opts->long_name && !strcmp(opts->long_name, long_name))
+                       return opts;
+       }
+       return NULL;
+}
 
 static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *ctx,
                                                         const char * const *usagestr,
                                                         const struct option *opts,
                                                         int full, int err)
 {
+       const struct option *all_opts = opts;
        FILE *outfile = err ? stderr : stdout;
        int need_newline;
 
@@ -1108,7 +1175,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
 
        for (; opts->type != OPTION_END; opts++) {
                size_t pos;
-               int pad;
+               const char *cp, *np;
+               const char *positive_name = NULL;
 
                if (opts->type == OPTION_SUBCOMMAND)
                        continue;
@@ -1127,7 +1195,7 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
                        need_newline = 0;
                }
 
-               pos = fprintf(outfile, "    ");
+               pos = usage_indent(outfile);
                if (opts->short_name) {
                        if (opts->flags & PARSE_OPT_NODASH)
                                pos += fprintf(outfile, "%c", opts->short_name);
@@ -1136,8 +1204,15 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
                }
                if (opts->long_name && opts->short_name)
                        pos += fprintf(outfile, ", ");
-               if (opts->long_name)
-                       pos += fprintf(outfile, "--%s", opts->long_name);
+               if (opts->long_name) {
+                       const char *long_name = opts->long_name;
+                       if ((opts->flags & PARSE_OPT_NONEG) ||
+                           skip_prefix(long_name, "no-", &positive_name))
+                               pos += fprintf(outfile, "--%s", long_name);
+                       else
+                               pos += fprintf(outfile, "--[no-]%s", long_name);
+               }
+
                if (opts->type == OPTION_NUMBER)
                        pos += utf8_fprintf(outfile, _("-NUM"));
 
@@ -1145,19 +1220,32 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
                    !(opts->flags & PARSE_OPT_NOARG))
                        pos += usage_argh(opts, outfile);
 
-               if (pos <= USAGE_OPTS_WIDTH)
-                       pad = USAGE_OPTS_WIDTH - pos;
-               else {
-                       fputc('\n', outfile);
-                       pad = USAGE_OPTS_WIDTH;
-               }
                if (opts->type == OPTION_ALIAS) {
-                       fprintf(outfile, "%*s", pad + USAGE_GAP, "");
+                       usage_padding(outfile, pos);
                        fprintf_ln(outfile, _("alias of --%s"),
                                   (const char *)opts->value);
                        continue;
                }
-               fprintf(outfile, "%*s%s\n", pad + USAGE_GAP, "", _(opts->help));
+
+               for (cp = opts->help ? _(opts->help) : ""; *cp; cp = np) {
+                       np = strchrnul(cp, '\n');
+                       if (*np)
+                               np++;
+                       usage_padding(outfile, pos);
+                       fwrite(cp, 1, np - cp, outfile);
+                       pos = 0;
+               }
+               fputc('\n', outfile);
+
+               if (positive_name) {
+                       if (find_option_by_long_name(all_opts, positive_name))
+                               continue;
+                       pos = usage_indent(outfile);
+                       pos += fprintf(outfile, "--%s", positive_name);
+                       usage_padding(outfile, pos);
+                       fprintf_ln(outfile, _("opposite of --no-%s"),
+                                  positive_name);
+               }
        }
        fputc('\n', outfile);
 
index 8e48efe524882a6dcd4c854de6fcdbe0ef76acda..bd62e20268d01d0e9d7afbcb300c440bb3adaa9f 100644 (file)
@@ -445,6 +445,8 @@ static inline void die_for_incompatible_opt3(int opt1, const char *opt1_name,
 
 /*----- incremental advanced APIs -----*/
 
+struct parse_opt_cmdmode_list;
+
 /*
  * It's okay for the caller to consume argv/argc in the usual way.
  * Other fields of that structure are private to parse-options and should not
@@ -459,7 +461,7 @@ struct parse_opt_ctx_t {
        unsigned has_subcommands;
        const char *prefix;
        const char **alias_groups; /* must be in groups of 3 elements! */
-       struct option *updated_options;
+       struct parse_opt_cmdmode_list *cmdmode_list;
 };
 
 void parse_options_start(struct parse_opt_ctx_t *ctx,
@@ -581,4 +583,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
 #define OPT_PATHSPEC_FILE_NUL(v)  OPT_BOOL(0, "pathspec-file-nul", v, N_("with --pathspec-from-file, pathspec elements are separated with NUL character"))
 #define OPT_AUTOSTASH(v) OPT_BOOL(0, "autostash", v, N_("automatically stash/stash pop before and after"))
 
+#define OPT_IPVERSION(v) \
+       OPT_SET_INT_F('4', "ipv4", (v), N_("use IPv4 addresses only"), \
+               TRANSPORT_FAMILY_IPV4, PARSE_OPT_NONEG), \
+       OPT_SET_INT_F('6', "ipv6", (v), N_("use IPv6 addresses only"), \
+               TRANSPORT_FAMILY_IPV6, PARSE_OPT_NONEG)
+
 #endif
diff --git a/parse.c b/parse.c
new file mode 100644 (file)
index 0000000..42d691a
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,182 @@
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "parse.h"
+
+static uintmax_t get_unit_factor(const char *end)
+{
+       if (!*end)
+               return 1;
+       else if (!strcasecmp(end, "k"))
+               return 1024;
+       else if (!strcasecmp(end, "m"))
+               return 1024 * 1024;
+       else if (!strcasecmp(end, "g"))
+               return 1024 * 1024 * 1024;
+       return 0;
+}
+
+int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
+{
+       if (value && *value) {
+               char *end;
+               intmax_t val;
+               intmax_t factor;
+
+               if (max < 0)
+                       BUG("max must be a positive integer");
+
+               errno = 0;
+               val = strtoimax(value, &end, 0);
+               if (errno == ERANGE)
+                       return 0;
+               if (end == value) {
+                       errno = EINVAL;
+                       return 0;
+               }
+               factor = get_unit_factor(end);
+               if (!factor) {
+                       errno = EINVAL;
+                       return 0;
+               }
+               if ((val < 0 && -max / factor > val) ||
+                   (val > 0 && max / factor < val)) {
+                       errno = ERANGE;
+                       return 0;
+               }
+               val *= factor;
+               *ret = val;
+               return 1;
+       }
+       errno = EINVAL;
+       return 0;
+}
+
+static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
+{
+       if (value && *value) {
+               char *end;
+               uintmax_t val;
+               uintmax_t factor;
+
+               /* negative values would be accepted by strtoumax */
+               if (strchr(value, '-')) {
+                       errno = EINVAL;
+                       return 0;
+               }
+               errno = 0;
+               val = strtoumax(value, &end, 0);
+               if (errno == ERANGE)
+                       return 0;
+               if (end == value) {
+                       errno = EINVAL;
+                       return 0;
+               }
+               factor = get_unit_factor(end);
+               if (!factor) {
+                       errno = EINVAL;
+                       return 0;
+               }
+               if (unsigned_mult_overflows(factor, val) ||
+                   factor * val > max) {
+                       errno = ERANGE;
+                       return 0;
+               }
+               val *= factor;
+               *ret = val;
+               return 1;
+       }
+       errno = EINVAL;
+       return 0;
+}
+
+int git_parse_int(const char *value, int *ret)
+{
+       intmax_t tmp;
+       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+int git_parse_int64(const char *value, int64_t *ret)
+{
+       intmax_t tmp;
+       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+int git_parse_ulong(const char *value, unsigned long *ret)
+{
+       uintmax_t tmp;
+       if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+int git_parse_ssize_t(const char *value, ssize_t *ret)
+{
+       intmax_t tmp;
+       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+int git_parse_maybe_bool_text(const char *value)
+{
+       if (!value)
+               return 1;
+       if (!*value)
+               return 0;
+       if (!strcasecmp(value, "true")
+           || !strcasecmp(value, "yes")
+           || !strcasecmp(value, "on"))
+               return 1;
+       if (!strcasecmp(value, "false")
+           || !strcasecmp(value, "no")
+           || !strcasecmp(value, "off"))
+               return 0;
+       return -1;
+}
+
+int git_parse_maybe_bool(const char *value)
+{
+       int v = git_parse_maybe_bool_text(value);
+       if (0 <= v)
+               return v;
+       if (git_parse_int(value, &v))
+               return !!v;
+       return -1;
+}
+
+/*
+ * Parse environment variable 'k' as a boolean (in various
+ * possible spellings); if missing, use the default value 'def'.
+ */
+int git_env_bool(const char *k, int def)
+{
+       const char *v = getenv(k);
+       int val;
+       if (!v)
+               return def;
+       val = git_parse_maybe_bool(v);
+       if (val < 0)
+               die(_("bad boolean environment value '%s' for '%s'"),
+                   v, k);
+       return val;
+}
+
+/*
+ * Parse environment variable 'k' as ulong with possibly a unit
+ * suffix; if missing, use the default value 'val'.
+ */
+unsigned long git_env_ulong(const char *k, unsigned long val)
+{
+       const char *v = getenv(k);
+       if (v && !git_parse_ulong(v, &val))
+               die(_("failed to parse %s"), k);
+       return val;
+}
diff --git a/parse.h b/parse.h
new file mode 100644 (file)
index 0000000..07d2193
--- /dev/null
+++ b/parse.h
@@ -0,0 +1,20 @@
+#ifndef PARSE_H
+#define PARSE_H
+
+int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);
+int git_parse_ssize_t(const char *, ssize_t *);
+int git_parse_ulong(const char *, unsigned long *);
+int git_parse_int(const char *value, int *ret);
+int git_parse_int64(const char *value, int64_t *ret);
+
+/**
+ * Same as `git_config_bool`, except that it returns -1 on error rather
+ * than dying.
+ */
+int git_parse_maybe_bool(const char *);
+int git_parse_maybe_bool_text(const char *value);
+
+int git_env_bool(const char *, int);
+unsigned long git_env_ulong(const char *, unsigned long);
+
+#endif /* PARSE_H */
index 19af7bee9840e4fd945b21a10364bcd5c1fb546f..c3e1a0dd216c80c92c47f0e2a98d74a57c422742 100644 (file)
@@ -1,6 +1,7 @@
 #include "git-compat-util.h"
 #include "diff.h"
 #include "commit.h"
+#include "hash.h"
 #include "hash-lookup.h"
 #include "hex.h"
 #include "patch-ids.h"
diff --git a/path.c b/path.c
index 7c1cd8182a81b9e8892960707cff8a0f7ff174cb..67e2690efef897b406d46eab6202b52fc65a55d0 100644 (file)
--- a/path.c
+++ b/path.c
 #include "submodule-config.h"
 #include "path.h"
 #include "packfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "lockfile.h"
 #include "exec-cmd.h"
-#include "wrapper.h"
 
 static int get_st_mode_bits(const char *path, int *mode)
 {
@@ -1213,6 +1212,26 @@ int normalize_path_copy(char *dst, const char *src)
        return normalize_path_copy_len(dst, src, NULL);
 }
 
+int strbuf_normalize_path(struct strbuf *src)
+{
+       struct strbuf dst = STRBUF_INIT;
+
+       strbuf_grow(&dst, src->len);
+       if (normalize_path_copy(dst.buf, src->buf) < 0) {
+               strbuf_release(&dst);
+               return -1;
+       }
+
+       /*
+        * normalize_path does not tell us the new length, so we have to
+        * compute it by looking for the new NUL it placed
+        */
+       strbuf_setlen(&dst, strlen(dst.buf));
+       strbuf_swap(src, &dst);
+       strbuf_release(&dst);
+       return 0;
+}
+
 /*
  * path = Canonical absolute path
  * prefixes = string_list containing normalized, absolute paths without
diff --git a/path.h b/path.h
index 60e83a49a98507a276efccf6e355a2e375ac64ea..639372edd9ee36127e3b89084f89ee59d12ff60f 100644 (file)
--- a/path.h
+++ b/path.h
@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);
 const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
 int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
 int normalize_path_copy(char *dst, const char *src);
+/**
+ * Normalize in-place the path contained in the strbuf. If an error occurs,
+ * the contents of "sb" are left untouched, and -1 is returned.
+ */
+int strbuf_normalize_path(struct strbuf *src);
 int longest_ancestor_length(const char *path, struct string_list *prefixes);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
index 6966b265d33aa8be6794a051b96668931c2b2092..bb1efe1f3929f116a216de5cae6fa6b83227569e 100644 (file)
@@ -1,16 +1,18 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
-#include "config.h"
+#include "parse.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "pathspec.h"
 #include "attr.h"
+#include "read-cache.h"
 #include "repository.h"
 #include "setup.h"
 #include "strvec.h"
 #include "symlinks.h"
 #include "quote.h"
+#include "wildmatch.h"
 
 /*
  * Finds which of the given pathspecs match items in the index.
@@ -465,7 +467,12 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
                match = prefix_path_gently(prefix, prefixlen,
                                           &prefixlen, copyfrom);
                if (!match) {
-                       const char *hint_path = get_git_work_tree();
+                       const char *hint_path;
+
+                       if (!have_git_dir())
+                               die(_("'%s' is outside the directory tree"),
+                                   copyfrom);
+                       hint_path = get_git_work_tree();
                        if (!hint_path)
                                hint_path = get_git_dir();
                        die(_("%s: '%s' is outside repository at '%s'"), elt,
@@ -531,24 +538,29 @@ static int pathspec_item_cmp(const void *a_, const void *b_)
        return strcmp(a->match, b->match);
 }
 
-static void NORETURN unsupported_magic(const char *pattern,
-                                      unsigned magic)
+void pathspec_magic_names(unsigned magic, struct strbuf *out)
 {
-       struct strbuf sb = STRBUF_INIT;
        int i;
        for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
                const struct pathspec_magic *m = pathspec_magic + i;
                if (!(magic & m->bit))
                        continue;
-               if (sb.len)
-                       strbuf_addstr(&sb, ", ");
+               if (out->len)
+                       strbuf_addstr(out, ", ");
 
                if (m->mnemonic)
-                       strbuf_addf(&sb, _("'%s' (mnemonic: '%c')"),
+                       strbuf_addf(out, _("'%s' (mnemonic: '%c')"),
                                    m->name, m->mnemonic);
                else
-                       strbuf_addf(&sb, "'%s'", m->name);
+                       strbuf_addf(out, "'%s'", m->name);
        }
+}
+
+static void NORETURN unsupported_magic(const char *pattern,
+                                      unsigned magic)
+{
+       struct strbuf sb = STRBUF_INIT;
+       pathspec_magic_names(magic, &sb);
        /*
         * We may want to substitute "this command" with a command
         * name. E.g. when "git add -p" or "git add -i" dies when running
index a5b38e0907a9b8c498d643653d445ed7cd71fe02..fec4399bbc940823c76f689808ee77e8804624bb 100644 (file)
@@ -130,6 +130,14 @@ void parse_pathspec_file(struct pathspec *pathspec,
 void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
 void clear_pathspec(struct pathspec *);
 
+/*
+ * Add a human-readable string to "out" representing the PATHSPEC_* flags set
+ * in "magic". The result is suitable for error messages, but not for
+ * parsing as pathspec magic itself (you get 'icase' with quotes, not
+ * :(icase)).
+ */
+void pathspec_magic_names(unsigned magic, struct strbuf *out);
+
 static inline int ps_strncmp(const struct pathspec_item *item,
                             const char *s1, const char *s2, size_t n)
 {
index 62b4208b66e15d72257f5a2b72f4fa6ce3684376..af83a19f4df5537da9f1c7a87ea29cb2f5903ea2 100644 (file)
@@ -5,7 +5,6 @@
 #include "hex.h"
 #include "run-command.h"
 #include "trace.h"
-#include "wrapper.h"
 #include "write-or-die.h"
 
 char packet_buffer[LARGE_PACKET_MAX];
@@ -373,10 +372,14 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size,
        return ret;
 }
 
-int packet_length(const char lenbuf_hex[4])
+int packet_length(const char lenbuf_hex[4], size_t size)
 {
-       int val = hex2chr(lenbuf_hex);
-       return (val < 0) ? val : (val << 8) | hex2chr(lenbuf_hex + 2);
+       if (size < 4)
+               BUG("buffer too small");
+       return  hexval(lenbuf_hex[0]) << 12 |
+               hexval(lenbuf_hex[1]) <<  8 |
+               hexval(lenbuf_hex[2]) <<  4 |
+               hexval(lenbuf_hex[3]);
 }
 
 static char *find_packfile_uri_path(const char *buffer)
@@ -419,7 +422,7 @@ enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
                return PACKET_READ_EOF;
        }
 
-       len = packet_length(linelen);
+       len = packet_length(linelen, sizeof(linelen));
 
        if (len < 0) {
                if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
index 7c23a4bfaf740312c09f25a84eed7bedda35de4d..954eec87197d3e0c50812879d47e0afbb008baa3 100644 (file)
@@ -94,7 +94,7 @@ int packet_read(int fd, char *buffer, unsigned size, int options);
  * If lenbuf_hex contains non-hex characters, return -1. Otherwise, return the
  * numeric value of the length header.
  */
-int packet_length(const char lenbuf_hex[4]);
+int packet_length(const char lenbuf_hex[4], size_t size);
 
 /*
  * Read a packetized line into a buffer like the 'packet_read()' function but
index 3e4f897d935918092f3dfd1a05637b7176bd9fe1..ec08aa24add4e3da7c02b990ba1851665825c2b0 100644 (file)
@@ -412,7 +412,7 @@ There are some conventions that l10n contributors must follow:
 - Do not use non-ASCII characters in the subject of a commit.
 
 - The length of commit subject (first line of the commit log) should
-  be less than 50 characters, and the length of other lines of the
+  be no more than 50 characters, and the length of other lines of the
   commit log should be no more than 72 characters.
 
 - Add "Signed-off-by" trailer to your commit log, like other commits
index 4b164f29912fe926ec260d1008c6f6820980c9da..6d64d7259a093df6e136ecf5ac27d8d7d2c89bc8 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -3,14 +3,16 @@
 # Alex Henrie <alexhenrie24@gmail.com>, 2014-2016.
 # Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2023
 #
-# Terminologia i criteris utilitzats
+# Terminologia
 #
 #   Anglès           |  Català
 #   -----------------+---------------------------------
 #   ahead            |  davant per
 #   amend            |  esmenar
+#   branch           |  branca
 #   broken           |  malmès
 #   bundle           |  farcell
+#   check out        |  agafar
 #   chunk            |  fragment
 #   cover letter     |  carta de presentació
 #   cruft            |  superflu
 #
 # Vegeu també https://git.github.io/htmldocs/gitglossary.html
 #
+# Criteris
+#   - Mantingueu en anglès les referències a seccions de la documentació, ja que no està traduïda.
+#   - Usem la convenció valenciana per a «per / per a», que inclou l'ús de «per a» davant d'infintiu
+#
 msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-20 14:03+0200\n"
-"PO-Revision-Date: 2023-05-26 19:00-0600\n"
+"POT-Creation-Date: 2023-08-16 18:22+0200\n"
+"PO-Revision-Date: 2023-08-16 19:00-0600\n"
 "Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
 "Language-Team: Catalan\n"
 "Language: ca\n"
@@ -584,6 +590,7 @@ msgstr "«git apply --cached» ha fallat"
 #. Consider translating (saying "no" discards!) as
 #. (saying "n" for "no" discards!) if the translation
 #. of the word "no" does not start with n.
+#.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -698,9 +705,8 @@ msgstr "Baixar no és possible perquè teniu fitxers sense fusionar."
 msgid "Reverting is not possible because you have unmerged files."
 msgstr "Revertir no és possible perquè teniu fitxers sense fusionar."
 
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "No és possible %s perquè teniu fitxers sense fusionar."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "Fer «rebase» no és possible perquè teniu fitxers sense fusionar."
 
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
@@ -845,6 +851,12 @@ msgstr "les opcions «%s» i «%s» no es poden usar juntes"
 msgid "'%s' outside a repository"
 msgstr "«%s» fora d'un repositori"
 
+msgid "failed to read patch"
+msgstr "s'ha produït un error en llegir el pedaç"
+
+msgid "patch too large"
+msgstr "el pedaç és massa gran"
+
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "No es pot preparar l'expressió regular de marca de temps %s"
@@ -1387,7 +1399,7 @@ msgstr "no es pot llegir «%s»"
 #, c-format
 msgid "pathspec '%s' matches files outside the current directory"
 msgstr ""
-"l'específicació de camí «%s» coincideix amb fitxers fora del directori actual"
+"l'especificació de camí «%s» coincideix amb fitxers fora del directori actual"
 
 #, c-format
 msgid "pathspec '%s' did not match any files"
@@ -1630,6 +1642,7 @@ msgstr[1] "(aproximadament %d passos)"
 
 #. TRANSLATORS: the last %s will be replaced with "(roughly %d
 #. steps)" translation.
+#.
 #, c-format
 msgid "Bisecting: %d revision left to test after this %s\n"
 msgid_plural "Bisecting: %d revisions left to test after this %s\n"
@@ -1715,17 +1728,20 @@ msgstr "no s'està seguint: informació ambigua per a la referència «%s»"
 #. 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.
+#.
 #, c-format
 msgid "  %s\n"
 msgstr "  %s\n"
 
 #. TRANSLATORS: The second argument is a \n-delimited list of
 #. duplicate refspecs, composed above.
+#.
 #, c-format
 msgid ""
 "There are multiple remotes whose fetch refspecs map to the remote\n"
@@ -1755,8 +1771,10 @@ msgid "a branch named '%s' already exists"
 msgstr "ja existeix una branca amb nom «%s»"
 
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "no es pot forçar l'actualització de la branca «%s», agafada a «%s»"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr ""
+"no es pot forçar l'actualització de la branca «%s» utilitzada per l'arbre de "
+"treball a «%s»"
 
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -1827,17 +1845,6 @@ msgstr "git add [<opcions>] [--] <especificació-de-camí>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "no es pot fer chmod %cx «%s»"
 
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "estat de diff inesperat %c"
-
-msgid "updating files failed"
-msgstr "s'ha produït un error en actualitzar els fitxers"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "elimina «%s»\n"
-
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Canvis «unstaged» després d'actualitzar l'índex:"
 
@@ -2139,6 +2146,7 @@ msgstr "El cos de la comissió és:"
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
+#.
 #, c-format
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "
 msgstr ""
@@ -2266,10 +2274,6 @@ msgstr "passa l'indicador -m a git-mailinfo"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "passa l'indicador --keep-cr a git-mailsplit per al format mbox"
 
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"no passis l'indicador --keep-cr a git-mailsplit independentment d'am.keepcr"
-
 msgid "strip everything before a scissors line"
 msgstr "elimina tot abans d'una línia de tisores"
 
@@ -2487,6 +2491,7 @@ msgstr "bisecant amb només una comissió %s"
 #. TRANSLATORS: Make sure to include [Y] and [n] in your
 #. translation. The program will only accept English input
 #. at this point.
+#.
 msgid "Are you sure [Y/n]? "
 msgstr "N'esteu segur [Y/n]? "
 
@@ -2564,6 +2569,7 @@ msgstr "Cal començar per «git bisect start»\n"
 #. TRANSLATORS: Make sure to include [Y] and [n] in your
 #. translation. The program will only accept English input
 #. at this point.
+#.
 msgid "Do you want me to do it for you [Y/n]? "
 msgstr "Voleu que ho faci per vostè [Y/n]? "
 
@@ -2784,6 +2790,7 @@ msgstr ""
 #. among various forms of relative timestamps, but
 #. your language may need more or fewer display
 #. columns.
+#.
 msgid "4 years, 11 months ago"
 msgstr "fa 4 anys i 11 mesos"
 
@@ -3322,12 +3329,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
@@ -3374,6 +3381,9 @@ msgstr "com a --batch, però no emetis <contents>"
 msgid "stdin is NUL-terminated"
 msgstr "l'entrada és acabada amb NUL"
 
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin i stdout estan terminats amb NUL"
+
 msgid "read commands from stdin"
 msgstr "llegeix les ordres de stdin"
 
@@ -4237,12 +4247,6 @@ msgstr "específic al servidor"
 msgid "option to transmit"
 msgstr "opció a transmetre"
 
-msgid "use IPv4 addresses only"
-msgstr "usa només adreces IPv4"
-
-msgid "use IPv6 addresses only"
-msgstr "usa només adreces IPv6"
-
 msgid "apply partial clone filters to submodules"
 msgstr "aplica els filtres de clonatge parcial als submòduls"
 
@@ -4684,6 +4688,9 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+msgid "updating files failed"
+msgstr "s'ha produït un error en actualitzar els fitxers"
+
 msgid "failed to unpack HEAD tree object"
 msgstr "s'ha produït un error en desempaquetar l'objecte d'arbre HEAD"
 
@@ -4743,8 +4750,8 @@ msgstr ""
 "no sigui usat en el missatge de comissió actual"
 
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "no s'ha pogut cercar la comissió %s"
+msgid "could not lookup commit '%s'"
+msgstr "no s'ha pogut cercar la comissió «%s»"
 
 #, c-format
 msgid "(reading log message from standard input)\n"
@@ -5006,6 +5013,7 @@ msgstr "reusa el missatge de la comissió especificada"
 
 #. TRANSLATORS: Leave "[(amend|reword):]" as-is,
 #. and only translate <commit>.
+#.
 msgid "[(amend|reword):]commit"
 msgstr "[(amend|reword):]commit"
 
@@ -5183,7 +5191,7 @@ msgid "remove a section: name"
 msgstr "elimina una secció: nom"
 
 msgid "list all"
-msgstr "llista tots"
+msgstr "llista'ls tots"
 
 msgid "use string equality when comparing values to 'value-pattern'"
 msgstr ""
@@ -5462,7 +5470,7 @@ msgid ""
 "However, there were unannotated tags: try --tags."
 msgstr ""
 "Cap etiqueta anotada pot descriure «%s».\n"
-"No obstant, hi havia etiquetes no anotades: proveu --tags."
+"No obstant això, hi havia etiquetes no anotades: proveu --tags."
 
 #, c-format
 msgid ""
@@ -6813,6 +6821,7 @@ msgstr "s'ha especificat un nombre de fils no vàlid (%d) per a %s"
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
+#.
 #, c-format
 msgid "no threads support, ignoring %s"
 msgstr "no s'admeten fils, s'ignorarà %s"
@@ -7380,77 +7389,6 @@ msgstr "s'ha donat --verify sense nom de fitxer de paquet"
 msgid "fsck error in pack objects"
 msgstr "error fsck als objectes del paquet"
 
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "no es pot fer stat en la plantilla «%s»"
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "no es pot fer opendir en el directori «%s»"
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "no es pot fer readlink en «%s»"
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "no es pot fer symlink en «%s» «%s»"
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "no es pot copiar «%s» a «%s»"
-
-#, c-format
-msgid "ignoring template %s"
-msgstr "s'està ignorant la plantilla %s"
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "plantilles no trobades a %s"
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "no s'estan copiant plantilles de «%s»: %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "nom de branca inicial no vàlid: «%s»"
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "no s'ha pogut gestionar el tipus de fitxer %d"
-
-#, c-format
-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 resum diferent"
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s ja existeix"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "reinicialització: s'ha ignorat --initial-branch=%s"
-
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "S'ha reinicialitzat el repositori compartit existent del Git en %s%s\n"
-
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "S'ha reinicialitzat el repositori existent del Git en %s%s\n"
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "S'ha inicialitzat un repositori compartit buit del Git en %s%s\n"
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "S'ha inicialitzat un repositori buit del Git en %s%s\n"
-
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7890,6 +7828,10 @@ msgstr ""
 "No s'ha pogut trobar una branca remota seguida. Especifiqueu <font> "
 "manualment.\n"
 
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "no s'ha pogut obtenir la informació sobre l'objecte «%s»"
+
 #, 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 «(»"
@@ -8034,10 +7976,6 @@ 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í>...]"
 
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "no s'ha pogut obtenir la informació sobre l'objecte «%s»"
-
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
 msgstr "format incorrecte del ls-tree: l'element '%s' no comença amb «(»"
@@ -8773,22 +8711,26 @@ msgid "git notes [--ref <notes-ref>] [list [<object>]]"
 msgstr "git notes [--ref <referència-de-notes>] [llista [<objecte>]]"
 
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <referència-de-notes>] add [-f] [--allow-empty] [-m "
-"<missatge> | -F <fitxer> | (-c | -C) <objecte>] [<objecte>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
 "git notes [--ref <referència-de-notes>] copy [-f] <d'objecte> <a-objecte>"
 
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <referència-de-notes>] append [--allow-empty] [-m "
-"<missatge> | -F <fitxer> | (-c | -C) <objecte>] [<objecte>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
 msgstr ""
@@ -8895,6 +8837,7 @@ msgstr "s'ha produït un error en copiar les notes de «%s» a «%s»"
 
 #. TRANSLATORS: the first %s will be replaced by a git
 #. notes command: 'add', 'merge', 'remove', etc.
+#.
 #, c-format
 msgid "refusing to %s notes in %s (outside of refs/notes/)"
 msgstr "s'està refusant %s les notes en %s (fora de refs/notes/)"
@@ -8921,6 +8864,15 @@ msgstr "permet l'emmagatzematge d'una nota buida"
 msgid "replace existing notes"
 msgstr "reemplaça les notes existents"
 
+msgid "<paragraph-break>"
+msgstr "<paragraph-break>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "insereix <paragraph-break> entre paràgrafs"
+
+msgid "remove unnecessary whitespace"
+msgstr "elimina l'espai en blanc innecessari"
+
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -9487,8 +9439,11 @@ msgstr ""
 msgid "refusing to run without --i-still-use-this"
 msgstr "es rebutja a executar sense --i-still-use-this"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <patró>] [--exclude <patró>]"
 
 msgid "pack everything"
 msgstr "empaqueta-ho tot"
@@ -9496,6 +9451,12 @@ msgstr "empaqueta-ho tot"
 msgid "prune loose refs (default)"
 msgstr "poda les referències soltes (per defecte)"
 
+msgid "references to include"
+msgstr "referències a incloure"
+
+msgid "references to exclude"
+msgstr "referències a excloure"
+
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
@@ -9554,6 +9515,12 @@ msgstr "força la sobreescriptura de la branca local"
 msgid "number of submodules pulled in parallel"
 msgstr "nombre de submòduls baixats en paral·lel"
 
+msgid "use IPv4 addresses only"
+msgstr "usa només adreces IPv4"
+
+msgid "use IPv6 addresses only"
+msgstr "usa només adreces IPv6"
+
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
@@ -9821,43 +9788,39 @@ msgstr ""
 
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"S'han rebutjat les actualitzacions perquè el punt de la vostra branca\n"
-"actual està darrere de la seva branca remota corresponent. Integreu\n"
-"els canvis remots (per exemple, «git pull ...») abans de pujar de nou.\n"
-"Vegeu la «Nota sobre avanços ràpids» a «git push --help» per a més "
-"informació."
+"S'han rebutjat les actualitzacions perquè la punta de la branca actual\n"
+"està darrere de la seva contrapart remota. Si voleu integrar els canvis,\n"
+"remots useu «git pull» abans de tornar a pujar.\n"
+"Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"S'han rebutjat les actualitzacions perquè un punt de branca pujada\n"
-"està darrere de la seva branca remota corresponent. Agafeu aquesta\n"
-"branca i integreu els canvis remots (per exemple, «git pull ...»)\n"
-"abans de pujar de nou.\n"
-"Vegeu la «Nota sobre avanços ràpids» a «git push --help» per a més "
-"informació."
+"Les actualitzacions s'han rebutjat perquè la branca pujada està darrere\n"
+"de la seva contrapart remota. Si voleu integrar els canvis remots,\n"
+"utilitzeu «git pull» abans de tornar a pujar.\n"
+"Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"S'han rebutjat les actualitzacions perquè el remot conté canvis\n"
-"que no teniu localment. Això acostuma a ser causat per un altre repositori\n"
-"que ha pujat a la mateixa referència. Pot ser que primer vulgueu\n"
-"integrar els canvis remots (per exemple, «git pull ...») abans de\n"
-"pujar de nou.\n"
-"Vegeu la «Nota sobre avanços ràpids» a «git push --help» per a més "
-"informació."
+"Les actualitzacions s'han rebutjat perquè el remot conté canvis que no "
+"teniu\n"
+"localment. Això sol ser causat per un altre repositori que a pujat a\n"
+"la mateixa referència. Si voleu integrar els canvis remots, utilitzeu\n"
+"«git pull» abans de tornar a pujar.\n"
+"Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
 msgid "Updates were rejected because the tag already exists in the remote."
 msgstr ""
@@ -9874,15 +9837,15 @@ msgstr ""
 "«--force».\n"
 
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"S'han rebutjat les actualitzacions perquè el punt actual de la vostra\n"
-"branca està darrere de la seva branca remota corresponent. Integreu\n"
-"els canvis localment (per exemple, «git pull ...») abans de forçar\n"
-"una pujada.\n"
+"Les actualitzacions s'han rebutjat perquè la branca de seguiment remot\n"
+"s'ha actualitzat des de l'última baixada. Si voleu integrar els\n"
+"canvis remots, utilitzeu «git pull» abans de tornar a pujar.\n"
+"Vegeu «Note about fast-forwards» a «git push --help» per a més detalls."
 
 #, c-format
 msgid "Pushing to %s\n"
@@ -10742,11 +10705,12 @@ msgstr "argument de «mirror» desconegut: %s"
 msgid "fetch the remote branches"
 msgstr "obtén les branques remotes"
 
-msgid "import all tags and associated objects when fetching"
-msgstr "en obtenir, importa totes les etiquetes i tots els objectes"
-
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "o no obtinguis cap etiqueta (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"importa totes les etiquetes i objectes associats en obtenir\n"
+"o no obtingueu cap etiqueta (--no-tags)"
 
 msgid "branch(es) to track"
 msgstr "branques a seguir"
@@ -10949,6 +10913,7 @@ msgstr "(sense URL)"
 #. TRANSLATORS: the colon ':' should align
 #. with the one in " Fetch URL: %s"
 #. translation.
+#.
 #, c-format
 msgid "  Push  URL: %s"
 msgstr "  URL de pujada: %s"
@@ -12706,6 +12671,10 @@ msgstr "S'està ometent el submòdul no fusionat %s"
 msgid "Skipping submodule '%s'"
 msgstr "S'està ometent el submòdul «%s»"
 
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "no es pot clonar el submòdul «%s» sense un URL"
+
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
 msgstr "S'ha produït un error en clonar «%s». S'ha programat un reintent"
@@ -13460,10 +13429,10 @@ msgstr "imprimeix els continguts de l'etiqueta"
 
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
-"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <camí> [<commit-ish>]"
+"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <cadena>]]\n"
+"                 [--orphan] [(-b | -B) <new-branch>] <camí> [<commit-ish>]"
 
 msgid "git worktree list [-v | --porcelain [-z]]"
 msgstr "git worktree list [-v | --porcelain [-z]]"
@@ -13486,6 +13455,37 @@ msgstr "git worktree repair [<camí>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <worktree>"
 
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "No hi ha cap branca d'origen possible, inferint «--orphan»"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"Si voleu crear un arbre de treball que contingui una branca orfe nova\n"
+"(branca sense comissions) per a aquest repositori, podeu fer-ho\n"
+"utilitzant l'argument --orphan:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"Si voleu crear un arbre de treball que contingui una branca orfe nova\n"
+"(branca sense comissions) per a aquest repositori, podeu fer-ho\n"
+"utilitzant l'argument --orphan:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #, c-format
 msgid "Removing %s/%s: %s"
 msgstr "S'està eliminant %s/%s: %s"
@@ -13557,10 +13557,35 @@ msgstr ""
 msgid "Preparing worktree (checking out '%s')"
 msgstr "S'està preparant l'arbre de treball (s'està agafant «%s»)"
 
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "no accessible: referència no vàlida: %s"
+
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "S'està preparant l'arbre de treball (HEAD %s separat)"
 
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD apunta a una referència no vàlida (o òrfena).\n"
+"Camí HEAD: «%s»\n"
+"Contingut HEAD: «%s»"
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"No hi ha referències locals o remotes malgrat que hi existeix almenys un\n"
+"remot, aturat; useu «add -f» per a forcar-ho o obtenir primer un remot"
+
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "les opcions «%s» i «%s» no es poden usar juntes"
+
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr "agafa <branca> encara que sigui agafada en altre arbre de treball"
 
@@ -13570,6 +13595,9 @@ msgstr "crea una branca nova"
 msgid "create or reset a branch"
 msgstr "crea o restableix una branca"
 
+msgid "create unborn/orphaned branch"
+msgstr "crea una branca no nascuda/òrfena"
+
 msgid "populate the new working tree"
 msgstr "emplena l'arbre de treball nou"
 
@@ -13591,6 +13619,13 @@ msgstr ""
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "les opcions «%s», «%s», i «%s» no es poden usar juntes"
 
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "les opcions «%s» i «%s» no es poden usar juntes"
+
+msgid "<commit-ish>"
+msgstr "<commit-ish>"
+
 msgid "added with --lock"
 msgstr "afegit amb --lock"
 
@@ -13822,6 +13857,14 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "El farcell requereix aquesta referència:"
 msgstr[1] "El farcell requereix aquestes %<PRIuMAX> referències:"
 
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "El farcell utilitza aquest algoritme de resum: %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "El farcell utilitza aquest filtre: %s"
+
 msgid "unable to dup bundle descriptor"
 msgstr "no s'ha pogut duplicar el descriptor del farcell"
 
@@ -14055,8 +14098,9 @@ msgstr "Imprimeix les línies coincidents amb un patró"
 msgid "A portable graphical interface to Git"
 msgstr "Una interfície gràfica portable per al Git"
 
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "Calcula l'ID de l'objecte i opcionalment crea un blob des del fitxer"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr ""
+"Calcula l'ID de l'objecte i opcionalment crea un objecte des del fitxer"
 
 msgid "Display help information about Git"
 msgstr "Mostra informació d'ajuda del Git"
@@ -14474,6 +14518,10 @@ msgstr "el fragment del graf de comissions no té grafs de base"
 msgid "commit-graph chain does not match"
 msgstr "la cadena del graf de comissions no coincideix"
 
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "el nombre de comissions en el graf base és massa alt: %<PRIuMAX>"
+
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
 msgstr ""
@@ -14569,6 +14617,14 @@ msgid "failed to rename temporary commit-graph file"
 msgstr ""
 "no s'ha pogut canviar el nom del fitxer temporal del graf de comissions"
 
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "no es poden fusionar els gràfics amb %<PRIuMAX>, %<PRIuMAX>entregues"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "no es pot fusionar el graf %s, hi ha massa comissions: %<PRIuMAX>"
+
 msgid "Scanning merged commits"
 msgstr "S'estan escanejant les comissions fusionades"
 
@@ -14603,9 +14659,6 @@ msgid "failed to parse commit %s from commit-graph"
 msgstr ""
 "s'ha produït un error en analitzar la comissió %s del graf de comissions"
 
-msgid "Verifying commits in commit graph"
-msgstr "S'estan verificant les comissions al graf de comissions"
-
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
 msgstr ""
@@ -14657,6 +14710,9 @@ msgstr ""
 "la data d'enviament per a la comissió %s en el graf de comissions és "
 "%<PRIuMAX> != %<PRIuMAX>"
 
+msgid "Verifying commits in commit graph"
+msgstr "S'estan verificant les comissions al graf de comissions"
+
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s no és una comissió!"
@@ -14835,7 +14891,7 @@ msgid "Invalid back reference"
 msgstr "Referència anterior no vàlida"
 
 msgid "Unmatched [ or [^"
-msgstr "[ or [^ no emparellat"
+msgstr "[ o [^ no emparellat"
 
 msgid "Unmatched ( or \\("
 msgstr "( o \\( no emparellat"
@@ -15613,6 +15669,12 @@ msgstr "no s'ha trobat una base de fusió"
 msgid "multiple merge bases found"
 msgstr "s'han trobat múltiples bases de fusió"
 
+msgid "cannot compare stdin to a directory"
+msgstr "no es pot comparar stdin amb un directori"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "no es pot comparar una canonada amb nom amb un directori"
+
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<opcions>] <camí> <camí>"
 
@@ -15673,6 +15735,13 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "el diff external s'ha mort, s'està aturant a %s"
 
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow requereix exactament una especificació de camí"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "el «pathspec» màgic no està suportat per --follow: %s"
+
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
 msgstr "les opcions «%s», «%s», «%s», i «%s» no es poden usar juntes"
@@ -15687,9 +15756,6 @@ msgid ""
 msgstr ""
 "les opcions «%s» i «%s» no es poden usar juntes, useu «%s» amb «%s» i «%s»"
 
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow requereix exactament una especificació de camí"
-
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "valor --stat no vàlid: %s"
@@ -16371,12 +16437,14 @@ msgstr "s'ha produït un error en processar els acks: %d"
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
+#.
 #, c-format
 msgid "expected packfile to be sent after '%s'"
 msgstr "s'esperava que el fitxer de paquet s'enviés després de «%s»"
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
+#.
 #, c-format
 msgid "expected no other sections to be sent after no '%s'"
 msgstr "no s'esperava que cap altra secció s'enviés després de «%s»"
@@ -16971,7 +17039,7 @@ msgid ""
 msgstr ""
 "No s'ha pogut crear «%s.lock»: %s.\n"
 "\n"
-"Sembla que un altre procés de git s'està executant en aquest\n"
+"Sembla que un altre procés git s'està executant en aquest\n"
 "repositori, per exemple, un editor obert per «git commit». \n"
 "Assegureu-vos que tots els processos s'hagin acabat i\n"
 "llavors proveu de nou. Si encara falla, pot ser un procés git\n"
@@ -17194,6 +17262,7 @@ msgstr ""
 #. 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"
@@ -17228,6 +17297,7 @@ msgstr ""
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
+#.
 #, c-format
 msgid "collecting merge info failed for trees %s, %s, %s"
 msgstr ""
@@ -17701,6 +17771,7 @@ msgstr "S'està refusant reescriure les notes en %s (fora de refs/notes/)"
 #. TRANSLATORS: The first %s is the name of
 #. the environment variable, the second %s is
 #. its value.
+#.
 #, c-format
 msgid "Bad %s value: '%s'"
 msgstr "Valor erroni de %s: «%s»"
@@ -17919,6 +17990,7 @@ msgstr "no s'han pogut desempaquetar els continguts de %s"
 #. TRANSLATORS: This is a line of ambiguous object
 #. output shown when we cannot look up or parse the
 #. object in question. E.g. "deadbeef [bad object]".
+#.
 #, c-format
 msgid "%s [bad object]"
 msgstr "%s [objecte incorrecte]"
@@ -17927,6 +17999,7 @@ msgstr "%s [objecte incorrecte]"
 #. object output. E.g.:
 #. *
 #.    "deadbeef commit 2021-01-01 - Some Commit Message"
+#.
 #, c-format
 msgid "%s commit %s - %s"
 msgstr "%s comissió %s - %s"
@@ -17941,6 +18014,7 @@ msgstr "%s comissió %s - %s"
 #. *
 #. The third argument is the "tag" string
 #. from object.c.
+#.
 #, c-format
 msgid "%s tag %s - %s"
 msgstr "%s etiqueta %s - %s"
@@ -17950,18 +18024,21 @@ msgstr "%s etiqueta %s - %s"
 #. the tag itself. E.g.:
 #. *
 #.    "deadbeef [bad tag, could not parse it]"
+#.
 #, c-format
 msgid "%s [bad tag, could not parse it]"
 msgstr "%s [etiqueta malmesa, no s'ha pogut analitzar]"
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef tree".
+#.
 #, c-format
 msgid "%s tree"
 msgstr "arbre %s"
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef blob".
+#.
 #, c-format
 msgid "%s blob"
 msgstr "blob %s"
@@ -17973,6 +18050,7 @@ msgstr "l'id d'objecte curt %s és ambigu"
 #. TRANSLATORS: The argument is the list of ambiguous
 #. objects composed in show_ambiguous_object(). See
 #. its "TRANSLATORS" comments for details.
+#.
 #, c-format
 msgid ""
 "The candidates are:\n"
@@ -18364,6 +18442,7 @@ msgstr "ús: %s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation.
+#.
 #, c-format
 msgid "   or: %s"
 msgstr "   o: %s"
@@ -18386,6 +18465,7 @@ msgstr "   o: %s"
 #. function. The "%s" is a line in the (hopefully already
 #. translated) N_() usage string, which contained embedded
 #. newlines before we split it up.
+#.
 #, c-format
 msgid "%*s%s"
 msgstr "%*s%s"
@@ -18605,6 +18685,13 @@ msgstr "s'ha produït un error en generar el diff"
 msgid "could not parse log for '%s'"
 msgstr "no s'ha pogut llegir el fitxer de registre per a «%s»"
 
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "punta extra extra no vàlida: «%s»"
+
+msgid "unable to enumerate additional recent objects"
+msgstr "no s'han pogut enumerar els objectes recents addicionals"
+
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr "no s'afegirà l'àlies «%s»: («%s» ja existeix en l'índex)"
@@ -18756,6 +18843,14 @@ msgstr "no s'han pogut corregir els bits de permisos en «%s»"
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: no es pot baixar fins al «stage» #0"
 
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "estat de diff inesperat %c"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "elimina «%s»\n"
+
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -18872,7 +18967,7 @@ msgid ""
 "\n"
 msgstr ""
 "\n"
-"No obstant, si elimineu tot, s'avortarà el «rebase».\n"
+"No obstant això, si elimineu tot, s'avortarà el «rebase».\n"
 "\n"
 
 #, c-format
@@ -18959,6 +19054,22 @@ msgstr "argument %%(trailers) desconegut: %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "valor positiu esperat conté:lines=%s"
 
+#, c-format
+msgid "argument expected for %s"
+msgstr "s'esperava un argument per a %s"
+
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "valor positiu esperat %s=%s"
+
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "no es pot analitzar completament %s=%s"
+
+#, c-format
+msgid "value expected %s="
+msgstr "s'esperava un valor %s="
+
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "valor positiu esperat «%s» a %%(%s)"
@@ -19034,6 +19145,9 @@ msgstr "aquesta ordre rebutja l'àtom %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "no es pot usar --format=%.*s amb --python, --shell, --tcl"
 
+msgid "failed to run 'describe'"
+msgstr "no s'ha pogut executar «describe»"
+
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(sense branca, s'està fent «rebase» %s)"
@@ -19095,6 +19209,9 @@ msgstr "clau"
 msgid "field name to sort on"
 msgstr "nom del camp en el qual ordenar"
 
+msgid "exclude refs which match pattern"
+msgstr "exclou refs que coincideixin amb el patró"
+
 #, c-format
 msgid "not a reflog: %s"
 msgstr "no és un registre de referència: %s"
@@ -19371,6 +19488,7 @@ msgstr ""
 #. TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
 #. <remote> <src>:<dst>" push, and "being pushed ('%s')" is
 #. the <src>.
+#.
 #, c-format
 msgid ""
 "The destination you provided is not a full refname (i.e.,\n"
@@ -19547,8 +19665,10 @@ msgstr[1] ""
 "La vostra branca i «%s» han divergit,\n"
 "i tenen %d i %d comissions distintes cada una, respectivament.\n"
 
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (useu «git pull» per a fusionar la branca remota amb la vostra)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr ""
+"  (utilitzeu «git pull» si voleu integrar la branca remota amb la vostra)\n"
 
 #, c-format
 msgid "cannot parse expected object name '%s'"
@@ -19660,6 +19780,10 @@ 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"
 
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "opció no vàlida: «%s» en mode --stdin"
+
 msgid "your current branch appears to be broken"
 msgstr "la vostra branca actual sembla malmesa"
 
@@ -19975,6 +20099,7 @@ msgstr "cometeu els vostres canvis o feu un «stash» per a procedir."
 
 #. TRANSLATORS: %s will be "revert", "cherry-pick" or
 #. "rebase".
+#.
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: No s'ha pogut escriure un fitxer d'índex nou"
@@ -20817,6 +20942,77 @@ msgstr "el «fork» ha fallat"
 msgid "setsid failed"
 msgstr "«setsid» ha fallat"
 
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "no es pot fer stat en la plantilla «%s»"
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "no es pot fer opendir en el directori «%s»"
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "no es pot fer readlink en «%s»"
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "no es pot fer symlink en «%s» «%s»"
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "no es pot copiar «%s» a «%s»"
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "s'està ignorant la plantilla %s"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "plantilles no trobades a %s"
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "no s'estan copiant plantilles de «%s»: %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "nom de branca inicial no vàlid: «%s»"
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "no s'ha pogut gestionar el tipus de fitxer %d"
+
+#, c-format
+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 resum diferent"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s ja existeix"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "reinicialització: s'ha ignorat --initial-branch=%s"
+
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "S'ha reinicialitzat el repositori compartit existent del Git en %s%s\n"
+
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "S'ha reinicialitzat el repositori existent del Git en %s%s\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "S'ha inicialitzat un repositori compartit buit del Git en %s%s\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "S'ha inicialitzat un repositori buit del Git en %s%s\n"
+
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "l'entrada d'índex és un directori, però no dispers (%08x)"
index 2ef0dc7a7265dfd2b40d00626e6d9086f6c79197..f7e49ce4a50e004ef64d065849f8b9e56e464610 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-22 17:14+0200\n"
-"PO-Revision-Date: 2023-05-22 17:16+0200\n"
+"POT-Creation-Date: 2023-08-17 16:53+0200\n"
+"PO-Revision-Date: 2023-08-17 16:55+0200\n"
 "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
 "Language-Team: German\n"
 "Language: de\n"
@@ -17,7 +17,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.3.1\n"
+"X-Generator: Poedit 3.3.2\n"
 
 #, c-format
 msgid "Huh (%s)?"
@@ -664,9 +664,9 @@ msgid "Reverting is not possible because you have unmerged files."
 msgstr ""
 "Reverten ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "%s ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr ""
+"Rebase ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
@@ -816,6 +816,12 @@ msgstr "die Optionen '%s' und '%s' können nicht gemeinsam verwendet werden"
 msgid "'%s' outside a repository"
 msgstr "'%s' außerhalb eines Repositories"
 
+msgid "failed to read patch"
+msgstr "Patch konnte nicht gelesen werden"
+
+msgid "patch too large"
+msgstr "Patch zu groß"
+
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Kann regulären Ausdruck für Zeitstempel %s nicht verarbeiten"
@@ -1692,12 +1698,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
@@ -1740,9 +1744,10 @@ msgid "a branch named '%s' already exists"
 msgstr "Branch '%s' existiert bereits"
 
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
 msgstr ""
-"kann Aktualisierung des Branches '%s' nicht erzwingen, ausgecheckt in '%s'"
+"Aktualisierung des vom Arbeitsverzeichnis '%2$s' verwendete Branch '%1$s' "
+"kann nicht erzwungen werden"
 
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -1812,17 +1817,6 @@ msgstr "git add [<Optionen>] [--] <Pfadspezifikation>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "kann chmod %cx '%s' nicht ausführen"
 
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "unerwarteter Differenz-Status %c"
-
-msgid "updating files failed"
-msgstr "Aktualisierung der Dateien fehlgeschlagen"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "lösche '%s'\n"
-
 msgid "Unstaged changes after refreshing the index:"
 msgstr ""
 "Nicht zum Commit vorgemerkte Änderungen nach Aktualisierung der Staging-Area:"
@@ -2270,9 +2264,6 @@ msgstr "-m an git-mailinfo übergeben"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "--keep-cr an git-mailsplit für mbox-Format übergeben"
 
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr "kein --keep-cr an git-mailsplit übergeben, unabhängig von am.keepcr"
-
 msgid "strip everything before a scissors line"
 msgstr "alles vor einer Scheren-Zeile entfernen"
 
@@ -3333,12 +3324,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
@@ -3385,6 +3376,9 @@ msgstr "wie --batch, aber keine Ausgabe von <Inhalten>"
 msgid "stdin is NUL-terminated"
 msgstr "stdin endet mit NUL"
 
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin und stdout sind NUL-beendet"
+
 msgid "read commands from stdin"
 msgstr "Befehle von der Standard-Eingabe lesen"
 
@@ -4269,12 +4263,6 @@ msgstr "serverspezifisch"
 msgid "option to transmit"
 msgstr "Option übertragen"
 
-msgid "use IPv4 addresses only"
-msgstr "nur IPv4-Adressen benutzen"
-
-msgid "use IPv6 addresses only"
-msgstr "nur IPv6-Adressen benutzen"
-
 msgid "apply partial clone filters to submodules"
 msgstr "partielle Klonfilter auf Submodule anwenden"
 
@@ -4738,6 +4726,9 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+msgid "updating files failed"
+msgstr "Aktualisierung der Dateien fehlgeschlagen"
+
 msgid "failed to unpack HEAD tree object"
 msgstr "Fehler beim Entpacken des Tree-Objektes von HEAD."
 
@@ -4798,8 +4789,8 @@ msgstr ""
 "der aktuellen Commit-Beschreibung verwendet wird."
 
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "Konnte Commit %s nicht nachschlagen"
+msgid "could not lookup commit '%s'"
+msgstr "konnte Commit '%s' nicht nachschlagen"
 
 #, c-format
 msgid "(reading log message from standard input)\n"
@@ -6889,7 +6880,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
@@ -7464,77 +7454,6 @@ msgstr "--verify wurde ohne Namen der Paketdatei angegeben"
 msgid "fsck error in pack objects"
 msgstr "fsck Fehler beim Packen von Objekten"
 
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "kann Vorlage '%s' nicht lesen"
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "kann Verzeichnis '%s' nicht öffnen"
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "kann Verweis '%s' nicht lesen"
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "kann symbolische Verknüpfung '%s' auf '%s' nicht erstellen"
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "kann '%s' nicht nach '%s' kopieren"
-
-#, c-format
-msgid "ignoring template %s"
-msgstr "ignoriere Vorlage %s"
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "Keine Vorlagen in %s gefunden."
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "kopiere keine Vorlagen von '%s': %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "ungültiger initialer Branchname: '%s'"
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "kann nicht mit Dateityp %d umgehen"
-
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "Konnte %s nicht nach %s verschieben"
-
-msgid "attempt to reinitialize repository with different hash"
-msgstr "Versuch, das Repository mit einem anderen Hash zu reinitialisieren"
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s existiert bereits"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "Neu-Initialisierung: --initial-branch=%s ignoriert"
-
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "Bestehendes verteiltes Git-Repository in %s%s neuinitialisiert\n"
-
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "Bestehendes Git-Repository in %s%s neuinitialisiert\n"
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "Leeres verteiltes Git-Repository in %s%s initialisiert\n"
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "Leeres Git-Repository in %s%s initialisiert\n"
-
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7973,6 +7892,10 @@ msgstr ""
 "Konnte gefolgten Remote-Branch nicht finden, bitte geben Sie <Upstream> "
 "manuell an.\n"
 
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "konnte Objekt-Informationen über '%s' nicht bestimmen"
+
 #, 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"
@@ -8122,10 +8045,6 @@ msgstr "zusätzlich zum Objekt die darauf verweisenden Referenzen anzeigen"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<Optionen>] <Commit-Referenz> [<Pfad>...]"
 
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "konnte Objekt-Informationen über '%s' nicht bestimmen"
-
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
 msgstr "ungültiges ls-tree-Format: Element '%s' fängt nicht mit '(' an"
@@ -8871,22 +8790,26 @@ msgid "git notes [--ref <notes-ref>] [list [<object>]]"
 msgstr "git notes [--ref <Notiz-Referenz>] [list [<Objekt>]]"
 
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <Notiz-Referenz>] add [-f] [--allow-empty] [-m "
-"<Beschreibung> | -F <Datei> | (-c | -C) <Objekt>] [<Objekt>]"
+"git notes [--ref <Notiz-Referenz>] add [-f] [--allow-empty] [--"
+"[no-]separator|--separator=<Absatz-Unterbrechung>] [--[no-]stripspace] [-m "
+"<Nachricht> | -F <Datei> | (-c | -C) <Objekt>] [<Objekt>]"
 
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
 "git notes [--ref <Notiz-Referenz>] copy [-f] <von-Objekt> <nach-Objekt>"
 
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <Notiz-Referenz>] append [--allow-empty] [-m <Beschreibung> "
-"| -F <Datei> | (-c | -C) <Objekt>] [<Objekt>]"
+"git notes [--ref <Notiz-Referenz>] append [--allow-empty] [--"
+"[no-]separator|--separator=<Absatz-Unterbrechnung>] [--[no-]stripspace] [-m "
+"<Nachricht> | -F <Datei> | (-c | -C) <Objekt>] [<Object>]"
 
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
 msgstr "git notes [--ref <Notiz-Referenz>] edit [--allow-empty] [<Objekt>]"
@@ -9021,6 +8944,15 @@ msgstr "Speichern leerer Notiz erlauben"
 msgid "replace existing notes"
 msgstr "existierende Notizen ersetzen"
 
+msgid "<paragraph-break>"
+msgstr "<Absatz-Unterbrechung>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "<Absatz-Unterbrechung> zwischen Absätzen einfügen"
+
+msgid "remove unnecessary whitespace"
+msgstr "unnötigen Whitespace entfernen"
+
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -9595,8 +9527,11 @@ msgstr ""
 msgid "refusing to run without --i-still-use-this"
 msgstr "Ausführung ohne --i-still-use-this verweigert"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <Muster>] [--exclude <Muster>]"
 
 msgid "pack everything"
 msgstr "alles packen"
@@ -9604,6 +9539,12 @@ msgstr "alles packen"
 msgid "prune loose refs (default)"
 msgstr "lose Referenzen entfernen (Standard)"
 
+msgid "references to include"
+msgstr "einzubeziehende Referenzen"
+
+msgid "references to exclude"
+msgstr "Referenzen zum Ausschluss"
+
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
@@ -9663,6 +9604,12 @@ msgstr "das Überschreiben von lokalen Branches erzwingen"
 msgid "number of submodules pulled in parallel"
 msgstr "Anzahl der parallel mit 'pull' zu verarbeitenden Submodule"
 
+msgid "use IPv4 addresses only"
+msgstr "nur IPv4-Adressen benutzen"
+
+msgid "use IPv6 addresses only"
+msgstr "nur IPv6-Adressen benutzen"
+
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
@@ -9938,35 +9885,37 @@ msgstr ""
 
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Aktualisierungen wurden zurückgewiesen, weil die Spitze Ihres aktuellen\n"
-"Branches hinter seinem externen Gegenstück zurückgefallen ist. Führen Sie\n"
-"die externen Änderungen zusammen (z. B. 'git pull ...') bevor Sie \"push\"\n"
-"erneut ausführen.\n"
-"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
-"für weitere Details."
+"Branches hinter seinem externen Gegenstück zurückgefallen ist. Wenn Sie\n"
+"die externen Änderungen integrieren wollen, verwenden Sie 'git pull' bevor\n"
+"Sie erneut push ausführen.\n"
+"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help' für "
+"weitere\n"
+"Informationen."
 
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n"
-"Branches hinter seinem externen Gegenstück zurückgefallen ist. Checken Sie\n"
-"diesen Branch aus und führen Sie die externen Änderungen zusammen\n"
-"(z. B. 'git pull ...') bevor Sie erneut \"push\" ausführen.\n"
-"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
-"für weitere Details."
-
-msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Branches hinter seinem externen Gegenstück zurückgefallen ist. Wenn Sie die\n"
+"externen Änderungen integrieren wollen, verwenden Sie 'git pull'\n"
+"bevor Sie erneut push ausführen.\n"
+"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help' für "
+"weitere\n"
+"Informationen."
+
+msgid ""
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Aktualisierungen wurden zurückgewiesen, weil das Remote-Repository Commits "
@@ -9974,11 +9923,12 @@ msgstr ""
 "die lokal nicht vorhanden sind. Das wird üblicherweise durch einen \"push\" "
 "von\n"
 "Commits auf dieselbe Referenz von einem anderen Repository aus verursacht.\n"
-"Vielleicht müssen Sie die externen Änderungen zusammenführen (z. B. 'git "
-"pull ...')\n"
-"bevor Sie erneut \"push\" ausführen.\n"
-"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n"
-"für weitere Details."
+"Wenn Sie die externen Änderungen integrieren wollen, verwenden Sie 'git "
+"pull'\n"
+"bevor Sie erneut push ausführen.\n"
+"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help' für "
+"weitere\n"
+"Informationen."
 
 msgid "Updates were rejected because the tag already exists in the remote."
 msgstr ""
@@ -9995,15 +9945,21 @@ msgstr ""
 "die Option '--force' zu verwenden.\n"
 
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Aktualisierungen wurden zurückgewiesen, weil die Spitze des Remote-\n"
-"Tracking-Branches seit dem letzen Checkout aktualisiert wurde. Sie möchten\n"
-"diese Änderungen vielleicht lokal integrieren (z. B. 'git pull ...') bevor\n"
-"Sie die Änderungen erzwingen.\n"
+"Aktualisierungen wurden zurückgewiesen, weil die Spitze des Remote-"
+"Tracking-\n"
+"Branches seit dem letzten Auschecken aktualisiert wurde. Wenn Sie die "
+"externen\n"
+"Änderungen integrieren wollen, verwenden Sie 'git pull' bevor Sie erneut "
+"push\n"
+"ausführen.\n"
+"Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help' für "
+"weitere\n"
+"Informationen."
 
 #, c-format
 msgid "Pushing to %s\n"
@@ -10886,11 +10842,12 @@ msgstr "unbekanntes Argument für Option mirror: %s"
 msgid "fetch the remote branches"
 msgstr "die Remote-Branches anfordern"
 
-msgid "import all tags and associated objects when fetching"
-msgstr "alle Tags und verbundene Objekte beim Anfordern importieren"
-
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "oder fordere gar keine Tags an (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"alle Tags und zugehörigen Objekte beim Abruf importieren\n"
+"oder überhaupt keine Tags abrufen (--no-tags)"
 
 msgid "branch(es) to track"
 msgstr "Branch(es) zur Übernahme"
@@ -12875,6 +12832,10 @@ msgstr "Überspringe nicht zusammengeführtes Submodul %s"
 msgid "Skipping submodule '%s'"
 msgstr "Überspringe Submodul '%s'"
 
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "kann Submodul '%s' nicht ohne URL klonen"
+
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
 msgstr "Fehler beim Klonen von '%s'. Weiterer Versuch geplant"
@@ -13649,11 +13610,12 @@ msgstr "Tag-Inhalte ausgeben"
 
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason "
 "<Zeichenkette>]]\n"
-"                 [-b <neuer-Branch>] <Pfad> [<Commit-Angabe>]"
+"                 [--orphan] [(-b | -B) <neuer-Branch>] <Pfad> [<Commit-"
+"Angabe>]"
 
 msgid "git worktree list [-v | --porcelain [-z]]"
 msgstr "git worktree list [-v | --porcelain [-z]]"
@@ -13676,6 +13638,41 @@ msgstr "git worktree repair [<Pfad>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <Arbeitsverzeichnis>"
 
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Kein möglicher Quell-Branch, der auf '--orphan' schließen lässt"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"Wenn Sie ein Arbeitsverzeichnis erstellen möchten, um einen neuen verwaisten "
+"Branch\n"
+"(Branch ohne Commits) für dieses Repository zu erstellen, können Sie dies "
+"mit\n"
+"der Option --orphan tun:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"Wenn Sie ein Arbeitsverzeichnis erstellen möchten, um einen neuen verwaisten "
+"Branch\n"
+"(Branch ohne Commits) für dieses Repository zu erstellen, können Sie dies "
+"mit\n"
+"der Option --orphan tun:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #, c-format
 msgid "Removing %s/%s: %s"
 msgstr "Entferne %s/%s: %s"
@@ -13746,10 +13743,38 @@ msgstr "Bereite Arbeitsverzeichnis vor (setze Branch '%s' um; war bei %s)"
 msgid "Preparing worktree (checking out '%s')"
 msgstr "Bereite Arbeitsverzeichnis vor (checke '%s' aus)"
 
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "unerreichbar: ungültige Referenz: %s"
+
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "Bereite Arbeitsverzeichnis vor (losgelöster HEAD %s)"
 
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD zeigt auf eine ungültige (oder verwaiste) Referenz.\n"
+"HEAD-Pfad: '%s'\n"
+"HEAD Inhalte: '%s'"
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"Es gibt keine lokalen oder entfernten Referenzen, obwohl mindestens ein "
+"Remote-Repository\n"
+"vorhanden ist. Angehalten. Verwenden Sie 'add -f', um eine entfernte "
+"Referenz zu überschreiben\n"
+"oder rufen Sie diese zuerst ab"
+
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "'%s' und '%s' können nicht zusammen verwendet werden"
+
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
 "<Branch> auschecken, auch wenn dieser bereits in einem anderen "
@@ -13761,6 +13786,9 @@ msgstr "neuen Branch erstellen"
 msgid "create or reset a branch"
 msgstr "Branch erstellen oder umsetzen"
 
+msgid "create unborn/orphaned branch"
+msgstr "ungeborenen/verwaisten Branch erstellen"
+
 msgid "populate the new working tree"
 msgstr "das neue Arbeitsverzeichnis auschecken"
 
@@ -13783,6 +13811,13 @@ msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr ""
 "die Optionen '%s', '%s' und '%s' können nicht gemeinsam verwendet werden"
 
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "die Optionen '%s' und '%s' können nicht gemeinsam verwendet werden"
+
+msgid "<commit-ish>"
+msgstr "<Commit-Angabe>"
+
 msgid "added with --lock"
 msgstr "mit --lock hinzugefügt"
 
@@ -14022,6 +14057,14 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "Das Paket benötigt diese Referenz:"
 msgstr[1] "Das Paket benötigt diese %<PRIuMAX> Referenzen:"
 
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "Das Paket verwendet diesen Hash-Algorithmus: %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Das Paket verwendet diesen Filter: %s"
+
 msgid "unable to dup bundle descriptor"
 msgstr "konnte dup für Descriptor des Pakets nicht ausführen"
 
@@ -14261,9 +14304,10 @@ msgstr "Zeilen darstellen, die einem Muster entsprechen"
 msgid "A portable graphical interface to Git"
 msgstr "eine portable grafische Schnittstelle zu Git"
 
-msgid "Compute object ID and optionally creates a blob from a file"
+msgid "Compute object ID and optionally create an object from a file"
 msgstr ""
-"von einer Datei die Objekt-ID berechnen und optional ein Blob erstellen"
+"Berechnung der Objekt-ID und optionales Erstellen eines Objekts aus einer "
+"Datei"
 
 msgid "Display help information about Git"
 msgstr "Hilfsinformationen über Git anzeigen"
@@ -14687,6 +14731,10 @@ msgstr "Commit-Graph hat keinen Basis-Graph-Chunk"
 msgid "commit-graph chain does not match"
 msgstr "Commit-Graph Verkettung stimmt nicht überein"
 
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "Anzahl der Commits im Basisgraph zu hoch: %<PRIuMAX>"
+
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
 msgstr "Ungültige Commit-Graph Verkettung: Zeile '%s' ist kein Hash"
@@ -14770,6 +14818,17 @@ msgstr "konnte Basis-Commit-Graph-Datei nicht umbenennen"
 msgid "failed to rename temporary commit-graph file"
 msgstr "konnte temporäre Commit-Graph-Datei nicht umbenennen"
 
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr ""
+"Graphen mit %<PRIuMAX>, %<PRIuMAX> Commits können nicht zusammengeführt "
+"werden"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr ""
+"Graph %s kann nicht zusammengeführt werden, zu viele Commits: %<PRIuMAX>"
+
 msgid "Scanning merged commits"
 msgstr "Durchsuche zusammengeführte Commits"
 
@@ -14801,9 +14860,6 @@ msgstr "Commit-Graph hat fehlerhaften Fanout-Wert: fanout[%d] = %u != %u"
 msgid "failed to parse commit %s from commit-graph"
 msgstr "konnte Commit %s von Commit-Graph nicht parsen"
 
-msgid "Verifying commits in commit graph"
-msgstr "Commit in Commit-Graph überprüfen"
-
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
 msgstr ""
@@ -14849,6 +14905,9 @@ msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
 msgstr ""
 "Commit-Datum für Commit %s in Commit-Graph ist %<PRIuMAX> != %<PRIuMAX>"
 
+msgid "Verifying commits in commit graph"
+msgstr "Commit in Commit-Graph überprüfen"
+
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s ist kein Commit!"
@@ -15816,6 +15875,12 @@ msgstr "keine Merge-Basis gefunden"
 msgid "multiple merge bases found"
 msgstr "mehrere Merge-Basen gefunden"
 
+msgid "cannot compare stdin to a directory"
+msgstr "kann stdin nicht mit einem Verzeichnis vergleichen"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "kann eine benannte Pipe nicht mit einem Verzeichnis vergleichen"
+
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<Optionen>] <Pfad> <Pfad>"
 
@@ -15873,6 +15938,13 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "externes Diff-Programm unerwartet beendet, angehalten bei %s"
 
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow erfordert genau eine Pfadspezifikation"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "Magie von Pfadspezifikationen wird von --follow nicht unterstützt: %s"
+
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
 msgstr ""
@@ -15892,9 +15964,6 @@ msgstr ""
 "die Optionen '%s' und '%s' können nicht gemeinsam verwendet werden, nutzen "
 "Sie '%s' mit '%s' und '%s'"
 
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow erfordert genau eine Pfadspezifikation"
-
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "Ungültiger --stat Wert: %s"
@@ -17404,7 +17473,7 @@ msgstr ""
 #. 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"
+#. - go to submodule (mysubmodule), and either merge commit abc1234"
 #.
 #, c-format
 msgid ""
@@ -18145,7 +18214,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"
@@ -18154,7 +18223,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.
@@ -18170,7 +18239,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]"
@@ -18827,6 +18896,13 @@ msgstr "Fehler beim Generieren des Diffs."
 msgid "could not parse log for '%s'"
 msgstr "Konnte Log für '%s' nicht parsen."
 
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "ungültiger zusätzlicher Schrotthinweis: '%s'"
+
+msgid "unable to enumerate additional recent objects"
+msgstr "zusätzliche neue Objekte konnten nicht aufgezählt werden"
+
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr ""
@@ -18980,6 +19056,14 @@ msgstr "Konnte Zugriffsberechtigung auf '%s' nicht setzen."
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: Kann nicht auf Stufe #0 wechseln."
 
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "unerwarteter Differenz-Status %c"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "lösche '%s'\n"
+
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -19180,6 +19264,22 @@ msgstr "unbekanntes %%(trailers) Argument: %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "Positiver Wert erwartet contents:lines=%s"
 
+#, c-format
+msgid "argument expected for %s"
+msgstr "Argument erwartet für %s"
+
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "positiver Wert erwartet %s=%s"
+
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "kann %s=%s nicht vollständig parsen"
+
+#, c-format
+msgid "value expected %s="
+msgstr "Wert erwartet %s="
+
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "positiver Wert erwartet '%s' in %%(%s)"
@@ -19254,6 +19354,9 @@ msgstr "dieser Befehl lehnt Atom ab %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s kann nicht mit --python, --shell, --tcl verwendet werden"
 
+msgid "failed to run 'describe'"
+msgstr "'describe' konnte nicht ausgeführt werden"
+
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(kein Branch, Rebase von %s)"
@@ -19315,6 +19418,9 @@ msgstr "Schüssel"
 msgid "field name to sort on"
 msgstr "sortiere nach diesem Feld"
 
+msgid "exclude refs which match pattern"
+msgstr "Ausschluss von Referenzen, die dem Muster entsprechen"
+
 #, c-format
 msgid "not a reflog: %s"
 msgstr "Kein Reflog: %s"
@@ -19772,10 +19878,11 @@ msgstr[1] ""
 "Ihr Branch und '%s' sind divergiert,\n"
 "und haben jeweils %d und %d unterschiedliche Commits.\n"
 
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
 msgstr ""
-"  (benutzen Sie \"git pull\", um Ihren Branch mit dem Remote-Branch "
-"zusammenzuführen)\n"
+"  (verwenden Sie \"git pull\", wenn Sie den Remote-Branch in Ihren "
+"integrieren wollen)\n"
 
 #, c-format
 msgid "cannot parse expected object name '%s'"
@@ -19887,6 +19994,10 @@ 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"
 
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "ungültige Option '%s' im Modus --stdin"
+
 msgid "your current branch appears to be broken"
 msgstr "Ihr aktueller Branch scheint fehlerhaft zu sein."
 
@@ -21056,6 +21167,77 @@ msgstr "fork fehlgeschlagen"
 msgid "setsid failed"
 msgstr "setsid fehlgeschlagen"
 
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "kann Vorlage '%s' nicht lesen"
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "kann Verzeichnis '%s' nicht öffnen"
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "kann Verweis '%s' nicht lesen"
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "kann symbolische Verknüpfung '%s' auf '%s' nicht erstellen"
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "kann '%s' nicht nach '%s' kopieren"
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "ignoriere Vorlage %s"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "Keine Vorlagen in %s gefunden."
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "kopiere keine Vorlagen von '%s': %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "ungültiger initialer Branchname: '%s'"
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "kann nicht mit Dateityp %d umgehen"
+
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "Konnte %s nicht nach %s verschieben"
+
+msgid "attempt to reinitialize repository with different hash"
+msgstr "Versuch, das Repository mit einem anderen Hash zu reinitialisieren"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s existiert bereits"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "Neu-Initialisierung: --initial-branch=%s ignoriert"
+
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "Bestehendes verteiltes Git-Repository in %s%s neuinitialisiert\n"
+
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "Bestehendes Git-Repository in %s%s neuinitialisiert\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "Leeres verteiltes Git-Repository in %s%s initialisiert\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "Leeres Git-Repository in %s%s initialisiert\n"
+
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "Index-Eintrag ist ein Verzeichnis, aber nicht partiell (%08x)"
index db6efc02508fc47815f485b99f1c7d1256cc396d..68a4d45fd8f6a734113f78dc26f246a1dbe48b76 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: 2023-05-20 12:25+0200\n"
-"PO-Revision-Date: 2023-05-18 18:50+0200\n"
+"POT-Creation-Date: 2023-08-16 11:48+0200\n"
+"PO-Revision-Date: 2023-08-16 11:49+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"
@@ -716,9 +716,8 @@ msgstr "Impossible de tirer car vous avez des fichiers non fusionnés."
 msgid "Reverting is not possible because you have unmerged files."
 msgstr "Impossible d'annuler car vous avez des fichiers non fusionnés."
 
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "%s n'est pas possible car vous avez des fichiers non fusionnés."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "Impossible de rebaser, car vous avez des fichiers non fusionnés."
 
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
@@ -868,6 +867,12 @@ msgstr "les options '%s' et '%s' ne peuvent pas être utilisées ensemble"
 msgid "'%s' outside a repository"
 msgstr "'%s' hors d'un dépôt"
 
+msgid "failed to read patch"
+msgstr "impossible de lire la rustine"
+
+msgid "patch too large"
+msgstr "la rustine est trop grosse"
+
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Impossible de préparer la regexp d'horodatage %s"
@@ -1787,9 +1792,10 @@ msgid "a branch named '%s' already exists"
 msgstr "Une branche nommée '%s' existe déjà"
 
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
 msgstr ""
-"impossible de forcer la mise à jour de la branche '%s' extraite dans '%s'"
+"impossible de forcer la mise à jour de la branche '%s' utilisée par l'arbre-"
+"de-travail dans '%s'"
 
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -1859,17 +1865,6 @@ msgstr "git add [<options>] [--] <chemin>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "impossible de chmod %cx '%s'"
 
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "état de diff inattendu %c"
-
-msgid "updating files failed"
-msgstr "échec de la mise à jour des fichiers"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "suppression de '%s'\n"
-
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Modifications non indexées après rafraîchissement de l'index :"
 
@@ -2305,10 +2300,6 @@ msgstr "passer l'option -m à git-mailinfo"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "passer l'option --keep-cr à git-mailsplit fpour le format mbox"
 
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"ne pas passer l'option --keep-cr à git-mailsplit indépendamment de am.keepcr"
-
 msgid "strip everything before a scissors line"
 msgstr "retirer tout le contenu avant la ligne des ciseaux"
 
@@ -3370,12 +3361,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
@@ -3420,6 +3411,9 @@ msgstr "comme --batch, mais ne pas émettre <contenu>"
 msgid "stdin is NUL-terminated"
 msgstr "l'entrée se termine par NUL"
 
+msgid "stdin and stdout is NUL-terminated"
+msgstr "l'entrée et la sortie standard se terminent par NUL"
+
 msgid "read commands from stdin"
 msgstr "lire les commandes depuis l'entrée standard"
 
@@ -4296,12 +4290,6 @@ msgstr "spécifique au serveur"
 msgid "option to transmit"
 msgstr "option à transmettre"
 
-msgid "use IPv4 addresses only"
-msgstr "n'utiliser que des adresses IPv4"
-
-msgid "use IPv6 addresses only"
-msgstr "n'utiliser que des adresses IPv6"
-
 msgid "apply partial clone filters to submodules"
 msgstr "appliquer les filtres de clone partiel aux sous-modules"
 
@@ -4753,6 +4741,9 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+msgid "updating files failed"
+msgstr "échec de la mise à jour des fichiers"
+
 msgid "failed to unpack HEAD tree object"
 msgstr "échec du dépaquetage de l'objet arbre HEAD"
 
@@ -4812,8 +4803,8 @@ msgstr ""
 "qui n'est pas utilisé dans le message de validation actuel"
 
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "impossible de rechercher le commit %s"
+msgid "could not lookup commit '%s'"
+msgstr "impossible de rechercher le commit '%s'"
 
 #, c-format
 msgid "(reading log message from standard input)\n"
@@ -7461,77 +7452,6 @@ msgstr "--verify sans nom de fichier paquet donné"
 msgid "fsck error in pack objects"
 msgstr "erreur de fsck dans les objets paquets"
 
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "impossible de faire un stat du modèle '%s'"
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "impossible d'ouvrir le répertoire '%s'"
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "impossible de lire le lien '%s'"
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "impossible de créer un lien symbolique de '%s' '%s'"
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "impossible de copier '%s' vers '%s'"
-
-#, c-format
-msgid "ignoring template %s"
-msgstr "modèle %s ignoré"
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "modèles non trouvés dans %s"
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "pas de copie des modèles depuis '%s' : %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "nom de branche initiale invalide : '%s'"
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "impossible de traiter le fichier de type %d"
-
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "impossible de déplacer %s vers %s"
-
-msgid "attempt to reinitialize repository with different hash"
-msgstr "essai de réinitialisation du dépôt avec une empreinte différente"
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s existe déjà"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-initialisation : --initial-branch=%s ignoré"
-
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "Dépôt Git existant partagé réinitialisé dans %s%s\n"
-
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "Dépôt Git existant réinitialisé dans %s%s\n"
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "Dépôt Git vide partagé initialisé dans %s%s\n"
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "Dépôt Git vide initialisé dans %s%s\n"
-
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7979,6 +7899,10 @@ msgstr ""
 "Impossible de trouver une branche distante suivie, merci de spécifier "
 "<branche_amont> manuellement.\n"
 
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "impossible d'obtenir l'information d'objet pour '%s'"
+
 #, 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 '('"
@@ -8126,10 +8050,6 @@ msgstr "afficher la réf sous-jacente en plus de l'objet pointé par elle"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<options>] <arbre ou apparenté> [<chemin>...]"
 
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "impossible d'obtenir l'information d'objet pour '%s'"
-
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
 msgstr "mauvais format ls-tree : l'élément '%s' ne commence pas par '('"
@@ -8872,22 +8792,26 @@ msgid "git notes [--ref <notes-ref>] [list [<object>]]"
 msgstr "git notes [--ref <références-notes>] [list [<object>]]"
 
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <références-notes>] add [-f] [--allow-empty] [-m <message> "
-"| -F <fichier> | (-c | -C) <objet>] [<objet>]"
+"git notes [--ref <référence-notes>] add [-f] [--allow-empty] [--"
+"[no-]separator|--separator=<coupure-paragraphe>] [--[no-]stripspace] [-m "
+"<message> | -F <fichier> | (-c | -C) <objet>] [<objet>]"
 
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
 "git notes [--ref <références-notes>] copy [-f] <depuis-objet> <vers-objet>"
 
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <références-notes>] append [--allow-empty] [-m <message> | -"
-"F <fichier> | (-c | -C) <objet>] [<objet>]"
+"git notes [--ref <références-notes>] append [--allow-empty] [--"
+"[no-]separator|--separator=<coupure-paragraphe>] [--[no-]stripspace]-m "
+"<message> | -F <fichier> | (-c | -C) <objet>] [<objet>]"
 
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
 msgstr "git notes [--ref <références-notes>] edit [--allow-empty] [<objet>]"
@@ -9019,6 +8943,15 @@ msgstr "permettre de stocker une note vide"
 msgid "replace existing notes"
 msgstr "remplacer les notes existantes"
 
+msgid "<paragraph-break>"
+msgstr "<séparateur-paragraphe>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "insérer <séparateur-paragraphe> entre les paragraphes"
+
+msgid "remove unnecessary whitespace"
+msgstr "retirer les espaces inutiles"
+
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -9584,8 +9517,11 @@ msgstr ""
 msgid "refusing to run without --i-still-use-this"
 msgstr "refus de lancer sans --i-still-use-this"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <motif>] [--exclude <motif>]"
 
 msgid "pack everything"
 msgstr "empaqueter tout"
@@ -9593,6 +9529,12 @@ msgstr "empaqueter tout"
 msgid "prune loose refs (default)"
 msgstr "élaguer les références perdues (défaut)"
 
+msgid "references to include"
+msgstr "références à inclure"
+
+msgid "references to exclude"
+msgstr "références à exclure"
+
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
@@ -9650,6 +9592,12 @@ msgstr "forcer l'écrasement de la branche locale"
 msgid "number of submodules pulled in parallel"
 msgstr "nombre de sous-modules tirés en parallèle"
 
+msgid "use IPv4 addresses only"
+msgstr "n'utiliser que des adresses IPv4"
+
+msgid "use IPv6 addresses only"
+msgstr "n'utiliser que des adresses IPv6"
+
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
@@ -9920,46 +9868,43 @@ msgstr ""
 
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Les mises à jour ont été rejetées car la pointe de la branche courante est "
+"Les mises à jour ont été rejetées car le sommet de la branche actuelle est "
 "derrière\n"
-"son homologue distant. Intégrez les changements distants (par exemple 'git "
-"pull ...')\n"
-"avant de pousser à nouveau.\n"
+"son homologue distant. Si vous souhaitez intégrer les changements distants,\n"
+"utilisez 'git pull' avant de pousser à nouveau.\n"
 "Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
 "d'information."
 
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Les mises à jour ont été rejetées car la pointe de la branche courante est "
+"Les mises à jour ont été rejetées, car le sommet d'une branche poussée est "
 "derrière\n"
-"son homologue distant. Extrayez cette branche et intégrez les changements "
-"distants\n"
-"(par exemple 'git pull ...') avant de pousser à nouveau.\n"
+"son homologue distant. Si vous souhaitez intégrer les changements distants,\n"
+"\"utilisez 'git pull' avant de pousser à nouveau.\n"
 "Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
 "d'information."
 
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Les mises à jour ont été rejetées car la branche distante contient du "
-"travail que\n"
-"vous n'avez pas en local. Ceci est généralement causé par un autre dépôt "
-"poussé\n"
-"vers la même référence. Vous pourriez intégrer d'abord les changements "
-"distants\n"
-"(par exemple 'git pull ...') avant de pousser à nouveau.\n"
+"Les mises à jour ont été rejetées car le distant contient du travail que "
+"vous\n"
+"n'avez pas localement. La cause probable est que quelqu'un a déjà poussé sur "
+"la même réf.\n"
+"depuis un autre dépôt. Si vous souhaitez intégrer les changements distants,\n"
+"\"utilisez 'git pull' avant de pousser à nouveau.\n"
 "Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
 "d'information."
 
@@ -9980,15 +9925,18 @@ msgstr ""
 "vers un objet qui n'est pas un commit, sans utiliser l'option '--force'.\n"
 
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Les mises à jour ont été rejetées, car la pointe de la branche\n"
-"de suivi a été mise à jour depuis la dernière extraction. Intégrez\n"
-"ces changements localement (par exemple 'git pull ...') avant de\n"
-"forcer à nouveau une mise à jour.\n"
+"Les mises à jour ont été rejetées, car le sommet de la branche de suivi à "
+"distance a\n"
+"été mis à jour depuis la dernière extraction. Si vous souhaitez intégrer les "
+"changements distants,\n"
+"\"utilisez 'git pull' avant de pousser à nouveau.\n"
+"Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
+"d'information."
 
 #, c-format
 msgid "Pushing to %s\n"
@@ -10860,12 +10808,13 @@ msgstr "argument miroir inconnu : %s"
 msgid "fetch the remote branches"
 msgstr "rapatrier les branches distantes"
 
-msgid "import all tags and associated objects when fetching"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
 msgstr ""
-"importer toutes les étiquettes et les objets associés lors du rapatriement"
-
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "ou ne rapatrier aucune étiquette (--no-tags)"
+"importer toutes les étiquettes et les objets associés lors de la "
+"récupération\n"
+"ou ne récupérer aucune étiquette (--no-tags)"
 
 msgid "branch(es) to track"
 msgstr "branche(s) à suivre"
@@ -12848,6 +12797,10 @@ msgstr "Sous-module non fusionné %s non traité"
 msgid "Skipping submodule '%s'"
 msgstr "Sous-module '%s' non traité"
 
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "impossible de cloner le sous-module '%s' sans une URL"
+
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
 msgstr "Impossible de cloner '%s'. Réessai prévu"
@@ -13611,10 +13564,11 @@ msgstr "afficher le contenu de l'étiquette"
 
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <chaîne>]]\n"
-"                 [-b <nouvelle-branche>] <chemin> [<commit-esque>]"
+"                 [--orphan] [(-b | -B) <nouvelle-branche>] <chemin> [<commit-"
+"esque>]"
 
 msgid "git worktree list [-v | --porcelain [-z]]"
 msgstr "git worktree list [-v | --porcelain [-z]]"
@@ -13637,6 +13591,37 @@ msgstr "git worktree repair [<chemin>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <arbre-de-travail>"
 
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Aucune branche source possible, activation de '--orphan'"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"Si vous vouliez créer un arbre-de-travail contenant une nouvelle branche\n"
+"orpheline (une branche sans commit) pour ce dépôt, vous pouvez le faire\n"
+"en utilisant le drapeau --orphan :\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"Si vous vouliez créer un arbre-de-travail contenant une nouvelle branche\n"
+"orpheline (une branche sans commit) pour ce dépôt, vous pouvez le faire\n"
+"en utilisant le drapeau --orphan :\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #, c-format
 msgid "Removing %s/%s: %s"
 msgstr "Suppression de %s/%s : %s"
@@ -13708,10 +13693,36 @@ msgstr ""
 msgid "Preparing worktree (checking out '%s')"
 msgstr "Préparation de l'arbre de travail (extraction de '%s')"
 
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "non joignable : référence invalide : %s"
+
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "Préparation de l'arbre de travail (HEAD détachée %s)"
 
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD pointe sur une référence invalide (ou orpheline).\n"
+"chemin de HEAD '%s'\n"
+"contenu de HEAD : '%s'"
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"Aucune réf locale ou distant n'existe malgré la présence d'au moins un "
+"distant,\n"
+"on arrête ; utilisez 'add -f' pour passe outre ou récupérer le distant avant"
+
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "'%s' et '%s' ne peuvent pas être utilisées ensemble"
+
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
 "extraire la <branche> même si elle est déjà extraite dans une autre copie de "
@@ -13723,6 +13734,9 @@ msgstr "créer une nouvelle branche"
 msgid "create or reset a branch"
 msgstr "créer ou réinitialiser une branche"
 
+msgid "create unborn/orphaned branch"
+msgstr "créer une branche non née/orpheline"
+
 msgid "populate the new working tree"
 msgstr "remplissage de la nouvelle copie de travail"
 
@@ -13742,6 +13756,13 @@ msgstr "essayer de nommer la nouvelle branche comme la branche amont"
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "les options '%s', '%s' et '%s' ne peuvent pas être utilisées ensemble"
 
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "les options '%s' et '%s' ne peuvent pas être utilisées ensemble"
+
+msgid "<commit-ish>"
+msgstr "<commit-esque>"
+
 msgid "added with --lock"
 msgstr "ajouté avec --lock"
 
@@ -13979,6 +14000,14 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "Le colis exige cette référence :"
 msgstr[1] "Le colis exige ces %<PRIuMAX> références :"
 
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "algorithme d'empreinte du colis : %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Le colis utilise ce filtre : %s"
+
 msgid "unable to dup bundle descriptor"
 msgstr "impossible de dupliquer le descripteur de liasse"
 
@@ -14214,9 +14243,9 @@ msgstr "Afficher les lignes correspondant à un motif"
 msgid "A portable graphical interface to Git"
 msgstr "Une interface graphique portable pour Git"
 
-msgid "Compute object ID and optionally creates a blob from a file"
+msgid "Compute object ID and optionally create an object from a file"
 msgstr ""
-"Calculer l'ID d'objet et créer optionnellement un blob depuis un fichier"
+"Calculer l'ID d'objet et créer optionnellement un objet depuis un fichier"
 
 msgid "Display help information about Git"
 msgstr "Afficher l'information d'aide à propos de Git"
@@ -14638,6 +14667,10 @@ msgstr "le graphe de commit n'a pas de section de graphes de base"
 msgid "commit-graph chain does not match"
 msgstr "la chaîne de graphe de commit ne correspond pas"
 
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "nombre de commits dans le graphe de base trop haut : %<PRIuMAX>"
+
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
 msgstr ""
@@ -14729,6 +14762,15 @@ msgstr "échec du renommage du fichier de graphe de commits"
 msgid "failed to rename temporary commit-graph file"
 msgstr "impossible de renommer le fichier temporaire de graphe de commits"
 
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr ""
+"impossible de fusionner des graphes avec %<PRIuMAX>, %<PRIuMAX> commits"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "impossible de fusionner le graphe %s, trop de commits : %<PRIuMAX>"
+
 msgid "Scanning merged commits"
 msgstr "Analyse des commits de fusion"
 
@@ -14761,9 +14803,6 @@ msgstr ""
 msgid "failed to parse commit %s from commit-graph"
 msgstr "échec de l'analyse le commit %s depuis le graphe de commits"
 
-msgid "Verifying commits in commit graph"
-msgstr "Verification des commits dans le graphe de commits"
-
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
 msgstr ""
@@ -14816,6 +14855,9 @@ msgstr ""
 "la date de validation pour le commit %s dans le graphe de commit est "
 "%<PRIuMAX> != %<PRIuMAX>"
 
+msgid "Verifying commits in commit graph"
+msgstr "Verification des commits dans le graphe de commits"
+
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s n'est pas un commit !"
@@ -15784,6 +15826,12 @@ msgstr "aucune base de fusion trouvée"
 msgid "multiple merge bases found"
 msgstr "bases multiples de fusion trouvées"
 
+msgid "cannot compare stdin to a directory"
+msgstr "impossible de comparer stdin à un répertoire"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "impossible de réparer un tuyau nommé à un répertoire"
+
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<options>] <chemin> <chemin>"
 
@@ -15843,6 +15891,14 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "l'application de diff externe a disparu, arrêt à %s"
 
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow a besoin d'une spécification de chemin unique"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr ""
+"le spécificateur magique de chemin n'est pas pris en charge par --follow : %s"
+
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
 msgstr ""
@@ -15861,9 +15917,6 @@ msgstr ""
 "les options '%s' et '%s' ne peuvent pas être utilisées ensemble, utilisez "
 "'%s' avec '%s' et '%s'"
 
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow a besoin d'une spécification de chemin unique"
-
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "valeur invalide de --stat : %s"
@@ -18794,6 +18847,13 @@ msgstr "échec de la génération de diff"
 msgid "could not parse log for '%s'"
 msgstr "impossible d'analyser le journal pour '%s'"
 
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "sommet supplémentaire dégénéré invalide : '%s'"
+
+msgid "unable to enumerate additional recent objects"
+msgstr "impossible d'énumérer les objets récents additionnels"
+
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr "pas d'ajout d'alias de fichier '%s'(« %s » existe déjà dans l'index)"
@@ -18946,6 +19006,14 @@ msgstr "impossible de régler les bits de droit de '%s'"
 msgid "%s: cannot drop to stage #0"
 msgstr "%s : impossible de revenir à l'étape 0"
 
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "état de diff inattendu %c"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "suppression de '%s'\n"
+
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -19148,6 +19216,22 @@ msgstr "argument %%(trailers) inconnu : %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "valeur positive attendue contents:lines=%s"
 
+#, c-format
+msgid "argument expected for %s"
+msgstr "argument attendu pour %s"
+
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "valeur positive attendue %s=%s"
+
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "impossible d'analyser complètement %s=%s"
+
+#, c-format
+msgid "value expected %s="
+msgstr "valeur attendue %s="
+
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "valeur positive attendue '%s' dans %%(%s)"
@@ -19222,6 +19306,9 @@ msgstr "cette commande rejette l'atome %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s ne peut pas être utilisé avec --python, --shell, --tcl"
 
+msgid "failed to run 'describe'"
+msgstr "échec pour lancer 'describe'"
+
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(aucune branche, rebasage de %s)"
@@ -19283,6 +19370,9 @@ msgstr "clé"
 msgid "field name to sort on"
 msgstr "nom du champ servant à trier"
 
+msgid "exclude refs which match pattern"
+msgstr "exclure les références correspondant à <motif>"
+
 #, c-format
 msgid "not a reflog: %s"
 msgstr "'%s' n'est pas un journal de références"
@@ -19736,9 +19826,10 @@ msgstr[1] ""
 "Votre branche et '%s' ont divergé,\n"
 "et ont %d et %d commits différents chacune respectivement.\n"
 
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
 msgstr ""
-"  (utilisez \"git pull\" pour fusionner la branche distante dans la vôtre)\n"
+"  (utilisez \"git pull\" pour intégrer la branche distante avec la vôtre)\n"
 
 #, c-format
 msgid "cannot parse expected object name '%s'"
@@ -19851,6 +19942,10 @@ msgstr ""
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<fichier-paquet> n'est plus géré"
 
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "option invalide '%s' en mode --stdin"
+
 msgid "your current branch appears to be broken"
 msgstr "votre branche actuelle semble cassée"
 
@@ -21013,6 +21108,77 @@ msgstr "échec de la bifurcation"
 msgid "setsid failed"
 msgstr "échec du setsid"
 
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "impossible de faire un stat du modèle '%s'"
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "impossible d'ouvrir le répertoire '%s'"
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "impossible de lire le lien '%s'"
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "impossible de créer un lien symbolique de '%s' '%s'"
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "impossible de copier '%s' vers '%s'"
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "modèle %s ignoré"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "modèles non trouvés dans %s"
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "pas de copie des modèles depuis '%s' : %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "nom de branche initiale invalide : '%s'"
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "impossible de traiter le fichier de type %d"
+
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "impossible de déplacer %s vers %s"
+
+msgid "attempt to reinitialize repository with different hash"
+msgstr "essai de réinitialisation du dépôt avec une empreinte différente"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s existe déjà"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-initialisation : --initial-branch=%s ignoré"
+
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "Dépôt Git existant partagé réinitialisé dans %s%s\n"
+
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "Dépôt Git existant réinitialisé dans %s%s\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "Dépôt Git vide partagé initialisé dans %s%s\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "Dépôt Git vide initialisé dans %s%s\n"
+
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "l'entrée d'index est un répertoire, mais pas clairsemé (%08x)"
@@ -22870,6 +23036,29 @@ 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] : "
 
+#, c-format
+#~ msgid "It is not possible to %s because you have unmerged files."
+#~ msgstr "%s n'est pas possible car vous avez des fichiers non fusionnés."
+
+#~ msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
+#~ msgstr ""
+#~ "ne pas passer l'option --keep-cr à git-mailsplit indépendamment de am."
+#~ "keepcr"
+
+#~ msgid ""
+#~ "Updates were rejected because the tip of the remote-tracking\n"
+#~ "branch has been updated since the last checkout. You may want\n"
+#~ "to integrate those changes locally (e.g., 'git pull ...')\n"
+#~ "before forcing an update.\n"
+#~ msgstr ""
+#~ "Les mises à jour ont été rejetées, car la pointe de la branche\n"
+#~ "de suivi a été mise à jour depuis la dernière extraction. Intégrez\n"
+#~ "ces changements localement (par exemple 'git pull ...') avant de\n"
+#~ "forcer à nouveau une mise à jour.\n"
+
+#~ msgid "or do not fetch any tag at all (--no-tags)"
+#~ msgstr "ou ne rapatrier aucune étiquette (--no-tags)"
+
 #~ msgid "current working directory is untracked"
 #~ msgstr "l'arbre de travail actuel est non-suivi"
 
index ccd38422c752e45022d2fda60c4231f13f98d845..e20e18e8931d9a5e08ce353cdc14df8d7bd71355 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: 2023-05-19 19:57+0000\n"
-"PO-Revision-Date: 2023-05-22 15:24+0700\n"
+"POT-Creation-Date: 2023-08-06 17:06+0700\n"
+"PO-Revision-Date: 2023-08-06 17:06+0700\n"
 "Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n"
 "Language-Team: Indonesian\n"
 "Language: id\n"
@@ -941,6 +941,14 @@ msgstr "Opsi '%s' dan '%s' tidak dapat digunakan bersamaan"
 msgid "'%s' outside a repository"
 msgstr "'%s' di luar repositori"
 
+#: apply.c
+msgid "failed to read patch"
+msgstr "gagal membaca tambalan"
+
+#: apply.c
+msgid "patch too large"
+msgstr "tambalan terlalu besar"
+
 #: apply.c
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
@@ -2062,8 +2070,10 @@ msgstr "sebuah cabang bernama '%s' sudah ada"
 
 #: branch.c
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "tidak dapat memperbarui paksa cabang '%s' yang ter-check out pada '%s'"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr ""
+"tidak dapat memperbarui paksa cabang '%s' yang yang digunakan oleh pohon "
+"kerja pada '%s'"
 
 #: branch.c
 #, c-format
@@ -2145,20 +2155,6 @@ msgstr "git add [<opsi>] [--] <pathspec>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "tidak dapat chmod %cx '%s'"
 
-#: builtin/add.c
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "status diff tak diharapkan %c"
-
-#: builtin/add.c builtin/commit.c
-msgid "updating files failed"
-msgstr "gagal memperbarui berkas"
-
-#: builtin/add.c
-#, c-format
-msgid "remove '%s'\n"
-msgstr "hapus '%s'\n"
-
 #: builtin/add.c
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Perubahan tak tergelar setelah menyegarkan indeks:"
@@ -2704,11 +2700,6 @@ msgstr "lewatkan opsi -m ke git-mailinfo"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "lewatkan opsi --keep-cr ke git-mailsplit untuk format mbox"
 
-#: builtin/am.c
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"jangan lewatkan opsi --keep-cr ke git-mailsplit tak bergantung pada am.keepcr"
-
 #: builtin/am.c
 msgid "strip everything before a scissors line"
 msgstr "copot semuanya sebelum garis gunting"
@@ -4022,7 +4013,7 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
@@ -4086,6 +4077,10 @@ msgstr "seperti --batch, tapi jangan keluarkan <isi>"
 msgid "stdin is NUL-terminated"
 msgstr "stdin diakhiri dengan NUL"
 
+#: builtin/cat-file.c
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin dan stdout diakhiri dengan NUL"
+
 #: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "baca perintah dari masukan standar"
@@ -4624,8 +4619,8 @@ msgid ""
 "Consider \"git merge --quit\" or \"git worktree add\"."
 msgstr ""
 "tidak dapat mengganti cabang saat penggabungan\n"
-"Pertimbangkan untuk menggunakan \"git merge --quit\" atau \"git worktree add"
-"\"."
+"Pertimbangkan untuk menggunakan \"git merge --quit\" atau \"git worktree "
+"add\"."
 
 #: builtin/checkout.c
 msgid ""
@@ -4641,8 +4636,8 @@ msgid ""
 "Consider \"git rebase --quit\" or \"git worktree add\"."
 msgstr ""
 "tidak dapat mengganti cabang saat pendasaran ulang\n"
-"Pertimbangkan untuk menggunakan \"git rebase --quit\" atau \"git worktree add"
-"\"."
+"Pertimbangkan untuk menggunakan \"git rebase --quit\" atau \"git worktree "
+"add\"."
 
 #: builtin/checkout.c
 msgid ""
@@ -4659,8 +4654,8 @@ msgid ""
 "Consider \"git revert --quit\" or \"git worktree add\"."
 msgstr ""
 "tidak dapat mengganti cabang saat pembalikan\n"
-"Pertimbangkan untuk menggunakan \"git revert --quit\" atau \"git worktree add"
-"\"."
+"Pertimbangkan untuk menggunakan \"git revert --quit\" atau \"git worktree "
+"add\"."
 
 #: builtin/checkout.c
 msgid "you are switching branch while bisecting"
@@ -4999,7 +4994,8 @@ msgid "remove whole directories"
 msgstr "hapus keseluruhan direktori"
 
 #: builtin/clean.c builtin/describe.c builtin/grep.c builtin/log.c
-#: builtin/ls-files.c builtin/name-rev.c builtin/show-ref.c
+#: builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c builtin/show-ref.c
+#: ref-filter.h
 msgid "pattern"
 msgstr "pola"
 
@@ -5171,14 +5167,6 @@ msgstr "spesifik ke server"
 msgid "option to transmit"
 msgstr "opsi untuk transmisi"
 
-#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/push.c
-msgid "use IPv4 addresses only"
-msgstr "gunakan hanya alamat IPv4"
-
-#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/push.c
-msgid "use IPv6 addresses only"
-msgstr "gunakan hanya alamat IPv6"
-
 #: builtin/clone.c
 msgid "apply partial clone filters to submodules"
 msgstr "terapkan saringan kloning parsial ke submodul"
@@ -5726,6 +5714,10 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+#: builtin/commit.c read-cache.c
+msgid "updating files failed"
+msgstr "gagal memperbarui berkas"
+
 #: builtin/commit.c
 msgid "failed to unpack HEAD tree object"
 msgstr "gagal membuka objek pohon HEAD"
@@ -5803,8 +5795,8 @@ msgstr ""
 
 #: builtin/commit.c builtin/merge-tree.c
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "tidak dapat mencari komit %s"
+msgid "could not lookup commit '%s'"
+msgstr "tidak dapat mencari komit '%s'"
 
 #: builtin/commit.c builtin/shortlog.c
 #, c-format
@@ -8065,7 +8057,7 @@ msgstr "Gagal men-fstat %s: %s"
 msgid "failed to parse '%s' value '%s'"
 msgstr "gagal menguraikan nilai '%s' '%s'"
 
-#: builtin/gc.c builtin/init-db.c
+#: builtin/gc.c setup.c
 #, c-format
 msgid "cannot stat '%s'"
 msgstr "tidak dapat men-stat '%s'"
@@ -9089,7 +9081,7 @@ msgstr "tidak dapat kembali ke direktori kerja saat ini"
 msgid "bad %s"
 msgstr "%s jelek"
 
-#: builtin/index-pack.c builtin/init-db.c
+#: builtin/index-pack.c builtin/init-db.c setup.c
 #, c-format
 msgid "unknown hash algorithm '%s'"
 msgstr "algoritma hash tak dikenal '%s'"
@@ -9106,95 +9098,6 @@ msgstr "--verify tanpa nama berkas paket diberikan"
 msgid "fsck error in pack objects"
 msgstr "kesalahan fsck dalam objek paket"
 
-#: builtin/init-db.c
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "tidak dapat men-stat templat '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "tidak dapat membuka direktori '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "tidak dapat membaca tautan '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "tidak dapat menautkan simbolik '%s' '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "tidak dapat menyalin '%s' ke '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "ignoring template %s"
-msgstr "mengabaikan templat %s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "templates not found in %s"
-msgstr "templat tidak ditemukan di %s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "tidak menyalin templat dari '%s': %s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "nama cabang asal salah: '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "tidak dapat menangani tipe berkas %d"
-
-#: builtin/init-db.c
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "tidak dapat memindahkan %s ke %s"
-
-#: builtin/init-db.c
-msgid "attempt to reinitialize repository with different hash"
-msgstr "mencoba menginisialisasi ulang repositori dengan hash yang berbeda"
-
-#: builtin/init-db.c
-#, c-format
-msgid "%s already exists"
-msgstr "%s sudah ada"
-
-#: builtin/init-db.c
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: --initial-branch=%s diabaikan"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "Repositori berbagi Git yang sudah ada diinisialisasi ulang di %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "Repositori Git diinisialisasi ulang di %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "Repositori berbagi Git kosong diinisialisasi di %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "Repositori Git kosong dinisialisasi di %s%s\n"
-
 #: builtin/init-db.c
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
@@ -9755,6 +9658,11 @@ msgstr ""
 "Tidak dapat menemukan cabang remote terlacak, mohon sebutkan <hulu>\n"
 "secara manual.\n"
 
+#: builtin/ls-files.c builtin/ls-tree.c
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "tidak dapat mendapatkan info objek tentang '%s'"
+
 #: builtin/ls-files.c
 #, c-format
 msgid "bad ls-files format: element '%s' does not start with '('"
@@ -9942,11 +9850,6 @@ msgstr "perlihatkan referensi pokok selain objek yang ditunjuk olehnya"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<opsi>] <mirip-pohon> [<jalur>...]"
 
-#: builtin/ls-tree.c
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "tidak dapat mendapatkan info objek tentang '%s'"
-
 #: builtin/ls-tree.c
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
@@ -10884,11 +10787,13 @@ msgstr "git notes [--ref <referensi catan>] [list [<objek>]]"
 
 #: builtin/notes.c
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <referensi catatan>] add [-f] [--allow-empty] [-m <pesan | -"
-"F <berkas> | (-c | -C) <objek>] [<objek>]"
+"git notes [--ref <referensi catatan>] add [-f] [--allow-empty] [--"
+"[no-]separator|--separator=<pemisah paragraf>] [--[no-]stripspace] [-m "
+"<pesan | -F <berkas> | (-c | -C) <objek>] [<objek>]"
 
 #: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
@@ -10897,11 +10802,13 @@ msgstr ""
 
 #: builtin/notes.c
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <referensi catatan>] append [--alow-empty] [-m <pesan> | -F "
-"<berkas> | (-c | -C) <objek>] [<objek>]"
+"git notes [--ref <referensi catatan>] append [--alow-empty] [--"
+"[no]separator|--separator=<pemisah paragraf>] [--[no-]stripspace] [-m "
+"<pesan> | -F <berkas> | (-c | -C) <objek>] [<objek>]"
 
 #: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
@@ -11071,6 +10978,18 @@ msgstr "perbolehkan menyimpan catatan kosong"
 msgid "replace existing notes"
 msgstr "timpa catatan yang sudah ada"
 
+#: builtin/notes.c
+msgid "<paragraph-break>"
+msgstr "<pemisah paragraf>"
+
+#: builtin/notes.c
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "masukkan <pemisah paragraf> di antara paragraf"
+
+#: builtin/notes.c
+msgid "remove unnecessary whitespace"
+msgstr "hapus spasi yang tidak diperlukan"
+
 #: builtin/notes.c
 #, c-format
 msgid ""
@@ -11771,8 +11690,11 @@ msgid "refusing to run without --i-still-use-this"
 msgstr "menolak menjalankan tanpa --i-still-use-this"
 
 #: builtin/pack-refs.c
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <pola>] [--exclude <pola>]"
 
 #: builtin/pack-refs.c
 msgid "pack everything"
@@ -11782,6 +11704,14 @@ msgstr "pak semuanya"
 msgid "prune loose refs (default)"
 msgstr "pangkas referensi longgar (asali)"
 
+#: builtin/pack-refs.c
+msgid "references to include"
+msgstr "referensi untuk ditambahkan"
+
+#: builtin/pack-refs.c
+msgid "references to exclude"
+msgstr "referensi untuk dikecualikan"
+
 #: builtin/patch-id.c
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
@@ -11858,6 +11788,14 @@ msgstr "paksa timpa cabang lokal"
 msgid "number of submodules pulled in parallel"
 msgstr "nomor submodul ditarik dalam paralel"
 
+#: builtin/pull.c parse-options.h
+msgid "use IPv4 addresses only"
+msgstr "gunakan hanya alamat IPv4"
+
+#: builtin/pull.c parse-options.h
+msgid "use IPv6 addresses only"
+msgstr "gunakan hanya alamat IPv6"
+
 #: builtin/pull.c
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
@@ -12163,39 +12101,39 @@ msgstr ""
 #: builtin/push.c
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Pembaruan ditolak karena ujung dari cabang Anda saat ini di belakang\n"
-"pasangan remotenya. Integrasikan perubahan remote (seperti\n"
-"'git pull') sebelum dorong lagi.\n"
+"pasangan remotenya. Jika Anda ingin mengintegrasikan perubahan remote,\n"
+"lakukan 'git pull' sebelum mendorong lagi.\n"
 "Lihat 'Note about fast-forwards' di 'git push --help' untuk selengkapnya."
 
 #: builtin/push.c
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Pembaruan ditolak karena ujung dari cabang yang didorong di belakang\n"
-"pasangan remotenya. Check out cabang itu dan integrasikan perubahan\n"
-"remote (seperti 'git pull') sebelum dorong lagi.\n"
+"pasangan remotenya. Jika anda ingin mengintegrasikan perubahan\n"
+"remote, lakukan 'git pull' sebelum mendorong lagi.\n"
 "Lihat 'Note about fast-forwards' di 'git push --help' untuk selengkapnya."
 
 #: builtin/push.c
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Pembaruan ditolak karena remote berisi kerja yang Anda tidak punya\n"
+"Pembaruan ditolak karena remote berisi karya yang Anda tidak punya\n"
 "di lokal. Ini biasanya disebabkan repositori yang lain dorong ke\n"
-"referensi yang sama. Mungkin Anda ingin integrasikan terlebih dahulu\n"
-"perubahan remote (seperti 'git pull') sebelum dorong lagi.\n"
+"referensi yang sama. Jika Anda ingin mengintegrasikan perubahan remote\n"
+"lakukan 'git pull' sebelum mendorong lagi.\n"
 "Lihat 'Note about fast-forwards' di 'git push --help' untuk selengkapnya."
 
 #: builtin/push.c
@@ -12214,15 +12152,15 @@ msgstr ""
 
 #: builtin/push.c
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Pembaruan ditolak karena ujung dari cabang pelacak remote\n"
-"sudah diperbarui sejak checkout terakhir. Mungkin Anda ingin\n"
-"integrasikan perubahan tersebut ke lokal (seperti 'git pull...')\n"
-"sebelum memaksa pembaruan.\n"
+"Pembaruan ditolak karena ujung dari cabang Anda saat ini sudah diperbarui\n"
+"sejak checkout terakhir. Jika Anda ingin mengintegrasikan perubahan remote,\n"
+"lakukan 'git pull' sebelum mendorong lagi.\n"
+"Lihat 'Note about fast-forwards' di 'git push --help' untuk selengkapnya."
 
 #: builtin/push.c
 #, c-format
@@ -12614,8 +12552,8 @@ msgstr "opsi apply dan opsi merge tidak dapat digunakan bersamaan"
 #: builtin/rebase.c
 #, 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 ""
 "tipe kosong tak dikenali '%s'; nilai yang valid adalah \"drop\", \"keep\", "
 "dan \"ask\"."
@@ -13282,12 +13220,12 @@ msgid "fetch the remote branches"
 msgstr "ambil cabang remote"
 
 #: builtin/remote.c
-msgid "import all tags and associated objects when fetching"
-msgstr "impor semua tag dan objek yang terkait ketika mengambil"
-
-#: builtin/remote.c
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "atau jangan mengambil tag apapun (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"impor semua tag dan objek yang terkait ketika mengambil atau jangan\n"
+"mengambil tag apapun (--no-tags)"
 
 #: builtin/remote.c
 msgid "branch(es) to track"
@@ -15719,6 +15657,11 @@ msgstr "Melewati submodul tak tergabung %s"
 msgid "Skipping submodule '%s'"
 msgstr "Melewati submodul '%s'"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "tidak dapat mengkloning submodul '%s' tanpa URL"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
@@ -16651,10 +16594,10 @@ msgstr "cetak isi tag"
 #: builtin/worktree.c
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <untai>]]\n"
-"                 [-b <cabang baru>] <jalur> [<mirip komit>]"
+"                 [--orphan] [(-b | -B) <cabang baru>] <jalur> [<mirip komit>]"
 
 #: builtin/worktree.c
 msgid "git worktree list [-v | --porcelain [-z]]"
@@ -16684,6 +16627,38 @@ msgstr "git worktree repair [<jalur>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <worktree>"
 
+#: builtin/worktree.c
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Tidak ada cabang sumber yang mungkin, menyimpulkan '--orphan'"
+
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"Jika maksud Anda ingin membuat pohon kerja berisi sebuah cabang yatim baru\n"
+"(cabang tanpa komit) untuk repositori ini, Anda dapat melakukannya dengan\n"
+"opsi --orphan:\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"Jika maksud Anda ingin membuat pohon kerja berisi sebuah cabang yatim baru\n"
+"(cabang tanpa komit) untuk repositori ini, Anda dapat melakukannya dengan\n"
+"opsi --orphan:\n"
+"    git worktree add --orphan %s\n"
+
 #: builtin/worktree.c
 #, c-format
 msgid "Removing %s/%s: %s"
@@ -16767,11 +16742,42 @@ msgstr ""
 msgid "Preparing worktree (checking out '%s')"
 msgstr "Menyiapkan pohon kerja (men-checkout '%s')"
 
+#: builtin/worktree.c
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "tidak dapat dicapat: referensi tidak valid: %s"
+
 #: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "Menyiapkan pohon kerja (HEAD terpisah %s)"
 
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD menunjuk pada referensi tidak valid (atau yatim).\n"
+"Jalur HEAD: '%s'\n"
+"Isi HEAD: '%s'"
+
+#: builtin/worktree.c
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"Tidak ada referensi lokal atau remote yang ada meskipun salah satu remote\n"
+"ada, berhenti. Gunakan 'add -f' untuk menimpa atau mengambil remote "
+"terlebih\n"
+"dahulu"
+
+#: builtin/worktree.c
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "'%s' dan '%s' tidak dapat digunakan bersamaan"
+
 #: builtin/worktree.c
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
@@ -16785,6 +16791,10 @@ msgstr "buat sebuah cabang baru"
 msgid "create or reset a branch"
 msgstr "buat atau setel ulang sebuah cabang"
 
+#: builtin/worktree.c
+msgid "create unborn/orphaned branch"
+msgstr "buat cabang belum lahir/yatim"
+
 #: builtin/worktree.c
 msgid "populate the new working tree"
 msgstr "isikan pohon kerja baru"
@@ -16810,6 +16820,15 @@ msgstr "coba cocokkan nama cabang baru dengan sebuah cabang pelacakan remote"
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "Opsi '%s', '%s', dan '%s' tidak dapat digunakan bersamaan"
 
+#: builtin/worktree.c
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "Opsi '%s', dan '%s' tidak dapat digunakan bersamaan"
+
+#: builtin/worktree.c
+msgid "<commit-ish>"
+msgstr "<mirip-komit>"
+
 #: builtin/worktree.c
 msgid "added with --lock"
 msgstr "tambahkan dengan --lock"
@@ -17095,6 +17114,16 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "Bundel membutuhkan referensi ini:"
 msgstr[1] "Bundel membutuhkan %<PRIuMAX> referensi berikut:"
 
+#: bundle.c
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "Bundel menggunakan algoritma hash ini: %s"
+
+#: bundle.c
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Bundel menggunakan penyaring ini: %s"
+
 #: bundle.c
 msgid "unable to dup bundle descriptor"
 msgstr "tidak dapat men-dup pendeskripsi bundel"
@@ -17398,8 +17427,8 @@ msgid "A portable graphical interface to Git"
 msgstr "Sebuah antarmuka grafis Git portabel"
 
 #: command-list.h
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "Hitung ID objek dan buat blob dari berkas (opsional)"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "Hitung ID objek dan buat objeck dari berkas (opsional)"
 
 #: command-list.h
 msgid "Display help information about Git"
@@ -17941,6 +17970,11 @@ msgstr "grafik komit tidak punya bingkah grafik dasar"
 msgid "commit-graph chain does not match"
 msgstr "rantai grafik komit tidak cocok"
 
+#: commit-graph.c
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "jumlah komit pada grafik dasar terlalu tinggi: %<PRIuMAX>"
+
 #: commit-graph.c
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
@@ -18048,6 +18082,16 @@ msgstr "gagal menamai ulang berkas grafik komit dasar"
 msgid "failed to rename temporary commit-graph file"
 msgstr "gagal menamai ulang berkas grafik komit sementara"
 
+#: commit-graph.c
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "tidak dapat menggabungkan grafik dengan %<PRIuMAX>, %<PRIuMAX> komit"
+
+#: commit-graph.c
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "tidak dapat menggabungkan grafik %s, terlalu banyak komit: %<PRIuMAX>"
+
 #: commit-graph.c
 msgid "Scanning merged commits"
 msgstr "Memindai komit tergabung"
@@ -18083,10 +18127,6 @@ msgstr "grafik komit punya nilai kipas keluar salah: fanout[%d] = %u != %u"
 msgid "failed to parse commit %s from commit-graph"
 msgstr "gagal menguraikan komit %s dari grafik komit"
 
-#: commit-graph.c
-msgid "Verifying commits in commit graph"
-msgstr "Memverifikasi komit di dalam grafik komit"
-
 #: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
@@ -18140,6 +18180,10 @@ msgstr ""
 "tanggal komit untuk komit %s di dalam grafik komit yaitu %<PRIuMAX> != "
 "%<PRIuMAX>"
 
+#: commit-graph.c
+msgid "Verifying commits in commit graph"
+msgstr "Memverifikasi komit di dalam grafik komit"
+
 #: commit.c
 #, c-format
 msgid "%s %s is not a commit!"
@@ -19313,6 +19357,14 @@ msgstr "dasar penggabungan tidak ditemukan"
 msgid "multiple merge bases found"
 msgstr "banyak dasar penggabungan ditemukan"
 
+#: diff-no-index.c
+msgid "cannot compare stdin to a directory"
+msgstr "tidak dapat membandingkan masukan standar dan sebuah direktori"
+
+#: diff-no-index.c
+msgid "cannot compare a named pipe to a directory"
+msgstr "tidak dapat membandingkan pipa bernama dan sebuah direktori"
+
 #: diff-no-index.c
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<opsi>] <jalur> <jalur>"
@@ -19380,6 +19432,15 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "diff eksternal mati, berhenti pada %s"
 
+#: diff.c
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow butuh tepatnya satu spek jalur"
+
+#: diff.c
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "spek jalur ajaib tidak didukung oleh --follow: %s"
+
 #: diff.c parse-options.c
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
@@ -19399,10 +19460,6 @@ msgstr ""
 "opsi '%s' dan '%s' tidak dapat digunakan bersamaan, gunakan '%s' dengan '%s' "
 "dan '%s'"
 
-#: diff.c
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow butuh tepatnya satu spek jalur"
-
 #: diff.c
 #, c-format
 msgid "invalid --stat value: %s"
@@ -21468,8 +21525,8 @@ msgstr ""
 #: merge-recursive.c
 #, 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 ""
 "KONFLIK (penamaan ulang/penamaan ulang): Penamaan ulang \"%s\"->\"%s\" di "
 "dalam cabang \"%s\" penamaan ulang \"%s\"->\"%s\" di \"%s\"%s"
@@ -22947,6 +23004,15 @@ msgstr "gagal membuat diff"
 msgid "could not parse log for '%s'"
 msgstr "tidak dapat menguraikan log untuk '%s'"
 
+#: reachable.c
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "ujung sampah tambahan tidak valid: '%s'"
+
+#: reachable.c
+msgid "unable to enumerate additional recent objects"
+msgstr "tidak dapat menghitung objeck terkini tambahan"
+
 #: read-cache.c
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
@@ -23137,6 +23203,16 @@ msgstr "tidak dapat memperbaiki bit perizinan pada '%s'"
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: tidak dapat menurunkan ke tahap #0"
 
+#: read-cache.c
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "status diff tak diharapkan %c"
+
+#: read-cache.c
+#, c-format
+msgid "remove '%s'\n"
+msgstr "hapus '%s'\n"
+
 #: rebase-interactive.c
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
@@ -23358,6 +23434,26 @@ msgstr "argumen %%(trailers) tidak dikenal: %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "nilai positif diharapkan contents:lines=%s"
 
+#: ref-filter.c
+#, c-format
+msgid "argument expected for %s"
+msgstr "argumen diharapkan untuk %s"
+
+#: ref-filter.c
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "nilai positif %s=%s diharapkan"
+
+#: ref-filter.c
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "tidak dapat menguraikan penuh %s=%s"
+
+#: ref-filter.c
+#, c-format
+msgid "value expected %s="
+msgstr "nilai %s= diharapkan"
+
 #: ref-filter.c
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
@@ -23450,6 +23546,10 @@ msgstr "perintah ini menolak atom %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s tidak dapat digunakan dengan --python, --shell, --tcl"
 
+#: ref-filter.c
+msgid "failed to run 'describe'"
+msgstr "gagal menjalankan 'describe'"
+
 #: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing %s)"
@@ -23527,6 +23627,10 @@ msgstr "kunci"
 msgid "field name to sort on"
 msgstr "nama bidang untuk diurutkan"
 
+#: ref-filter.h
+msgid "exclude refs which match pattern"
+msgstr "hanya gunakan referensi yang cocok dengan pola"
+
 #: reflog.c
 #, c-format
 msgid "not a reflog: %s"
@@ -24067,8 +24171,11 @@ msgstr[1] ""
 "dan masing-masing punya %d dan %d komit berbeda.\n"
 
 #: remote.c
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (gunakan \"git pull\" untuk gabungkan cabang remote ke milik Anda)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr ""
+"  (gunakan \"git pull\" jika Anda ingin mengintegrasikan cabang remote pada\n"
+"   milik Anda)\n"
 
 #: remote.c
 #, c-format
@@ -24210,6 +24317,11 @@ msgstr "tidak dapat mendapatkan komit untuk argumen jalur leluhur '%s'"
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<berkas pak> tidak didukung lagi"
 
+#: revision.c
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "opsi tidak valid: '%s' di mode --stdin"
+
 #: revision.c
 msgid "your current branch appears to be broken"
 msgstr "sepertinya cabang Anda saat ini rusak"
@@ -25618,6 +25730,95 @@ msgstr "penggarpuan gagal"
 msgid "setsid failed"
 msgstr "setsid gagal"
 
+#: setup.c
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "tidak dapat men-stat templat '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "tidak dapat membuka direktori '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "tidak dapat membaca tautan '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "tidak dapat menautkan simbolik '%s' '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "tidak dapat menyalin '%s' ke '%s'"
+
+#: setup.c
+#, c-format
+msgid "ignoring template %s"
+msgstr "mengabaikan templat %s"
+
+#: setup.c
+#, c-format
+msgid "templates not found in %s"
+msgstr "templat tidak ditemukan di %s"
+
+#: setup.c
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "tidak menyalin templat dari '%s': %s"
+
+#: setup.c
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "nama cabang asal salah: '%s'"
+
+#: setup.c
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "tidak dapat menangani tipe berkas %d"
+
+#: setup.c
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "tidak dapat memindahkan %s ke %s"
+
+#: setup.c
+msgid "attempt to reinitialize repository with different hash"
+msgstr "mencoba menginisialisasi ulang repositori dengan hash yang berbeda"
+
+#: setup.c
+#, c-format
+msgid "%s already exists"
+msgstr "%s sudah ada"
+
+#: setup.c
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: --initial-branch=%s diabaikan"
+
+#: setup.c
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "Repositori berbagi Git yang sudah ada diinisialisasi ulang di %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "Repositori Git diinisialisasi ulang di %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "Repositori berbagi Git kosong diinisialisasi di %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "Repositori Git kosong dinisialisasi di %s%s\n"
+
 #: sparse-index.c
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
@@ -27845,3 +28046,22 @@ msgstr "Melewati %s dengan akhiran cadangan '%s'.\n"
 #, perl-format
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "Anda benar-benar ingin mengirim %s? [y|N]: "
+
+#~ msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
+#~ msgstr ""
+#~ "jangan lewatkan opsi --keep-cr ke git-mailsplit tak bergantung pada am."
+#~ "keepcr"
+
+#~ msgid ""
+#~ "Updates were rejected because the tip of the remote-tracking\n"
+#~ "branch has been updated since the last checkout. You may want\n"
+#~ "to integrate those changes locally (e.g., 'git pull ...')\n"
+#~ "before forcing an update.\n"
+#~ msgstr ""
+#~ "Pembaruan ditolak karena ujung dari cabang pelacak remote\n"
+#~ "sudah diperbarui sejak checkout terakhir. Mungkin Anda ingin\n"
+#~ "integrasikan perubahan tersebut ke lokal (seperti 'git pull...')\n"
+#~ "sebelum memaksa pembaruan.\n"
+
+#~ msgid "or do not fetch any tag at all (--no-tags)"
+#~ msgstr "atau jangan mengambil tag apapun (--no-tags)"
index 803208c4d52d855f36dc9fe493dc95a6c75390e9..3e56eb546eadf320c95d9a358c337ae22beb421f 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -4,28 +4,28 @@
 #
 # Translators:
 # Alexander Golubev <fatzer2@gmail.com>, 2020
-# Dimitriy Ryazantcev <DJm00n@mail.ru>, 2014-2022
+# Dimitriy Ryazantcev <DJm00n@mail.ru>, 2014-2023
 # insolor, 2014
 # insolor, 2014
 # Sergey Alyoshin <alyoshin.s@gmail.com>, 2020-2021
 # Sergey Kuznetsov <votkinsk@gmail.com>, 2021-2022
-# Чук Таблицоменделеев <aurum444an@gmail.com>, 2019
+# Чук Таблицоменделеев (Aurum79) <aurum444an@gmail.com>, 2019
 msgid ""
 msgstr ""
 "Project-Id-Version: Git Russian Localization Project\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-06-26 20:30+0800\n"
+"POT-Creation-Date: 2023-06-30 12:55+0300\n"
 "PO-Revision-Date: 2014-02-18 23:30+0000\n"
-"Last-Translator: Dimitriy Ryazantcev <DJm00n@mail.ru>, 2014-2022\n"
-"Language-Team: Russian (http://www.transifex.com/djm00n/git-po-ru/language/"
+"Last-Translator: Dimitriy Ryazantcev <DJm00n@mail.ru>, 2014-2023\n"
+"Language-Team: Russian (http://app.transifex.com/djm00n/git-po-ru/language/"
 "ru/)\n"
-"Language: ru\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
-"%100>=11 && n%100<=14)? 2 : 3);\n"
+"Language: ru\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
+"(n%100>=11 && n%100<=14)? 2 : 3);\n"
 
 #, c-format
 msgid "Huh (%s)?"
@@ -53,7 +53,7 @@ msgstr " не удалось проиндексировать «%s»"
 msgid "could not write index"
 msgstr "не удалось записать индекс"
 
-#, c-format, perl-format
+#, c-format
 msgid "updated %d path\n"
 msgid_plural "updated %d paths\n"
 msgstr[0] "обновлён %d путь\n"
@@ -61,7 +61,7 @@ msgstr[1] "обновлено %d пути\n"
 msgstr[2] "обновлено %d путей\n"
 msgstr[3] "обновлено %d пути\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "note: %s is untracked now.\n"
 msgstr "примечание: %s теперь неотслеживаемый.\n"
 
@@ -75,7 +75,7 @@ msgstr "Обратить изменения"
 msgid "Could not parse HEAD^{tree}"
 msgstr "Не удалось разобрать HEAD^{tree}"
 
-#, c-format, perl-format
+#, c-format
 msgid "reverted %d path\n"
 msgid_plural "reverted %d paths\n"
 msgstr[0] "обращены изменения %d пути\n"
@@ -90,7 +90,7 @@ msgstr "Нет неотслеживаемых файлов.\n"
 msgid "Add untracked"
 msgstr "Добавить неотслеживаемый"
 
-#, c-format, perl-format
+#, c-format
 msgid "added %d path\n"
 msgid_plural "added %d paths\n"
 msgstr[0] "добавлен %d путь\n"
@@ -188,19 +188,19 @@ msgstr "не удалось обновить индекс"
 msgid "Bye.\n"
 msgstr "До свидания.\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
 msgstr "Проиндексировать изменение режима доступа [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
 msgstr "Проиндексировать удаление [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage addition [y,n,q,a,d%s,?]? "
 msgstr "Добавить к индексу [y,n,q,a,d%s,?]?"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Индексировать этот блок [y,n,q,a,d%s,?]? "
 
@@ -224,19 +224,19 @@ msgstr ""
 "a - индексировать этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
 msgstr "Спрятать изменение режима доступа [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
 msgstr "Спрятать удаление файла [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash addition [y,n,q,a,d%s,?]? "
 msgstr "Добавить к спрятанному [y,n,q,a,d%s,?]?"
 
-#, c-format, perl-format
+#, c-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
 msgstr "Спрятать этот блок [y,n,q,a,d%s,?]? "
 
@@ -259,19 +259,19 @@ msgstr ""
 "a - спрятать этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
 msgstr "Убрать изменения режима доступа из индекса [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
 msgstr "Убрать удаление из индекса [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
 msgstr "Убрать из индекса [y,n,q,a,d%s,?]?"
 
-#, c-format, perl-format
+#, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
 msgstr "Убрать из индекса этот блок [y,n,q,a,d%s,?]? "
 
@@ -289,25 +289,25 @@ msgid ""
 "a - unstage this hunk and all later hunks in the file\n"
 "d - do not unstage this hunk or any of the later hunks in the file\n"
 msgstr ""
-"y - убрать из индекса этот блок\n"
+"y - убрать этот блок из индекса\n"
 "n - пропустить этот блок\n"
 "q - выход; пропустить этот и все последующие блоки\n"
 "a - убрать из индекса этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
 msgstr "Применить изменение режима доступа к индексу [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
 msgstr "Применить удаление к индексу [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index [y,n,q,a,d%s,?]? "
 msgstr "Применить добавление к индексу [y,n,q,a,d%s,?]?"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
 msgstr "Принять этот блок в индекс [y,n,q,a,d%s,?]? "
 
@@ -331,21 +331,21 @@ msgstr ""
 "a - принять этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
 msgstr "Отменить изменения режима доступа в рабочем каталоге [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
 msgstr "Отменить удаление в рабочем каталоге [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
 msgstr "Отменить добавления из рабочего каталога [y,n,q,a,d%s,?]?"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
-msgstr "Ð\9eÑ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ñ\80абоÑ\87его Ð´ÐµÑ\80ева [y,n,q,a,d%s,?]?"
+msgstr "Ð\9eÑ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ñ\80абоÑ\87его ÐºÐ°Ñ\82алога [y,n,q,a,d%s,?]?"
 
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
@@ -360,29 +360,29 @@ msgid ""
 "a - discard this hunk and all later hunks in the file\n"
 "d - do not discard this hunk or any of the later hunks in the file\n"
 msgstr ""
-"y - Ð¾Ñ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ñ\80абоÑ\87его Ð´ÐµÑ\80ева\n"
+"y - Ð¾Ñ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ñ\80абоÑ\87его ÐºÐ°Ñ\82алога\n"
 "n - пропустить этот блок\n"
 "q - выход; пропустить этот и все последующие блоки\n"
 "a - отбросить этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
-"Отменить изменения режима доступа в индексе и рабочем каталоге [y,n,q,a,d"
-"%s,?]? "
+"Отменить изменения режима доступа в индексе и рабочем каталоге [y,n,q,a,"
+"d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Отменить удаление в индексе и рабочем каталоге [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Отменить добавление в индекс и рабочий каталог [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Ð\9eÑ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ð¸Ð½Ð´ÐµÐºÑ\81а Ñ\80абоÑ\87его Ð´ÐµÑ\80ева [y,n,q,a,d%s,?]? "
+msgstr "Ð\9eÑ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ð¸Ð½Ð´ÐµÐºÑ\81а Ñ\80абоÑ\87его ÐºÐ°Ñ\82алога [y,n,q,a,d%s,?]? "
 
 msgid ""
 "y - discard this hunk from index and worktree\n"
@@ -391,27 +391,27 @@ msgid ""
 "a - discard this hunk and all later hunks in the file\n"
 "d - do not discard this hunk or any of the later hunks in the file\n"
 msgstr ""
-"y - Ð¾Ñ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ñ\80абоÑ\87его Ð´ÐµÑ\80ева\n"
+"y - Ð¾Ñ\82бÑ\80оÑ\81иÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð¸Ð· Ñ\80абоÑ\87его ÐºÐ°Ñ\82алога\n"
 "n - пропустить этот блок\n"
 "q - выход; пропустить этот и все последующие блоки\n"
 "a - отбросить этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
 msgstr ""
-"Применить изменения режима доступа к индексу и рабочему каталогу [y,n,q,a,d"
-"%s,?]? "
+"Применить изменения режима доступа к индексу и рабочему каталогу [y,n,q,a,"
+"d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Применить удаление к индексу и рабочему каталогу [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Применить добавление к индексу и рабочему каталогу [y,n,q,a,d%s,?]? "
 
-#, c-format, perl-format
+#, c-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
 msgstr "Принять этот блок в индекс и рабочий каталог [y,n,q,a,d%s,?]? "
 
@@ -422,12 +422,28 @@ msgid ""
 "a - apply this hunk and all later hunks in the file\n"
 "d - do not apply this hunk or any of the later hunks in the file\n"
 msgstr ""
-"y - Ð¿Ñ\80инÑ\8fÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð² Ð¸Ð½Ð´ÐµÐºÑ\81 Ð¸ Ñ\80абоÑ\87ее Ð´ÐµÑ\80ево\n"
+"y - Ð¿Ñ\80инÑ\8fÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð² Ð¸Ð½Ð´ÐµÐºÑ\81 Ð¸ Ñ\80абоÑ\87ий ÐºÐ°Ñ\82алог\n"
 "n - пропустить этот блок\n"
 "q - выход; пропустить этот и все последующие блоки\n"
 "a - принять этот и остальные блоки файла\n"
 "d - пропустить этот и остальные блоки файла\n"
 
+#, c-format
+msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+
+#, c-format
+msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+
+#, c-format
+msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
+msgstr ""
+
+#, c-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"
@@ -435,7 +451,7 @@ msgid ""
 "a - apply this hunk and all later hunks in the file\n"
 "d - do not apply this hunk or any of the later hunks in the file\n"
 msgstr ""
-"y - Ð¿Ñ\80инÑ\8fÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð² Ñ\80абоÑ\87ее Ð´ÐµÑ\80ево\n"
+"y - Ð¿Ñ\80инÑ\8fÑ\82Ñ\8c Ñ\8dÑ\82оÑ\82 Ð±Ð»Ð¾Ðº Ð² Ñ\80абоÑ\87ий ÐºÐ°Ñ\82алог\n"
 "n - пропустить этот блок\n"
 "q - выход; пропустить этот и все последующие блоки\n"
 "a - принять этот и остальные блоки файла\n"
@@ -445,10 +461,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 "не удалось разобрать список изменений (diff)"
 
@@ -457,15 +469,18 @@ msgstr "не удалось разобрать цветной список из
 
 #, c-format
 msgid "failed to run '%s'"
-msgstr ""
+msgstr "не удалось запустить «%s»"
 
 msgid "mismatched output from interactive.diffFilter"
-msgstr ""
+msgstr "несовпадение вывода из interactive.diffFilter"
 
 msgid ""
 "Your filter must maintain a one-to-one correspondence\n"
 "between its input and output lines."
 msgstr ""
+"Ваш фильтр должен поддерживать соответствие\n"
+"один-к-одному между его входными и выходными\n"
+"строками."
 
 #, c-format
 msgid ""
@@ -504,8 +519,6 @@ msgstr ""
 "Чтобы убрать «%c»-строки, удалите их.\n"
 "Строки, начинающиеся с %cбудут удалены.\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"
 "edit again.  If all lines of the hunk are removed, then the edit is\n"
@@ -517,25 +530,16 @@ msgstr ""
 "и блок останется без изменений.\n"
 
 msgid "could not parse hunk header"
-msgstr ""
+msgstr "не удалось разобрать заголовок блока изменений"
 
 msgid "'git apply --cached' failed"
-msgstr ""
+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.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
 msgid ""
 "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
 msgstr ""
@@ -543,7 +547,7 @@ msgstr ""
 "«нет»!) [y/n]? "
 
 msgid "The selected hunks do not apply to the index!"
-msgstr ""
+msgstr "Выбранные блоки не применяются без ошибок к индексу!"
 
 msgid "Apply them to the worktree anyway? "
 msgstr "Все равно применить их к рабочему каталогу? "
@@ -562,15 +566,24 @@ msgid ""
 "e - manually edit the current hunk\n"
 "? - print help\n"
 msgstr ""
+"j - не принимать решение по этому блоку, перейти на следующий нерешенный\n"
+"J - не принимать решение по этому блоку, перейти на следующий\n"
+"k - не принимать решение по этому блоку, перейти на предыдущий нерешенный\n"
+"K - не принимать решение по этому блоку, перейти на предыдущий\n"
+"g - выбрать блок изменений на который нужно перейти\n"
+"/ - поиск блока изменений с помощью регулярного выражения\n"
+"s - разделить текущий блок на блоки меньшего размера\n"
+"e - вручную отредактировать текущий блок\n"
+"? - вывести справку\n"
 
 msgid "No previous hunk"
-msgstr ""
+msgstr "Нет предыдущего блока"
 
 msgid "No next hunk"
-msgstr ""
+msgstr "Не следующего блока"
 
 msgid "No other hunks to goto"
-msgstr ""
+msgstr "Нет других блоков для перехода"
 
 msgid "go to which hunk (<ret> to see more)? "
 msgstr "на какой блок перейти (нажмите <ввод> чтобы увидеть еще)? "
@@ -580,41 +593,41 @@ msgstr "на какой блок перейти? "
 
 #, c-format
 msgid "Invalid number: '%s'"
-msgstr ""
+msgstr "Недопустимый номер: «%s»"
 
 #, c-format
 msgid "Sorry, only %d hunk available."
 msgid_plural "Sorry, only %d hunks available."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Простите, но только %d блок изменений доступнен."
+msgstr[1] "Простите, но только %d блока изменений доступно."
+msgstr[2] "Простите, но только %d блоков изменений доступно."
+msgstr[3] "Простите, но только %d блока изменений доступно."
 
 msgid "No other hunks to search"
-msgstr ""
+msgstr "Нет других блоков для поиска"
 
 msgid "search for regex? "
 msgstr "искать с помощью регулярного выражения? "
 
 #, c-format
 msgid "Malformed search regexp %s: %s"
-msgstr ""
+msgstr "Регулярное выражение для поиска в неправильном формате %s: %s"
 
 msgid "No hunk matches the given pattern"
-msgstr ""
+msgstr "Не найдены блоки, которые соответствуют указанному шаблону"
 
 msgid "Sorry, cannot split this hunk"
 msgstr ""
 
 #, c-format
 msgid "Split into %d hunks."
-msgstr ""
+msgstr "Разбито на %d блока изменений."
 
 msgid "Sorry, cannot edit this hunk"
 msgstr ""
 
 msgid "'git apply' failed"
-msgstr ""
+msgstr "сбой при выполнении «git apply»"
 
 #, c-format
 msgid ""
@@ -666,6 +679,16 @@ msgstr "Перед слиянием, выполните коммит ваших
 msgid "Exiting because of unfinished merge."
 msgstr "Выход из-за незавершенного слияния."
 
+msgid ""
+"Diverging branches can't be fast-forwarded, you need to either:\n"
+"\n"
+"\tgit merge --no-ff\n"
+"\n"
+"or:\n"
+"\n"
+"\tgit rebase\n"
+msgstr ""
+
 msgid "Not possible to fast-forward, aborting."
 msgstr "Быстрая перемотка невозможна, отменяем."
 
@@ -724,19 +747,35 @@ msgstr ""
 "advice.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 ""
+
+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 ""
+
 msgid "cmdline ends with \\"
 msgstr "командная строка заканчивается символом \\"
 
 msgid "unclosed quote"
 msgstr "пропущена закрывающая кавычка"
 
+msgid "too many arguments"
+msgstr ""
+
 #, c-format
 msgid "unrecognized whitespace option '%s'"
-msgstr "неопознанная опция для пробелов «%s»"
+msgstr "неопознанный параметр для пробелов «%s»"
 
 #, c-format
 msgid "unrecognized whitespace ignore option '%s'"
-msgstr "неопознанная опция для игнорирования пробелов «%s»"
+msgstr "неопознанный параметр для игнорирования пробелов «%s»"
 
 #, c-format
 msgid "options '%s' and '%s' cannot be used together"
@@ -1100,6 +1139,10 @@ msgstr "усечение имени .rej файла до %.*s.rej"
 msgid "cannot open %s"
 msgstr "не удалось открыть %s"
 
+#, c-format
+msgid "cannot unlink '%s'"
+msgstr ""
+
 #, c-format
 msgid "Hunk #%d applied cleanly."
 msgstr "Блок №%d применен без ошибок."
@@ -1255,6 +1298,10 @@ msgstr "не удалось создать поток двоичного объ
 msgid "unsupported file mode: 0%o (SHA1: %s)"
 msgstr "неподдерживаемый режим доступа к файлу: 0%o (SHA1: %s)"
 
+#, c-format
+msgid "deflate error (%d)"
+msgstr "ошибка сжатия (%d)"
+
 #, c-format
 msgid "unable to start '%s' filter"
 msgstr "не удалось запустить фильтр «%s»"
@@ -1274,10 +1321,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 "ошибка сжатия (%d)"
-
 #, c-format
 msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "отметка времени слишком большая для этой системы: %<PRIuMAX>"
@@ -1297,6 +1340,10 @@ msgstr "git archive --remote <репозиторий> [--exec <команда>]
 msgid "cannot read '%s'"
 msgstr "не удалось прочитать «%s»"
 
+#, c-format
+msgid "pathspec '%s' matches files outside the current directory"
+msgstr ""
+
 #, c-format
 msgid "pathspec '%s' did not match any files"
 msgstr "спецификатор пути «%s» не соответствует ни одному файлу"
@@ -1313,9 +1360,6 @@ msgstr "недопустимое имя объекта: %s"
 msgid "not a tree object: %s"
 msgstr "недействительный объект дерева: %s"
 
-msgid "current working directory is untracked"
-msgstr "текущий рабочий каталог не отслеживается"
-
 #, c-format
 msgid "File not found: %s"
 msgstr ""
@@ -1366,6 +1410,12 @@ msgstr "читать .gitattributes в рабочем каталоге"
 msgid "report archived files on stderr"
 msgstr "отчет об архивированных файлах в stderr"
 
+msgid "time"
+msgstr "время"
+
+msgid "set modification time of archive entries"
+msgstr ""
+
 msgid "set compression level"
 msgstr ""
 
@@ -1406,6 +1456,13 @@ msgstr "Аргумент не поддерживается для формата
 msgid "%.*s is not a valid attribute name"
 msgstr "%.*s не является допустимым именем атрибута"
 
+msgid "unable to add additional attribute"
+msgstr ""
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr ""
+
 #, c-format
 msgid "%s not allowed: %s:%d"
 msgstr "%s не разрешено: %s:%d"
@@ -1418,6 +1475,21 @@ msgstr ""
 "Используйте «\\!» для буквального использования символа в значении "
 "«восклицательный знак»."
 
+#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr ""
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr ""
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr ""
+
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr ""
+
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Плохое содержимое файла «%s»: %s"
@@ -1514,7 +1586,6 @@ msgstr[3] "(примерно %d шагов)"
 
 #. TRANSLATORS: the last %s will be replaced with "(roughly %d
 #. steps)" translation.
-#.
 #, c-format
 msgid "Bisecting: %d revision left to test after this %s\n"
 msgid_plural "Bisecting: %d revisions left to test after this %s\n"
@@ -1526,9 +1597,6 @@ msgstr[3] "Бинарный поиск: %d редакций осталось п
 msgid "--contents and --reverse do not blend well."
 msgstr "--contents и --reverse не очень сочетаются."
 
-msgid "cannot use --contents with final commit object name"
-msgstr "нельзя использовать --contents с указанием финального имени объекта"
-
 msgid "--reverse and --first-parent together require specified latest commit"
 msgstr ""
 "при --reverse и --first-parent вместе нужно указывать конкретный последний "
@@ -1597,20 +1665,17 @@ msgstr ""
 #. 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.
-#.
 #, c-format
 msgid "  %s\n"
 msgstr ""
 
 #. TRANSLATORS: The second argument is a \n-delimited list of
 #. duplicate refspecs, composed above.
-#.
 #, c-format
 msgid ""
 "There are multiple remotes whose fetch refspecs map to the remote\n"
@@ -1680,8 +1745,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
 msgstr ""
 
 #, c-format
@@ -1692,10 +1757,6 @@ msgstr ""
 msgid "'%s' is already checked out at '%s'"
 msgstr "«%s» уже находится на «%s»"
 
-#, c-format
-msgid "HEAD of working tree %s is not updated"
-msgstr "HEAD рабочего каталога %s не обновлён"
-
 msgid "git add [<options>] [--] <pathspec>..."
 msgstr "git add [<опции>] [--] <спецификатор-пути>..."
 
@@ -1717,6 +1778,11 @@ msgstr "удалить «%s»\n"
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Непроиндексированные изменения после обновления индекса:"
 
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+
 msgid "Could not read the index"
 msgstr "Не удалось прочитать индекс"
 
@@ -2006,7 +2072,6 @@ msgstr "Тело коммита:"
 #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
 #. in your translation. The program will only accept English
 #. input at this point.
-#.
 #, c-format
 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "
 msgstr ""
@@ -2103,6 +2168,9 @@ msgstr "git am [<опции>] (--continue | --skip | --abort)"
 msgid "run interactively"
 msgstr "запустить в интерактивном режиме"
 
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr ""
+
 msgid "historical option -- no-op"
 msgstr "историческая опция — ничего не делает"
 
@@ -2245,31 +2313,24 @@ msgstr "git archive: ошибка протокола"
 msgid "git archive: expected a flush"
 msgstr "git archive: ожидался сброс буфера"
 
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr ""
-
 msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--]    [<pathspec>...]"
 msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<термин> --term-{old,"
-"good}=<термин>] [--no-checkout] [--first-parent] [<плохая-редация> [<хорошая-"
-"редация>...]] [--] [<пути>...]"
 
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
+msgid "git bisect (good|bad) [<rev>...]"
 msgstr ""
 
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
 msgstr ""
 
-msgid "git bisect--helper --bisect-replay <filename>"
+msgid "git bisect reset [<commit>]"
 msgstr ""
 
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
+msgid "git bisect replay <logfile>"
 msgstr ""
 
-msgid "git bisect--helper --bisect-run <cmd>..."
+msgid "git bisect run <cmd>..."
 msgstr ""
 
 #, c-format
@@ -2348,7 +2409,6 @@ msgstr ""
 #. TRANSLATORS: Make sure to include [Y] and [n] in your
 #. translation. The program will only accept English input
 #. at this point.
-#.
 msgid "Are you sure [Y/n]? "
 msgstr "Вы уверены [Y - да/n - нет]? "
 
@@ -2406,9 +2466,6 @@ msgstr ""
 msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'."
 msgstr ""
 
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "нельзя выполнить двоичный поиск на дереве после cg-seek"
-
 msgid "bad HEAD - strange symbolic ref"
 msgstr ""
 
@@ -2422,7 +2479,6 @@ msgstr ""
 #. TRANSLATORS: Make sure to include [Y] and [n] in your
 #. translation. The program will only accept English input
 #. at this point.
-#.
 msgid "Do you want me to do it for you [Y/n]? "
 msgstr "Вы уверены, что хотите, чтобы я сделал это [Y] - да/[n] - нет? "
 
@@ -2460,7 +2516,7 @@ msgid "bisect run failed: no command provided."
 msgstr "сбой при выполнении двоичного поиска: не передана команда."
 
 #, c-format
-msgid "unable to verify '%s' on good revision"
+msgid "unable to verify %s on good revision"
 msgstr ""
 
 #, c-format
@@ -2468,7 +2524,7 @@ msgid "bogus exit code %d for good revision"
 msgstr ""
 
 #, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
 msgstr ""
 
 #, c-format
@@ -2478,74 +2534,48 @@ msgstr ""
 msgid "bisect run cannot continue any more"
 msgstr "bisect run больше не может продолжать"
 
-#, c-format
 msgid "bisect run success"
 msgstr "bisect run выполнен успешно"
 
-#, c-format
 msgid "bisect found first bad commit"
 msgstr ""
 
 #, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-
-msgid "reset the bisection state"
-msgstr ""
-
-msgid "check whether bad or good terms exist"
-msgstr ""
-
-msgid "print out the bisect terms"
-msgstr ""
-
-msgid "start the bisect session"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
 msgstr ""
 
-msgid "find the next bisection commit"
-msgstr ""
-
-msgid "mark the state of ref (or refs)"
-msgstr ""
-
-msgid "list the bisection steps so far"
-msgstr ""
-
-msgid "replay the bisection process from the given file"
-msgstr ""
-
-msgid "skip some commits for checkout"
-msgstr ""
-
-msgid "visualize the bisection"
-msgstr ""
-
-msgid "use <cmd>... to automatically bisect"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
 msgstr ""
 
-msgid "no log for BISECT_WRITE"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
 msgstr ""
 
-msgid "--bisect-reset requires either no argument or a commit"
+#, c-format
+msgid "'%s' requires 0 arguments"
 msgstr ""
 
-msgid "--bisect-terms requires 0 or 1 argument"
+msgid "no logfile given"
 msgstr ""
 
-msgid "--bisect-next requires 0 arguments"
+#, c-format
+msgid "'%s' failed: no command provided."
 msgstr ""
 
-msgid "--bisect-log requires 0 arguments"
+msgid "need a command"
 msgstr ""
 
-msgid "no logfile given"
+#, c-format
+msgid "unknown command: '%s'"
 msgstr ""
 
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<опции>] [<опции-редакции>] [<редакция>] [--] <файл>"
 
+msgid "git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>"
+msgstr ""
+
 msgid "<rev-opts> are documented in git-rev-list(1)"
 msgstr "<опции-rev-list> документированы в git-rev-list(1)"
 
@@ -2659,7 +2689,6 @@ msgstr ""
 #. among various forms of relative timestamps, but
 #. your language may need more or fewer display
 #. columns.
-#.
 msgid "4 years, 11 months ago"
 msgstr "4 года и 11 месяцев назад"
 
@@ -2734,9 +2763,6 @@ msgstr "Не удалось обновить файл конфигурации"
 msgid "cannot use -a with -d"
 msgstr "нельзя использовать одновременно ключи -a и -d"
 
-msgid "Couldn't look up commit object for HEAD"
-msgstr "Не удалось найти объект коммита для HEAD"
-
 #, c-format
 msgid "Cannot delete branch '%s' checked out at '%s'"
 msgstr "Нельзя удалить ветку «%s» т.к. она активна на «%s»"
@@ -2745,6 +2771,12 @@ msgstr "Нельзя удалить ветку «%s» т.к. она активн
 msgid "remote-tracking branch '%s' not found."
 msgstr "внешняя отслеживаемая ветка «%s» не найдена."
 
+#, c-format
+msgid ""
+"branch '%s' not found.\n"
+"Did you forget --remote?"
+msgstr ""
+
 #, c-format
 msgid "branch '%s' not found."
 msgstr "ветка «%s» не найдена."
@@ -2775,20 +2807,22 @@ msgstr "Производится перемещение ветки %s на %s"
 msgid "Branch %s is being bisected at %s"
 msgstr "Производится двоичный поиск в ветке %s на %s"
 
-msgid "cannot copy the current branch while not on any."
-msgstr ""
-"невозможно скопировать текущую ветку, если вы не находитесь ни на одной из "
-"веток."
-
-msgid "cannot rename the current branch while not on any."
-msgstr ""
-"невозможно переименовать текущую ветку, если вы не находитесь ни на одной из "
-"них."
+#, c-format
+msgid "HEAD of working tree %s is not updated"
+msgstr "HEAD рабочего каталога %s не обновлён"
 
 #, c-format
 msgid "Invalid branch name: '%s'"
 msgstr "Недействительное имя ветки: «%s»"
 
+#, c-format
+msgid "No commit on branch '%s' yet."
+msgstr "Еще нет коммита на ветке «%s»."
+
+#, c-format
+msgid "No branch named '%s'."
+msgstr "Нет ветки с именем «%s»."
+
 msgid "Branch rename failed"
 msgstr "Сбой переименования ветки"
 
@@ -2877,6 +2911,9 @@ msgstr "переместить/переименовать ветки и ее ж
 msgid "move/rename a branch, even if target exists"
 msgstr "переместить/переименовать ветку, даже если целевое имя уже существует"
 
+msgid "do not output a newline after empty formatted refs"
+msgstr ""
+
 msgid "copy a branch and its reflog"
 msgstr "скопировать ветку и её журнал ссылок"
 
@@ -2945,13 +2982,15 @@ msgstr "Нельзя дать описание отсоединённому ук
 msgid "cannot edit description of more than one branch"
 msgstr "нельзя изменить описание более одной ветки за раз"
 
-#, c-format
-msgid "No commit on branch '%s' yet."
-msgstr "Еще нет коммита на ветке «%s»."
+msgid "cannot copy the current branch while not on any."
+msgstr ""
+"невозможно скопировать текущую ветку, если вы не находитесь ни на одной из "
+"веток."
 
-#, c-format
-msgid "No branch named '%s'."
-msgstr "Нет ветки с именем «%s»."
+msgid "cannot rename the current branch while not on any."
+msgstr ""
+"невозможно переименовать текущую ветку, если вы не находитесь ни на одной из "
+"них."
 
 msgid "too many branches for a copy operation"
 msgstr "слишком много веток для операции копирования"
@@ -3017,7 +3056,9 @@ msgstr ""
 msgid "not run from a git repository - no hooks to show\n"
 msgstr ""
 
-msgid "git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"
+msgid ""
+"git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"              [--diagnose[=<mode>]]"
 msgstr ""
 
 msgid ""
@@ -3038,16 +3079,27 @@ msgid ""
 "You can delete any lines you don't wish to share.\n"
 msgstr ""
 
-msgid "specify a destination for the bugreport file"
+msgid "mode"
+msgstr "режим"
+
+msgid ""
+"create an additional zip archive of detailed diagnostics (default 'stats')"
 msgstr ""
 
-msgid "specify a strftime format suffix for the filename"
+msgid "specify a destination for the bugreport file(s)"
+msgstr ""
+
+msgid "specify a strftime format suffix for the filename(s)"
 msgstr ""
 
 #, c-format
 msgid "could not create leading directories for '%s'"
 msgstr ""
 
+#, c-format
+msgid "unable to create diagnostics archive %s"
+msgstr ""
+
 msgid "System Info"
 msgstr ""
 
@@ -3062,16 +3114,21 @@ msgstr ""
 msgid "Created new report at '%s'.\n"
 msgstr ""
 
-msgid "git bundle create [<options>] <file> <git-rev-list args>"
+msgid ""
+"git bundle create [-q | --quiet | --progress]\n"
+"                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
 
-msgid "git bundle verify [<options>] <file>"
+msgid "git bundle verify [-q | --quiet] <file>"
 msgstr ""
 
 msgid "git bundle list-heads <file> [<refname>...]"
 msgstr ""
 
-msgid "git bundle unbundle <file> [<refname>...]"
+msgid "git bundle unbundle [--progress] <file> [<refname>...]"
+msgstr ""
+
+msgid "need a <file> argument"
 msgstr ""
 
 msgid "do not show progress meter"
@@ -3080,11 +3137,11 @@ msgstr "не выводить прогресс выполнения"
 msgid "show progress meter"
 msgstr "показать прогресс выполнения"
 
-msgid "show progress meter during object writing phase"
-msgstr "показать прогресс выполнения во время записи объектов"
+msgid "historical; same as --progress"
+msgstr ""
 
-msgid "similar to --all-progress when progress meter is shown"
-msgstr "похоже на --all-progress при включенном прогрессе выполнения"
+msgid "historical; does nothing"
+msgstr ""
 
 msgid "specify bundle format version"
 msgstr ""
@@ -3105,10 +3162,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»"
@@ -3131,10 +3184,6 @@ msgstr ""
 msgid "%s takes no arguments"
 msgstr ""
 
-#, c-format
-msgid "unknown command: '%s'"
-msgstr ""
-
 msgid "only one batch option may be specified"
 msgstr ""
 
@@ -3151,7 +3200,7 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters]"
+"             [--textconv | --filters] [-z]"
 msgstr ""
 
 msgid ""
@@ -3180,6 +3229,9 @@ msgstr "показать размер объекта"
 msgid "allow -s and -t to work with broken/corrupt objects"
 msgstr "разрешить -s и -t работать с повреждёнными объектами"
 
+msgid "use mail map file"
+msgstr ""
+
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
 msgstr ""
 
@@ -3189,6 +3241,9 @@ msgstr ""
 msgid "like --batch, but don't emit <contents>"
 msgstr ""
 
+msgid "stdin is NUL-terminated"
+msgstr ""
+
 msgid "read commands from stdin"
 msgstr ""
 
@@ -3250,18 +3305,18 @@ msgstr ""
 msgid "<object> required with '-%c'"
 msgstr ""
 
-msgid "too many arguments"
-msgstr ""
-
 #, c-format
 msgid "only two arguments allowed in <type> <object> mode, not %d"
 msgstr ""
 
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <атрибут>...] [--] <путь>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
 
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <атрибут>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
 
 msgid "report all attributes set on file"
 msgstr "вывести все атрибуты установленные для файла"
@@ -3275,6 +3330,12 @@ msgstr "прочитать имена файлов из стандартного
 msgid "terminate input and output records by a NUL character"
 msgstr "окончание ввода и вывода записей по НУЛЕВОМУ символу"
 
+msgid "<tree-ish>"
+msgstr ""
+
+msgid "which tree-ish to check attributes at"
+msgstr ""
+
 msgid "suppress progress reporting"
 msgstr "не выводить прогресс выполнения"
 
@@ -3787,9 +3848,9 @@ msgid "use overlay mode"
 msgstr ""
 
 msgid ""
-"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] "
+"[<pathspec>...]"
 msgstr ""
-"git clean [-d] [-f] [-i] [-n] [-q] [-e <шаблон>] [-x | -X] [--] <пути>..."
 
 #, c-format
 msgid "Removing %s\n"
@@ -3853,7 +3914,7 @@ msgstr ""
 "*          - выбрать все элементы\n"
 "           - (пусто) завершить выделение\n"
 
-#, c-format, perl-format
+#, c-format
 msgid "Huh (%s)?\n"
 msgstr "Хм (%s)?\n"
 
@@ -4006,9 +4067,6 @@ msgstr "глубина"
 msgid "create a shallow clone of that depth"
 msgstr "сделать частичный клон указанной глубины"
 
-msgid "time"
-msgstr "время"
-
 msgid "create a shallow clone since a specific time"
 msgstr "сделать частичный клон до определенного времени"
 
@@ -4062,6 +4120,12 @@ msgstr ""
 msgid "initialize sparse-checkout file to include only files at root"
 msgstr ""
 
+msgid "uri"
+msgstr ""
+
+msgid "a URI for downloading bundles before fetching from origin remote"
+msgstr ""
+
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
 msgstr "информация: Не удалось добавить альтернативу для «%s»: %s\n"
@@ -4074,10 +4138,18 @@ msgstr "не удалось выполнить stat «%s»"
 msgid "%s exists and is not a directory"
 msgstr "%s уже существует и не является каталогом"
 
+#, c-format
+msgid "'%s' is a symlink, refusing to clone with --local"
+msgstr ""
+
 #, c-format
 msgid "failed to start iterator over '%s'"
 msgstr ""
 
+#, c-format
+msgid "symlink '%s' exists, refusing to clone with --local"
+msgstr ""
+
 #, c-format
 msgid "failed to unlink '%s'"
 msgstr "сбой отсоединения «%s»"
@@ -4124,10 +4196,8 @@ 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"
 
 msgid "unable to checkout working tree"
 msgstr "не удалось переключиться на версию в рабочем каталоге"
@@ -4147,8 +4217,9 @@ msgstr "Слишком много аргументов."
 msgid "You must specify a repository to clone."
 msgstr "Вы должны указать репозиторий для клонирования."
 
-#, c-format
-msgid "options '%s' and '%s %s' cannot be used together"
+msgid ""
+"--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-"
+"exclude"
 msgstr ""
 
 #, c-format
@@ -4227,6 +4298,16 @@ 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 ""
+
+msgid "failed to fetch advertised bundles"
+msgstr ""
+
 msgid "remote transport reported error"
 msgstr ""
 
@@ -4262,13 +4343,16 @@ msgid "--command must be the first argument"
 msgstr "параметр --command должен быть первым"
 
 msgid ""
-"git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"
+"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
 msgstr ""
 
 msgid ""
-"git commit-graph write [--object-dir <objdir>] [--append] [--"
-"split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] [--changed-"
-"paths] [--[no-]max-new-filters <n>] [--[no-]progress] <split options>"
+"git commit-graph write [--object-dir <dir>] [--append]\n"
+"                       [--split[=<strategy>]] [--reachable | --stdin-packs | "
+"--stdin-commits]\n"
+"                       [--changed-paths] [--[no-]max-new-filters <n>] [--"
+"[no-]progress]\n"
+"                       <split options>"
 msgstr ""
 
 msgid "dir"
@@ -4337,13 +4421,12 @@ msgstr ""
 msgid "Collecting commits from input"
 msgstr ""
 
-#, c-format
-msgid "unrecognized subcommand: %s"
+msgid "git commit-tree <tree> [(-p <parent>)...]"
 msgstr ""
 
 msgid ""
-"git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F "
-"<file>)...] <tree>"
+"git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
+"                [(-F <file>)...] <tree>"
 msgstr ""
 
 #, c-format
@@ -4386,11 +4469,20 @@ msgstr "необходимо указать одно дерево"
 msgid "git commit-tree: failed to read"
 msgstr "git commit-tree: сбой при чтении"
 
-msgid "git commit [<options>] [--] <pathspec>..."
-msgstr "git commit [<опции>] [--] <спецификатор-пути>..."
+msgid ""
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+"           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|"
+"reword):]<commit>)]\n"
+"           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
+"           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
+"           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+"           [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+"           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
+"           [--] [<pathspec>...]"
+msgstr ""
 
-msgid "git status [<options>] [--] <pathspec>..."
-msgstr "git status [<опции>] [--] <спецификатор-пути>..."
+msgid "git status [<options>] [--] [<pathspec>...]"
+msgstr ""
 
 msgid ""
 "You asked to amend the most recent commit, but doing so would make\n"
@@ -4672,9 +4764,6 @@ msgstr "показать статус в длинном формате (по у
 msgid "terminate entries with NUL"
 msgstr "завершать записи НУЛЕВЫМ байтом"
 
-msgid "mode"
-msgstr "режим"
-
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "показать неотслеживаемые файлы, опциональные режимы: all (все), normal (как "
@@ -4747,7 +4836,6 @@ msgstr "использовать сообщение указанного ком
 
 #. TRANSLATORS: Leave "[(amend|reword):]" as-is,
 #. and only translate <commit>.
-#.
 msgid "[(amend|reword):]commit"
 msgstr ""
 
@@ -5136,11 +5224,16 @@ msgstr ""
 msgid "unable to get credential storage lock in %d ms"
 msgstr ""
 
-msgid "git describe [<options>] [<commit-ish>...]"
-msgstr "git describe [<опции>] [<указатель-коммита>...]"
+msgid ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
+msgstr ""
+
+msgid ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
+msgstr ""
 
-msgid "git describe [<options>] --dirty"
-msgstr "git describe [<опции>] --dirty"
+msgid "git describe <blob>"
+msgstr ""
 
 msgid "head"
 msgstr "указатель на ветку"
@@ -5262,6 +5355,20 @@ msgstr "Имена не найдены, не могу ничего описат
 msgid "option '%s' and commit-ishes cannot be used together"
 msgstr ""
 
+msgid ""
+"git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+"             [--mode=<mode>]"
+msgstr ""
+
+msgid "specify a destination for the diagnostics archive"
+msgstr ""
+
+msgid "specify a strftime format suffix for the filename"
+msgstr ""
+
+msgid "specify the content of the diagnostic archive"
+msgstr ""
+
 msgid "--merge-base only works with two commits"
 msgstr ""
 
@@ -5269,6 +5376,9 @@ msgstr ""
 msgid "'%s': not a regular file or symlink"
 msgstr "«%s»: не является обычным файлом или символьной ссылкой"
 
+msgid "no merge given, only parents."
+msgstr ""
+
 #, c-format
 msgid "invalid option: %s"
 msgstr "неправильный параметр: %s"
@@ -5380,25 +5490,6 @@ msgstr "не передана <утилита> для --tool=<утилита>"
 msgid "no <cmd> given for --extcmd=<cmd>"
 msgstr "не передана <команда> для --extcmd=<команда>"
 
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr ""
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr ""
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr ""
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not `"
-"%s`"
-msgstr ""
-
 msgid "git fast-export [<rev-list-opts>]"
 msgstr ""
 
@@ -5507,113 +5598,13 @@ msgstr "git fetch --all [<опции>]"
 msgid "fetch.parallel cannot be negative"
 msgstr ""
 
-msgid "fetch from all remotes"
-msgstr "извлечь со всех внешних репозиториев"
-
-msgid "set upstream for git pull/fetch"
-msgstr ""
-
-msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr "дописать к .git/FETCH_HEAD вместо перезаписи"
-
-msgid "use atomic transaction to update references"
-msgstr ""
-
-msgid "path to upload pack on remote end"
-msgstr "путь к программе упаковки пакета на машине с внешним репозиторием"
-
-msgid "force overwrite of local reference"
-msgstr ""
-
-msgid "fetch from multiple remotes"
-msgstr "извлечь с нескольких внешних репозиториев"
-
-msgid "fetch all tags and associated objects"
-msgstr "извлечь все метки и связанные объекты"
-
-msgid "do not fetch all tags (--no-tags)"
-msgstr "не извлекать все метки (--no-tags)"
-
-msgid "number of submodules fetched in parallel"
-msgstr "количество подмодулей, которые будут скачаны парралельно"
-
-msgid "modify the refspec to place all refs within refs/prefetch/"
-msgstr ""
-
-msgid "prune remote-tracking branches no longer on remote"
-msgstr ""
-"почистить отслеживаемые внешние ветки, которых уже нет на внешнем репозитории"
-
-msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
-
-msgid "on-demand"
-msgstr "по требованию"
-
-msgid "control recursive fetching of submodules"
-msgstr "управление рекурсивным извлечением подмодулей"
-
-msgid "write fetched references to the FETCH_HEAD file"
-msgstr ""
-
-msgid "keep downloaded pack"
-msgstr "оставить загруженный пакет данных"
-
-msgid "allow updating of HEAD ref"
-msgstr "разрешить обновление указателя HEAD"
-
-msgid "deepen history of shallow clone"
-msgstr "углубить историю частичного клона"
-
-msgid "deepen history of shallow repository based on time"
-msgstr "углубить историю частичного клона основываясь на времени"
-
-msgid "convert to a complete repository"
-msgstr "преобразовать в полный репозиторий"
-
-msgid "re-fetch without negotiating common commits"
-msgstr ""
-
-msgid "prepend this to submodule path output"
-msgstr "присоединять это спереди к выводу путей подмодуля"
-
-msgid ""
-"default for recursive fetching of submodules (lower priority than config "
-"files)"
-msgstr ""
-"настроить по умолчанию рекурсивное извлечение подмодулей (более низкий "
-"приоритет, чем файлы конфигурации)"
-
-msgid "accept refs that update .git/shallow"
-msgstr "принимать ссылки, которые обновляют .git/shallow"
-
-msgid "refmap"
-msgstr "соответствие-ссылок"
-
-msgid "specify fetch refmap"
-msgstr "указать соответствие ссылок при извлечении"
-
-msgid "report that we have only objects reachable from this object"
-msgstr ""
-
-msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
-msgstr ""
-
-msgid "run 'maintenance --auto' after fetching"
-msgstr ""
-
-msgid "check for forced-updates on all updated branches"
-msgstr ""
-
-msgid "write the commit-graph after fetching"
-msgstr ""
-
-msgid "accept refspecs from stdin"
-msgstr ""
-
 msgid "couldn't find remote ref HEAD"
 msgstr ""
 
+#, c-format
+msgid "From %.*s\n"
+msgstr "Из %.*s\n"
+
 #, c-format
 msgid "object %s not found"
 msgstr "объект %s не найден"
@@ -5624,10 +5615,7 @@ msgstr "[актуально]"
 msgid "[rejected]"
 msgstr "[отклонено]"
 
-msgid "can't fetch in current branch"
-msgstr "нельзя извлечь текущую ветку"
-
-msgid "checked out in another worktree"
+msgid "can't fetch into checked-out branch"
 msgstr ""
 
 msgid "[tag update]"
@@ -5680,10 +5668,6 @@ msgstr "%s не отправил все необходимые объекты\n"
 msgid "rejected %s because shallow roots are not allowed to be updated"
 msgstr ""
 
-#, c-format
-msgid "From %.*s\n"
-msgstr "Из %.*s\n"
-
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -5769,72 +5753,180 @@ msgstr ""
 msgid "you need to specify a tag name"
 msgstr ""
 
-msgid "--negotiate-only needs one or more --negotiation-tip=*"
-msgstr ""
+msgid "fetch from all remotes"
+msgstr "извлечь со всех внешних репозиториев"
 
-msgid "negative depth in --deepen is not supported"
+msgid "set upstream for git pull/fetch"
 msgstr ""
 
-msgid "--unshallow on a complete repository does not make sense"
-msgstr "--unshallow не имеет смысла на полном репозитории"
+msgid "append to .git/FETCH_HEAD instead of overwriting"
+msgstr "дописать к .git/FETCH_HEAD вместо перезаписи"
 
-msgid "fetch --all does not take a repository argument"
-msgstr "fetch --all не принимает имя репозитория как аргумент"
+msgid "use atomic transaction to update references"
+msgstr ""
 
-msgid "fetch --all does not make sense with refspecs"
-msgstr "fetch --all не имеет смысла при указании спецификаторов ссылок"
+msgid "path to upload pack on remote end"
+msgstr "путь к программе упаковки пакета на машине с внешним репозиторием"
 
-#, c-format
-msgid "no such remote or remote group: %s"
+msgid "force overwrite of local reference"
 msgstr ""
 
-msgid "fetching a group and specifying refspecs does not make sense"
-msgstr ""
+msgid "fetch from multiple remotes"
+msgstr "извлечь с нескольких внешних репозиториев"
 
-msgid "must supply remote when using --negotiate-only"
-msgstr ""
+msgid "fetch all tags and associated objects"
+msgstr "извлечь все метки и связанные объекты"
 
-msgid "protocol does not support --negotiate-only, exiting"
-msgstr ""
+msgid "do not fetch all tags (--no-tags)"
+msgstr "не извлекать все метки (--no-tags)"
 
-msgid ""
-"--filter can only be used with the remote configured in extensions."
-"partialclone"
-msgstr ""
+msgid "number of submodules fetched in parallel"
+msgstr "количество подмодулей, которые будут скачаны парралельно"
 
-msgid "--atomic can only be used when fetching from one remote"
+msgid "modify the refspec to place all refs within refs/prefetch/"
 msgstr ""
 
-msgid "--stdin can only be used when fetching from one remote"
+msgid "prune remote-tracking branches no longer on remote"
 msgstr ""
+"почистить отслеживаемые внешние ветки, которых уже нет на внешнем репозитории"
 
-msgid ""
-"git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"
+msgid "prune local tags no longer on remote and clobber changed tags"
 msgstr ""
-"git fmt-merge-msg [-m <сообщение>] [--log[=<n>] | --no-log] [--file <файл>]"
-
-msgid "populate log with at most <n> entries from shortlog"
-msgstr "отправить в журнал <n> записей из короткого журнала"
-
-msgid "alias for --log (deprecated)"
-msgstr "сокращение для --log (устаревшее)"
 
-msgid "text"
-msgstr "текст"
+msgid "on-demand"
+msgstr "по требованию"
 
-msgid "use <text> as start of message"
-msgstr "использовать <текст> как начальное сообщение"
+msgid "control recursive fetching of submodules"
+msgstr "управление рекурсивным извлечением подмодулей"
 
-msgid "use <name> instead of the real target branch"
+msgid "write fetched references to the FETCH_HEAD file"
 msgstr ""
 
-msgid "file to read from"
-msgstr "файл для чтения"
+msgid "keep downloaded pack"
+msgstr "оставить загруженный пакет данных"
 
-msgid "git for-each-ref [<options>] [<pattern>]"
-msgstr "git for-each-ref [<опции>] [<шаблон>]"
+msgid "allow updating of HEAD ref"
+msgstr "разрешить обновление указателя HEAD"
 
-msgid "git for-each-ref [--points-at <object>]"
+msgid "deepen history of shallow clone"
+msgstr "углубить историю частичного клона"
+
+msgid "deepen history of shallow repository based on time"
+msgstr "углубить историю частичного клона основываясь на времени"
+
+msgid "convert to a complete repository"
+msgstr "преобразовать в полный репозиторий"
+
+msgid "re-fetch without negotiating common commits"
+msgstr ""
+
+msgid "prepend this to submodule path output"
+msgstr "присоединять это спереди к выводу путей подмодуля"
+
+msgid ""
+"default for recursive fetching of submodules (lower priority than config "
+"files)"
+msgstr ""
+"настроить по умолчанию рекурсивное извлечение подмодулей (более низкий "
+"приоритет, чем файлы конфигурации)"
+
+msgid "accept refs that update .git/shallow"
+msgstr "принимать ссылки, которые обновляют .git/shallow"
+
+msgid "refmap"
+msgstr "соответствие-ссылок"
+
+msgid "specify fetch refmap"
+msgstr "указать соответствие ссылок при извлечении"
+
+msgid "report that we have only objects reachable from this object"
+msgstr ""
+
+msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
+msgstr ""
+
+msgid "run 'maintenance --auto' after fetching"
+msgstr ""
+
+msgid "check for forced-updates on all updated branches"
+msgstr ""
+
+msgid "write the commit-graph after fetching"
+msgstr ""
+
+msgid "accept refspecs from stdin"
+msgstr ""
+
+msgid "--negotiate-only needs one or more --negotiation-tip=*"
+msgstr ""
+
+msgid "negative depth in --deepen is not supported"
+msgstr ""
+
+msgid "--unshallow on a complete repository does not make sense"
+msgstr "--unshallow не имеет смысла на полном репозитории"
+
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr ""
+
+msgid "fetch --all does not take a repository argument"
+msgstr "fetch --all не принимает имя репозитория как аргумент"
+
+msgid "fetch --all does not make sense with refspecs"
+msgstr "fetch --all не имеет смысла при указании спецификаторов ссылок"
+
+#, c-format
+msgid "no such remote or remote group: %s"
+msgstr ""
+
+msgid "fetching a group and specifying refspecs does not make sense"
+msgstr ""
+
+msgid "must supply remote when using --negotiate-only"
+msgstr ""
+
+msgid "protocol does not support --negotiate-only, exiting"
+msgstr ""
+
+msgid ""
+"--filter can only be used with the remote configured in extensions."
+"partialclone"
+msgstr ""
+
+msgid "--atomic can only be used when fetching from one remote"
+msgstr ""
+
+msgid "--stdin can only be used when fetching from one remote"
+msgstr ""
+
+msgid ""
+"git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"
+msgstr ""
+"git fmt-merge-msg [-m <сообщение>] [--log[=<n>] | --no-log] [--file <файл>]"
+
+msgid "populate log with at most <n> entries from shortlog"
+msgstr "отправить в журнал <n> записей из короткого журнала"
+
+msgid "alias for --log (deprecated)"
+msgstr "сокращение для --log (устаревшее)"
+
+msgid "text"
+msgstr "текст"
+
+msgid "use <text> as start of message"
+msgstr "использовать <текст> как начальное сообщение"
+
+msgid "use <name> instead of the real target branch"
+msgstr ""
+
+msgid "file to read from"
+msgstr "файл для чтения"
+
+msgid "git for-each-ref [<options>] [<pattern>]"
+msgstr "git for-each-ref [<опции>] [<шаблон>]"
+
+msgid "git for-each-ref [--points-at <object>]"
 msgstr "git for-each-ref [--points-at <объект>]"
 
 msgid "git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"
@@ -5878,7 +5970,13 @@ msgstr "вывод только ссылок, которые содержат к
 msgid "print only refs which don't contain the commit"
 msgstr "вывод только ссылок, которые не содержат коммит"
 
-msgid "git for-each-repo --config=<config> <command-args>"
+msgid "read reference patterns from stdin"
+msgstr ""
+
+msgid "unknown arguments supplied with --stdin"
+msgstr ""
+
+msgid "git for-each-repo --config=<config> [--] <arguments>"
 msgstr ""
 
 msgid "config"
@@ -5890,6 +5988,10 @@ msgstr ""
 msgid "missing --config=<config>"
 msgstr ""
 
+#, c-format
+msgid "got bad config --config=%s"
+msgstr ""
+
 msgid "unknown"
 msgstr ""
 
@@ -6034,18 +6136,35 @@ msgstr "%s: отсоединённый указатель HEAD ни на что
 msgid "notice: %s points to an unborn branch (%s)"
 msgstr ""
 
-msgid "Checking cache tree"
+#, c-format
+msgid "Checking cache tree of %s"
 msgstr ""
 
 #, c-format
-msgid "%s: invalid sha1 pointer in cache-tree"
+msgid "%s: invalid sha1 pointer in cache-tree of %s"
 msgstr ""
 
 msgid "non-tree in cache-tree"
 msgstr ""
 
-msgid "git fsck [<options>] [<object>...]"
-msgstr "git fsck [<опции>] [<объект>...]"
+#, c-format
+msgid "%s: invalid sha1 pointer in resolve-undo of %s"
+msgstr ""
+
+#, c-format
+msgid "unable to load rev-index for pack '%s'"
+msgstr ""
+
+#, c-format
+msgid "invalid rev-index for pack '%s'"
+msgstr ""
+
+msgid ""
+"git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
+"         [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
+"         [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
+"         [--[no-]name-objects] [<object>...]"
+msgstr ""
 
 msgid "show unreachable objects"
 msgstr "показать недоступные объекты"
@@ -6100,12 +6219,6 @@ msgstr ""
 msgid "git fsmonitor--daemon run [<options>]"
 msgstr ""
 
-msgid "git fsmonitor--daemon stop"
-msgstr ""
-
-msgid "git fsmonitor--daemon status"
-msgstr ""
-
 #, c-format
 msgid "value of '%s' out of range: %d"
 msgstr ""
@@ -6342,7 +6455,19 @@ msgstr ""
 msgid "use at most one of --auto and --schedule=<frequency>"
 msgstr ""
 
-msgid "failed to run 'git config'"
+#, c-format
+msgid "unable to add '%s' value of '%s'"
+msgstr ""
+
+msgid "return success even if repository was not registered"
+msgstr ""
+
+#, c-format
+msgid "unable to unset '%s' value of '%s'"
+msgstr ""
+
+#, c-format
+msgid "repository '%s' is not registered"
 msgstr ""
 
 #, c-format
@@ -6369,10 +6494,13 @@ msgstr ""
 msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr ""
 
-msgid "failed to run 'crontab'; your system might not support 'cron'"
+msgid "failed to create crontab temporary file"
+msgstr ""
+
+msgid "failed to open temporary file"
 msgstr ""
 
-msgid "failed to open stdin of 'crontab'"
+msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
 
 msgid "'crontab' died"
@@ -6421,10 +6549,6 @@ msgstr ""
 msgid "git maintenance <subcommand> [<options>]"
 msgstr ""
 
-#, c-format
-msgid "invalid subcommand: %s"
-msgstr ""
-
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<опции>] [-e] <шаблон> [<редакция>...] [[--] <путь>...]"
 
@@ -6440,7 +6564,6 @@ msgstr "указано недопустимое количество поток
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
 #. grep.threads
-#.
 #, c-format
 msgid "no threads support, ignoring %s"
 msgstr "нет поддержки потоков, игнорирование %s"
@@ -6595,6 +6718,9 @@ msgstr "показать совпадающие файлы с помощью п
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "разрешить вызов grep(1) (игнорируется в этой сборке)"
 
+msgid "maximum number of results per file"
+msgstr ""
+
 msgid "no pattern given"
 msgstr ""
 
@@ -6630,11 +6756,12 @@ msgid "both --cached and trees are given"
 msgstr ""
 
 msgid ""
-"git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] "
-"[--] <file>..."
+"git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
+"                [--stdin [--literally]] [--] <file>..."
+msgstr ""
+
+msgid "git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"
 msgstr ""
-"git hash-object [-t <тип>] [-w] [--path=<файл> | --no-filters] [--stdin] "
-"[--] <файл>..."
 
 msgid "object type"
 msgstr "тип объекта"
@@ -6683,10 +6810,16 @@ 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>]"
+msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
 msgstr ""
 
 #, c-format
@@ -6756,12 +6889,17 @@ msgstr "использование: %s%s"
 msgid "'git help config' for more information"
 msgstr ""
 
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
 msgstr ""
 
 msgid "silently ignore missing requested <hook-name>"
 msgstr ""
 
+msgid "file to read into hooks' stdin"
+msgstr ""
+
 #, c-format
 msgid "object type mismatch at %s"
 msgstr "несоответствие типа объекта на %s"
@@ -7065,11 +7203,11 @@ msgid "Initialized empty Git repository in %s%s\n"
 msgstr "Инициализирован пустой репозиторий Git в %s%s\n"
 
 msgid ""
-"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--"
-"shared[=<permissions>]] [<directory>]"
+"git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
+"         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+"         [-b <branch-name> | --initial-branch=<branch-name>]\n"
+"         [--shared[=<permissions>]] [<directory>]"
 msgstr ""
-"git init [-q | --quiet] [--bare] [--template=<каталог-шаблонов>] [--"
-"shared[=<права-доступа>]] [<каталог>]"
 
 msgid "permissions"
 msgstr "права-доступа"
@@ -7111,11 +7249,10 @@ msgid "--separate-git-dir incompatible with bare repository"
 msgstr ""
 
 msgid ""
-"git interpret-trailers [--in-place] [--trim-empty] [(--trailer "
-"<token>[(=|:)<value>])...] [<file>...]"
+"git interpret-trailers [--in-place] [--trim-empty]\n"
+"                       [(--trailer <token>[(=|:)<value>])...]\n"
+"                       [--parse] [<file>...]"
 msgstr ""
-"git interpret-trailers [--in-place] [--trim-empty] [(--trailer "
-"<ключ>[(=|:)<значение>])...] [<файл>...]"
 
 msgid "edit files in place"
 msgstr "редактировать файлы на месте"
@@ -7172,7 +7309,7 @@ msgstr "не выводить список изменений"
 msgid "show source"
 msgstr "показать источник"
 
-msgid "use mail map file"
+msgid "clear all previously-defined decoration filters"
 msgstr ""
 
 msgid "only decorate refs that match <pattern>"
@@ -7422,6 +7559,9 @@ msgstr ""
 msgid "percentage by which creation is weighted"
 msgstr ""
 
+msgid "show in-body From: even if identical to the e-mail header"
+msgstr ""
+
 #, c-format
 msgid "invalid ident line: %s"
 msgstr "неправильная строка идентификации: %s"
@@ -7482,6 +7622,18 @@ msgstr ""
 "Не удалось найти отслеживаемую внешнюю ветку, укажите <вышестоящую-ветку> "
 "вручную.\n"
 
+#, c-format
+msgid "bad ls-files format: element '%s' does not start with '('"
+msgstr ""
+
+#, c-format
+msgid "bad ls-files format: element '%s' does not end in ')'"
+msgstr ""
+
+#, c-format
+msgid "bad ls-files format: %%%.*s"
+msgstr ""
+
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<опции>] [<файл>...]"
 
@@ -7568,10 +7720,15 @@ msgstr ""
 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 ""
+
 msgid ""
 "git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
-"              [-q | --quiet] [--exit-code] [--get-url]\n"
-"              [--symref] [<repository> [<refs>...]]"
+"              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
+"              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
 
 msgid "do not print remote URL"
@@ -7704,12 +7861,12 @@ msgstr "git merge-base [-a | --all] <коммит> <коммит>..."
 msgid "git merge-base [-a | --all] --octopus <commit>..."
 msgstr "git merge-base [-a | --all] --octopus <коммит>..."
 
-msgid "git merge-base --independent <commit>..."
-msgstr "git merge-base --independent <коммит>..."
-
 msgid "git merge-base --is-ancestor <commit> <commit>"
 msgstr "git merge-base --is-ancestor <коммит> <коммит>"
 
+msgid "git merge-base --independent <commit>..."
+msgstr "git merge-base --independent <коммит>..."
+
 msgid "git merge-base --fork-point <ref> [<commit>]"
 msgstr "git merge-base --fork-point <ссылка> [<коммит>]"
 
@@ -7789,6 +7946,56 @@ 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 ""
+
+msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
+msgstr ""
+
+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 "perform multiple merges, one per line of input"
+msgstr ""
+
+msgid "specify a merge-base for the merge"
+msgstr ""
+
+msgid "--trivial-merge is incompatible with all other options"
+msgstr ""
+
+msgid "--merge-base is incompatible with --stdin"
+msgstr ""
+
+#, c-format
+msgid "malformed input line: '%s'."
+msgstr "неправильная введенная строка: «%s»."
+
+#, c-format
+msgid "merging cannot continue; got unclean result of %d"
+msgstr ""
+
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<опции>] [<коммит>...]"
 
@@ -7870,9 +8077,6 @@ msgstr ""
 msgid "continue the current in-progress merge"
 msgstr "продолжить выполнение происходящего слияния"
 
-msgid "allow merging unrelated histories"
-msgstr "разрешить слияние несвязанных историй изменений"
-
 msgid "bypass pre-merge-commit and commit-msg hooks"
 msgstr ""
 
@@ -7994,9 +8198,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 не принимает аргументы"
 
@@ -8046,13 +8247,16 @@ 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 ""
+
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Попытка тривиального слияния в индексе...\n"
@@ -8087,6 +8291,10 @@ msgstr ""
 "Автоматическое слияние прошло успешно; как и запрашивали, остановлено перед "
 "выполнением коммита\n"
 
+#, c-format
+msgid "When finished, apply stashed changes with `git stash pop`\n"
+msgstr ""
+
 #, c-format
 msgid "warning: tag input does not pass fsck: %s"
 msgstr ""
@@ -8201,6 +8409,9 @@ msgstr "Проверка переименования из «%s» в «%s»\n"
 msgid "bad source"
 msgstr "плохой источник"
 
+msgid "destination exists"
+msgstr "целевой путь уже существует"
+
 msgid "can not move directory into itself"
 msgstr "нельзя переместить каталог в самого себя"
 
@@ -8216,9 +8427,6 @@ msgstr "не под версионным контролем"
 msgid "conflicted"
 msgstr ""
 
-msgid "destination exists"
-msgstr "целевой путь уже существует"
-
 #, c-format
 msgid "overwriting '%s'"
 msgstr "перезапись «%s»"
@@ -8232,6 +8440,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"
@@ -8398,17 +8609,12 @@ msgstr "не удалось прочитать объект «%s»."
 msgid "cannot read note data from non-blob object '%s'."
 msgstr "не удалось прочитать данные заметки из недвоичного объекта «%s»."
 
-#, c-format
-msgid "malformed input line: '%s'."
-msgstr "неправильная введенная строка: «%s»."
-
 #, c-format
 msgid "failed to copy notes from '%s' to '%s'"
 msgstr "не удалось скопировать заметку из «%s» в «%s»"
 
 #. TRANSLATORS: the first %s will be replaced by a git
 #. notes command: 'add', 'merge', 'remove', etc.
-#.
 #, c-format
 msgid "refusing to %s notes in %s (outside of refs/notes/)"
 msgstr "отказ в перезаписи %s заметок в %s (за пределами refs/notes/)"
@@ -8590,20 +8796,15 @@ msgid "use notes from <notes-ref>"
 msgstr "использовать заметку из <ссылка-на-заметку>"
 
 #, c-format
-msgid "unknown subcommand: %s"
-msgstr "неизвестная подкоманда: %s"
+msgid "unknown subcommand: `%s'"
+msgstr ""
 
-msgid ""
-"git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"
+msgid "git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"
 msgstr ""
-"git pack-objects --stdout [<опции>...] [< <список-ссылок> | < <список-"
-"объектов>]"
 
 msgid ""
-"git pack-objects [<options>...] <base-name> [< <ref-list> | < <object-list>]"
+"git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"
 msgstr ""
-"git pack-objects [<опции>...] <имя-базы> [< <список-ссылок> | < <список-"
-"объектов>]"
 
 #, c-format
 msgid ""
@@ -8782,6 +8983,12 @@ msgstr "неподдерживаемая версия индекса %s"
 msgid "bad index version '%s'"
 msgstr "плохая версия индекса «%s»"
 
+msgid "show progress meter during object writing phase"
+msgstr "показать прогресс выполнения во время записи объектов"
+
+msgid "similar to --all-progress when progress meter is shown"
+msgstr "похоже на --all-progress при включенном прогрессе выполнения"
+
 msgid "<version>[,<offset>]"
 msgstr ""
 
@@ -8967,8 +9174,11 @@ msgid ""
 "to <git@vger.kernel.org>.  Thanks.\n"
 msgstr ""
 
-msgid "git pack-refs [<options>]"
-msgstr "git pack-refs [<опции>]"
+msgid "refusing to run without --i-still-use-this"
+msgstr ""
+
+msgid "git pack-refs [--all] [--no-prune]"
+msgstr ""
 
 msgid "pack everything"
 msgstr "паковать всё"
@@ -8976,6 +9186,18 @@ msgstr "паковать всё"
 msgid "prune loose refs (default)"
 msgstr "почистить слабые ссылки (по умолчанию)"
 
+msgid "git patch-id [--stable | --unstable | --verbatim]"
+msgstr ""
+
+msgid "use the unstable patch-id algorithm"
+msgstr ""
+
+msgid "use the stable patch-id algorithm"
+msgstr ""
+
+msgid "don't strip whitespace from the patch"
+msgstr ""
+
 msgid "git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"
 msgstr ""
 "git prune [-n] [-v] [--progress] [--expire <время>] [--] [<редакция>...]"
@@ -9114,8 +9336,8 @@ msgstr ""
 msgid "pull with rebase"
 msgstr "получение с перемещением"
 
-msgid "please commit or stash them."
-msgstr "сделайте коммит или спрячьте их."
+msgid "Please commit or stash them."
+msgstr "Сделайте коммит или спрячьте их."
 
 #, c-format
 msgid ""
@@ -9175,9 +9397,8 @@ msgstr ""
 
 msgid ""
 "\n"
-"To avoid automatically configuring upstream branches when their name\n"
-"doesn't match the local branch, see option 'simple' of branch."
-"autoSetupMerge\n"
+"To avoid automatically configuring an upstream branch when its name\n"
+"won't match the local branch, see option 'simple' of branch.autoSetupMerge\n"
 "in 'git help config'.\n"
 msgstr ""
 
@@ -9321,6 +9542,11 @@ msgstr "Отправка в %s\n"
 msgid "failed to push some refs to '%s'"
 msgstr "не удалось отправить некоторые ссылки в «%s»"
 
+msgid ""
+"recursing into submodule with push.recurseSubmodules=only; using on-demand "
+"instead"
+msgstr ""
+
 #, c-format
 msgid "invalid value for '%s'"
 msgstr ""
@@ -9328,8 +9554,8 @@ msgstr ""
 msgid "repository"
 msgstr "репозиторий"
 
-msgid "push all refs"
-msgstr "отправить все ссылки"
+msgid "push all branches"
+msgstr ""
 
 msgid "mirror all refs"
 msgstr "сделать зеркало всех ссылок"
@@ -9337,8 +9563,8 @@ msgstr "сделать зеркало всех ссылок"
 msgid "delete refs"
 msgstr "удалить ссылки"
 
-msgid "push tags (can't be used with --all or --mirror)"
-msgstr "отправить метки (нельзя использовать вместе с --all или --mirror)"
+msgid "push tags (can't be used with --all or --branches or --mirror)"
+msgstr ""
 
 msgid "force updates"
 msgstr "принудительное обновление"
@@ -9440,20 +9666,26 @@ msgstr ""
 msgid "only emit output related to the second range"
 msgstr ""
 
+#, c-format
+msgid "not a revision: '%s'"
+msgstr ""
+
 #, c-format
 msgid "not a commit range: '%s'"
 msgstr ""
 
-msgid "single arg format must be symmetric range"
+#, c-format
+msgid "not a symmetric range: '%s'"
 msgstr ""
 
 msgid "need two commit ranges"
 msgstr ""
 
 msgid ""
-"git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) "
-"[-u | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-"
-"ish1> [<tree-ish2> [<tree-ish3>]])"
+"git read-tree [(-m [--trivial] [--aggressive] | --reset | --"
+"prefix=<prefix>)\n"
+"              [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]\n"
+"              (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
 msgstr ""
 
 msgid "write resulting index to <file>"
@@ -9542,7 +9774,7 @@ msgid "%s requires the merge backend"
 msgstr ""
 
 #, c-format
-msgid "could not get 'onto': '%s'"
+msgid "invalid onto: '%s'"
 msgstr ""
 
 #, c-format
@@ -9581,14 +9813,27 @@ msgid ""
 "As a result, git cannot rebase them."
 msgstr ""
 
+#, c-format
+msgid "Unknown rebase-merges mode: %s"
+msgstr ""
+
 #, c-format
 msgid "could not switch to %s"
 msgstr ""
 
+msgid "apply options and merge options cannot be used together"
+msgstr ""
+
 #, 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 ""
+
+msgid ""
+"--rebase-merges with an empty string argument is deprecated and will stop "
+"working in a future version of Git. Use --rebase-merges without an argument "
+"instead, which does the same thing."
 msgstr ""
 
 #, c-format
@@ -9693,6 +9938,9 @@ msgstr ""
 msgid "move commits that begin with squash!/fixup! under -i"
 msgstr ""
 
+msgid "update branches that point to commits that are being rebased"
+msgstr ""
+
 msgid "add exec lines after each commit of the editable list"
 msgstr ""
 
@@ -9779,14 +10027,22 @@ msgstr ""
 msgid "switch `C' expects a numerical value"
 msgstr ""
 
-#, c-format
-msgid "Unknown mode: %s"
+msgid "--strategy requires --merge or --interactive"
 msgstr ""
 
-msgid "--strategy requires --merge or --interactive"
+msgid ""
+"apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
+"autosquash"
 msgstr ""
 
-msgid "apply options and merge options cannot be used together"
+msgid ""
+"apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
+"no-rebase-merges"
+msgstr ""
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
+"update-refs"
 msgstr ""
 
 #, c-format
@@ -9811,7 +10067,7 @@ msgstr ""
 msgid "No such ref: %s"
 msgstr "Нет такой ссылки: %s"
 
-msgid "Could not resolve HEAD to a revision"
+msgid "Could not resolve HEAD to a commit"
 msgstr ""
 
 #, c-format
@@ -9826,9 +10082,6 @@ msgstr ""
 msgid "Does not point to a valid commit '%s'"
 msgstr ""
 
-msgid "Please commit or stash them."
-msgstr "Сделайте коммит или спрячьте их."
-
 msgid "HEAD is up to date."
 msgstr "HEAD уже в актуальном состоянии."
 
@@ -10203,6 +10456,9 @@ msgstr " новая (следующее извлечение сохранит е
 msgid " tracked"
 msgstr " отслеживается"
 
+msgid " skipped"
+msgstr ""
+
 msgid " stale (use 'git remote prune' to remove)"
 msgstr " недействительна (используйте «git remote prune», чтобы удалить)"
 
@@ -10287,7 +10543,6 @@ msgstr "(нет URL)"
 #. TRANSLATORS: the colon ':' should align
 #. with the one in " Fetch URL: %s"
 #. translation.
-#.
 #, c-format
 msgid "  Push  URL: %s"
 msgstr "    URL для отправки: %s"
@@ -10472,6 +10727,10 @@ msgstr ""
 msgid "could not close refs snapshot tempfile"
 msgstr ""
 
+#, c-format
+msgid "could not remove stale bitmap: %s"
+msgstr ""
+
 msgid "pack everything in a single pack"
 msgstr "упаковать всё в один пакет"
 
@@ -10484,7 +10743,7 @@ msgstr ""
 msgid "approxidate"
 msgstr "примерная-дата"
 
-msgid "with -C, expire objects older than this"
+msgid "with --cruft, expire objects older than this"
 msgstr ""
 
 msgid "remove redundant packs, and run git-prune-packed"
@@ -10544,6 +10803,9 @@ msgstr ""
 msgid "write a multi-pack index of the resulting packs"
 msgstr ""
 
+msgid "pack prefix to store a pack containing pruned objects"
+msgstr ""
+
 msgid "cannot delete packs in a precious-objects repo"
 msgstr "нельзя удалять пакеты в precious-objects репозитории"
 
@@ -10555,7 +10817,11 @@ msgid "pack prefix %s does not begin with objdir %s"
 msgstr ""
 
 #, c-format
-msgid "missing required file: %s"
+msgid "renaming pack to '%s' failed"
+msgstr ""
+
+#, c-format
+msgid "pack-objects did not write a '%s' file for pack %s-%s"
 msgstr ""
 
 #, c-format
@@ -10743,8 +11009,9 @@ msgstr ""
 msgid "only one pattern can be given with -l"
 msgstr ""
 
-msgid "git rerere [clear | forget <path>... | status | remaining | diff | gc]"
-msgstr "git rerere [clear | forget <путь>... | status | remaining | diff | gc]"
+msgid ""
+"git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
+msgstr ""
 
 msgid "register clean resolutions in index"
 msgstr "записать чистые разрешения конфликтов в индекс"
@@ -10866,6 +11133,10 @@ msgstr "Не удалось записать новый файл индекса.
 msgid "unable to get disk usage of %s"
 msgstr ""
 
+#, c-format
+msgid "invalid value for '%s': '%s', the only allowed format is '%s'"
+msgstr ""
+
 msgid "rev-list does not support display of notes"
 msgstr "rev-list не поддерживает отображение заметок"
 
@@ -10891,6 +11162,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 ""
 
@@ -10938,6 +11212,15 @@ msgstr ""
 msgid "unknown mode for --abbrev-ref: %s"
 msgstr ""
 
+msgid "--exclude-hidden cannot be used together with --branches"
+msgstr ""
+
+msgid "--exclude-hidden cannot be used together with --tags"
+msgstr ""
+
+msgid "--exclude-hidden cannot be used together with --remotes"
+msgstr ""
+
 msgid "this operation must be run in a work tree"
 msgstr ""
 
@@ -10945,17 +11228,21 @@ msgstr ""
 msgid "unknown mode for --show-object-format: %s"
 msgstr ""
 
-msgid "git revert [<options>] <commit-ish>..."
-msgstr "git revert [<опции>] <указатель-коммита>..."
+msgid ""
+"git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
+"<commit>..."
+msgstr ""
 
-msgid "git revert <subcommand>"
-msgstr "git revert <подкоманда>"
+msgid "git revert (--continue | --skip | --abort | --quit)"
+msgstr ""
 
-msgid "git cherry-pick [<options>] <commit-ish>..."
-msgstr "git cherry-pick [<опции>] <указатель-коммита>..."
+msgid ""
+"git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
+"                [-S[<keyid>]] <commit>..."
+msgstr ""
 
-msgid "git cherry-pick <subcommand>"
-msgstr "git cherry-pick <подкоманда>"
+msgid "git cherry-pick (--continue | --skip | --abort | --quit)"
+msgstr ""
 
 #, c-format
 msgid "option `%s' expects a number greater than zero"
@@ -11017,8 +11304,11 @@ msgstr "сбой обращения изменений коммита"
 msgid "cherry-pick failed"
 msgstr "сбой при копировании коммита"
 
-msgid "git rm [<options>] [--] <file>..."
-msgstr "git rm [<опции>] [--] <файл>..."
+msgid ""
+"git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
+"       [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+"       [--] [<pathspec>...]"
+msgstr ""
 
 msgid ""
 "the following file has staged content different from both the\n"
@@ -11101,12 +11391,16 @@ msgid ""
 "git send-pack [--mirror] [--dry-run] [--force]\n"
 "              [--receive-pack=<git-receive-pack>]\n"
 "              [--verbose] [--thin] [--atomic]\n"
+"              [--[no-]signed | --signed=(true|false|if-asked)]\n"
 "              [<host>:]<directory> (--all | <ref>...)"
 msgstr ""
 
 msgid "remote name"
 msgstr "имя внешнего репозитория"
 
+msgid "push all refs"
+msgstr "отправить все ссылки"
+
 msgid "use stateless RPC protocol"
 msgstr "протокол без сохранения состояния для RPC"
 
@@ -11125,7 +11419,8 @@ msgstr "git log --pretty=short | git shortlog [<опции>]"
 msgid "using multiple --group options with stdin is not supported"
 msgstr ""
 
-msgid "using --group=trailer with stdin is not supported"
+#, c-format
+msgid "using %s with stdin is not supported"
 msgstr ""
 
 #, c-format
@@ -11163,7 +11458,8 @@ msgid ""
 "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
 "                [--current] [--color[=<when>] | --no-color] [--sparse]\n"
 "                [--more=<n> | --list | --independent | --merge-base]\n"
-"                [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"
+"                [--no-name | --sha1-name] [--topics]\n"
+"                [(<rev> | <glob>)...]"
 msgstr ""
 
 msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
@@ -11270,11 +11566,10 @@ msgid "Unknown hash algorithm"
 msgstr ""
 
 msgid ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --"
-"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"
+"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
+"             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
+"             [--heads] [--] [<pattern>...]"
 msgstr ""
-"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --"
-"hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<шаблон>...]"
 
 msgid "git show-ref --exclude-existing[=<pattern>]"
 msgstr "git show-ref --exclude-existing[=<шаблон>]"
@@ -11305,7 +11600,9 @@ msgid "show refs from stdin that aren't in local repository"
 msgstr ""
 "вывести ссылки со стандартного ввода, которых нет в локальном репозитории"
 
-msgid "git sparse-checkout (init|list|set|add|reapply|disable) <options>"
+msgid ""
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<options>]"
 msgstr ""
 
 msgid "this worktree is not sparse"
@@ -11413,57 +11710,59 @@ msgstr ""
 msgid "error while refreshing working directory"
 msgstr ""
 
-msgid "git stash list [<options>]"
-msgstr "git stash list [<опции>]"
+msgid ""
+"git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
+"file <file>]"
+msgstr ""
 
-msgid "git stash show [<options>] [<stash>]"
-msgstr "git stash show [<опциии>] [<спрятанные-изменения>]"
+msgid "terminate input and output files by a NUL character"
+msgstr ""
 
-msgid "git stash drop [-q|--quiet] [<stash>]"
-msgstr "git stash drop [-q|--quiet] [<спрятанные-изменения>]"
+msgid "when used with --rules-file interpret patterns as cone mode patterns"
+msgstr ""
 
-msgid "git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"
+msgid "use patterns in <file> instead of the current ones."
 msgstr ""
-"git stash ( pop | apply ) [--index] [-q|--quiet] [<спрятанные-изменения>]"
 
-msgid "git stash branch <branchname> [<stash>]"
-msgstr "git stash branch <имя-ветки> [<спрятанные-изменения>]"
+msgid "git stash list [<log-options>]"
+msgstr ""
 
 msgid ""
-"git stash [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
-"quiet]\n"
-"          [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
-"          [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
-"          [--] [<pathspec>...]]"
+"git stash show [-u | --include-untracked | --only-untracked] [<diff-"
+"options>] [<stash>]"
 msgstr ""
 
-msgid ""
-"git stash save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--"
-"quiet]\n"
-"          [-u|--include-untracked] [-a|--all] [<message>]"
+msgid "git stash drop [-q | --quiet] [<stash>]"
+msgstr ""
+
+msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
 msgstr ""
 
-msgid "git stash pop [--index] [-q|--quiet] [<stash>]"
-msgstr "git stash pop [--index] [-q|--quiet] [<спрятанные-изменения>]"
+msgid "git stash apply [--index] [-q | --quiet] [<stash>]"
+msgstr ""
 
-msgid "git stash apply [--index] [-q|--quiet] [<stash>]"
-msgstr "git stash apply [--index] [-q|--quiet] [<спрятанные-изменения>]"
+msgid "git stash branch <branchname> [<stash>]"
+msgstr "git stash branch <имя-ветки> [<спрятанные-изменения>]"
 
-msgid "git stash store [-m|--message <message>] [-q|--quiet] <commit>"
-msgstr "git stash store [-m|--message <сообщение>] [-q|--quiet] <коммит>"
+msgid "git stash store [(-m | --message) <message>] [-q | --quiet] <commit>"
+msgstr ""
 
 msgid ""
-"git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-"          [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
+"git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
+"| --quiet]\n"
+"          [-u | --include-untracked] [-a | --all] [(-m | --message) "
+"<message>]\n"
+"          [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
 "          [--] [<pathspec>...]]"
 msgstr ""
-"git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-"          [-u|--include-untracked] [-a|--all] [-m|--message <сообщение>]\n"
-"          [--] [<спецификатор-пути>...]]"
 
 msgid ""
-"git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
-"               [-u|--include-untracked] [-a|--all] [<message>]"
+"git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | "
+"--quiet]\n"
+"          [-u | --include-untracked] [-a | --all] [<message>]"
+msgstr ""
+
+msgid "git stash create [<message>]"
 msgstr ""
 
 #, c-format
@@ -11636,18 +11935,16 @@ msgstr "добавить перед каждой строкой символ к
 msgid "Expecting a full ref name, got %s"
 msgstr "Ожидалось полное имя ссылки, а получено %s"
 
+#, c-format
+msgid "could not get a repository handle for submodule '%s'"
+msgstr ""
+
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
 "authoritative upstream."
 msgstr ""
 
-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 "URL для подмодуля по пути «%s» не найден в .gitmodules"
@@ -11675,7 +11972,7 @@ msgstr ""
 msgid "recurse into nested submodules"
 msgstr "проходить вглубь вложенных подмодулей"
 
-msgid "git submodule--helper foreach [--quiet] [--recursive] [--] <command>"
+msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
 msgstr ""
 
 #, c-format
@@ -11697,7 +11994,7 @@ msgstr "Сбой регистрации режима обновления для
 msgid "suppress output for initializing a submodule"
 msgstr ""
 
-msgid "git submodule--helper init [<options>] [<path>]"
+msgid "git submodule init [<options>] [<path>]"
 msgstr ""
 
 #, c-format
@@ -11723,9 +12020,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 ""
@@ -11758,7 +12052,7 @@ msgstr ""
 msgid "limit the summary size"
 msgstr ""
 
-msgid "git submodule--helper summary [<options>] [<commit>] [--] [<path>]"
+msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
 msgstr ""
 
 msgid "could not fetch a revision for HEAD"
@@ -11772,10 +12066,6 @@ msgstr ""
 msgid "failed to register url for submodule path '%s'"
 msgstr ""
 
-#, c-format
-msgid "failed to get the default remote for submodule '%s'"
-msgstr ""
-
 #, c-format
 msgid "failed to update remote for submodule '%s'"
 msgstr ""
@@ -11783,8 +12073,8 @@ msgstr ""
 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 ""
 
 #, c-format
 msgid ""
@@ -11837,6 +12127,10 @@ msgid ""
 "'--reference-if-able' instead of '--reference'."
 msgstr ""
 
+#, c-format
+msgid "could not get a repository handle for gitdir '%s'"
+msgstr ""
+
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
 msgstr "подмодулю «%s» не удалось добавить альтернативу: %s"
@@ -11866,6 +12160,9 @@ msgstr ""
 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 "куда должен быть склонирован новый подмодуль"
 
@@ -11890,10 +12187,6 @@ msgid ""
 "<filter-spec>] --url <url> --path <path>"
 msgstr ""
 
-#, c-format
-msgid "Invalid update mode '%s' for submodule path '%s'"
-msgstr ""
-
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
 msgstr ""
@@ -11963,6 +12256,10 @@ msgid ""
 "of that commit failed."
 msgstr ""
 
+#, c-format
+msgid "could not initialize submodule at path '%s'"
+msgstr ""
+
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
@@ -11971,10 +12268,6 @@ msgstr ""
 "Ветка подмодуля (%s) настроена на наследование ветки из родительского "
 "проекта, но он не находится ни на одной ветке"
 
-#, c-format
-msgid "could not get a repository handle for submodule '%s'"
-msgstr ""
-
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
 msgstr ""
@@ -12006,14 +12299,14 @@ msgstr ""
 msgid "don't fetch new objects from the remote site"
 msgstr ""
 
-msgid "path into the working tree"
-msgstr "путь в рабочем каталоге"
+msgid "use the 'checkout' update strategy (default)"
+msgstr ""
 
-msgid "path into the working tree, across nested submodule boundaries"
-msgstr "путь в рабочем каталоге, в пределах границ подмодуля"
+msgid "use the 'merge' update strategy"
+msgstr ""
 
-msgid "rebase, merge, checkout or none"
-msgstr "rebase, merge, checkout или none"
+msgid "use the 'rebase' update strategy"
+msgstr ""
 
 msgid "create a shallow clone truncated to the specified number of revisions"
 msgstr ""
@@ -12029,6 +12322,9 @@ msgstr ""
 msgid "don't print cloning progress"
 msgstr "вы выводить прогресс клонирования"
 
+msgid "disallow cloning into non-empty directory, implies --init"
+msgstr ""
+
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
 "[-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-"
@@ -12036,34 +12332,13 @@ msgid ""
 "[--] [<path>...]"
 msgstr ""
 
-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 "check if it is safe to write to the .gitmodules file"
-msgstr ""
-
-msgid "unset the config in the .gitmodules file"
-msgstr ""
-
-msgid "git submodule--helper config <name> [<value>]"
-msgstr "git submodule--helper config <имя> [<значение>]"
-
-msgid "git submodule--helper config --unset <name>"
-msgstr "git submodule--helper config --unset <имя>"
-
-msgid "please make sure that the .gitmodules file is in the working tree"
+msgid "git submodule absorbgitdirs [<options>] [<path>...]"
 msgstr ""
 
 msgid "suppress output for setting url of a submodule"
 msgstr ""
 
-msgid "git submodule--helper set-url [--quiet] <path> <newurl>"
+msgid "git submodule set-url [--quiet] <path> <newurl>"
 msgstr ""
 
 msgid "set the default tracking branch to master"
@@ -12072,11 +12347,10 @@ msgstr ""
 msgid "set the default tracking branch"
 msgstr ""
 
-msgid "git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"
+msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
 msgstr ""
 
-msgid ""
-"git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
+msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
 msgstr ""
 
 msgid "--branch or --default required"
@@ -12130,6 +12404,9 @@ msgstr ""
 msgid "unable to checkout submodule '%s'"
 msgstr ""
 
+msgid "please make sure that the .gitmodules file is in the working tree"
+msgstr ""
+
 #, c-format
 msgid "Failed to add submodule '%s'"
 msgstr ""
@@ -12164,7 +12441,7 @@ msgid ""
 "path"
 msgstr ""
 
-msgid "git submodule--helper add [<options>] [--] <repository> [<path>]"
+msgid "git submodule add [<options>] [--] <repository> [<path>]"
 msgstr ""
 
 msgid "Relative path can only be used from the toplevel of the working tree"
@@ -12180,19 +12457,17 @@ msgstr ""
 msgid "'%s' is not a valid submodule name"
 msgstr ""
 
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s не поддерживает параметр --super-prefix"
+msgid "git submodule--helper <command>"
+msgstr ""
 
-#, c-format
-msgid "'%s' is not a valid submodule--helper subcommand"
-msgstr "«%s» не является подкомандой submodule--helper"
+msgid "git symbolic-ref [-m <reason>] <name> <ref>"
+msgstr ""
 
-msgid "git symbolic-ref [<options>] <name> [<ref>]"
-msgstr "git symbolic-ref [<опции>] <имя> [<ссылка>]"
+msgid "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
+msgstr ""
 
-msgid "git symbolic-ref -d [-q] <name>"
-msgstr "git symbolic-ref -d [-q] <имя>"
+msgid "git symbolic-ref --delete [-q] <name>"
+msgstr ""
 
 msgid "suppress error message for non-symbolic (detached) refs"
 msgstr ""
@@ -12204,6 +12479,9 @@ msgstr "удалить символьные ссылки"
 msgid "shorten ref output"
 msgstr "укороченный вывод ссылок"
 
+msgid "recursively dereference (default)"
+msgstr ""
+
 msgid "reason"
 msgstr "причина"
 
@@ -12211,18 +12489,18 @@ msgid "reason of the update"
 msgstr "причина обновления"
 
 msgid ""
-"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
-"        <tagname> [<head>]"
+"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+"        <tagname> [<commit> | <object>]"
 msgstr ""
 
 msgid "git tag -d <tagname>..."
 msgstr "git tag -d <имя-метки>..."
 
 msgid ""
-"git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--"
-"points-at <object>]\n"
-"        [--format=<format>] [--merged <commit>] [--no-merged <commit>] "
-"[<pattern>...]"
+"git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
+"        [--points-at <object>] [--column[=<options>] | --no-column]\n"
+"        [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+"        [--merged <commit>] [--no-merged <commit>] [<pattern>...]"
 msgstr ""
 
 msgid "git tag -v [--format=<format>] <tagname>..."
@@ -12363,6 +12641,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 ""
+
+msgid "invalid blob object from stream"
+msgstr ""
+
 msgid "Unpacking objects"
 msgstr "Распаковка объектов"
 
@@ -12592,8 +12880,10 @@ msgstr "прочитать обновления из стандартного в
 msgid "update the info files from scratch"
 msgstr "обновить информацию о серверах с нуля"
 
-msgid "git upload-pack [<options>] <dir>"
-msgstr "git upload-pack [<опции>] <каталог>"
+msgid ""
+"git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
+"                [--advertise-refs] <directory>"
+msgstr ""
 
 msgid "quit after a single request/response exchange"
 msgstr "выход после обмена одним запросом/ответом"
@@ -12607,8 +12897,8 @@ msgstr "не проверять <каталог>/.git/ если <каталог>
 msgid "interrupt transfer after <n> seconds of inactivity"
 msgstr "прервать передачу после <кол> секунд простоя"
 
-msgid "git verify-commit [-v | --verbose] <commit>..."
-msgstr "git verify-commit [-v | --verbose] <коммит>..."
+msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
+msgstr ""
 
 msgid "print commit contents"
 msgstr "вывести содержимое коммита"
@@ -12616,8 +12906,8 @@ msgstr "вывести содержимое коммита"
 msgid "print raw gpg status output"
 msgstr "выводить сырой вывод статуса от gpg"
 
-msgid "git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."
-msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] <пакет>..."
+msgid "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
+msgstr ""
 
 msgid "verbose"
 msgstr "быть многословнее"
@@ -12625,35 +12915,37 @@ msgstr "быть многословнее"
 msgid "show statistics only"
 msgstr "вывести только статистику"
 
-msgid "git verify-tag [-v | --verbose] [--format=<format>] <tag>..."
-msgstr "git verify-tag [-v | --verbose] [--format=<формат>] <метка>..."
+msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
+msgstr ""
 
 msgid "print tag contents"
 msgstr "вывести содержимое метки"
 
-msgid "git worktree add [<options>] <path> [<commit-ish>]"
-msgstr "git worktree add [<опции>] <путь> [<указатель-коммита>]"
+msgid ""
+"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
+"                 [-b <new-branch>] <path> [<commit-ish>]"
+msgstr ""
 
-msgid "git worktree list [<options>]"
-msgstr "git worktree list [<опции>]"
+msgid "git worktree list [-v | --porcelain [-z]]"
+msgstr ""
 
-msgid "git worktree lock [<options>] <path>"
-msgstr "git worktree lock [<опции>] <путь>"
+msgid "git worktree lock [--reason <string>] <worktree>"
+msgstr ""
 
 msgid "git worktree move <worktree> <new-path>"
 msgstr "git worktree move <рабочий-каталог> <новый-путь>"
 
-msgid "git worktree prune [<options>]"
-msgstr "git worktree prune [<опции>]"
+msgid "git worktree prune [-n] [-v] [--expire <expire>]"
+msgstr ""
 
-msgid "git worktree remove [<options>] <worktree>"
-msgstr "git worktree remove [<опции>] <рабочий-каталог>"
+msgid "git worktree remove [-f] <worktree>"
+msgstr ""
 
 msgid "git worktree repair [<path>...]"
 msgstr ""
 
-msgid "git worktree unlock <path>"
-msgstr "git worktree unlock <путь>"
+msgid "git worktree unlock <worktree>"
+msgstr ""
 
 #, c-format
 msgid "Removing %s/%s: %s"
@@ -12722,7 +13014,7 @@ msgstr "Готовится рабочая копия (отсоединённый
 
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
-"переключиться на <ветка> даже если она уже активна в другом рабочесм каталоге"
+"переключиться на <ветка> даже если она уже активна в другом рабочем каталоге"
 
 msgid "create a new branch"
 msgstr "создать новую ветку"
@@ -12866,6 +13158,62 @@ msgstr "вывести объект дерева для подкаталога 
 msgid "only useful for debugging"
 msgstr "используется только при отладке"
 
+msgid "core.fsyncMethod = batch is unsupported on this platform"
+msgstr ""
+
+#, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr ""
+
+#, c-format
+msgid "bundle list at '%s' has no mode"
+msgstr ""
+
+msgid "failed to create temporary file"
+msgstr ""
+
+msgid "insufficient capabilities"
+msgstr ""
+
+#, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr ""
+
+msgid "failed to store maximum creation token"
+msgstr ""
+
+#, c-format
+msgid "unrecognized bundle mode from URI '%s'"
+msgstr ""
+
+#, c-format
+msgid "exceeded bundle URI recursion limit (%d)"
+msgstr ""
+
+#, c-format
+msgid "failed to download bundle from URI '%s'"
+msgstr ""
+
+#, c-format
+msgid "file at URI '%s' is not a bundle or bundle list"
+msgstr ""
+
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr ""
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr ""
+
+msgid "bundle-uri: got an empty line"
+msgstr ""
+
+msgid "bundle-uri: line is not of the form 'key=value'"
+msgstr ""
+
+msgid "bundle-uri: line has empty key or value"
+msgstr ""
+
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
 msgstr ""
@@ -12888,6 +13236,11 @@ msgstr "В репозитории отсутствуют необходимые
 msgid "need a repository to verify a bundle"
 msgstr ""
 
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -13072,6 +13425,9 @@ msgstr "Очень простой сервер для Git репозиторие
 msgid "Give an object a human readable name based on an available ref"
 msgstr "Присвоение объекту удобочитаемое имя на основе доступной ссылки"
 
+msgid "Generate a zip archive of diagnostic information"
+msgstr ""
+
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "Вывод разницы между коммитами, коммитом и рабочим каталогом и т.д."
 
@@ -13205,8 +13561,8 @@ 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 "Запуск инструментов разрешения конфликтов слияния"
@@ -13405,6 +13761,9 @@ msgstr "Проверка файлов упакованных архивов Git"
 msgid "Check the GPG signature of tags"
 msgstr "Проверка подписи GPG меток"
 
+msgid "Display version information about Git"
+msgstr ""
+
 msgid "Show logs with difference each commit introduces"
 msgstr "Вывод журнала с изменениями, которые вводил каждый из коммитов"
 
@@ -13438,6 +13797,24 @@ msgstr "Полезный минимум команд для каждодневн
 msgid "Frequently asked questions about using Git"
 msgstr ""
 
+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"
 
@@ -13459,19 +13836,34 @@ msgstr "Определение свойств подмодулей"
 msgid "Git namespaces"
 msgstr "Пространства имён Git"
 
-msgid "Helper programs to interact with remote repositories"
+msgid "Protocol v0 and v1 capabilities"
 msgstr ""
 
-msgid "Git Repository Layout"
-msgstr "Содержимое репозитория Git"
+msgid "Things common to various protocols"
+msgstr ""
 
-msgid "Specifying revisions and ranges for Git"
-msgstr "Указание редакций и диапазонов для Git"
+msgid "Git HTTP-based protocols"
+msgstr ""
 
-msgid "Mounting one repository inside another"
+msgid "How packs are transferred over-the-wire"
 msgstr ""
 
-msgid "A tutorial introduction to Git"
+msgid "Git Wire Protocol, Version 2"
+msgstr ""
+
+msgid "Helper programs to interact with remote repositories"
+msgstr ""
+
+msgid "Git Repository Layout"
+msgstr "Содержимое репозитория Git"
+
+msgid "Specifying revisions and ranges for Git"
+msgstr "Указание редакций и диапазонов для Git"
+
+msgid "Mounting one repository inside another"
+msgstr ""
+
+msgid "A tutorial introduction to Git"
 msgstr "Обучающее введение в Git"
 
 msgid "A tutorial introduction to Git: part two"
@@ -13483,6 +13875,9 @@ msgstr "Веб интерфейс Git (веб-интерфейс для Git ре
 msgid "An overview of recommended workflows with Git"
 msgstr "Обзор рекомендуемых последовательностей выполняемых действий с Git"
 
+msgid "A tool for managing large Git repositories"
+msgstr ""
+
 msgid "commit-graph file is too small"
 msgstr "файл commit-graph слишком маленький"
 
@@ -13723,6 +14118,14 @@ msgstr ""
 msgid "no libc information available\n"
 msgstr ""
 
+#, c-format
+msgid "could not determine free disk size for '%s'"
+msgstr ""
+
+#, c-format
+msgid "could not get info for '%s'"
+msgstr ""
+
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
 msgstr ""
@@ -13747,6 +14150,10 @@ msgstr ""
 msgid "health thread wait failed [GLE %ld]"
 msgstr ""
 
+#, c-format
+msgid "Invalid path: %s"
+msgstr ""
+
 msgid "Unable to create FSEventStream."
 msgstr ""
 
@@ -13777,6 +14184,30 @@ msgstr ""
 msgid "could not read directory changes [GLE %ld]"
 msgstr ""
 
+#, c-format
+msgid "opendir('%s') failed"
+msgstr ""
+
+#, c-format
+msgid "lstat('%s') failed"
+msgstr ""
+
+#, c-format
+msgid "strbuf_readlink('%s') failed"
+msgstr ""
+
+#, c-format
+msgid "closedir('%s') failed"
+msgstr ""
+
+#, c-format
+msgid "[GLE %ld] unable to open for read '%ls'"
+msgstr ""
+
+#, c-format
+msgid "[GLE %ld] unable to get protocol information for '%ls'"
+msgstr ""
+
 #, c-format
 msgid "failed to copy SID (%ld)"
 msgstr ""
@@ -14047,7 +14478,7 @@ msgstr ""
 msgid "bad zlib compression level %d"
 msgstr "неправильный уровень сжатия zlib %d"
 
-msgid "core.commentChar should only be one character"
+msgid "core.commentChar should only be one ASCII character"
 msgstr ""
 
 #, c-format
@@ -14158,6 +14589,10 @@ msgstr "не удалось установить «%s» в «%s»"
 msgid "invalid section name: %s"
 msgstr ""
 
+#, c-format
+msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
+msgstr ""
+
 #, c-format
 msgid "missing value for '%s'"
 msgstr ""
@@ -14213,15 +14648,22 @@ msgid "unknown object format '%s' specified by server"
 msgstr ""
 
 #, c-format
-msgid "invalid ls-refs response: %s"
+msgid "error on bundle-uri response line %d: %s"
 msgstr ""
 
-msgid "expected flush after ref listing"
+msgid "expected flush after bundle-uri listing"
 msgstr ""
 
 msgid "expected response end packet after ref listing"
 msgstr ""
 
+#, c-format
+msgid "invalid ls-refs response: %s"
+msgstr ""
+
+msgid "expected flush after ref listing"
+msgstr ""
+
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr ""
@@ -14305,175 +14747,6 @@ msgstr "сбой записи в rev-list"
 msgid "failed to close rev-list's stdin"
 msgstr "сбой закрытия стандартного ввода у rev-list"
 
-#, c-format
-msgid "'%s' does not exist"
-msgstr "«%s» не существует"
-
-msgid "need a working directory"
-msgstr ""
-
-msgid "could not find enlistment root"
-msgstr ""
-
-#, c-format
-msgid "could not switch to '%s'"
-msgstr ""
-
-#, c-format
-msgid "could not configure %s=%s"
-msgstr ""
-
-msgid "could not configure log.excludeDecoration"
-msgstr ""
-
-msgid "Scalar enlistments require a worktree"
-msgstr ""
-
-#, c-format
-msgid "could not open directory '%s'"
-msgstr "не удалось открыть каталог «%s»"
-
-#, c-format
-msgid "skipping '%s', which is neither file nor directory"
-msgstr ""
-
-#, c-format
-msgid "could not determine free disk size for '%s'"
-msgstr ""
-
-#, c-format
-msgid "could not get info for '%s'"
-msgstr ""
-
-#, c-format
-msgid "remote HEAD is not a branch: '%.*s'"
-msgstr ""
-
-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 ""
-
-#, c-format
-msgid "cannot deduce worktree name from '%s'"
-msgstr ""
-
-#, c-format
-msgid "directory '%s' exists already"
-msgstr ""
-
-#, c-format
-msgid "failed to get default branch for '%s'"
-msgstr ""
-
-#, c-format
-msgid "could not configure remote in '%s'"
-msgstr ""
-
-#, c-format
-msgid "could not configure '%s'"
-msgstr ""
-
-msgid "partial clone failed; attempting full clone"
-msgstr ""
-
-msgid "could not configure for full clone"
-msgstr ""
-
-msgid "scalar diagnose [<enlistment>]"
-msgstr ""
-
-#, c-format
-msgid "could not create directory for '%s'"
-msgstr ""
-
-msgid "could not duplicate stdout"
-msgstr ""
-
-msgid "failed to write archive"
-msgstr ""
-
-msgid "`scalar list` does not take arguments"
-msgstr ""
-
-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 ""
-
-#, c-format
-msgid "git repository gone in '%s'"
-msgstr ""
-
-msgid ""
-"scalar run <task> [<enlistment>]\n"
-"Tasks:\n"
-msgstr ""
-
-#, c-format
-msgid "no such task: '%s'"
-msgstr ""
-
-msgid "scalar unregister [<enlistment>]"
-msgstr ""
-
-msgid "scalar delete <enlistment>"
-msgstr ""
-
-msgid "refusing to delete current working directory"
-msgstr ""
-
-msgid "include Git version"
-msgstr ""
-
-msgid "include Git's build options"
-msgstr ""
-
-msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr ""
-
-msgid "-C requires a <directory>"
-msgstr ""
-
-#, c-format
-msgid "could not change to '%s'"
-msgstr ""
-
-msgid "-c requires a <key>=<value> argument"
-msgstr ""
-
-msgid ""
-"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
-"\n"
-"Commands:\n"
-msgstr ""
-
 #, c-format
 msgid "illegal crlf_action %d"
 msgstr ""
@@ -14689,6 +14962,32 @@ msgstr ""
 msgid "Marked %d islands, done.\n"
 msgstr ""
 
+#, c-format
+msgid "invalid --%s value '%s'"
+msgstr ""
+
+#, c-format
+msgid "could not archive missing directory '%s'"
+msgstr ""
+
+#, c-format
+msgid "could not open directory '%s'"
+msgstr "не удалось открыть каталог «%s»"
+
+#, c-format
+msgid "skipping '%s', which is neither file nor directory"
+msgstr ""
+
+msgid "could not duplicate stdout"
+msgstr ""
+
+#, c-format
+msgid "could not add directory '%s' to archiver"
+msgstr ""
+
+msgid "failed to write archive"
+msgstr ""
+
 msgid "--merge-base does not work with ranges"
 msgstr ""
 
@@ -14951,6 +15250,9 @@ msgstr ""
 msgid "do not show any source or destination prefix"
 msgstr ""
 
+msgid "use default prefixes a/ and b/"
+msgstr ""
+
 msgid "show context between diff hunks up to the specified number of lines"
 msgstr ""
 
@@ -15238,6 +15540,14 @@ msgstr "не удалось переместить каталог git с «%s»
 msgid "hint: Waiting for your editor to close the file...%c"
 msgstr "подсказка: Ожидание, пока вы закроете редактор с файлом...%c"
 
+#, c-format
+msgid "could not write to '%s'"
+msgstr "не удалось записать в «%s»"
+
+#, c-format
+msgid "could not edit '%s'"
+msgstr ""
+
 msgid "Filtering content"
 msgstr "Фильтруется содержимое"
 
@@ -15269,6 +15579,9 @@ msgstr "git fetch-pack: ожидается ACK/NAK, а получено «%s»"
 msgid "unable to write to remote"
 msgstr ""
 
+msgid "Server supports filter"
+msgstr "Сервер поддерживает фильтрацию"
+
 #, c-format
 msgid "invalid shallow line: %s"
 msgstr "неправильная строка частичного получения: %s"
@@ -15379,9 +15692,6 @@ msgstr ""
 msgid "Server does not support shallow requests"
 msgstr "Сервер не поддерживает частичные запросы"
 
-msgid "Server supports filter"
-msgstr "Сервер поддерживает фильтрацию"
-
 msgid "unable to write request to remote"
 msgstr ""
 
@@ -15403,14 +15713,12 @@ msgstr ""
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
-#.
 #, c-format
 msgid "expected packfile to be sent after '%s'"
 msgstr ""
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
-#.
 #, c-format
 msgid "expected no other sections to be sent after no '%s'"
 msgstr ""
@@ -15481,7 +15789,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"
+"socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
+"sockets support"
 msgstr ""
 
 msgid ""
@@ -15490,8 +15799,7 @@ msgid ""
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-"           [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-"           <command> [<args>]"
+"           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
 
 msgid ""
@@ -15519,15 +15827,15 @@ msgid "no namespace given for --namespace\n"
 msgstr ""
 
 #, c-format
-msgid "no prefix given for --super-prefix\n"
+msgid "-c expects a configuration string\n"
 msgstr ""
 
 #, c-format
-msgid "-c expects a configuration string\n"
+msgid "no config key given for --config-env\n"
 msgstr ""
 
 #, c-format
-msgid "no config key given for --config-env\n"
+msgid "no attribute source given for --attr-source\n"
 msgstr ""
 
 #, c-format
@@ -15626,8 +15934,11 @@ msgstr ""
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
 msgstr ""
 
-msgid "gpg failed to sign the data"
-msgstr "gpg не удалось подписать данные"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
 
 msgid "user.signingKey needs to be set for ssh signing"
 msgstr ""
@@ -15706,6 +16017,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»"
@@ -15719,6 +16036,12 @@ msgstr "Стандартные команды Git используемые в р
 msgid "The Git concept guides are:"
 msgstr ""
 
+msgid "User-facing repository, command and file interfaces:"
+msgstr ""
+
+msgid "File formats, protocols and other developer interfaces:"
+msgstr ""
+
 msgid "External commands"
 msgstr ""
 
@@ -15778,8 +16101,8 @@ msgstr[3] ""
 "\n"
 "Самые похожие команды:"
 
-msgid "git version [<options>]"
-msgstr "git version [<options>]"
+msgid "git version [--build-options]"
+msgstr ""
 
 #, c-format
 msgid "%s: %s - %s"
@@ -15814,10 +16137,6 @@ msgstr ""
 "Вы можете отключить это предупреждение с помощью команды «git config advice."
 "ignoredHook false»."
 
-#, c-format
-msgid "Couldn't start hook '%s'\n"
-msgstr ""
-
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
 msgstr ""
@@ -16001,16 +16320,14 @@ msgstr ""
 msgid "quoted CRLF detected"
 msgstr ""
 
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-"  %s"
-msgstr ""
-
 #, 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 ""
+
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
 msgstr "Не удалось слить подмодуль %s (нет коммитов)"
@@ -16029,24 +16346,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"Failed to merge submodule %s, but a possible merge resolution exists:\n"
-"%s\n"
-msgstr ""
-
-#, 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 ""
-"Если оно верное, то просто добавьте его в индекс, например так:\n"
-"\n"
-"  git update-index --cacheinfo 160000 %s \"%s\"\n"
-"\n"
-"тем самым принимая это предположение.\n"
 
 #, c-format
 msgid ""
@@ -16174,15 +16475,33 @@ msgid ""
 "of %s left in tree."
 msgstr ""
 
+#. 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 ""
+
+#, 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 ""
 
 #. TRANSLATORS: The %s arguments are: 1) tree hash of a merge
 #. base, and 2-3) the trees for the two trees we're merging.
-#.
 #, c-format
 msgid "collecting merge info failed for trees %s, %s, %s"
 msgstr ""
@@ -16248,6 +16567,21 @@ msgstr "Не удалось слить подмодуль %s (нельзя сд
 msgid "Found a possible merge resolution for the submodule:\n"
 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 (найдено несколько слияний)"
@@ -16316,8 +16650,8 @@ msgstr "Отказ потери неотслеживаемого файла %s;
 
 #, 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 ""
 "КОНФЛИКТ (переименование/переименование): Переименование «%s»→«%s» в ветке "
 "«%s» и переименование «%s»→«%s» в ветке «%s»%s"
@@ -16612,7 +16946,6 @@ msgstr "Отказ в перезаписи заметок в %s (за преде
 #. TRANSLATORS: The first %s is the name of
 #. the environment variable, the second %s is
 #. its value.
-#.
 #, c-format
 msgid "Bad %s value: '%s'"
 msgstr "Неправильное значение переменной %s: «%s»"
@@ -16629,10 +16962,6 @@ msgstr ""
 msgid "%s: ignoring alternate object stores, nesting too deep"
 msgstr ""
 
-#, c-format
-msgid "unable to normalize object directory: %s"
-msgstr ""
-
 msgid "unable to fdopen alternates lockfile"
 msgstr ""
 
@@ -16691,6 +17020,10 @@ msgstr ""
 msgid "garbage at end of loose object '%s'"
 msgstr ""
 
+#, c-format
+msgid "unable to open loose object %s"
+msgstr ""
+
 #, c-format
 msgid "unable to parse %s header"
 msgstr ""
@@ -16707,17 +17040,13 @@ msgid "header for %s too long, exceeds %d bytes"
 msgstr ""
 
 #, c-format
-msgid "failed to read object %s"
+msgid "loose object %s (stored in %s) is corrupt"
 msgstr ""
 
 #, c-format
 msgid "replacement %s not found for %s"
 msgstr ""
 
-#, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr ""
-
 #, c-format
 msgid "packed object %s (stored in %s) is corrupt"
 msgstr ""
@@ -16730,9 +17059,6 @@ msgstr ""
 msgid "unable to set permission to '%s'"
 msgstr ""
 
-msgid "file write error"
-msgstr ""
-
 msgid "error when closing loose object file"
 msgstr ""
 
@@ -16758,14 +17084,31 @@ msgstr ""
 msgid "confused by unstable object source data for %s"
 msgstr ""
 
+#, c-format
+msgid "write stream object %ld != %<PRIuMAX>"
+msgstr ""
+
+#, c-format
+msgid "unable to stream deflate new object (%d)"
+msgstr ""
+
+#, c-format
+msgid "deflateEnd on stream object failed (%d)"
+msgstr ""
+
+#, c-format
+msgid "unable to create directory %s"
+msgstr ""
+
 #, c-format
 msgid "cannot read object for %s"
 msgstr ""
 
-msgid "corrupt commit"
+#, c-format
+msgid "object fails fsck: %s"
 msgstr ""
 
-msgid "corrupt tag"
+msgid "refusing to create malformed object"
 msgstr ""
 
 #, c-format
@@ -16815,7 +17158,6 @@ msgstr ""
 #. TRANSLATORS: This is a line of ambiguous object
 #. output shown when we cannot look up or parse the
 #. object in question. E.g. "deadbeef [bad object]".
-#.
 #, c-format
 msgid "%s [bad object]"
 msgstr ""
@@ -16824,7 +17166,6 @@ msgstr ""
 #. object output. E.g.:
 #. *
 #.    "deadbeef commit 2021-01-01 - Some Commit Message"
-#.
 #, c-format
 msgid "%s commit %s - %s"
 msgstr ""
@@ -16839,7 +17180,6 @@ msgstr ""
 #. *
 #. The third argument is the "tag" string
 #. from object.c.
-#.
 #, c-format
 msgid "%s tag %s - %s"
 msgstr ""
@@ -16849,21 +17189,18 @@ msgstr ""
 #. the tag itself. E.g.:
 #. *
 #.    "deadbeef [bad tag, could not parse it]"
-#.
 #, c-format
 msgid "%s [bad tag, could not parse it]"
 msgstr ""
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef tree".
-#.
 #, c-format
 msgid "%s tree"
 msgstr ""
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef blob".
-#.
 #, c-format
 msgid "%s blob"
 msgstr ""
@@ -16875,7 +17212,6 @@ msgstr ""
 #. TRANSLATORS: The argument is the list of ambiguous
 #. objects composed in show_ambiguous_object(). See
 #. its "TRANSLATORS" comments for details.
-#.
 #, c-format
 msgid ""
 "The candidates are:\n"
@@ -16929,57 +17265,154 @@ msgid ""
 msgstr ""
 
 #, c-format
-msgid "path '%s' exists on disk, but not in the index"
+msgid "path '%s' exists on disk, but not in the index"
+msgstr ""
+
+#, c-format
+msgid "path '%s' does not exist (neither on disk nor in the index)"
+msgstr ""
+
+msgid "relative path syntax can't be used outside working tree"
+msgstr ""
+
+#, c-format
+msgid "<object>:<path> required, only <object> '%s' given"
+msgstr ""
+
+#, c-format
+msgid "invalid object name '%.*s'."
+msgstr ""
+
+#, c-format
+msgid "invalid object type \"%s\""
+msgstr ""
+
+#, c-format
+msgid "object %s is a %s, not a %s"
+msgstr ""
+
+#, c-format
+msgid "object %s has unknown type id %d"
+msgstr ""
+
+#, 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 ""
+
+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 ""
+
+#, c-format
+msgid "corrupt ewah bitmap: truncated header for entry %d"
+msgstr ""
+
+#, c-format
+msgid "corrupt ewah bitmap: commit index %u out of range"
+msgstr ""
+
+msgid "corrupted bitmap pack index"
+msgstr ""
+
+msgid "invalid XOR offset in bitmap pack index"
+msgstr ""
+
+msgid "cannot fstat bitmap file"
+msgstr ""
+
+msgid "checksum doesn't match in MIDX and bitmap"
+msgstr ""
+
+msgid "multi-pack bitmap is missing required reverse index"
+msgstr ""
+
+#, c-format
+msgid "could not open pack %s"
+msgstr ""
+
+#, c-format
+msgid "preferred pack (%s) is invalid"
 msgstr ""
 
-#, c-format
-msgid "path '%s' does not exist (neither on disk nor in the index)"
+msgid "corrupt bitmap lookup table: triplet position out of index"
 msgstr ""
 
-msgid "relative path syntax can't be used outside working tree"
+msgid "corrupt bitmap lookup table: xor chain exceeds entry count"
 msgstr ""
 
 #, c-format
-msgid "<object>:<path> required, only <object> '%s' given"
+msgid "corrupt bitmap lookup table: commit index %u out of range"
 msgstr ""
 
 #, c-format
-msgid "invalid object name '%.*s'."
+msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""
 msgstr ""
 
 #, c-format
-msgid "invalid object type \"%s\""
+msgid "object '%s' not found in type bitmaps"
 msgstr ""
 
 #, c-format
-msgid "object %s is a %s, not a %s"
+msgid "object '%s' does not have a unique type"
 msgstr ""
 
 #, c-format
-msgid "object %s has unknown type id %d"
+msgid "object '%s': real type '%s', expected: '%s'"
 msgstr ""
 
 #, c-format
-msgid "unable to parse object: %s"
-msgstr "не удалось разобрать объект: %s"
+msgid "object not in bitmap: '%s'"
+msgstr ""
+
+msgid "failed to load bitmap indexes"
+msgstr ""
+
+msgid "you must specify exactly one commit to test"
+msgstr ""
 
 #, c-format
-msgid "hash mismatch %s"
-msgstr "несоответствие хэш-кода %s"
+msgid "commit '%s' doesn't have an indexed bitmap"
+msgstr ""
 
-msgid "multi-pack bitmap is missing required reverse index"
+msgid "mismatch in bitmap results"
 msgstr ""
 
 #, c-format
-msgid "could not open pack %s"
+msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>"
 msgstr ""
 
 #, c-format
-msgid "preferred pack (%s) is invalid"
+msgid "unable to get disk usage of '%s'"
 msgstr ""
 
 #, c-format
-msgid "could not find %s in pack %s at offset %<PRIuMAX>"
+msgid "bitmap file '%s' has invalid checksum"
 msgstr ""
 
 #, c-format
@@ -17022,6 +17455,13 @@ msgstr ""
 msgid "reverse-index file %s has unsupported hash id %<PRIu32>"
 msgstr ""
 
+msgid "invalid checksum"
+msgstr ""
+
+#, c-format
+msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
+msgstr ""
+
 msgid "cannot both write and verify reverse index"
 msgstr ""
 
@@ -17104,6 +17544,9 @@ msgstr "имелось в виду `--%s` (с двумя дефисами)?"
 msgid "alias of --%s"
 msgstr ""
 
+msgid "need a subcommand"
+msgstr ""
+
 #, c-format
 msgid "unknown option `%s'"
 msgstr ""
@@ -17125,7 +17568,6 @@ msgstr "использование: %s"
 
 #. TRANSLATORS: the colon here should align with the
 #. one in "usage: %s" translation.
-#.
 #, c-format
 msgid "   or: %s"
 msgstr "          или: %s"
@@ -17148,7 +17590,6 @@ msgstr "          или: %s"
 #. function. The "%s" is a line in the (hopefully already
 #. translated) N_() usage string, which contained embedded
 #. newlines before we split it up.
-#.
 #, c-format
 msgid "%*s%s"
 msgstr ""
@@ -17175,6 +17616,9 @@ msgstr "тихий режим"
 msgid "use <n> digits to display object names"
 msgstr ""
 
+msgid "prefixed path to initial superproject"
+msgstr ""
+
 msgid "how to strip spaces and #comments from message"
 msgstr "как удалять пробелы и #комментарии из сообщения коммита"
 
@@ -17322,6 +17766,10 @@ msgstr ""
 msgid "promisor remote name cannot begin with '/': %s"
 msgstr ""
 
+#, c-format
+msgid "could not fetch %s from promisor remote"
+msgstr ""
+
 msgid "object-info: expected flush after arguments"
 msgstr ""
 
@@ -17537,9 +17985,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 ""
@@ -17636,6 +18087,14 @@ msgstr "позади %d"
 msgid "ahead %d, behind %d"
 msgstr "впереди %d, позади %d"
 
+#, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr ""
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr ""
+
 #, c-format
 msgid "expected format: %%(color:<color>)"
 msgstr "ожидаемый формат: %%(color:<color>)"
@@ -17652,22 +18111,6 @@ msgstr "Ожидается целочисленное значение refname:l
 msgid "Integer value expected refname:rstrip=%s"
 msgstr "Ожидается целочисленное значение refname:rstrip=%s"
 
-#, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "неопознанный аргумент %%(%s): %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr ""
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr ""
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "параметр %%(body) не принимает аргументы"
-
 #, c-format
 msgid "expected %%(trailers:key=<value>)"
 msgstr ""
@@ -17684,10 +18127,6 @@ msgstr "положительное значение ожидает contents:line
 msgid "positive value expected '%s' in %%(%s)"
 msgstr ""
 
-#, c-format
-msgid "unrecognized email option: %s"
-msgstr ""
-
 #, c-format
 msgid "expected format: %%(align:<width>,<position>)"
 msgstr "ожидаемый формат: %%(align:<width>,<position>)"
@@ -17700,12 +18139,16 @@ msgstr "неопознанная позиция:%s"
 msgid "unrecognized width:%s"
 msgstr "неопознанная ширина:%s"
 
+#, c-format
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "неопознанный аргумент %%(%s): %s"
+
 #, c-format
 msgid "positive width expected with the %%(align) atom"
 msgstr "ожидается положительная ширина с указанием частицы %%(align)"
 
 #, c-format
-msgid "%%(rest) does not take arguments"
+msgid "expected format: %%(ahead-behind:<committish>)"
 msgstr ""
 
 #, c-format
@@ -17997,6 +18440,13 @@ msgstr ""
 msgid "http transport does not support %s"
 msgstr ""
 
+msgid "protocol error: expected '<url> <path>', missing space"
+msgstr ""
+
+#, c-format
+msgid "failed to download file at URL '%s'"
+msgstr ""
+
 msgid "git-http-push failed"
 msgstr ""
 
@@ -18063,7 +18513,6 @@ msgstr "src refspec %s соответствует более чем одному
 #. TRANSLATORS: "matches '%s'%" is the <dst> part of "git push
 #. <remote> <src>:<dst>" push, and "being pushed ('%s')" is
 #. the <src>.
-#.
 #, c-format
 msgid ""
 "The destination you provided is not a full refname (i.e.,\n"
@@ -18305,10 +18754,6 @@ msgstr ""
 msgid "no remembered resolution for '%s'"
 msgstr ""
 
-#, c-format
-msgid "cannot unlink '%s'"
-msgstr ""
-
 #, c-format
 msgid "Updated preimage for '%s'"
 msgstr ""
@@ -18332,6 +18777,21 @@ msgstr ""
 msgid "failed to find tree of %s"
 msgstr "не удалось найти дерево для %s"
 
+#, c-format
+msgid "unsupported section for hidden refs: %s"
+msgstr ""
+
+msgid "--exclude-hidden= passed more than once"
+msgstr ""
+
+#, c-format
+msgid "resolve-undo records `%s` which is missing"
+msgstr ""
+
+#, c-format
+msgid "could not get commit for ancestry-path argument %s"
+msgstr ""
+
 msgid "--unpacked=<packfile> no longer supported"
 msgstr ""
 
@@ -18352,6 +18812,175 @@ msgstr ""
 msgid "cannot create async thread: %s"
 msgstr ""
 
+#, c-format
+msgid "'%s' does not exist"
+msgstr "«%s» не существует"
+
+#, c-format
+msgid "could not switch to '%s'"
+msgstr ""
+
+msgid "need a working directory"
+msgstr ""
+
+msgid "Scalar enlistments require a worktree"
+msgstr ""
+
+#, c-format
+msgid "could not configure %s=%s"
+msgstr ""
+
+msgid "could not configure log.excludeDecoration"
+msgstr ""
+
+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 ""
+
+msgid "could not turn off maintenance"
+msgstr ""
+
+msgid "could not remove enlistment"
+msgstr ""
+
+#, c-format
+msgid "remote HEAD is not a branch: '%.*s'"
+msgstr ""
+
+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 ""
+
+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 ""
+
+#, c-format
+msgid "cannot deduce worktree name from '%s'"
+msgstr ""
+
+#, c-format
+msgid "directory '%s' exists already"
+msgstr ""
+
+#, c-format
+msgid "failed to get default branch for '%s'"
+msgstr ""
+
+#, c-format
+msgid "could not configure remote in '%s'"
+msgstr ""
+
+#, c-format
+msgid "could not configure '%s'"
+msgstr ""
+
+msgid "partial clone failed; attempting full clone"
+msgstr ""
+
+msgid "could not configure for full clone"
+msgstr ""
+
+msgid "scalar diagnose [<enlistment>]"
+msgstr ""
+
+msgid "`scalar list` does not take arguments"
+msgstr ""
+
+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 ""
+
+#, c-format
+msgid "could not remove stale scalar.repo '%s'"
+msgstr ""
+
+#, c-format
+msgid "removing stale scalar.repo '%s'"
+msgstr ""
+
+#, c-format
+msgid "git repository gone in '%s'"
+msgstr ""
+
+msgid ""
+"scalar run <task> [<enlistment>]\n"
+"Tasks:\n"
+msgstr ""
+
+#, c-format
+msgid "no such task: '%s'"
+msgstr ""
+
+msgid "scalar unregister [<enlistment>]"
+msgstr ""
+
+msgid "scalar delete <enlistment>"
+msgstr ""
+
+msgid "refusing to delete current working directory"
+msgstr ""
+
+msgid "include Git version"
+msgstr ""
+
+msgid "include Git's build options"
+msgstr ""
+
+msgid "scalar verbose [-v | --verbose] [--build-options]"
+msgstr ""
+
+msgid "-C requires a <directory>"
+msgstr ""
+
+#, c-format
+msgid "could not change to '%s'"
+msgstr ""
+
+msgid "-c requires a <key>=<value> argument"
+msgstr ""
+
+msgid ""
+"scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]\n"
+"\n"
+"Commands:\n"
+msgstr ""
+
 msgid "unexpected flush packet while reading remote unpack status"
 msgstr "неожиданный пустой пакет при чтении статуса внешней распаковки"
 
@@ -18441,10 +19070,6 @@ msgstr ""
 msgid "could not lock '%s'"
 msgstr "не удалось заблокировать «%s»"
 
-#, c-format
-msgid "could not write to '%s'"
-msgstr "не удалось записать в «%s»"
-
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "не удалось записать eol в «%s»"
@@ -18460,13 +19085,8 @@ 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".
-#.
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: Не удалось записать файл индекса"
@@ -18725,6 +19345,22 @@ msgstr "git %s: сбой чтения индекса"
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: сбой обновления индекса"
 
+#, c-format
+msgid "'%s' is not a valid label"
+msgstr ""
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr ""
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr ""
+
 #, c-format
 msgid "%s does not accept arguments: '%s'"
 msgstr "параметр %s не принимает аргументы: «%s»"
@@ -18795,11 +19431,8 @@ msgstr ""
 msgid "could not create sequencer directory '%s'"
 msgstr "не удалось создать каталог для указателя следования коммитов «%s»"
 
-msgid "could not lock HEAD"
-msgstr "не удалось заблокировать HEAD"
-
 msgid "no cherry-pick or revert in progress"
-msgstr "копиÑ\80ование Ð¸Ð»Ð¸ Ð¾Ð±Ñ\80аÑ\89ение Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ ÐºÐ¾Ð¼Ð¼Ð¸Ñ\82а Ñ\83же выполняются"
+msgstr "копиÑ\80ование Ð¸Ð»Ð¸ Ð¾Ð±Ñ\80аÑ\89ение Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ ÐºÐ¾Ð¼Ð¼Ð¸Ñ\82а Ñ\81ейÑ\87аÑ\81 Ð½е выполняются"
 
 msgid "cannot resolve HEAD"
 msgstr "не удалось определить HEAD"
@@ -18885,39 +19518,33 @@ msgstr ""
 "  git rebase --continue\n"
 "\n"
 
-msgid "and made changes to the index and/or the working tree\n"
-msgstr "и были сделаны изменения в индексе и/или в рабочем каталоге\n"
+msgid "and made changes to the index and/or the working tree.\n"
+msgstr ""
 
 #, c-format
 msgid ""
 "execution succeeded: %s\n"
-"but left changes to the index and/or the working tree\n"
+"but left changes to the index and/or the working tree.\n"
 "Commit or stash your changes, and then run\n"
 "\n"
 "  git rebase --continue\n"
 "\n"
 msgstr ""
-"успешное выполнение: %s\n"
-"но остались изменения в индексе и/или в рабочем каталоге\n"
-"Сделайте коммит или спрячьте ваши изменения, а затем выполните\n"
-"\n"
-"  git rebase --continue\n"
-"\n"
 
 #, c-format
 msgid "illegal label name: '%.*s'"
 msgstr ""
 
+#, c-format
+msgid "could not resolve '%s'"
+msgstr "не удалось распознать «%s»"
+
 msgid "writing fake root commit"
 msgstr "запись поддельного корневого коммита"
 
 msgid "writing squash-onto"
 msgstr "запить уплотнить-над"
 
-#, c-format
-msgid "could not resolve '%s'"
-msgstr "не удалось распознать «%s»"
-
 msgid "cannot merge without a current revision"
 msgstr "нельзя слить без текущей редакции"
 
@@ -18943,6 +19570,23 @@ 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 ""
+
+#, c-format
+msgid ""
+"Updated the following refs with %s:\n"
+"%s"
+msgstr ""
+
+#, c-format
+msgid ""
+"Failed to update the following refs with %s:\n"
+"%s"
+msgstr ""
+
 msgid "Cannot autostash"
 msgstr "Не удалось автоматически спрятать изменения"
 
@@ -19099,6 +19743,10 @@ msgstr ""
 msgid "the script was already rearranged."
 msgstr "сценарий уже был перестроен."
 
+#, c-format
+msgid "update-refs file at '%s' is invalid"
+msgstr ""
+
 #, c-format
 msgid "'%s' is outside repository at '%s'"
 msgstr ""
@@ -19225,12 +19873,16 @@ 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 ""
 
+#, c-format
+msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')"
+msgstr ""
+
 #, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
@@ -19298,16 +19950,12 @@ msgstr[1] "%u байта/с"
 msgstr[2] "%u байтов/с"
 msgstr[3] "%u байта/с"
 
-#, c-format
-msgid "could not edit '%s'"
-msgstr ""
-
 #, c-format
 msgid "ignoring suspicious submodule name: %s"
 msgstr "игнорирую подозрительный подмодуль с именем: %s"
 
 msgid "negative values not allowed for submodule.fetchJobs"
-msgstr "нельзя использовать отприцательные значения для submodule.fetchJobs"
+msgstr "нельзя использовать отрицательные значения для submodule.fetchJobs"
 
 #, c-format
 msgid "ignoring '%s' which may be interpreted as a command-line option: %s"
@@ -19472,6 +20120,25 @@ msgstr "ls-tree вернул неожиданный код %d"
 msgid "failed to lstat '%s'"
 msgstr ""
 
+msgid "no remote configured to get bundle URIs from"
+msgstr ""
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr ""
+
+msgid "could not get the bundle-uri list"
+msgstr ""
+
+msgid "test-tool cache-tree <options> (control|prime|update)"
+msgstr ""
+
+msgid "clear the cache tree before each iteration"
+msgstr ""
+
+msgid "number of entries in the cache tree to invalidate (default 0)"
+msgstr ""
+
 msgid "unhandled options"
 msgstr ""
 
@@ -19806,6 +20473,12 @@ msgstr "Прерываю."
 msgid "failed to push all needed submodules"
 msgstr ""
 
+msgid "bundle-uri operation not supported by protocol"
+msgstr ""
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr ""
+
 msgid "too-short tree object"
 msgstr "слишком  короткий объект дерева"
 
@@ -20077,6 +20750,18 @@ msgstr "неправильный номер порта"
 msgid "invalid '..' path segment"
 msgstr "неправильная часть пути «..»"
 
+msgid "usage: "
+msgstr ""
+
+msgid "fatal: "
+msgstr ""
+
+msgid "error: "
+msgstr ""
+
+msgid "warning: "
+msgstr ""
+
 msgid "Fetching objects"
 msgstr ""
 
@@ -20530,14 +21215,16 @@ msgstr "Игнорируемые файлы"
 
 #, c-format
 msgid ""
-"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-"may speed it up, but you have to be careful not to forget to add\n"
-"new files yourself (see 'git help status')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
+msgstr ""
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr ""
+
+msgid "See 'git help status' for information on how to improve this."
 msgstr ""
-"%.2f сек занял вывод списка неотслеживаемых файлов.\n"
-"«status -uno» возможно ускорит это, но будьте внимательны\n"
-"и не забудьте добавить новые файлы вручную\n"
-"(смотрите «git help status» для подробностей)."
 
 #, c-format
 msgid "Untracked files not listed%s"
@@ -20687,296 +21374,6 @@ msgstr "Вам нужно запускать эту команду находя
 msgid "Unable to determine absolute path of git directory"
 msgstr "Не удалось определить абсолютный путь к каталогу git"
 
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%12s %12s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "тронут %d путь\n"
-msgstr[1] "тронуты %d пути\n"
-msgstr[2] "тронуты %d путей\n"
-msgstr[3] "тронуты %d пути\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Если патч применяется без ошибок, то изменённый блок будет сразу помечен для "
-"индексирования."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Если патч применяется без ошибок, то изменённый блок будет сразу помечен для "
-"прятанья."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Если патч применяется без ошибок, то изменённый блок будет сразу помечен для "
-"убирания из индекса."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Если патч применяется без ошибок, то изменённый блок будет сразу помечен для "
-"применения."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Если патч применяется без ошибок, то изменённый блок будет сразу помечен для "
-"отмены изменений."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "не удалось открыть файл редактирования блока изменений для записи: %s"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"---\n"
-"Чтобы удалить «%s» строки, сделайте их ' ' строками (контекст).\n"
-"Чтобы удалить «%s» строки, удалите их.\n"
-"Строки, начинающиеся с %s будут удалены.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr "не удалось открыть файл редактирования блока изменений для чтения: %s"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - индексировать этот блок\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все оставшиеся блоки\n"
-"a - индексировать этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y - спрятать этот блок\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - спрятать этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y - убрать из индекса этот блок\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - убрать из индекса этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - принять этот блок в индекс\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - принять этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - отбросить этот блок из рабочего дерева\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - отбросить этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y - отбросить этот блок из индекса и рабочего дерева\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - отбросить этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - принять этот блок в индекс и рабочее дерево\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - принять этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y - принять этот блок в рабочее дерево\n"
-"n - пропустить этот блок\n"
-"q - выход; пропустить этот и все последующие блоки\n"
-"a - принять этот и остальные блоки файла\n"
-"d - пропустить этот и остальные блоки файла"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g - выбрать блок изменений на который нужно перейти\n"
-"/ - поиск блока изменений с помощью регулярного выражения\n"
-"j - не принимать решение по этому блоку, перейти на следующий нерешенный\n"
-"J - не принимать решение по этому блоку, перейти на следующий\n"
-"k - не принимать решение по этому блоку, перейти на предыдущий нерешенный\n"
-"K - не принимать решение по этому блоку, перейти на предыдущий\n"
-"s - разделить текущий блок на блоки меньшего размера\n"
-"e - вручную отредактировать текущий блок\n"
-"? - вывести справку\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Выбранные блоки не применяются без ошибок к индексу!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "игнорирую не слитое: %s\n"
-
-#, perl-format
-msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
-#, perl-format
-msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
-#, perl-format
-msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-
-#, 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 ""
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Неверный номер: «%s»\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Простите, но только %d блок изменений доступен.\n"
-msgstr[1] "Простите, но только %d блока изменений доступно.\n"
-msgstr[2] "Простите, но только %d блоков изменений доступно.\n"
-msgstr[3] "Простите, но только %d блока изменений доступно.\n"
-
-msgid "No other hunks to search\n"
-msgstr ""
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Регулярное выражение для поиска в неверном формате %s: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Не найдены блоки, которые соответствуют указанному шаблону\n"
-
-msgid "No previous hunk\n"
-msgstr "Нет предыдущего блока\n"
-
-msgid "No next hunk\n"
-msgstr "Не следующего блока\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr ""
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Разбито на %d блок изменений.\n"
-msgstr[1] "Разбито на %d блока изменений.\n"
-msgstr[2] "Разбито на %d блоков изменений.\n"
-msgstr[3] "Разбито на %d блока изменений.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr ""
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status        - show paths with changes\n"
-"update        - add working tree state to the staged set of changes\n"
-"revert        - revert staged set of changes back to the HEAD version\n"
-"patch         - pick hunks and update selectively\n"
-"diff          - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status        - показать пути с изменениями\n"
-"update        - добавить состояние рабочей копии в индекс\n"
-"revert        - вернуть проиндексированный набор изменений к HEAD-версии\n"
-"patch         - выбрать и выборочно обновить блоки\n"
-"diff          - просмотреть различия между HEAD и индексом\n"
-"add untracked - добавить содержимое неотслеживаемых файлов в индекс\n"
-
-msgid "missing --"
-msgstr "отсутствует --"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "неизвестный режим для --patch: %s"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "недопустимый аргумент %s, ожидается --"
-
 msgid "local zone differs from GMT by a non-minute interval\n"
 msgstr "локальный часовой пояс отличается от GMT на не минутный интервал\n"
 
@@ -21255,13 +21652,17 @@ msgid "(%s) Could not execute '%s'"
 msgstr "(%s) Не удалось выполнить «%s»"
 
 #, perl-format
-msgid "(%s) Adding %s: %s from: '%s'\n"
-msgstr "(%s) Добавление %s: %s из: «%s»\n"
+msgid "(%s) Malformed output from '%s'"
+msgstr ""
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
 msgstr "(%s) не удалось закрыть поток к «%s»"
 
+#, perl-format
+msgid "(%s) Adding %s: %s from: '%s'\n"
+msgstr "(%s) Добавление %s: %s из: «%s»\n"
+
 msgid "cannot send message as 7bit"
 msgstr "не удалось отправить сообщение в 7 битной кодировке"
 
index 284da9061818dc28584d65df2520831953cbb0a0..a14d0d6f38a3daefadd1bda92fddaa751ed807b7 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -5,12 +5,12 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git 2.41.0\n"
+"Project-Id-Version: git 2.42.0\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-31 13:14+0100\n"
-"PO-Revision-Date: 2023-05-31 13:15+0100\n"
+"POT-Creation-Date: 2023-08-16 07:40+0100\n"
+"PO-Revision-Date: 2023-08-16 07:42+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
-"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
+"Language-Team: Svenska <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -619,13 +619,11 @@ msgstr "%stips: %.*s%s\n"
 
 msgid "Cherry-picking is not possible because you have unmerged files."
 msgstr ""
-"Du kan inte utföra en cherry-pick eftersom du har filer som inte slagits "
+"Du kan inte utföra en \"cherry-pick\" eftersom du har filer som inte slagits "
 "samman."
 
 msgid "Committing is not possible because you have unmerged files."
-msgstr ""
-"Du kan inte utföra en incheckning eftersom du har filer som inte slagits "
-"samman."
+msgstr "Du kan inte checka in eftersom du har filer som inte slagits samman."
 
 msgid "Merging is not possible because you have unmerged files."
 msgstr ""
@@ -637,14 +635,10 @@ msgstr ""
 "Du kan inte utföra en \"pull\" eftersom du har filer som inte slagits samman."
 
 msgid "Reverting is not possible because you have unmerged files."
-msgstr ""
-"Du kan inte utföra en \"revert\" eftersom du har filer som inte slagits "
-"samman."
+msgstr "Du kan inte återställa eftersom du har filer som inte slagits samman."
 
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr ""
-"Du kan inte utföra en \"%s\" eftersom du har filer som inte slagits samman."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "Du kan inte ombasera eftersom du har filer som inte slagits samman."
 
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
@@ -790,6 +784,12 @@ msgstr "flaggorna \"%s\" och \"%s\" kan inte användas samtidigt"
 msgid "'%s' outside a repository"
 msgstr "\"%s\" utanför arkiv"
 
+msgid "failed to read patch"
+msgstr "misslyckades läsa patchen"
+
+msgid "patch too large"
+msgstr "patchen är för stor"
+
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Kan inte förbereda reguljärt uttryck för tidsstämpeln %s"
@@ -1689,9 +1689,10 @@ msgid "a branch named '%s' already exists"
 msgstr "det finns redan en gren som heter \"%s\""
 
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
 msgstr ""
-"kan inte tvinga uppdatering av grenen \"%s\" som är utcheckad på \"%s\""
+"kan inte tvinga uppdatering av grenen \"%s\" som används av arbetskatalogen "
+"på \"%s\""
 
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -1760,17 +1761,6 @@ msgstr "git add [<flaggor>] [--] <sökväg>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "kan inte utföra chmod %cx \"%s\""
 
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "diff-status %c förväntades inte"
-
-msgid "updating files failed"
-msgstr "misslyckades uppdatera filer"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "ta bort \"%s\"\n"
-
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Oköade ändringar efter att ha uppdaterat indexet:"
 
@@ -2195,9 +2185,6 @@ msgstr "sänd flaggan -m till git-mailinfo"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "sänd flaggan --keep-cr till git-mailsplit för mbox-formatet"
 
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr "sänd inte flaggan --keep-cr till git-mailsplit oberoende av am.keepcr"
-
 msgid "strip everything before a scissors line"
 msgstr "ta bort allting före en saxlinje"
 
@@ -3235,12 +3222,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
@@ -3286,6 +3273,9 @@ msgstr "som --batch, men mata inte ut <innehåll>"
 msgid "stdin is NUL-terminated"
 msgstr "standard in är NUL-terminerad"
 
+msgid "stdin and stdout is NUL-terminated"
+msgstr "standard in och standard ut är NUL-terminerade"
+
 msgid "read commands from stdin"
 msgstr "läs kommandon från standard in"
 
@@ -4145,12 +4135,6 @@ msgstr "serverspecifik"
 msgid "option to transmit"
 msgstr "flagga att sända"
 
-msgid "use IPv4 addresses only"
-msgstr "använd endast IPv4-adresser"
-
-msgid "use IPv6 addresses only"
-msgstr "använd endast IPv6-adresser"
-
 msgid "apply partial clone filters to submodules"
 msgstr "tillämpa delvisa klonfilter på undermoduler"
 
@@ -4587,6 +4571,9 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+msgid "updating files failed"
+msgstr "misslyckades uppdatera filer"
+
 msgid "failed to unpack HEAD tree object"
 msgstr "misslyckades packa upp HEAD:s trädobjekt"
 
@@ -4646,8 +4633,8 @@ msgstr ""
 "i det befintliga incheckningsmeddelandet"
 
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "kunde inte slå upp incheckningen %s"
+msgid "could not lookup commit '%s'"
+msgstr "kunde inte slå upp incheckningen \"%s\""
 
 #, c-format
 msgid "(reading log message from standard input)\n"
@@ -7243,77 +7230,6 @@ msgstr "--verify angavs utan paketfilnamn"
 msgid "fsck error in pack objects"
 msgstr "fsck-fel i packat objekt"
 
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "kan inte ta status på mallen \"%s\""
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "kan inte öppna katalogen (opendir) \"%s\""
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "kan inte läsa länk (readlink) \"%s\""
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "kan inte skapa symbolisk länk \"%s\" \"%s\""
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "kan inte kopiera \"%s\" till \"%s\""
-
-#, c-format
-msgid "ignoring template %s"
-msgstr "ignorerar mallen %s"
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "mallarna hittades inte i %s"
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "kopierade inte mallar från \"%s\": %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "ogiltigt namn på första gren: \"%s\""
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "kan inte hantera filtyp %d"
-
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "kan inte flytta %s till %s"
-
-msgid "attempt to reinitialize repository with different hash"
-msgstr "försöker initiera arkivet på nytt med annan hash"
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s finns redan"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: ignorerade --initial-branch=%s"
-
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "Ominitierade befintligt delat Git-arkiv i %s%s\n"
-
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "Ominitierade befintligt Git-arkiv i %s%s\n"
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "Initierade tomt delat Git-arkiv i %s%s\n"
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "Initierade tomt Git-arkiv i %s%s\n"
-
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7740,6 +7656,10 @@ 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 "could not get object info about '%s'"
+msgstr "kunde inte hämta objektinfo om \"%s\""
+
 #, c-format
 msgid "bad ls-files format: element '%s' does not start with '('"
 msgstr "felaktigt ls-files-format: elementet \"%s\" börjar inte med \"(\""
@@ -7882,10 +7802,6 @@ msgstr "visa underliggande referens och objektet det pekar på"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<flaggor>] <träd-igt> [<sökväg>...]"
 
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "kunde inte hämta objektinfo om \"%s\""
-
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
 msgstr "felaktigt ls-tree-format: elementet \"%s\" börjar inte med \"(\""
@@ -8612,22 +8528,26 @@ msgid "git notes [--ref <notes-ref>] [list [<object>]]"
 msgstr "git notes [--ref <anteckningsref>] [list [<objekt>]]"
 
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <anteckningsref>] add [-f] [--allow-empty] [-m <medd> | -F "
-"<fil> | (-c | -C) <objekt>] [<objekt>]"
+"git notes [--ref <anteckningsref>] add [-f] [--allow-empty] [--"
+"[no-]separator|--separator=<styckebrytning>] [--[no-]stripspace] [-m <medd> "
+"| -F <fil> | (-c | -C) <objekt>] [<objekt>]"
 
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
 "git notes [--ref <anteckningsref>] copy [-f] <från-objekt> <till-objekt>"
 
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <anteckningsref>] append [--allow-empty] [-m <medd> | -F "
-"<fil> | (-c | -C) <objekt>] [<objekt>]"
+"git notes [--ref <anteckningsref>] append [--allow-empty] [--"
+"[no-]separator|--separator=<styckebrytning>] [--[no-]stripspace] [-m <medd> "
+"| -F <fil> | (-c | -C) <objekt>] [<objekt>]"
 
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
 msgstr "git notes [--ref <anteckningsref>] edit [--allow-empty] [<objekt>]"
@@ -8759,6 +8679,15 @@ msgstr "tillåt lagra tom anteckning"
 msgid "replace existing notes"
 msgstr "ersätt befintliga anteckningar"
 
+msgid "<paragraph-break>"
+msgstr "<styckebrytning>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "sätt in <styckebrytning> mellan stycken"
+
+msgid "remove unnecessary whitespace"
+msgstr "ta bort onödiga blanksteg"
+
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -9306,8 +9235,12 @@ msgstr ""
 msgid "refusing to run without --i-still-use-this"
 msgstr "vägrar köra utan --i-still-use-this"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <mönster>] [--exclude "
+"<mönster>]"
 
 msgid "pack everything"
 msgstr "packa allt"
@@ -9315,6 +9248,12 @@ msgstr "packa allt"
 msgid "prune loose refs (default)"
 msgstr "ta bort lösa referenser (standard)"
 
+msgid "references to include"
+msgstr "referenser att ta med"
+
+msgid "references to exclude"
+msgstr "referenser att utesluta"
+
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
@@ -9372,6 +9311,12 @@ msgstr "tvinga överskrivning av lokal gren"
 msgid "number of submodules pulled in parallel"
 msgstr "antal undermoduler som hämtas parallellt"
 
+msgid "use IPv4 addresses only"
+msgstr "använd endast IPv4-adresser"
+
+msgid "use IPv6 addresses only"
+msgstr "använd endast IPv6-adresser"
+
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
@@ -9632,37 +9577,38 @@ msgstr ""
 
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Uppdateringar avvisades då änden på din befintliga gren är bakom\n"
-"dess fjärrmotsvarighet. Integrera fjärrändringarna (t.ex\n"
-"\"git pull ....\") innan du sänder igen.\n"
+"dess fjärrmotsvarighet. Om du vill integrera fjärrändringarna,\n"
+"använd \"git pull\" innan du sänder igen.\t\n"
 "Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
 
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Uppdateringar avvisades då änden på en gren som sänds in är bakom dess\n"
-"fjärrmotsvarighet. Checka ut grenen och integrera fjärrändringarna (t.ex.\n"
-"\"git pull ...\") innan du sänder igen.\n"
+"fjärrmotsvarighet. Om du vill integrera fjärrändringarna, använd \"git pull"
+"\"\n"
+"innan du sänder igen.\n"
 "Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
 
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Uppdateringar avvisades då fjärren innehåller ändringar som du inte\n"
 "har lokalt. Det beror oftast på att ett annat arkiv har sänt in samma\n"
-"referenser. Det kan vara en idé att först integrera fjärrändringarna\n"
-"(t.ex. \"git pull ...\") innan du sänder igen.\n"
+"referenser. Om du vill integrera fjärrändringarna, använd \"git pull\"\n"
+"innan du sänder igen.\n"
 "Se avsnittet \"Note about fast-forwards\" i \"git push --help\" för detaljer."
 
 msgid "Updates were rejected because the tag already exists in the remote."
@@ -9679,15 +9625,15 @@ msgstr ""
 "\"--force\".\n"
 
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Uppdateringar avvisades då änden på den fjärrspårande grenen\n"
-"har uppdaterats sedan senaste utcheckning. Integrera\n"
-"fjärrändringarna lokalt (t.ex \"git pull ....\") innan du\n"
-"tvingar en uppdatering.\n"
+"Uppdateringar avvisades då änden på din befintliga gren är bakom\n"
+"dess fjärrmotsvarighet. Om du vill integrera fjärrändringarna,\n"
+"använd \"git pull\" innan du sänder igen.\n"
+"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer."
 
 #, c-format
 msgid "Pushing to %s\n"
@@ -10541,11 +10487,12 @@ msgstr "okänt argument till mirror: %s"
 msgid "fetch the remote branches"
 msgstr "hämta fjärrgrenarna"
 
-msgid "import all tags and associated objects when fetching"
-msgstr "importera alla taggar och associerade objekt vid hämtning"
-
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "eller hämta inte några taggar alls (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"importera alla taggar och associerade objekt vid hämtning\n"
+"eller hämta inte några taggar alls (--no-tags)"
 
 msgid "branch(es) to track"
 msgstr "gren(ar) att spåra"
@@ -12467,6 +12414,10 @@ msgstr "Hoppar över ej sammanslagen undermodul %s"
 msgid "Skipping submodule '%s'"
 msgstr "Hoppar över undermodulen \"%s\""
 
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "kan inte klona undermodulen \"%s\" utan en URL"
+
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
 msgstr "Misslyckades klona \"%s\". Nytt försök planlagt"
@@ -13203,10 +13154,11 @@ msgstr "visa innehåll för tag"
 
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <sträng>]]\n"
-"                 [-b <ny-gren>] <sökväg> [<incheckning-igt>]"
+"                 [--orphan] [(-b | -B) <ny-gren>] <sökväg> [<incheckning-"
+"igt>]"
 
 msgid "git worktree list [-v | --porcelain [-z]]"
 msgstr "git worktree list [-v | --porcelain [-z]]"
@@ -13229,6 +13181,37 @@ msgstr "git worktree repair [<sökväg>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <arbetskatalog>"
 
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Ingen möjlig källgren, använder \"--orphan\""
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"Om meningen var att skapa en arbetskatalog från en ny föräldrals\n"
+"gren (gren utan incheckningar) för det här arkivet kan du göra\n"
+"det med flaggan --orphan:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"Om meningen var att skapa en arbetskatalog från en ny föräldrals\n"
+"gren (gren utan incheckningar) för det här arkivet kan du göra\n"
+"det med flaggan --orphan:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #, c-format
 msgid "Removing %s/%s: %s"
 msgstr "Tar bort %s/%s: %s"
@@ -13299,10 +13282,36 @@ msgstr "Förbereder arbetskatalog (återställer gren \"%s\"; var på %s)"
 msgid "Preparing worktree (checking out '%s')"
 msgstr "Förbereder arbetskatalog (checkar ut \"%s\")"
 
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "onåbar: felaktig referens: %s"
+
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "Förbereder arbetskatalog (frånkopplat HEAD %s)"
 
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD pekar på en ogiltig (eller övergiven) referens.\n"
+"HEAD-sökväg: \"%s\"\n"
+"HEAD-innehåll: \"%s\""
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"Ingen lokal eller fjärr-referens finns trots att åtminstone en fjärr\n"
+"finns, avslutar; använd \"add -f\" för att överstyra eller hämta från en "
+"fjärr först"
+
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "\"%s\" och \"%s\" kan inte användas samtidigt"
+
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
 "checka ut <gren> även om den redan är utcheckad i en annan arbetskatalog"
@@ -13313,6 +13322,9 @@ msgstr "skapa en ny gren"
 msgid "create or reset a branch"
 msgstr "skapa eller återställ en gren"
 
+msgid "create unborn/orphaned branch"
+msgstr "skapa en ofödd/övergiven gren"
+
 msgid "populate the new working tree"
 msgstr "befolka den nya arbetskatalogen"
 
@@ -13332,6 +13344,13 @@ msgstr "försök träffa namn på ny gren mot en fjärrspårande gren"
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "flaggorna \"%s\", \"%s\" och \"%s\" kan inte användas samtidigt"
 
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "flaggorna \"%s\" och \"%s\" kan inte användas samtidigt"
+
+msgid "<commit-ish>"
+msgstr "<incheckning-igt>"
+
 msgid "added with --lock"
 msgstr "lagt till med --lock"
 
@@ -13560,6 +13579,14 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "Bunten kräver denna referens:"
 msgstr[1] "Bunten kräver dessa %<PRIuMAX> referenser:"
 
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "Bunten använder denna hashningsalgoritm: %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Bunten använder detta filter. %s"
+
 msgid "unable to dup bundle descriptor"
 msgstr "kan inte duplicera bunthandtag"
 
@@ -13785,8 +13812,8 @@ msgstr "Visa rader som motsvarar mönster"
 msgid "A portable graphical interface to Git"
 msgstr "Ett portabelt grafiskt gränssnitt för Git"
 
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "Beräkna objekt-id och möjligen skapa en blob från en fil"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "Beräkna objekt-ID och möjligen skapa ett objekt från en fil"
 
 msgid "Display help information about Git"
 msgstr "Visa hjälpinformation om Git"
@@ -14192,6 +14219,10 @@ msgstr "incheckningsgrafen har inga bas-graf-stycken"
 msgid "commit-graph chain does not match"
 msgstr "incheckningsgrafens kedja stämmer inte"
 
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "antalet incheckningar i basgrafen för högt: %<PRIuMAX>"
+
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
 msgstr "ogiltig incheckingsgrafkedja: rad \"%s\" är inte ett hash-värde"
@@ -14275,6 +14306,14 @@ msgstr "kunde inte byta namn på bas-incheckingsgraffilen"
 msgid "failed to rename temporary commit-graph file"
 msgstr "kunde inte byta namn på temporär incheckningsgraffil"
 
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "kan inte slå ihop grafer med %<PRIuMAX>, %<PRIuMAX> incheckningar"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "kan inte slå ihop grafen %s, med för många incheckningar: %<PRIuMAX>"
+
 msgid "Scanning merged commits"
 msgstr "Söker sammanslagna incheckningar"
 
@@ -14306,9 +14345,6 @@ msgstr ""
 msgid "failed to parse commit %s from commit-graph"
 msgstr "kunde inte tolka incheckning %s från incheckningsgraf"
 
-msgid "Verifying commits in commit graph"
-msgstr "Bekräftar incheckningar i incheckningsgrafen"
-
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
 msgstr ""
@@ -14357,6 +14393,9 @@ msgstr ""
 "incheckningsdatumet för incheckningen %s i incheckningsgrafen är %<PRIuMAX> !"
 "= %<PRIuMAX>"
 
+msgid "Verifying commits in commit graph"
+msgstr "Bekräftar incheckningar i incheckningsgrafen"
+
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s är inte en incheckning!"
@@ -15301,6 +15340,12 @@ msgstr "ingen sammanslagningsbas hittades"
 msgid "multiple merge bases found"
 msgstr "flera sammanslagningsbaser hittades"
 
+msgid "cannot compare stdin to a directory"
+msgstr "kan inte jämföra standard in med en katalog"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "kan inte jämföra ett namngivet rör med en katalog"
+
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<flaggor>] <sökväg> <sökväg>"
 
@@ -15358,6 +15403,13 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "extern diff dog, stannar vid %s"
 
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow kräver exakt en sökvägsangivelse"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "sökvägs-magi stöds inte av --follow: %s"
+
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
 msgstr ""
@@ -15376,9 +15428,6 @@ msgstr ""
 "flaggorna \"%s\" och  \"%s\" kan inte användas samtidigt, använd \"%s\" med "
 "\"%s\" och \"%s\""
 
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow kräver exakt en sökvägsangivelse"
-
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "ogiltigt värde för --stat: %s"
@@ -18226,6 +18275,13 @@ msgstr "misslyckades skapa diff"
 msgid "could not parse log for '%s'"
 msgstr "kunde inte tolka loggen för \"%s\""
 
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "ogiltig extra överbliven ände: \"%s\""
+
+msgid "unable to enumerate additional recent objects"
+msgstr "kan inte räkna ytterligare nyliga objekt"
+
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr "lägger inte till filalias \"%s\" (\"%s\" finns redan i indexet)"
@@ -18377,6 +18433,14 @@ msgstr "kan inte rätta behörighetsbitar på \"%s\""
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: kan inte återgå till kö 0"
 
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "diff-status %c förväntades inte"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "ta bort \"%s\"\n"
+
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -18580,6 +18644,22 @@ msgstr "okänt %%(trailers)-argument: %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "positivt värde förväntat contents:lines=%s"
 
+#, c-format
+msgid "argument expected for %s"
+msgstr "argument förväntades för %s"
+
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "positivt värde förväntat %s=%s"
+
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "kan inte helt tolka %s=%s"
+
+#, c-format
+msgid "value expected %s="
+msgstr "vädre förväntades %s="
+
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "positivt värde förväntat \"%s\" i %%(%s)"
@@ -18654,6 +18734,9 @@ msgstr "kommandot förkastar atom %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s kan inte användas med --python, --shell, --tcl"
 
+msgid "failed to run 'describe'"
+msgstr "misslyckades att köra \"describe\""
+
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(ingen gren, ombaserar %s)"
@@ -18715,6 +18798,9 @@ msgstr "nyckel"
 msgid "field name to sort on"
 msgstr "fältnamn att sortera på"
 
+msgid "exclude refs which match pattern"
+msgstr "uteslut referenser som motsvarar mönster"
+
 #, c-format
 msgid "not a reflog: %s"
 msgstr "inte en referenslogg: %s"
@@ -19154,8 +19240,10 @@ msgstr[1] ""
 "Din gren och \"%s\" har divergerat,\n"
 "och har %d respektive %d olika incheckningar.\n"
 
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (använd \"git pull\" för att slå ihop fjärrgrenen med din egen)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr ""
+"  (använd \"git pull\" om du vill integrera fjärrgrenen med din egen)\n"
 
 #, c-format
 msgid "cannot parse expected object name '%s'"
@@ -19266,6 +19354,10 @@ 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"
 
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "ogiltig flagga \"%s\" i --stdin-läge"
+
 msgid "your current branch appears to be broken"
 msgstr "din nuvarande gren verkar vara trasig"
 
@@ -20411,6 +20503,77 @@ msgstr "\"fork\" misslyckades"
 msgid "setsid failed"
 msgstr "\"setsid\" misslyckades"
 
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "kan inte ta status på mallen \"%s\""
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "kan inte öppna katalogen (opendir) \"%s\""
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "kan inte läsa länk (readlink) \"%s\""
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "kan inte skapa symbolisk länk \"%s\" \"%s\""
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "kan inte kopiera \"%s\" till \"%s\""
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "ignorerar mallen %s"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "mallarna hittades inte i %s"
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "kopierade inte mallar från \"%s\": %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "ogiltigt namn på första gren: \"%s\""
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "kan inte hantera filtyp %d"
+
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "kan inte flytta %s till %s"
+
+msgid "attempt to reinitialize repository with different hash"
+msgstr "försöker initiera arkivet på nytt med annan hash"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s finns redan"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: ignorerade --initial-branch=%s"
+
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "Ominitierade befintligt delat Git-arkiv i %s%s\n"
+
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "Ominitierade befintligt Git-arkiv i %s%s\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "Initierade tomt delat Git-arkiv i %s%s\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "Initierade tomt Git-arkiv i %s%s\n"
+
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "indexposten är en katalog, men inte gles (%08x)"
index d788dfe93e9273e1366e0cc8ad42f6c918a90ceb..bc3acbcc8496d3216654d522f70349204ac06595 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -39,6 +39,8 @@
 # mark                        | im(lemek)                   #
 # merge                       | birleştirme(k)              #
 # octopus                     | ahtapot                     #
+# orphan                      | yetim                       #
+# orphaned                    | yetim bırakılmış            #
 # overlay                     | yerpaylaşım                 #
 # pack                        | paket                       #
 # parent                      | üst öge                     #
@@ -92,8 +94,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: 2023-05-20 12:55+0300\n"
-"PO-Revision-Date: 2023-05-20 14:00+0300\n"
+"POT-Creation-Date: 2023-08-16 14:34+0300\n"
+"PO-Revision-Date: 2023-08-16 15: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"
@@ -718,9 +720,10 @@ msgstr "Çekme yapılamaz; birleştirmesi tamamlanmamış dosyalarınız var."
 msgid "Reverting is not possible because you have unmerged files."
 msgstr "Geriye al yapılamaz; birleştirmesi tamamlanmamış dosyalarınız var."
 
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "%s yapılamıyor; birleştirmesi tamamlanmamış dosyalarınız var."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr ""
+"Yeniden temellendirme yapılamaz; birleştirmesi tamamlanmamış dosyalarınız "
+"var."
 
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
@@ -866,6 +869,12 @@ msgstr "'%s' ve '%s' seçenekleri birlikte kullanılamaz"
 msgid "'%s' outside a repository"
 msgstr "'%s' bir depo dışında"
 
+msgid "failed to read patch"
+msgstr "yama okunamadı"
+
+msgid "patch too large"
+msgstr "yama pek büyük"
+
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Zaman damgası düzenli ifadesi %s hazırlanamıyor"
@@ -1760,8 +1769,10 @@ msgid "a branch named '%s' already exists"
 msgstr "'%s' adında bir dal halihazırda var"
 
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "'%s' dalı zorla güncellenemiyor, '%s' konumunda çıkış yapılmış"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr ""
+"şuradaki çalışma ağacı tarafından kullanılan '%s' dalı zorla "
+"güncellenemiyor: '%s'"
 
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -1829,17 +1840,6 @@ msgstr "git add [<seçenekler>] [--] <yol-blrtç>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "%cx '%s' chmod yapılamıyor"
 
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "beklenmedik diff durumu %c"
-
-msgid "updating files failed"
-msgstr "dosyaları güncelleme başarısız"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "kaldır: '%s'\n"
-
 msgid "Unstaged changes after refreshing the index:"
 msgstr "İndeksi yeniledikten sonra hazırlanmamış değişiklikler:"
 
@@ -2270,10 +2270,6 @@ msgstr "'git-mailinfo'ya -m bayrağını geçir"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "'git-mailsplit'e mbox biçimi için --keep-cr bayrağını geçir"
 
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"'git-mailsplit'e 'am.keepcr'dan bağımsız olarak --keep-cr bayrağını geçirme"
-
 msgid "strip everything before a scissors line"
 msgstr "bir kesim çizgisinden önceki her şeyi çıkar"
 
@@ -3305,12 +3301,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
@@ -3355,6 +3351,9 @@ msgstr "--batch gibi; ancak <içerik> yayma"
 msgid "stdin is NUL-terminated"
 msgstr "stdin, NUL ile sonlandırılmış"
 
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin ve stdout NUL ile sonlandırılmış"
+
 msgid "read commands from stdin"
 msgstr "komutları stdin'den oku"
 
@@ -4216,12 +4215,6 @@ msgstr "sunucuya özel"
 msgid "option to transmit"
 msgstr "iletme seçeneği"
 
-msgid "use IPv4 addresses only"
-msgstr "yalnızca IPv4 adresleri kullan"
-
-msgid "use IPv6 addresses only"
-msgstr "yalnızca IPv6 adresleri kullan"
-
 msgid "apply partial clone filters to submodules"
 msgstr "altmodüllere kısımsal klon süzgeçlerini uygula"
 
@@ -4661,6 +4654,9 @@ msgstr ""
 "\tgit cherry-pick --skip\n"
 "\n"
 
+msgid "updating files failed"
+msgstr "dosyaları güncelleme başarısız"
+
 msgid "failed to unpack HEAD tree object"
 msgstr "HEAD ağaç nesnesi açılamadı"
 
@@ -4720,8 +4716,8 @@ msgstr ""
 "karakteri seçilemiyor"
 
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "%s işlemesi aranamadı"
+msgid "could not lookup commit '%s'"
+msgstr "'%s' işlemesi aranamadı"
 
 #, c-format
 msgid "(reading log message from standard input)\n"
@@ -7325,77 +7321,6 @@ msgstr "--verify ile bir paket dosyası adı verilmedi"
 msgid "fsck error in pack objects"
 msgstr "paket nesnelerinde fsck hatası"
 
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "'%s' şablonunun bilgileri alınamıyor"
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "'%s' opendir yapılamıyor"
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "'%s' readlink yapılamıyor"
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "'%s', '%s' ögesine sembolik bağla bağlanamıyor"
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "'%s' şuraya kopyalanamıyor: '%s'"
-
-#, c-format
-msgid "ignoring template %s"
-msgstr "%s şablonu yok sayılıyor"
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "şablonlar %s içinde bulunamadı"
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "şablonlar '%s' konumundan kopyalanmıyor: %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "geçersiz başlangıç dalı adı: '%s'"
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "%d dosya türü ele alınamıyor"
-
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "%s şuraya taşınamıyor: %s"
-
-msgid "attempt to reinitialize repository with different hash"
-msgstr "depoyu başka bir sağlama ile yeniden ilklendirme deneniyor"
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s halihazırda var"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-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 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 var olan Git deposu yeniden ilklendirildi\n"
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "%s%s içinde paylaşılan boş Git deposu ilklendirildi\n"
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "%s%s içinde boş Git deposu ilklendirildi\n"
-
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
@@ -7825,6 +7750,10 @@ 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 "could not get object info about '%s'"
+msgstr "'%s' hakkında nesne bilgisi alınamadı"
+
 #, 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"
@@ -7967,10 +7896,6 @@ msgstr "işaret ettiği nesneye ek olarak altında yatan başvuruyu göster"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<seçenekler>] <ağacımsı> [<yol>...]"
 
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "'%s' hakkında nesne bilgisi alınamadı"
-
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
 msgstr "hatalı ls-tree biçimi: '%s' ögesi '(' ile başlamıyor"
@@ -8695,21 +8620,25 @@ msgid "git notes [--ref <notes-ref>] [list [<object>]]"
 msgstr "git notes [--ref <not-bşvr>] [list [<nesne>]]"
 
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <not-bşvr>] add [-f] [--allow-empty] [-m <ileti> | -F "
-"<dosya> | (-c | -C) <nesne>] [<nesne>]"
+"git notes [--ref <not-bşv>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraf-sonu>] [--[no-]stripspace] [-m <ilet> | -F <dosya> | (-c "
+"| -C) <nesne>] [<nesne>]"
 
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr "git notes [--ref <not-bşvr>] copy [-f] <nesneden> <nesneye>"
 
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <not-bşvr>] append [--allow-empty] [-m <ileti> | -F <dosya> "
-"| (-c | -C) <nesne>] [<nesne>]"
+"git notes [--ref <not-bşv>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraf-sonu>] [--[no-]stripspace] [-m <ileti> | -F <dosya> | (-"
+"c | -C) <nesne>] [<nesne>]"
 
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
 msgstr "git notes [--ref <not-bşvr>] edit [--allow-empty] [<nesne>]"
@@ -8840,6 +8769,15 @@ msgstr "boş not depolamasına izin ver"
 msgid "replace existing notes"
 msgstr "var olan notları başkalarıyla değiştir"
 
+msgid "<paragraph-break>"
+msgstr "<paragraf-sonu>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "paragraflar arasında <paragraf-sonu> ekle"
+
+msgid "remove unnecessary whitespace"
+msgstr "gereksiz boşlukları kaldır"
+
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -9392,8 +9330,12 @@ msgstr ""
 msgid "refusing to run without --i-still-use-this"
 msgstr "--i-still-use-this olmadan çalıştırma reddediliyor"
 
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune]git pack-refs [--all] [--no-prune] [--"
+"include <dizgi>] [--exclude <dizgi>]"
 
 msgid "pack everything"
 msgstr "her şeyi paketle"
@@ -9401,6 +9343,12 @@ msgstr "her şeyi paketle"
 msgid "prune loose refs (default)"
 msgstr "gevşek başvuruları buda (öntanımlı)"
 
+msgid "references to include"
+msgstr "içerilecek başvurular"
+
+msgid "references to exclude"
+msgstr "dışarıda tutulacak başvurular"
+
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
@@ -9459,6 +9407,12 @@ msgstr "zorla yerel dalın üzerine yaz"
 msgid "number of submodules pulled in parallel"
 msgstr "paralelde çekilen altmodüllerin sayısı"
 
+msgid "use IPv4 addresses only"
+msgstr "yalnızca IPv4 adresleri kullan"
+
+msgid "use IPv6 addresses only"
+msgstr "yalnızca IPv6 adresleri kullan"
+
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
@@ -9717,39 +9671,39 @@ msgstr ""
 
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 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 tümleştirin (örn. 'git pull ...').\n"
+"uzak konum karşıtından geride. Uzaktaki değişiklikleri tümleştirmek\n"
+"istiyorsanız yeniden itmeden önce 'git pull' yapın.\n"
 "Ayrıntılar için 'git push --help' içinde 'Notes about fast-forwards'a\n"
 "bakın."
 
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 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 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."
+"uzak konum karşıtından geride. Uzaktaki değişiklikleri tümleştirmek\n"
+"istiyorsanız yeniden itmeden önce 'git pull' yapın.\n"
+"Ayrıntılar için 'git push --help' içinde 'Notes about fast-forwards'a\n"
+"bakın."
 
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 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 tümleş-\n"
-"tirmek isteyebilirsiniz (örn. 'git pull ...').\n"
+"dolayı olur. Uzaktaki değişiklikleri tümleştirmek istiyorsanız yeniden\n"
+"itmeden önce 'git pull' yapın..\n"
 "Ayrıntılar için 'git push --help' içinde 'Notes about fast-forwards'a\n"
 "bakın."
 
@@ -9766,19 +9720,20 @@ msgstr ""
 "olmayan bir nesneye işaret etmesini sağlaması için güncelleyemezsiniz.\n"
 
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 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 tümleştirmek isteye-\n"
-"bilirsiniz (örn. 'git pull ...'\n"
+"Güncellemeler reddedildi; çünkü geçerli dalınızın ucu kendisinin\n"
+"uzak konum karşıtından geride. Uzaktaki değişiklikleri tümleştirmek\n"
+"istiyorsanız yeniden itmeden önce 'git pull' yapın.\n"
+"Ayrıntılar için 'git push --help' içinde 'Notes about fast-forwards'a\n"
+"bakın."
 
 #, c-format
 msgid "Pushing to %s\n"
-msgstr "İtme konumu: %s\n"
+msgstr "Şuraya itiliyor: %s\n"
 
 #, c-format
 msgid "failed to push some refs to '%s'"
@@ -10636,11 +10591,12 @@ msgstr "bilinmeyen yansı argümanı: %s"
 msgid "fetch the remote branches"
 msgstr "uzak konum dallarını getir"
 
-msgid "import all tags and associated objects when fetching"
-msgstr "getirirken tüm etiketleri ve ilişkili nesneleri içe aktar"
-
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "veya hiçbir etiketi getirme (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"getirirken tüm etiketleri ve ilişkili nesneleri\n"
+"içe aktar veya etiketleri hiç içe aktarma (--no-tags)"
 
 msgid "branch(es) to track"
 msgstr "izlenecek dal(lar)"
@@ -12569,6 +12525,10 @@ msgstr "Birleştirilmemiş altmodül %s atlanıyor"
 msgid "Skipping submodule '%s'"
 msgstr "'%s' altmodülü atlanıyor"
 
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "bir URL olmadan '%s' altmodülü içe aktarılamıyor"
+
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
 msgstr "'%s' klonlanamadı. Yeniden deneme zamanlandı"
@@ -13306,10 +13266,10 @@ msgstr "etiket içeriğini yazdır"
 
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <dizi>]]\n"
-"                 [-b <yeni-dal>] <yol> [<işlememsi>]"
+"                 [--orphan] [(-b | -B) <yeni-dal>] <yol> [<işlememsi>]"
 
 msgid "git worktree list [-v | --porcelain [-z]]"
 msgstr "git worktree list [-v | --porcelain [-z]]"
@@ -13332,6 +13292,37 @@ msgstr "git worktree repair [<yol>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <çalışma-ağacı>"
 
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Olası kaynak dal yok, '--orphan' anlamı çıkarılıyor"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"Bu depo için yeni bir yetim dal içeren (işlemesiz dal) bir\n"
+"çalışma ağacı oluşturmak istediyseniz bunu --orphan bayrağı\n"
+"ile yapabilirsiniz:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"Bu depo için yeni bir yetim dal içeren (işlemesiz dal) bir\n"
+"çalışma ağacı oluşturmak istediyseniz bunu --orphan bayrağı\n"
+"ile yapabilirsiniz:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #, c-format
 msgid "Removing %s/%s: %s"
 msgstr "%s/%s kaldırılıyor: %s"
@@ -13398,10 +13389,36 @@ msgstr "Çalışma ağacı hazırlanıyor ('%s' dalı sıfırlanıyor; %s konumu
 msgid "Preparing worktree (checking out '%s')"
 msgstr "Çalışma ağacı hazırlanıyor ('%s' çıkış yapılıyor)"
 
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "erişilemiyor: geçersiz başvuru: %s"
+
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "Çalışma ağacı hazırlanıyor (ayrık HEAD %s)"
 
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD, geçersiz (veya yetim bırakılmış bir başvuruya işaret ediyor.\n"
+"HEAD yolu: '%s'\n"
+"HEAD içeriği: '%s'"
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"Bir uzak konum olmasına rağmen hiçbir yerel veya uzak başvuru\n"
+"yok, durduruluyor; geçersiz kılmak için 'add -f' kullanın veya\n"
+"önce bir uzak konum getirin"
+
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "'%s' ve '%s' birlikte kullanılamaz"
+
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr "diğer çalışma ağacında çıkış yapılmış olsa bile <dal> çıkışını yap"
 
@@ -13411,6 +13428,9 @@ msgstr "yeni bir dal oluştur"
 msgid "create or reset a branch"
 msgstr "yeni bir dal oluştur veya sıfırla"
 
+msgid "create unborn/orphaned branch"
+msgstr "doğmamış/yetim bırakılmış dal oluştur"
+
 msgid "populate the new working tree"
 msgstr "yeni çalışma ağacını doldur"
 
@@ -13430,6 +13450,13 @@ msgstr "yeni dalın adını bir uzak izleme dalıyla eşleştirmeyi dene"
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "'%s', '%s' ve '%s' seçenekleri birlikte kullanılamaz"
 
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "'%s' ve '%s' seçenekleri birlikte kullanılamaz"
+
+msgid "<commit-ish>"
+msgstr "<işlememsi>"
+
 msgid "added with --lock"
 msgstr "--lock ile eklendi"
 
@@ -13657,6 +13684,14 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "Demet bu başvuruyu gerektiriyor:"
 msgstr[1] "Demet bu %<PRIuMAX> başvuruyu gerektiriyor:"
 
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "Demet, bu sağlama algoritmasını kullanıyor: %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Demet, bu süzgeci kullanıyor: %s"
+
 msgid "unable to dup bundle descriptor"
 msgstr "demet açıklayıcısı çoğaltılamıyor"
 
@@ -13881,8 +13916,8 @@ msgstr "Bir dizgi ile eşleşen satırları yazdır"
 msgid "A portable graphical interface to Git"
 msgstr "Git için taşınabilir bir grafik arabirim"
 
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "Sağlamayı hesapla ve isteğe göre dosyadan ikili oluştur"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "Nesne kimliğini hesapla/dosyadan isteğe bağlı nesne oluştur"
 
 msgid "Display help information about Git"
 msgstr "Git yardım bilgisini görüntüle"
@@ -14288,6 +14323,10 @@ msgstr "commit-graph temel grafiği iri parçasına iye değil"
 msgid "commit-graph chain does not match"
 msgstr "commit-graph zinciri eşleşmiyor"
 
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "temel grafikteki işleme sayısı pek yüksek: %<PRIuMAX>"
+
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
 msgstr "geçersiz commit-graph zinciri: '%s'. satır bir sağlama değil"
@@ -14372,6 +14411,14 @@ msgstr "temel commit-graph dosyası yeniden adlandırılamadı"
 msgid "failed to rename temporary commit-graph file"
 msgstr "geçici commit-graph dosyası yeniden adlandırılamadı"
 
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "%<PRIuMAX>, %<PRIuMAX> işlemeli grafikler birleştirilemiyor"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "%s grafiği birleştirilemiyor, pek çok işleme: %<PRIuMAX>"
+
 msgid "Scanning merged commits"
 msgstr "Birleştirilen işlemeler taranıyor"
 
@@ -14401,9 +14448,6 @@ msgstr "commit-graph hatalı fanout değerine iye: fanout[%d] = %u != %u"
 msgid "failed to parse commit %s from commit-graph"
 msgstr "%s işlemesi commit-graph'tan ayrıştırılamadı"
 
-msgid "Verifying commits in commit graph"
-msgstr "İşleme grafiğindeki işlemeler doğrulanıyor"
-
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
 msgstr ""
@@ -14449,6 +14493,9 @@ msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
 msgstr ""
 "%s işlemesi için commit-graph içindeki işleme tarihi %<PRIuMAX> != %<PRIuMAX>"
 
+msgid "Verifying commits in commit graph"
+msgstr "İşleme grafiğindeki işlemeler doğrulanıyor"
+
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s bir işleme değil!"
@@ -15396,6 +15443,12 @@ msgstr "bir birleştirme temeli bulunamadı"
 msgid "multiple merge bases found"
 msgstr "birden çok birleştirme temeli bulundu"
 
+msgid "cannot compare stdin to a directory"
+msgstr "stdin, bir dizinle karşılaştırılamıyor"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "adlandırılmış bir veriyolu bir dizinle karşılaştırılamıyor"
+
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<seçenekler>] <yol> <yol>"
 
@@ -15452,6 +15505,13 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "dış diff sonlandı, %s konumunda durdu"
 
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow tam olarak yalnızca bir yol belirteci gerektiriyor"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "yol belirteci sihri --follow tarafından desteklenmiyor: %s"
+
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
 msgstr "'%s', '%s', '%s' ve '%s' seçenekleri birlikte kullanılamaz"
@@ -15469,9 +15529,6 @@ msgstr ""
 "'%s' ve '%s' seçenekleri birlikte kullanılamaz, '%s' seçeneğini '%s' ve '%s' "
 "ile kullanın"
 
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow tam olarak yalnızca bir yol belirteci gerektiriyor"
-
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "geçersiz --stat değeri: %s"
@@ -18330,6 +18387,13 @@ msgstr "diff oluşturulamadı"
 msgid "could not parse log for '%s'"
 msgstr "'%s' günlüğü ayrıştırılamadı"
 
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "geçersiz ek süprüntü ucu: '%s'"
+
+msgid "unable to enumerate additional recent objects"
+msgstr "ek son kullanılan nesneler numaralandırılamıyor"
+
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
 msgstr "dosya arması '%s' eklenmeyecek ('%s' indekste halihazırda var)"
@@ -18481,6 +18545,14 @@ msgstr "'%s' üzerindeki izin bitleri onarılamıyor"
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: #0 numaralı hazırlama alanına bırakılamıyor"
 
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "beklenmedik diff durumu %c"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "kaldır: '%s'\n"
+
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -18676,6 +18748,22 @@ msgstr "bilinmeyen %%(trailers) argümanı: %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "pozitif değer şunu bekliyordu: contents:lines=%s"
 
+#, c-format
+msgid "argument expected for %s"
+msgstr "%s için argüman bekleniyordu"
+
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "pozitif değer şunu bekliyordu: %s=%s"
+
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "tümüyle ayrıştırılamıyor: %s=%s"
+
+#, c-format
+msgid "value expected %s="
+msgstr "değer şunu bekliyordu: %s="
+
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "pozitif değer şurada '%s' bekliyordu: %%(%s)"
@@ -18750,6 +18838,9 @@ msgstr "bu komut atom %%(%.*s) reddediyor"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s, --python, --shell ve --tcl ile kullanılamaz"
 
+msgid "failed to run 'describe'"
+msgstr "'describe' çalıştırılamadı"
+
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(dal yok, %s yeniden temellendiriliyor)"
@@ -18811,6 +18902,9 @@ msgstr "anahtar"
 msgid "field name to sort on"
 msgstr "üzerine sıralanacak alan adı"
 
+msgid "exclude refs which match pattern"
+msgstr "dizgiyle eşleşen başvuruları dışarıda bırak"
+
 #, c-format
 msgid "not a reflog: %s"
 msgstr "bir başvuru günlüğü değil: %s"
@@ -19252,8 +19346,11 @@ msgstr[1] ""
 "Sizin dalınız ve '%s' birbirinden uzaklaşmış ve sırasıyla\n"
 "her birinde %d ve %d işleme var.\n"
 
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (uzak dalı kendi dalınıza birleştirmek için \"git pull\" kullanın)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr ""
+"  (uzak dalı kendi dalınızla birleştirmek istiyorsanız \"git pull\" "
+"kullanın)\n"
 
 #, c-format
 msgid "cannot parse expected object name '%s'"
@@ -19365,6 +19462,10 @@ msgstr "soy yolu argümanı %s için işleme alınamadı"
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<paketdosyası> artık desteklenmiyor"
 
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "--stdin kipinde geçersiz seçenek '%s'"
+
 msgid "your current branch appears to be broken"
 msgstr "geçerli dalınız bozuk gibi görünüyor"
 
@@ -20507,6 +20608,77 @@ msgstr "çatallama başarısız"
 msgid "setsid failed"
 msgstr "setsid başarısız"
 
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "'%s' şablonunun bilgileri alınamıyor"
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "'%s' opendir yapılamıyor"
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "'%s' readlink yapılamıyor"
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "'%s', '%s' ögesine sembolik bağla bağlanamıyor"
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "'%s' şuraya kopyalanamıyor: '%s'"
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "%s şablonu yok sayılıyor"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "şablonlar %s içinde bulunamadı"
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "şablonlar '%s' konumundan kopyalanmıyor: %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "geçersiz başlangıç dalı adı: '%s'"
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "%d dosya türü ele alınamıyor"
+
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "%s şuraya taşınamıyor: %s"
+
+msgid "attempt to reinitialize repository with different hash"
+msgstr "depoyu başka bir sağlama ile yeniden ilklendirme deneniyor"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s halihazırda var"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+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 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 var olan Git deposu yeniden ilklendirildi\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "%s%s içinde paylaşılan boş Git deposu ilklendirildi\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "%s%s içinde boş Git deposu ilklendirildi\n"
+
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
 msgstr "indeks girdisi bir dizin; ancak aralıklı değil (%08x)"
index 11c57b958b1cb707bc3983778ed8def055311e4d..5a11cc661467245e81b056368e140840470f00e8 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -6,19 +6,19 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: Git v2.41\n"
+"Project-Id-Version: Git v2.42.0\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-15 23:57+0000\n"
-"PO-Revision-Date: 2023-05-17 13:51-0700\n"
+"POT-Creation-Date: 2023-08-15 15:28-0700\n"
+"PO-Revision-Date: 2023-08-15 15:31-0700\n"
 "Last-Translator: Arkadii Yakovets <ark@cho.red>\n"
-"Language-Team: Ukrainian <https://github.com/arkid15r/git-ukrainian-l10n/>\n"
+"Language-Team: Ukrainian <https://github.com/arkid15r/git-uk-l10n/>\n"
 "Language: uk\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
 "n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
-"X-Generator: Poedit 3.3.1\n"
+"X-Generator: Poedit 3.3.2\n"
 
 #, c-format
 msgid "Huh (%s)?"
@@ -41,7 +41,7 @@ msgstr "Оновити"
 
 #, c-format
 msgid "could not stage '%s'"
-msgstr "не вдалося додати до індекса %s"
+msgstr "не вдалося додати до індексу %s"
 
 msgid "could not write index"
 msgstr "не вдалося записати індекс"
@@ -59,7 +59,7 @@ msgstr "примітка: %s зараз не відстежується.\n"
 
 #, c-format
 msgid "make_cache_entry failed for path '%s'"
-msgstr "невдала спроба make_cache_entry для шляху '%s'"
+msgstr "невдала спроба make_cache_entry для шляху \"%s\""
 
 msgid "Revert"
 msgstr "Вивернути"
@@ -90,7 +90,7 @@ msgstr[2] "додано %d шляхів\n"
 
 #, c-format
 msgid "ignoring unmerged: %s"
-msgstr "ігноруються незлиті записи: %s"
+msgstr "ігноруються не злиті записи: %s"
 
 #, c-format
 msgid "Only binary files changed.\n"
@@ -101,7 +101,7 @@ msgid "No changes.\n"
 msgstr "Нічого не змінено.\n"
 
 msgid "Patch update"
-msgstr "Ð\9eновленнÑ\8f Ð¿Ð°Ñ\82Ñ\87а"
+msgstr "Ð\9eновленнÑ\8f Ð»Ð°Ñ\82ки"
 
 msgid "Review diff"
 msgstr "Переглянути різницю"
@@ -125,7 +125,7 @@ msgid "add contents of untracked files to the staged set of changes"
 msgstr "додати вміст невідстежуваних файлів до індексу"
 
 msgid "Prompt help:"
-msgstr "Ð\86нÑ\84оÑ\80маÑ\86Ñ\96Ñ\8f Ð¿Ñ\80о Ð¾Ð¿Ñ\86Ñ\96Ñ\97:"
+msgstr "Ð\9fÑ\96дказка Ð¿Ð¾ Ð¾Ð¿Ñ\86Ñ\96Ñ\8fм:"
 
 msgid "select a single item"
 msgstr "вибрати один елемент"
@@ -196,7 +196,7 @@ msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "staging."
 msgstr ""
-"ЯкÑ\89о Ð¿Ð°Ñ\82Ñ\87 Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81овано без помилок, відредагований шматок буде одразу ж "
+"ЯкÑ\89о Ð»Ð°Ñ\82ка Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81ована без помилок, відредагований шматок буде одразу ж "
 "позначено для індексації."
 
 msgid ""
@@ -232,7 +232,7 @@ msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "stashing."
 msgstr ""
-"ЯкÑ\89о Ð¿Ð°Ñ\82Ñ\87 Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81овано без помилок, відредагований шматок буде одразу ж "
+"ЯкÑ\89о Ð»Ð°Ñ\82ка Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81ована без помилок, відредагований шматок буде одразу ж "
 "позначено для схову."
 
 msgid ""
@@ -250,25 +250,25 @@ msgstr ""
 
 #, c-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
-msgstr "РозÑ\96ндекÑ\81Ñ\83ваÑ\82и зміну режиму [y,n,q,a,d%s,?]? "
+msgstr "Ð\9fÑ\80ибÑ\80аÑ\82и Ð· Ñ\96ндекÑ\81Ñ\83 зміну режиму [y,n,q,a,d%s,?]? "
 
 #, c-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
-msgstr "РозÑ\96ндекÑ\81Ñ\83ваÑ\82и видалення [y,n,q,a,d%s,?]? "
+msgstr "Ð\9fÑ\80ибÑ\80аÑ\82и Ð· Ñ\96ндекÑ\81Ñ\83 видалення [y,n,q,a,d%s,?]? "
 
 #, c-format
 msgid "Unstage addition [y,n,q,a,d%s,?]? "
-msgstr "РозÑ\96ндекÑ\81Ñ\83ваÑ\82и додавання [y,n,q,a,d%s,?]? "
+msgstr "Ð\9fÑ\80ибÑ\80аÑ\82и Ð· Ñ\96ндекÑ\81Ñ\83 додавання [y,n,q,a,d%s,?]? "
 
 #, c-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
-msgstr "РозÑ\96ндекÑ\81Ñ\83ваÑ\82и цей шматок [y,n,q,a,d%s,?]? "
+msgstr "Ð\9fÑ\80ибÑ\80аÑ\82и Ð· Ñ\96ндекÑ\81Ñ\83 цей шматок [y,n,q,a,d%s,?]? "
 
 msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "unstaging."
 msgstr ""
-"ЯкÑ\89о Ð¿Ð°Ñ\82Ñ\87 Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81овано без помилок, відредагований шматок буде одразу ж "
+"ЯкÑ\89о Ð»Ð°Ñ\82ка Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81ована без помилок, відредагований шматок буде одразу ж "
 "позначено для розіндексації."
 
 msgid ""
@@ -278,11 +278,11 @@ msgid ""
 "a - unstage this hunk and all later hunks in the file\n"
 "d - do not unstage this hunk or any of the later hunks in the file\n"
 msgstr ""
-"y - розіндексувати цей шматок\n"
-"n - не розіндексовувати цей шматок\n"
-"q - вийти; не розіндексовувати ні цей шматок, ні решту\n"
-"a - розіндексувати цей шматок і всі наступні шматки у файлі\n"
-"d - не розіндексувати цей шматок і всі наступні шматки у файлі\n"
+"y - прибрати з індексу цей шматок\n"
+"n - не прибирати з індексу цей шматок\n"
+"q - вийти; не прибирати з індексу ні цей шматок, ні решту\n"
+"a - прибрати з індексу цей шматок і всі наступні шматки у файлі\n"
+"d - не прибирати з індексу цей шматок і всі наступні шматки у файлі\n"
 
 #, c-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
@@ -304,7 +304,7 @@ msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "applying."
 msgstr ""
-"ЯкÑ\89о Ð¿Ð°Ñ\82Ñ\87 Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81овано без помилок, відредагований шматок буде одразу ж "
+"ЯкÑ\89о Ð»Ð°Ñ\82ка Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81ована без помилок, відредагований шматок буде одразу ж "
 "позначено для застосування."
 
 msgid ""
@@ -340,7 +340,7 @@ msgid ""
 "If the patch applies cleanly, the edited hunk will immediately be marked for "
 "discarding."
 msgstr ""
-"ЯкÑ\89о Ð¿Ð°Ñ\82Ñ\87 Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81овано без помилок, відредагований шматок буде одразу ж "
+"ЯкÑ\89о Ð»Ð°Ñ\82ка Ð±Ñ\83де Ð·Ð°Ñ\81Ñ\82оÑ\81ована без помилок, відредагований шматок буде одразу ж "
 "позначено для відкидання."
 
 msgid ""
@@ -586,9 +586,9 @@ msgstr "Неприпустиме число: \"%s\""
 #, c-format
 msgid "Sorry, only %d hunk available."
 msgid_plural "Sorry, only %d hunks available."
-msgstr[0] "Вибачте, доступний лише %d шматок."
-msgstr[1] "Вибачте, доступно лише %d шматки."
-msgstr[2] "Вибачте, доступно лише %d шматків."
+msgstr[0] "Вибачайте, доступний лише %d шматок."
+msgstr[1] "Вибачайте, доступно лише %d шматки."
+msgstr[2] "Вибачайте, доступно лише %d шматків."
 
 msgid "No other hunks to search"
 msgstr "Немає інших шматків для пошуку"
@@ -604,14 +604,14 @@ msgid "No hunk matches the given pattern"
 msgstr "Жоден шматок не відповідає заданому шаблону"
 
 msgid "Sorry, cannot split this hunk"
-msgstr "Вибачте, не можу розділити цей шматок"
+msgstr "Вибачайте, не можу розщепити цей шматок"
 
 #, c-format
 msgid "Split into %d hunks."
-msgstr "Розділити на %d шматків."
+msgstr "Розщепити на %d шматків."
 
 msgid "Sorry, cannot edit this hunk"
-msgstr "Вибачте, не можу редагувати цей шматок"
+msgstr "Вибачайте, не можу редагувати цей шматок"
 
 msgid "'git apply' failed"
 msgstr "\"git apply\" завершився невдало"
@@ -643,20 +643,19 @@ msgstr "Отримання неможливе, оскільки у вас є н
 msgid "Reverting is not possible because you have unmerged files."
 msgstr "Вивертання неможливе, оскільки у вас є не злиті файли."
 
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "Неможливо виконати %s, оскільки у вас є не злиті файли."
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "Перебазування неможливе, оскільки у вас є не злиті файли."
 
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
 "as appropriate to mark resolution and make a commit."
 msgstr ""
-"Ð\92ипÑ\80авÑ\82е Ñ\97Ñ\85 Ñ\83 Ñ\80обоÑ\87омÑ\83 Ð´ÐµÑ\80евÑ\96, Ð° Ð¿Ð¾Ñ\82Ñ\96м Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8f командою \"git add/rm "
+"Ð\92ипÑ\80авÑ\82е Ñ\97Ñ\85 Ñ\83 Ñ\80обоÑ\87омÑ\83 Ð´ÐµÑ\80евÑ\96, Ð° Ð¿Ð¾Ñ\82Ñ\96м Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8c командою \"git add/rm "
 "<файл>\"\n"
-"щоб позначити розвʼязання і зробити коміт."
+"щоб позначити вирішення і зробити коміт."
 
 msgid "Exiting because of an unresolved conflict."
-msgstr "Вихід через нерозв’язаний конфлікт."
+msgstr "Вихід через невирішений конфлікт."
 
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "Ви не завершили злиття (існує MERGE_HEAD)."
@@ -695,7 +694,7 @@ msgid ""
 "updated in the index:\n"
 msgstr ""
 "Наступні шляхи та/або визначники шляхів відповідають шляхам, які існують\n"
-"за Ð¼ÐµÐ¶Ð°Ð¼Ð¸ Ð²Ð¸Ð·Ð½Ð°Ñ\87еннÑ\8f Ð²Ð°Ñ\88ого Ñ\87аÑ\81Ñ\82кового переходу, тому не будуть\n"
+"за Ð¼ÐµÐ¶Ð°Ð¼Ð¸ Ð²Ð¸Ð·Ð½Ð°Ñ\87еннÑ\8f Ð²Ð°Ñ\88ого Ñ\80озÑ\80Ñ\96дженого переходу, тому не будуть\n"
 "оновлені в індексі:\n"
 
 msgid ""
@@ -706,7 +705,7 @@ msgstr ""
 "Якщо ви маєте намір оновити такі записи, спробуйте один із наведених нижче "
 "способів:\n"
 "* Використайте параметр --sparse.\n"
-"* Ð\92имкнÑ\96Ñ\82Ñ\8c Ð°Ð±Ð¾ Ð·Ð¼Ñ\96нÑ\96Ñ\82Ñ\8c Ð¿Ñ\80авила Ñ\87аÑ\81Ñ\82ковості."
+"* Ð\92имкнÑ\96Ñ\82Ñ\8c Ð°Ð±Ð¾ Ð·Ð¼Ñ\96нÑ\96Ñ\82Ñ\8c Ð¿Ñ\80авила Ñ\80озÑ\80Ñ\96дженості."
 
 #, c-format
 msgid ""
@@ -735,7 +734,7 @@ msgstr ""
 "внести експериментальні\n"
 "зміни і зробити коміт, також ви можете відкинути будь-які коміти, зроблені у "
 "цьому\n"
-"Ñ\81Ñ\82анÑ\96, Ð½Ðµ Ð²Ð¿Ð»Ð¸Ð²Ð°Ñ\8eÑ\87и Ð½Ð° Ñ\96нÑ\88Ñ\96 Ð³Ñ\96лки, Ð¿Ñ\80оÑ\81Ñ\82о Ð¿ÐµÑ\80ейÑ\88овÑ\88и Ð´Ð¾ Ñ\96нÑ\88ноÑ\97 Ð³Ñ\96лки.\n"
+"стані, не впливаючи на інші гілки, просто перейшовши до іншої гілки.\n"
 "\n"
 "Якщо ви хочете створити нову гілку для збереження зроблених вами комітів, ви "
 "можете\n"
@@ -756,8 +755,8 @@ msgid ""
 "sparse-checkout definition but are not sparse due to local\n"
 "modifications.\n"
 msgstr ""
-"Ð\9dаÑ\81Ñ\82Ñ\83пнÑ\96 Ñ\88лÑ\8fÑ\85и, Ñ\89о Ð±Ñ\83ло Ð²Ð¸Ð½ÐµÑ\81ено Ð·Ð° Ð¼ÐµÐ¶Ñ\96 Ð²Ð¸Ð·Ð½Ð°Ñ\87еннÑ\8f Ñ\87аÑ\81Ñ\82кового\n"
-"пеÑ\80еÑ\85одÑ\83, Ð½Ðµ Ñ\94 Ñ\87аÑ\81Ñ\82ковими через локальні\n"
+"Ð\9dаÑ\81Ñ\82Ñ\83пнÑ\96 Ñ\88лÑ\8fÑ\85и, Ñ\89о Ð±Ñ\83ло Ð²Ð¸Ð½ÐµÑ\81ено Ð·Ð° Ð¼ÐµÐ¶Ñ\96 Ð²Ð¸Ð·Ð½Ð°Ñ\87еннÑ\8f Ñ\80озÑ\80Ñ\96дженого\n"
+"пеÑ\80еÑ\85одÑ\83, Ð½Ðµ Ñ\94 Ñ\80озÑ\80Ñ\96дженими через локальні\n"
 "зміни.\n"
 
 msgid ""
@@ -765,10 +764,10 @@ msgid ""
 "* Use \"git add --sparse <paths>\" to update the index\n"
 "* Use \"git sparse-checkout reapply\" to apply the sparsity rules"
 msgstr ""
-"Щоб Ð²Ð¸Ð¿Ñ\80авиÑ\82и Ñ\87аÑ\81Ñ\82ковість цих шляхів, виконайте наступне:\n"
+"Щоб Ð²Ð¸Ð¿Ñ\80авиÑ\82и Ñ\80озÑ\80Ñ\96дженість цих шляхів, виконайте наступне:\n"
 "* Використайте \"git add --sparse <шляхи>\" для оновлення індексу\n"
 "* Використайте \"git sparse-checkout reapply\", щоб застосувати правила "
-"Ñ\87аÑ\81Ñ\82ковості"
+"Ñ\80озÑ\80Ñ\96дженості"
 
 msgid "cmdline ends with \\"
 msgstr "cmdline завершується символом \\"
@@ -789,12 +788,18 @@ msgstr "нерозпізнана опція ігнорування пробіл
 
 #, c-format
 msgid "options '%s' and '%s' cannot be used together"
-msgstr "опції '%s' і '%s' не можна використовувати разом"
+msgstr "опції \"%s\" і \"%s\" не можна використовувати разом"
 
 #, c-format
 msgid "'%s' outside a repository"
 msgstr "\"%s\" поза сховищем"
 
+msgid "failed to read patch"
+msgstr "не вдалося прочитати латку"
+
+msgid "patch too large"
+msgstr "латка занадто велика"
+
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
 msgstr "Неможливо підготувати регвир позначки часу %s"
@@ -805,30 +810,30 @@ msgstr "regexec повернув %d для вводу: %s"
 
 #, c-format
 msgid "unable to find filename in patch at line %d"
-msgstr "не вдалося знайти ім’я файлу у латці в рядку %d"
+msgstr "не вдалося знайти назву файла в рядку %d латки"
 
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
 msgstr ""
-"git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð¾Ñ\87Ñ\96кÑ\83вавÑ\81Ñ\8f /dev/null, отримано %s у рядку %d"
+"git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c /dev/null, отримано %s у рядку %d"
 
 #, c-format
 msgid "git apply: bad git-diff - inconsistent new filename on line %d"
 msgstr ""
-"git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð½ÐµÐ²Ñ\96дповÑ\96дне Ñ\96мâ\80\99Ñ\8f Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ñ\84айлÑ\83 Ñ\83 рядку %d"
+"git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð½ÐµÐ²Ñ\96дповÑ\96дна Ð½Ð°Ð·Ð²Ð° Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ñ\84айлÑ\83 Ð² рядку %d"
 
 #, c-format
 msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
-"git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð½ÐµÐ²Ñ\96дповÑ\96дне Ñ\96мâ\80\99Ñ\8f Ñ\81Ñ\82аÑ\80ого Ñ\84айлÑ\83 Ñ\83 рядку %d"
+"git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð½ÐµÐ²Ñ\96дповÑ\96дна Ð½Ð°Ð·Ð²Ð° Ñ\81Ñ\82аÑ\80ого Ñ\84айлÑ\83 Ð² рядку %d"
 
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
-msgstr "git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð¾Ñ\87Ñ\96кÑ\83вавÑ\81Ñ\8f /dev/null у рядку %d"
+msgstr "git apply: Ð½ÐµÐ²Ñ\96Ñ\80ний git-diff - Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c /dev/null у рядку %d"
 
 #, c-format
 msgid "invalid mode on line %d: %s"
-msgstr "недÑ\96йÑ\81ний режим у рядку %d: %s"
+msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82имий режим у рядку %d: %s"
 
 #, c-format
 msgid "inconsistent header lines %d and %d"
@@ -965,7 +970,7 @@ msgstr "бінарна латка не застосовується до \"%s\""
 #, c-format
 msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
 msgstr ""
-"бÑ\96наÑ\80на Ð»Ð°Ñ\82ка Ð´Ð»Ñ\8f \"%s\" Ð¿Ñ\80изводиÑ\82Ñ\8c Ð´Ð¾ Ð½ÐµÐºÐ¾Ñ\80екÑ\82ного Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82Ñ\83 (оÑ\87Ñ\96кÑ\83валоÑ\81Ñ\8f "
+"бÑ\96наÑ\80на Ð»Ð°Ñ\82ка Ð´Ð»Ñ\8f \"%s\" Ð¿Ñ\80изводиÑ\82Ñ\8c Ð´Ð¾ Ð½ÐµÐºÐ¾Ñ\80екÑ\82ного Ñ\80езÑ\83лÑ\8cÑ\82аÑ\82Ñ\83 (оÑ\87Ñ\96кÑ\83валоÑ\81Ñ\8c "
 "%s, отримано %s)"
 
 #, c-format
@@ -1033,7 +1038,7 @@ msgstr "%s: невірний тип"
 
 #, c-format
 msgid "%s has type %o, expected %o"
-msgstr "%s Ð¼Ð°Ñ\94 Ñ\82ип %o, Ð¾Ñ\87Ñ\96кÑ\83вавÑ\81Ñ\8f %o"
+msgstr "%s Ð¼Ð°Ñ\94 Ñ\82ип %o, Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c %o"
 
 #, c-format
 msgid "invalid path '%s'"
@@ -1101,7 +1106,7 @@ msgstr "не вдалося отримати інформацію про щой
 
 #, c-format
 msgid "unable to create backing store for newly created file %s"
-msgstr "не вдалося створити підтримуюче сховище для щойно створеного файлу %s"
+msgstr "не вдалося зробити запис для щойно створеного файлу %s"
 
 #, c-format
 msgid "unable to add cache entry for %s"
@@ -1143,7 +1148,7 @@ msgstr "неможливо відкрити %s"
 
 #, c-format
 msgid "cannot unlink '%s'"
-msgstr "неможливо відʼєднати \"%s\""
+msgstr "неможливо видалити \"%s\""
 
 #, c-format
 msgid "Hunk #%d applied cleanly."
@@ -1232,7 +1237,7 @@ msgid "accept a patch that touches outside the working area"
 msgstr "прийняти латку, яка виходить за межі робочого простору"
 
 msgid "also apply the patch (use with --stat/--summary/--check)"
-msgstr "Ñ\82акож Ð·Ð°Ñ\81Ñ\82оÑ\81Ñ\83ваÑ\82и Ð¿Ð°Ñ\82Ñ\87 (використовуйте з --stat/--summary/--check)"
+msgstr "Ñ\82акож Ð·Ð°Ñ\81Ñ\82оÑ\81Ñ\83ваÑ\82и Ð»Ð°Ñ\82кÑ\83 (використовуйте з --stat/--summary/--check)"
 
 msgid "attempt three-way merge, fall back on normal patch if that fails"
 msgstr ""
@@ -1320,12 +1325,12 @@ msgid "timestamp too large for this system: %<PRIuMAX>"
 msgstr "позначка часу занадто велика для цієї системи: %<PRIuMAX>"
 
 msgid "git archive [<options>] <tree-ish> [<path>...]"
-msgstr "git archive [<опції>] <деревоподібне джерело> [<шлях>...]"
+msgstr "git archive [<опції>] <деревоподібне-джерело> [<шлях>...]"
 
 msgid ""
 "git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
 msgstr ""
-"git archive --remote <сховище> [--exec <команда>] [<опції>] <деревоподібне "
+"git archive --remote <сховище> [--exec <команда>] [<опції>] <деревоподібне-"
 "джерело> [<шлях>...]"
 
 msgid "git archive --remote <repo> [--exec <cmd>] --list"
@@ -1337,7 +1342,7 @@ msgstr "неможливо прочитати \"%s\""
 
 #, c-format
 msgid "pathspec '%s' matches files outside the current directory"
-msgstr ""
+msgstr "визначник шляху \"%s\" відповідає файлам поза поточною директорією"
 
 #, c-format
 msgid "pathspec '%s' did not match any files"
@@ -1434,7 +1439,7 @@ msgstr "Неочікувана опція --remote"
 
 #, c-format
 msgid "the option '%s' requires '%s'"
-msgstr "опÑ\86Ñ\96Ñ\8f \"%s\" Ð²Ð¸Ð¼Ð°Ð³Ð°є \"%s\""
+msgstr "опÑ\86Ñ\96Ñ\8f \"%s\" Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є \"%s\""
 
 msgid "Unexpected option --output"
 msgstr "Неочікувана опція --output"
@@ -1481,17 +1486,20 @@ msgstr "ігнорування надто великого файлу gitattribu
 msgid "ignoring overly large gitattributes blob '%s'"
 msgstr "ігнорування надто великих gitattributes blob \"%s\""
 
+msgid "bad --attr-source or GIT_ATTR_SOURCE"
+msgstr "невірний --attr-source або GIT_ATTR_SOURCE"
+
 #, c-format
 msgid "Badly quoted content in file '%s': %s"
 msgstr "Невірно процитований вміст у файлі \"%s\": %s"
 
 #, c-format
 msgid "We cannot bisect more!\n"
-msgstr "Ð\9dеможливо Ð±Ñ\96Ñ\81екÑ\82Ñ\83ваÑ\82и Ð±Ñ\96лÑ\8cÑ\88е!\n"
+msgstr "Ð\9fодалÑ\8cÑ\88е Ð±Ñ\96Ñ\81екÑ\82Ñ\83ваннÑ\8f Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾!\n"
 
 #, c-format
 msgid "Not a valid commit name %s"
-msgstr "Не є дійсною назвою коміта %s"
+msgstr "Не є дійсною назвою коміту %s"
 
 #, c-format
 msgid ""
@@ -1567,7 +1575,7 @@ msgid ""
 "Maybe you started with bad path arguments?\n"
 msgstr ""
 "Не знайдено коміт для тестування.\n"
-"Ð\9cожливо, Ð²Ð¸ Ð¿Ð¾Ñ\87али Ð· Ð½ÐµÐ¿Ñ\80авилÑ\8cних аргументів шляху?\n"
+"Ð\9cожливо, Ð²Ð¸ Ð¿Ð¾Ñ\87али Ð· Ð½ÐµÐ²Ñ\96Ñ\80них аргументів шляху?\n"
 
 #, c-format
 msgid "(roughly %d step)"
@@ -1599,7 +1607,7 @@ msgstr "не вдалося налаштувати проходження по 
 msgid ""
 "--reverse --first-parent together require range along first-parent chain"
 msgstr ""
-"--reverse --first-parent разом вимагають вказівки діапазона вздовж ланцюжка "
+"--reverse --first-parent разом вимагають вказівки діапазону вздовж ланцюжка "
 "першого батька"
 
 #, c-format
@@ -1614,7 +1622,7 @@ msgid ""
 "cannot inherit upstream tracking configuration of multiple refs when "
 "rebasing is requested"
 msgstr ""
-"неможливо успадковувати першоджерельну конфігурацію відстежування декількох "
+"неможливо успадкувати першоджерельну конфігурацію відстежування кількох "
 "посилань при запиті перебазування"
 
 #, c-format
@@ -1627,14 +1635,14 @@ msgstr "гілку \"%s\" налаштовано на відстежування
 
 #, c-format
 msgid "branch '%s' set up to track '%s'."
-msgstr "гілку \"%s\" налаштовано на відстежуваня \"%s\"."
+msgstr "гілку \"%s\" налаштовано на відстежування \"%s\"."
 
 #, c-format
 msgid "branch '%s' set up to track:"
 msgstr "гілку \"%s\" налаштовано на відстежування:"
 
 msgid "unable to write upstream branch configuration"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð¿Ð¸Ñ\81аÑ\82и ÐºÐ¾Ð½Ñ\84Ñ\96гÑ\83Ñ\80аÑ\86Ñ\96Ñ\8e Ð³Ñ\96лки Ð¿ÐµÑ\80Ñ\88оджеÑ\80елÑ\8cного Ñ\81Ñ\85овиÑ\89а"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð¿Ð¸Ñ\81аÑ\82и ÐºÐ¾Ð½Ñ\84Ñ\96гÑ\83Ñ\80аÑ\86Ñ\96Ñ\8e Ð²Ð¸Ñ\81Ñ\85Ñ\96дноÑ\97 Ð³Ñ\96лки"
 
 msgid ""
 "\n"
@@ -1689,16 +1697,16 @@ msgid ""
 "different remotes' fetch refspecs map into different\n"
 "tracking namespaces."
 msgstr ""
-"Ð\86Ñ\81нÑ\83Ñ\94 Ð´ÐµÐºÑ\96лÑ\8cка Ð²Ñ\96ддалениÑ\85 Ð¿Ñ\80изнаÑ\87енÑ\8c, Ð²Ð¸Ð·Ð½Ð°Ñ\87ники Ð¾Ñ\82Ñ\80имÑ\83вання посилань яких "
+"Ð\86Ñ\81нÑ\83Ñ\94 ÐºÑ\96лÑ\8cка Ð²Ñ\96ддалениÑ\85 Ð¿Ñ\80изнаÑ\87енÑ\8c, Ð²Ð¸Ð·Ð½Ð°Ñ\87ники Ð¾Ñ\82Ñ\80имання посилань яких "
 "розвʼязуються у віддалено \n"
 "відстежуване посилання \"%s\":\n"
 "%s\n"
 "Зазвичай це помилка конфігурації.\n"
 "\n"
 "Щоб підтримувати налаштування гілок відстежування, переконайтеся, що\n"
-"визначники отримування посилань різних віддалених призначень розвʼязуються у "
+"визначники отримання посилань різних віддалених призначень розвʼязуються у "
 "різні\n"
-" простори імен відстежування."
+"простори імен відстежування."
 
 #, c-format
 msgid "'%s' is not a valid branch name"
@@ -1709,8 +1717,10 @@ msgid "a branch named '%s' already exists"
 msgstr "гілка з ім’ям \"%s\" вже існує"
 
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "неможливо примусово оновити гілку \"%s\", розташовану в \"%s\""
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr ""
+"неможливо примусово оновити гілку \"%s\", яка використовується робочим "
+"деревом у \"%s\""
 
 #, c-format
 msgid "cannot set up tracking information; starting point '%s' is not a branch"
@@ -1720,7 +1730,7 @@ msgstr ""
 
 #, c-format
 msgid "the requested upstream branch '%s' does not exist"
-msgstr "запиÑ\82Ñ\83вана Ð³Ñ\96лка \"%s\" Ð½Ðµ Ñ\96Ñ\81нÑ\83Ñ\94 Ñ\83 Ð¿ÐµÑ\80Ñ\88оджеÑ\80елÑ\8cномÑ\83 Ñ\81Ñ\85овиÑ\89Ñ\96"
+msgstr "запиÑ\82Ñ\83вана Ð²Ð¸Ñ\81Ñ\85Ñ\96дна Ð³Ñ\96лка \"%s\" Ð½Ðµ Ñ\96Ñ\81нÑ\83Ñ\94"
 
 msgid ""
 "\n"
@@ -1744,15 +1754,15 @@ msgstr ""
 
 #, c-format
 msgid "not a valid object name: '%s'"
-msgstr "не Ñ\94 Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82имим Ñ\96мâ\80\99Ñ\8fм об’єкта: \"%s\""
+msgstr "не Ñ\94 Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82имоÑ\8e Ð½Ð°Ð·Ð²Ð¾Ñ\8e об’єкта: \"%s\""
 
 #, c-format
 msgid "ambiguous object name: '%s'"
-msgstr "неоднознаÑ\87не Ñ\96мâ\80\99Ñ\8f об’єкта: \"%s\""
+msgstr "неоднознаÑ\87на Ð½Ð°Ð·Ð²Ð° об’єкта: \"%s\""
 
 #, c-format
 msgid "not a valid branch point: '%s'"
-msgstr "не Ñ\94 Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82имим Ñ\96мâ\80\99Ñ\8fм Ñ\82оÑ\87ки розгалуження: \"%s\""
+msgstr "не Ñ\94 Ð´Ð¾Ð¿Ñ\83Ñ\81Ñ\82имоÑ\8e Ñ\82оÑ\87коÑ\8e розгалуження: \"%s\""
 
 #, c-format
 msgid "submodule '%s': unable to find submodule"
@@ -1781,17 +1791,6 @@ msgstr "git add [<опції>] [--] <визначник шляху>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "неможливо виконати chmod %cx \"%s\""
 
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "неочікуваний статус diff %c"
-
-msgid "updating files failed"
-msgstr "не вдалося оновити файли"
-
-#, c-format
-msgid "remove '%s'\n"
-msgstr "видалити \"%s\"\n"
-
 msgid "Unstaged changes after refreshing the index:"
 msgstr "Неіндексовані зміни після оновлення індексу:"
 
@@ -1850,7 +1849,7 @@ msgid "renormalize EOL of tracked files (implies -u)"
 msgstr "перенормувати EOL відстежуваних файлів (мається на увазі -u)"
 
 msgid "record only the fact that the path will be added later"
-msgstr "записати лише той факт, що шлях будe додано пізніше"
+msgstr "записати лише той факт, що шлях буде додано пізніше"
 
 msgid "add changes from all tracked and untracked files"
 msgstr "додати зміни з усіх відстежуваних і невідстежуваних файлів"
@@ -1870,7 +1869,7 @@ msgstr ""
 "пробного запуску"
 
 msgid "allow updating entries outside of the sparse-checkout cone"
-msgstr "дозволиÑ\82и Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ\8f Ð·Ð°Ð¿Ð¸Ñ\81Ñ\96в Ð·Ð° Ð¼ÐµÐ¶Ð°Ð¼Ð¸ ÐºÐ¾Ð½Ñ\83Ñ\81а Ñ\87аÑ\81Ñ\82кового переходу"
+msgstr "дозволиÑ\82и Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ\8f Ð·Ð°Ð¿Ð¸Ñ\81Ñ\96в Ð·Ð° Ð¼ÐµÐ¶Ð°Ð¼Ð¸ ÐºÐ¾Ð½Ñ\83Ñ\81а Ñ\80озÑ\80Ñ\96дженого переходу"
 
 msgid "override the executable bit of the listed files"
 msgstr "перевизначити біт виконання для зазначених файлів"
@@ -1897,7 +1896,7 @@ msgstr ""
 "Ви додали ще одне git сховище всередині вашого поточного сховища.\n"
 "Клони зовнішнього сховища не міститимуть вмісту\n"
 "вбудованого сховища і не знатимуть, як його отримати.\n"
-"ЯкÑ\89о Ð²Ð¸ Ñ\85оÑ\87еÑ\82е Ð´Ð¾Ð´Ð°Ñ\82и Ð¿Ñ\96дмодÑ\83лÑ\8c, Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8f командою\n"
+"ЯкÑ\89о Ð²Ð¸ Ñ\85оÑ\87еÑ\82е Ð´Ð¾Ð´Ð°Ñ\82и Ð¿Ñ\96дмодÑ\83лÑ\8c, Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8c командою\n"
 "\n"
 "\tgit submodule add <url> %s\n"
 "\n"
@@ -2014,7 +2013,7 @@ msgid "failed to create directory '%s'"
 msgstr "не вдалося створити директорію \"%s\""
 
 msgid "Failed to split patches."
-msgstr "Не вдалося розділити латки."
+msgstr "Не вдалося розщепити латки."
 
 #, c-format
 msgid "When you have resolved this problem, run \"%s --continue\"."
@@ -2060,7 +2059,7 @@ msgstr ""
 
 msgid "Using index info to reconstruct a base tree..."
 msgstr ""
-"Використання індексної інформації для реконстрування базового дерева..."
+"Використання індексної інформації для реконструювання базового дерева..."
 
 msgid ""
 "Did you hand edit your patch?\n"
@@ -2133,7 +2132,7 @@ msgstr "Латання не вдалося на %s %.*s"
 
 msgid "Use 'git am --show-current-patch=diff' to see the failed patch"
 msgstr ""
-"Ð\92икоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е \"git am --show-current-patch=diff\", щоб побачити невдалу "
+"СкоÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8c \"git am --show-current-patch=diff\", щоб побачити невдалу "
 "латку"
 
 msgid "No changes - recorded it as an empty commit."
@@ -2173,8 +2172,8 @@ msgid ""
 "You seem to have moved HEAD since the last 'am' failure.\n"
 "Not rewinding to ORIG_HEAD"
 msgstr ""
-"Здається, ви пересунули HEAD після останньої невдачі з \"am\".\n"
-"Ð\9dе Ð²Ñ\96дбÑ\83ваÑ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ð¿ÐµÑ\80емоÑ\82Ñ\83ваннÑ\8f Ð´Ð¾ ORIG_HEAD"
+"Здається, ви перемістили HEAD після останньої невдачі з \"am\".\n"
+"Ð\9fеÑ\80емоÑ\82Ñ\83ваннÑ\8f Ð²Ð¿ÐµÑ\80ед Ð´Ð¾ ORIG_HEAD Ð½Ðµ Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f"
 
 #, c-format
 msgid "failed to read '%s'"
@@ -2206,7 +2205,7 @@ msgid "be quiet"
 msgstr "працювати тихесенько"
 
 msgid "add a Signed-off-by trailer to the commit message"
-msgstr "додати Signed-off-by причеп у допис до коміту"
+msgstr "додати Signed-off-by причіп у допис до коміту"
 
 msgid "recode into utf8 (default)"
 msgstr "перекодувати в utf8 (за замовчуванням)"
@@ -2223,10 +2222,6 @@ msgstr "передати -m прапорець до git-mailinfo"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "передати --keep-cr прапорець до git-mailsplit для формату mbox"
 
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr ""
-"не передавати --keep-cr прапорець до git-mailsplit незалежно від am.keepcr"
-
 msgid "strip everything before a scissors line"
 msgstr "прибрати все раніше відрізної лінії"
 
@@ -2237,7 +2232,7 @@ msgid "pass it through git-apply"
 msgstr "передати через git-apply"
 
 msgid "n"
-msgstr "n"
+msgstr "н"
 
 msgid "format"
 msgstr "формат"
@@ -2249,7 +2244,7 @@ msgid "override error message when patch failure occurs"
 msgstr "перевизначити повідомлення про помилку при збої латання"
 
 msgid "continue applying patches after resolving a conflict"
-msgstr "продовжити застосування латки після розвʼязання конфлікту"
+msgstr "продовжити застосування латки після вирішення конфлікту"
 
 msgid "synonyms for --continue"
 msgstr "те ж саме, що й --continue"
@@ -2308,13 +2303,13 @@ msgid ""
 "Use \"git am --abort\" to remove it."
 msgstr ""
 "Знайдено блукаючу директорію %s.\n"
-"Скористайтеся командою \"git am --abort\", щоб вилучити її."
+"скористайтесь командою \"git am --abort\", щоб вилучити її."
 
 msgid "Resolve operation not in progress, we are not resuming."
-msgstr "Наразі не виконується операція розвʼязання, ми не продовжуємо."
+msgstr "Наразі не виконується операція вирішення, не поновлено."
 
 msgid "interactive mode requires patches on the command line"
-msgstr "Ñ\96нÑ\82еÑ\80акÑ\82ивний Ñ\80ежим Ð²Ð¸Ð¼Ð°Ð³Ð°є латки у командному рядку"
+msgstr "Ñ\96нÑ\82еÑ\80акÑ\82ивний Ñ\80ежим Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є латки у командному рядку"
 
 msgid "git apply [<options>] [<patch>...]"
 msgstr "git apply [<опції>] [<латка>...]"
@@ -2326,7 +2321,7 @@ msgid "git archive: Remote with no URL"
 msgstr "git archive: віддалене призначення без URL"
 
 msgid "git archive: expected ACK/NAK, got a flush packet"
-msgstr "git archive: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8f ACK/NAK, отримано flush-пакет"
+msgstr "git archive: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c ACK/NAK, отримано flush-пакет"
 
 #, c-format
 msgid "git archive: NACK %s"
@@ -2336,7 +2331,7 @@ msgid "git archive: protocol error"
 msgstr "git archive: помилка протоколу"
 
 msgid "git archive: expected a flush"
-msgstr "git archive: Ð¾Ñ\87Ñ\96кÑ\83вавÑ\81Ñ\8f flush"
+msgstr "git archive: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c flush"
 
 msgid ""
 "git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]    [--no-"
@@ -2594,18 +2589,18 @@ msgstr ""
 
 #, c-format
 msgid "'%s' requires either no argument or a commit"
-msgstr "\"%s\" Ð²Ð¸Ð¼Ð°Ð³Ð°є або відсутності аргументу, або коміт"
+msgstr "\"%s\" Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є або відсутності аргументу, або коміт"
 
 #, c-format
 msgid "'%s' requires 0 or 1 argument"
-msgstr "\"%s\" Ð²Ð¸Ð¼Ð°Ð³Ð°є 0 або 1 аргумент"
+msgstr "\"%s\" Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є 0 або 1 аргумент"
 
 #, c-format
 msgid "'%s' requires 0 arguments"
-msgstr "\"%s\" Ð²Ð¸Ð¼Ð°Ð³Ð°є 0 аргументів"
+msgstr "\"%s\" Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є 0 аргументів"
 
 msgid "no logfile given"
-msgstr "не надано лог-файл"
+msgstr "не надано файл журналу"
 
 #, c-format
 msgid "'%s' failed: no command provided."
@@ -2645,13 +2640,13 @@ msgid "do not show object names of boundary commits (Default: off)"
 msgstr "не показувати назви об’єктів межевих комітів (за замовчуванням: off)"
 
 msgid "do not treat root commits as boundaries (Default: off)"
-msgstr "не розглядати кореневі коміти як межі (за замовчуванням: off)"
+msgstr "не обробляти кореневі коміти як межі (за замовчуванням: off)"
 
 msgid "show work cost statistics"
 msgstr "показати статистику вартості робіт"
 
 msgid "force progress reporting"
-msgstr "примусово звітувати прогрес"
+msgstr "примусово звітувати про хід виконання"
 
 msgid "show output score for blame entries"
 msgstr "показати вихідний показник для blame записів"
@@ -2660,70 +2655,75 @@ msgid "show original filename (Default: auto)"
 msgstr "показати оригінальне ім’я файлу (за замовчуванням: auto)"
 
 msgid "show original linenumber (Default: off)"
-msgstr "показати початковий номер рядка (за замовчуванням: off)"
+msgstr "показувати початковий номер рядка (за замовчуванням: off)"
 
 msgid "show in a format designed for machine consumption"
-msgstr ""
+msgstr "показувати у форматі, призначеному для машинного споживання"
 
 msgid "show porcelain format with per-line commit information"
 msgstr ""
+"показати у porcelain форматі з інформацією про кожен коміт в окремому рядку"
 
 msgid "use the same output mode as git-annotate (Default: off)"
 msgstr ""
+"використовувати той самий режим виводу, що і git-annotate (за замовчуванням: "
+"off)"
 
 msgid "show raw timestamp (Default: off)"
-msgstr ""
+msgstr "показувати необроблену мітку часу (за замовчуванням: off)"
 
 msgid "show long commit SHA1 (Default: off)"
-msgstr ""
+msgstr "показувати довгу версію SHA1 коміту (за замовчуванням: off)"
 
 msgid "suppress author name and timestamp (Default: off)"
-msgstr ""
+msgstr "приховати ім’я автора та мітку часу (за замовчуванням: off)"
 
 msgid "show author email instead of name (Default: off)"
-msgstr ""
+msgstr "показувати email автора замість імені (за замовчуванням: off)"
 
 msgid "ignore whitespace differences"
-msgstr ""
+msgstr "ігнорувати різницю між пробільними символами"
 
 msgid "rev"
-msgstr ""
+msgstr "ревізія"
 
 msgid "ignore <rev> when blaming"
-msgstr ""
+msgstr "ігнорувати <ревізію> при blame"
 
 msgid "ignore revisions from <file>"
-msgstr ""
+msgstr "ігнорувати ревізії з <файлу>"
 
 msgid "color redundant metadata from previous line differently"
-msgstr ""
+msgstr "розфарбувати надлишкові метадані з попереднього рядка інакше"
 
 msgid "color lines by age"
-msgstr ""
+msgstr "розфарбувати рядки за віком"
 
 msgid "spend extra cycles to find better match"
-msgstr ""
+msgstr "витрачати додаткові цикли для пошуку кращого варіанта"
 
 msgid "use revisions from <file> instead of calling git-rev-list"
-msgstr ""
+msgstr "використовувати ревізії з <файлу> замість виклику git-rev-list"
 
 msgid "use <file>'s contents as the final image"
-msgstr ""
+msgstr "використовувати вміст <файлу> як кінцевий образ"
 
 msgid "score"
-msgstr ""
+msgstr "показник"
 
 msgid "find line copies within and across files"
-msgstr ""
+msgstr "знаходити копії рядків у файлах та між ними"
 
 msgid "find line movements within and across files"
-msgstr ""
+msgstr "знаходити переміщення рядків у файлі та між ними"
 
 msgid "range"
-msgstr ""
+msgstr "діапазон"
 
 msgid "process only line range <start>,<end> or function :<funcname>"
 msgstr ""
+"обробити тільки діапазон рядків <початок>,<кінець> або функцію :<назва-"
+"функції>"
 
 msgid "--progress can't be used with --incremental or porcelain formats"
 msgstr ""
@@ -2739,25 +2739,27 @@ msgstr ""
 #.
 
 msgid "4 years, 11 months ago"
-msgstr ""
+msgstr "4 роки, 11 місяців тому"
 
 #, c-format
 msgid "file %s has only %lu line"
 msgid_plural "file %s has only %lu lines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "файл %s містить лише %lu рядок"
+msgstr[1] "файл %s містить лише %lu рядки"
+msgstr[2] "файл %s містить лише %lu рядків"
 
 msgid "Blaming lines"
-msgstr ""
+msgstr "Blaming рядки"
 
 msgid "git branch [<options>] [-r | -a] [--merged] [--no-merged]"
-msgstr ""
+msgstr "git branch [<опції>] [-r | -a] [--merged] [--no-merged]"
 
 msgid ""
 "git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-"
 "point>]"
 msgstr ""
+"git branch [<опції>] [-f] [--recurse-submodules] <назва-гілки> [<початкова-"
+"точка>]"
 
 msgid "git branch [<options>] [-l] [<pattern>...]"
 msgstr "git branch [<опції>] [-l] [<шаблон>...]"
@@ -2782,12 +2784,16 @@ msgid ""
 "deleting branch '%s' that has been merged to\n"
 "         '%s', but not yet merged to HEAD."
 msgstr ""
+"видалення гілки \"%s\", яка була злита з\n"
+"         \"%s\", але ще не злита з HEAD."
 
 #, c-format
 msgid ""
 "not deleting branch '%s' that is not yet merged to\n"
 "         '%s', even though it is merged to HEAD."
 msgstr ""
+"утримання гілки \"%s\", яка ще не була злита з\n"
+"         \"%s\", незважаючи на те, що вже злита з HEAD."
 
 #, c-format
 msgid "Couldn't look up commit object for '%s'"
@@ -2798,9 +2804,11 @@ msgid ""
 "The branch '%s' is not fully merged.\n"
 "If you are sure you want to delete it, run 'git branch -D %s'."
 msgstr ""
+"Гілка \"%s\" злита не повністю.\n"
+"Якщо ви впевнені, що хочете її видалити, виконайте \"git branch -D %s\"."
 
 msgid "Update of config-file failed"
-msgstr ""
+msgstr "Не вдалося оновити конфігураційний файл"
 
 msgid "cannot use -a with -d"
 msgstr "не можна використовувати -a з -d"
@@ -2827,7 +2835,7 @@ msgstr "гілка \"%s\" не знайдена."
 
 #, c-format
 msgid "Deleted remote-tracking branch %s (was %s).\n"
-msgstr ""
+msgstr "Видалено гілку віддаленого відстеження %s (була %s).\n"
 
 #, c-format
 msgid "Deleted branch %s (was %s).\n"
@@ -2845,7 +2853,7 @@ msgstr "HEAD (%s) пунктів за межами refs/heads/"
 
 #, c-format
 msgid "Branch %s is being rebased at %s"
-msgstr ""
+msgstr "Гілка %s перебазується на %s"
 
 #, c-format
 msgid "Branch %s is being bisected at %s"
@@ -2868,28 +2876,28 @@ msgid "No branch named '%s'."
 msgstr "Немає гілки з ім’ям \"%s\"."
 
 msgid "Branch rename failed"
-msgstr ""
+msgstr "Не вдалося перейменувати гілку"
 
 msgid "Branch copy failed"
-msgstr ""
+msgstr "Не вдалося створити копію гілки"
 
 #, c-format
 msgid "Created a copy of a misnamed branch '%s'"
-msgstr "СÑ\82воÑ\80ено ÐºÐ¾Ð¿Ñ\96Ñ\8e Ð½ÐµÐ¿Ñ\80авилÑ\8cно названої гілки \"%s\""
+msgstr "СÑ\82воÑ\80ено ÐºÐ¾Ð¿Ñ\96Ñ\8e Ð½ÐµÐ²Ñ\96Ñ\80но названої гілки \"%s\""
 
 #, c-format
 msgid "Renamed a misnamed branch '%s' away"
-msgstr "Ð\9fеÑ\80ейменовано Ð½ÐµÐ¿Ñ\80авилÑ\8cно названу гілку \"%s\""
+msgstr "Ð\9fеÑ\80ейменовано Ð½ÐµÐ²Ñ\96Ñ\80но названу гілку \"%s\""
 
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr ""
+msgstr "Гілку перейменовано на %s, але HEAD не оновлено!"
 
 msgid "Branch is renamed, but update of config-file failed"
-msgstr ""
+msgstr "Гілку перейменовано, але не вдалося оновити конфігураційний файл"
 
 msgid "Branch is copied, but update of config-file failed"
-msgstr ""
+msgstr "Гілку скопійовано, але не вдалося оновити конфігураційний файл"
 
 #, c-format
 msgid ""
@@ -2897,69 +2905,73 @@ msgid ""
 "  %s\n"
 "Lines starting with '%c' will be stripped.\n"
 msgstr ""
+"Будь ласка, відредагуйте опис гілки\n"
+"  %s\n"
+"Рядки, що починаються з \"%c\", будуть вилучені.\n"
 
 msgid "Generic options"
-msgstr ""
+msgstr "Загальні опції"
 
 msgid "show hash and subject, give twice for upstream branch"
 msgstr ""
+"показувати хеш і тему, додайте двічі, щоб застосувати для висхідної гілки"
 
 msgid "suppress informational messages"
-msgstr ""
+msgstr "приховати інформаційні повідомлення"
 
 msgid "set branch tracking configuration"
 msgstr "налаштувати конфігурацію відстежуваних гілок"
 
 msgid "do not use"
-msgstr ""
+msgstr "не використовувати"
 
 msgid "upstream"
-msgstr ""
+msgstr "першоджерельне сховище"
 
 msgid "change the upstream info"
-msgstr ""
+msgstr "змінити інформацію щодо першоджерельного сховища"
 
 msgid "unset the upstream info"
-msgstr ""
+msgstr "скинути інформацію щодо першоджерельного сховища"
 
 msgid "use colored output"
-msgstr ""
+msgstr "використовувати кольоровий вивід"
 
 msgid "act on remote-tracking branches"
 msgstr "працювати з віддалено відстежуваними гілками"
 
 msgid "print only branches that contain the commit"
-msgstr ""
+msgstr "виводити тільки гілки, що містять цей коміт"
 
 msgid "print only branches that don't contain the commit"
-msgstr ""
+msgstr "виводити тільки гілки, що не містять цей коміт"
 
 msgid "Specific git-branch actions:"
-msgstr ""
+msgstr "Специфічні git-branch дії:"
 
 msgid "list both remote-tracking and local branches"
-msgstr ""
+msgstr "показати як віддалено відстежувані, так і локальні гілки"
 
 msgid "delete fully merged branch"
-msgstr ""
+msgstr "видалити повністю злиту гілку"
 
 msgid "delete branch (even if not merged)"
-msgstr ""
+msgstr "видалити гілку (навіть не повністю злиту)"
 
 msgid "move/rename a branch and its reflog"
-msgstr ""
+msgstr "перемістити/перейменувати гілку та її журнал посилань"
 
 msgid "move/rename a branch, even if target exists"
-msgstr ""
+msgstr "перемістити/перейменувати гілку, навіть якщо призначення існує"
 
 msgid "do not output a newline after empty formatted refs"
-msgstr ""
+msgstr "не виводити новий рядок після порожніх форматованих посилань"
 
 msgid "copy a branch and its reflog"
-msgstr ""
+msgstr "скопіювати гілку та її журнал посилань"
 
 msgid "copy a branch, even if target exists"
-msgstr ""
+msgstr "скопіювати гілку, навіть якщо призначення існує"
 
 msgid "list branch names"
 msgstr "показати назви гілок"
@@ -2968,80 +2980,84 @@ msgid "show current branch name"
 msgstr "показати назву поточної гілки"
 
 msgid "create the branch's reflog"
-msgstr ""
+msgstr "створити журнал посилань гілки"
 
 msgid "edit the description for the branch"
 msgstr "редагувати опис гілки"
 
 msgid "force creation, move/rename, deletion"
-msgstr ""
+msgstr "примусове створення, переміщення/перейменування, видалення"
 
 msgid "print only branches that are merged"
-msgstr ""
+msgstr "вивести тільки злиті гілки"
 
 msgid "print only branches that are not merged"
-msgstr ""
+msgstr "вивести тільки не злиті гілки"
 
 msgid "list branches in columns"
-msgstr ""
+msgstr "виводити гілки в стовпчиках"
 
 msgid "object"
-msgstr ""
+msgstr "обʼєкт"
 
 msgid "print only branches of the object"
-msgstr ""
+msgstr "виводити тільки гілки об’єкта"
 
 msgid "sorting and filtering are case insensitive"
-msgstr ""
+msgstr "сортувати та фільтрувати незалежно від регістру"
 
 msgid "recurse through submodules"
 msgstr "рекурсивно через підмодулі"
 
 msgid "format to use for the output"
-msgstr ""
+msgstr "формат, що використовувати для виводу"
 
 msgid "Failed to resolve HEAD as a valid ref."
 msgstr "Не вдалося розпізнати HEAD як дійсне посилання."
 
 msgid "HEAD not found below refs/heads!"
-msgstr "HEAD не знайдено під посиланнями/заголовками!"
+msgstr "HEAD не знайдено під refs/heads!"
 
 msgid ""
 "branch with --recurse-submodules can only be used if submodule."
 "propagateBranches is enabled"
 msgstr ""
+"гілку з --recurse-submodules можна використовувати лише якщо увімкнено "
+"submodule.propagateBranches"
 
 msgid "--recurse-submodules can only be used to create branches"
-msgstr ""
+msgstr "--recurse-submodules можна використовувати лише для створення гілок"
 
 msgid "branch name required"
-msgstr ""
+msgstr "назва гілки є обовʼязковою"
 
 msgid "Cannot give description to detached HEAD"
-msgstr ""
+msgstr "Неможливо встановити опис відокремленому HEAD"
 
 msgid "cannot edit description of more than one branch"
-msgstr ""
+msgstr "неможливо редагувати опис більш ніж однієї гілки"
 
 msgid "cannot copy the current branch while not on any."
-msgstr ""
+msgstr "неможливо скопіювати поточну гілку, не перебуваючи на жодній з них."
 
 msgid "cannot rename the current branch while not on any."
-msgstr ""
+msgstr "неможливо перейменувати поточну гілку, не перебуваючи на жодній з них."
 
 msgid "too many branches for a copy operation"
-msgstr ""
+msgstr "забагато гілок для операції копіювання"
 
 msgid "too many arguments for a rename operation"
-msgstr ""
+msgstr "забагато аргументів для операції перейменування"
 
 msgid "too many arguments to set new upstream"
-msgstr ""
+msgstr "забагато аргументів для встановлення нового першоджерельного сховища"
 
 #, c-format
 msgid ""
 "could not set upstream of HEAD to %s when it does not point to any branch."
 msgstr ""
+"не вдалося встановити першождерельне сховище HEAD у %s, який не вказує на "
+"жодну гілку."
 
 #, c-format
 msgid "no such branch '%s'"
@@ -3056,7 +3072,7 @@ msgstr "забагато аргументів для скидання значе
 
 msgid "could not unset upstream of HEAD when it does not point to any branch."
 msgstr ""
-"неможливво скинути значення першоджерельного сховища для HEAD, якщо він не "
+"неможливво скинути значення першоджерельного сховища для HEAD, який не "
 "вказує на жодну гілку."
 
 #, c-format
@@ -3067,32 +3083,38 @@ msgid ""
 "The -a, and -r, options to 'git branch' do not take a branch name.\n"
 "Did you mean to use: -a|-r --list <pattern>?"
 msgstr ""
+"Опції -a та -r для \"git branch\" не приймають назву гілки.\n"
+"Ви хотіли використати -a|-r --list <шаблон>?"
 
 msgid ""
 "the '--set-upstream' option is no longer supported. Please use '--track' or "
 "'--set-upstream-to' instead."
 msgstr ""
+"опція \"--set-upstream\" більше не підтримується. Будь ласка, використовуйте "
+"\"--track\" або \"--set-upstream-to\"."
 
 msgid "git version:\n"
-msgstr ""
+msgstr "версія git:\n"
 
 #, c-format
 msgid "uname() failed with error '%s' (%d)\n"
-msgstr ""
+msgstr "uname() завершився невдало з помилкою \"%s\" (%d)\n"
 
 msgid "compiler info: "
-msgstr ""
+msgstr "інформація щодо компілятора: "
 
 msgid "libc info: "
-msgstr ""
+msgstr "информація щодо libc: "
 
 msgid "not run from a git repository - no hooks to show\n"
-msgstr ""
+msgstr "запущено не з git сховища - немає гачків для показу\n"
 
 msgid ""
 "git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
 "              [--diagnose[=<mode>]]"
 msgstr ""
+"git bugreport [(-o | --output-directory) <шлях>] [(-s | --suffix) <формат>]\n"
+"              [--diagnose[=<режим>]]"
 
 msgid ""
 "Thank you for filling out a Git bug report!\n"
@@ -3111,19 +3133,38 @@ msgid ""
 "Please review the rest of the bug report below.\n"
 "You can delete any lines you don't wish to share.\n"
 msgstr ""
+"Дякуємо, що заповнили звіт про помилку в Git!\n"
+"Будь ласка, дайте відповіді на наступні питання, щоб допомогти нам зрозуміти "
+"вашу проблему.\n"
+"\n"
+"Що ви робили до того, як сталася помилка (кроки для відтворення вашої "
+"проблеми)\n"
+"\n"
+"Який результат ви очікували? (Очікувана поведінка)\n"
+"\n"
+"Що сталося замість цього? (Фактична поведінка)\n"
+"\n"
+"Чим відрізняється те, що ви очікували, від того, що сталося насправді?\n"
+"\n"
+"Будь-що інше, що ви хочете додати:\n"
+"\n"
+"Будь ласка, перегляньте решту повідомлення про ваду нижче.\n"
+"Ви можете видалити будь-які рядки, якими не хочете ділитися.\n"
 
 msgid "mode"
-msgstr ""
+msgstr "режим"
 
 msgid ""
 "create an additional zip archive of detailed diagnostics (default 'stats')"
 msgstr ""
+"створити додатковий zip-архів з детальною діагностикою (за замовчуванням "
+"\"stats\")"
 
 msgid "specify a destination for the bugreport file(s)"
-msgstr ""
+msgstr "вказати місце призначення для файла(-ів) звіта про помилку"
 
 msgid "specify a strftime format suffix for the filename(s)"
-msgstr ""
+msgstr "вказати суфікс формату strftime для назви файла(-ів)"
 
 #, c-format
 msgid "could not create leading directories for '%s'"
@@ -3134,10 +3175,10 @@ msgid "unable to create diagnostics archive %s"
 msgstr "не вдалося створити архів діагностики %s"
 
 msgid "System Info"
-msgstr ""
+msgstr "Інформація про систему"
 
 msgid "Enabled Hooks"
-msgstr ""
+msgstr "Увімкнені гачки"
 
 #, c-format
 msgid "unable to write to %s"
@@ -3145,49 +3186,51 @@ msgstr "не вдалося записати до %s"
 
 #, c-format
 msgid "Created new report at '%s'.\n"
-msgstr ""
+msgstr "Створено новий звіт в \"%s\".\n"
 
 msgid ""
 "git bundle create [-q | --quiet | --progress]\n"
 "                  [--version=<version>] <file> <git-rev-list-args>"
 msgstr ""
+"git bundle create [-q | --quiet | --progress]\n"
+"                  [--version=<версія>] <файл> <git-rev-list-агрументи>"
 
 msgid "git bundle verify [-q | --quiet] <file>"
-msgstr ""
+msgstr "git bundle verify [-q | --quiet] <файл>"
 
 msgid "git bundle list-heads <file> [<refname>...]"
-msgstr ""
+msgstr "git bundle list-heads <файл> [<назва-посилання>...]"
 
 msgid "git bundle unbundle [--progress] <file> [<refname>...]"
-msgstr ""
+msgstr "git bundle unbundle [--progress] <файл> [<назва-посилання>...]"
 
 msgid "need a <file> argument"
-msgstr ""
+msgstr "потрібен аргумент <файл>"
 
 msgid "do not show progress meter"
-msgstr ""
+msgstr "не показувати хід виконання"
 
 msgid "show progress meter"
-msgstr "показувати прогрес виконання"
+msgstr "показувати хід виконання"
 
 msgid "historical; same as --progress"
-msgstr ""
+msgstr "історичний; те саме, що --progress"
 
 msgid "historical; does nothing"
 msgstr "історична; не робить нічогісенько"
 
 msgid "specify bundle format version"
-msgstr ""
+msgstr "вказати версію формату пакунка"
 
 msgid "Need a repository to create a bundle."
-msgstr ""
+msgstr "Для створення пакунка потрібне сховище."
 
 msgid "do not show bundle details"
-msgstr ""
+msgstr "не показувати деталі пакунка"
 
 #, c-format
 msgid "%s is okay\n"
-msgstr ""
+msgstr "%s у порядку\n"
 
 msgid "Need a repository to unbundle."
 msgstr "Потрібне сховище для розділення."
@@ -3200,258 +3243,273 @@ msgid "cannot read object %s '%s'"
 msgstr "неможливо прочитати об’єкт %s \"%s\""
 
 msgid "flush is only for --buffer mode"
-msgstr ""
+msgstr "flush тільки для режиму --buffer"
 
 msgid "empty command in input"
-msgstr ""
+msgstr "порожня команда на вході"
 
 #, c-format
 msgid "whitespace before command: '%s'"
-msgstr ""
+msgstr "пробільний символ перед командою: \"%s\""
 
 #, c-format
 msgid "%s requires arguments"
-msgstr ""
+msgstr "%s потребує аргументів"
 
 #, c-format
 msgid "%s takes no arguments"
 msgstr "%s не потребує аргументів"
 
 msgid "only one batch option may be specified"
-msgstr ""
+msgstr "можна вказати лише одну групову опцію"
 
 msgid "git cat-file <type> <object>"
-msgstr ""
+msgstr "git cat-file <тип> <об’єкт>"
 
 msgid "git cat-file (-e | -p) <object>"
-msgstr ""
+msgstr "git cat-file (-e | -p) <об’єкт>"
 
 msgid "git cat-file (-t | -s) [--allow-unknown-type] <object>"
-msgstr ""
+msgstr "git cat-file (-t | -s) [--allow-unknown-type] <об’єкт>"
 
 msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
+"git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
+"objects]\n"
+"             [--buffer] [--follow-symlinks] [--unordered]\n"
+"             [--textconv | --filters] [-Z]"
 
 msgid ""
 "git cat-file (--textconv | --filters)\n"
 "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"
 msgstr ""
+"git cat-file (--textconv | --filters)\n"
+"             [<ревізія>:<шлях|деревоподібне-джерело> | --path=<шлях|"
+"деревоподібне-джерело> <ревізія>]"
 
 msgid "Check object existence or emit object contents"
-msgstr ""
+msgstr "Перевірити існування об’єкта або видати вміст об’єкта"
 
 msgid "check if <object> exists"
 msgstr "перевірити, чи існує <об’єкт>"
 
 msgid "pretty-print <object> content"
-msgstr ""
+msgstr "pretty-print вміст <об’єкта>"
 
 msgid "Emit [broken] object attributes"
-msgstr ""
+msgstr "Видати [пошкоджені] атрибути об’єкта"
 
 msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"
 msgstr ""
+"показати тип об’єкта (один з \"blob\", \"tree\", \"commit\", \"tag\", ...)"
 
 msgid "show object size"
-msgstr ""
+msgstr "показати розмір об’єкта"
 
 msgid "allow -s and -t to work with broken/corrupt objects"
-msgstr ""
+msgstr "дозволити -s та -t працювати з пошкодженими/зіпсованими об’єктами"
 
 msgid "use mail map file"
-msgstr ""
+msgstr "використовувати файл відповідності поштових адрес"
 
 msgid "Batch objects requested on stdin (or --batch-all-objects)"
-msgstr ""
+msgstr "Пакетний запит об’єктів з stdin (або --batch-all-objects)"
 
 msgid "show full <object> or <rev> contents"
-msgstr ""
+msgstr "показати повний вміст <об’єкта> або <ревізії>"
 
 msgid "like --batch, but don't emit <contents>"
-msgstr ""
+msgstr "як --batch, але не виводить <вміст>"
 
 msgid "stdin is NUL-terminated"
-msgstr ""
+msgstr "stdin закінчується NUL"
+
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin та stdout закінчуються NUL"
 
 msgid "read commands from stdin"
 msgstr "читати команди з stdin"
 
 msgid "with --batch[-check]: ignores stdin, batches all known objects"
-msgstr ""
+msgstr "з --batch[-check]: ігнорує stdin, групує всі відомі об’єкти"
 
 msgid "Change or optimize batch output"
-msgstr ""
+msgstr "Змінити або оптимізувати груповий вивід"
 
 msgid "buffer --batch output"
-msgstr ""
+msgstr "буферизувати --batch вивід"
 
 msgid "follow in-tree symlinks"
-msgstr ""
+msgstr "розвʼязувати символьні посилання в дереві"
 
 msgid "do not order objects before emitting them"
-msgstr ""
+msgstr "не упорядковувати об’єкти перед випуском"
 
 msgid ""
 "Emit object (blob or tree) with conversion or filter (stand-alone, or with "
 "batch)"
 msgstr ""
+"Видавати об’єкт (blob або tree) з перетворенням або фільтром (окремо або з "
+"групою)"
 
 msgid "run textconv on object's content"
-msgstr ""
+msgstr "виконати textconv над вмістом об’єкта"
 
 msgid "run filters on object's content"
-msgstr ""
+msgstr "запустити фільтри на вміст об’єкта"
 
 msgid "blob|tree"
-msgstr ""
+msgstr "blob|дерево"
 
 msgid "use a <path> for (--textconv | --filters); Not with 'batch'"
-msgstr ""
+msgstr "використати <шлях> для (--textconv | --filters); не з \"batch\""
 
 #, c-format
 msgid "'%s=<%s>' needs '%s' or '%s'"
-msgstr ""
+msgstr "\"%s=<%s>\" потребує \"%s\" або \"%s\""
 
 msgid "path|tree-ish"
-msgstr ""
+msgstr "шлях|деревоподібне-джерело"
 
 #, c-format
 msgid "'%s' requires a batch mode"
-msgstr ""
+msgstr "\"%s\" потребує групового режиму"
 
 #, c-format
 msgid "'-%c' is incompatible with batch mode"
-msgstr ""
+msgstr "\"-%c\" несумісний з груповим режимом"
 
 msgid "batch modes take no arguments"
-msgstr ""
+msgstr "групові режими не потребують аргументів"
 
 #, c-format
 msgid "<rev> required with '%s'"
-msgstr ""
+msgstr "<ревізія> є обов’язковою для \"%s\""
 
 #, c-format
 msgid "<object> required with '-%c'"
-msgstr ""
+msgstr "<об’єкт> є обов’язковим для \"-%c\""
 
 #, c-format
 msgid "only two arguments allowed in <type> <object> mode, not %d"
-msgstr ""
+msgstr "у режимі <тип> <об’єкт> дозволено лише два аргументи, а не %d"
 
 msgid ""
 "git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
 "<pathname>..."
 msgstr ""
+"git check-attr [--source <деревоподібне-джерело>] [-a | --all | "
+"<атрибут>...] [--] <назва-шляху>..."
 
 msgid ""
 "git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
 msgstr ""
-"git check-attr --stdin [-z] [--source <деревоподібне джерело>] [-a | --all | "
+"git check-attr --stdin [-z] [--source <деревоподібне-джерело>] [-a | --all | "
 "<атрибут>...]"
 
 msgid "report all attributes set on file"
-msgstr ""
+msgstr "звітувати про всі атрибути, встановлені у файлі"
 
 msgid "use .gitattributes only from the index"
-msgstr ""
+msgstr "використовувати .gitattributes тільки з індексу"
 
 msgid "read file names from stdin"
-msgstr ""
+msgstr "зчитувати назви файлів з stdin"
 
 msgid "terminate input and output records by a NUL character"
-msgstr ""
+msgstr "завершувати вхідні та вихідні записи символом NUL"
 
 msgid "<tree-ish>"
-msgstr ""
+msgstr "<деревоподібне-джерело>"
 
 msgid "which tree-ish to check attributes at"
 msgstr "атрибути якого деревоподібного джерела перевіряти"
 
 msgid "suppress progress reporting"
-msgstr "не звітувати прогрес"
+msgstr "не звітувати про хід виконання"
 
 msgid "show non-matching input paths"
-msgstr ""
+msgstr "показати неспівпадіння вхідних шляхів"
 
 msgid "ignore index when checking"
-msgstr ""
+msgstr "ігнорувати індекс під час перевірки"
 
 msgid "cannot specify pathnames with --stdin"
-msgstr ""
+msgstr "неможливо вказувати назви шляхів із --stdin"
 
 msgid "-z only makes sense with --stdin"
-msgstr ""
+msgstr "-z має сенс тільки з --stdin"
 
 msgid "no path specified"
-msgstr "Ñ\88лÑ\8fÑ\85 Ð½Ðµ Ð²ÐºÐ°Ð·Ð°но"
+msgstr "Ñ\88лÑ\8fÑ\85 Ð½Ðµ Ð·Ð°Ð·Ð½Ð°Ñ\87ено"
 
 msgid "--quiet is only valid with a single pathname"
-msgstr ""
+msgstr "--quiet дійсний лише з однією назвою шляху"
 
 msgid "cannot have both --quiet and --verbose"
-msgstr ""
+msgstr "неможливо мати одночасно --quiet і --verbose"
 
 msgid "--non-matching is only valid with --verbose"
-msgstr ""
+msgstr "--non-matching діє тільки з --verbose"
 
 msgid "git check-mailmap [<options>] <contact>..."
 msgstr "git check-mailmap [<опції>] <контакт>..."
 
 msgid "also read contacts from stdin"
-msgstr ""
+msgstr "також читати контакти з stdin"
 
 #, c-format
 msgid "unable to parse contact: %s"
 msgstr "не вдалося розібрати контакт: %s"
 
 msgid "no contacts specified"
-msgstr ""
+msgstr "контакти не вказані"
 
 msgid "git checkout--worker [<options>]"
 msgstr "git checkout--worker [<опції>]"
 
 msgid "string"
-msgstr ""
+msgstr "строка"
 
 msgid "when creating files, prepend <string>"
-msgstr ""
+msgstr "при створенні файлів додавати <строку> напочатку"
 
 msgid "git checkout-index [<options>] [--] [<file>...]"
 msgstr "git checkout-index [<опції>] [—] [<файл>...]"
 
 msgid "stage should be between 1 and 3 or all"
-msgstr ""
+msgstr "стадія має бути від 1 до 3 або all"
 
 msgid "check out all files in the index"
-msgstr ""
+msgstr "переключити стан для всіх файлів в індексі"
 
 msgid "do not skip files with skip-worktree set"
-msgstr ""
+msgstr "не пропускати файли зі встановленим skip-worktree"
 
 msgid "force overwrite of existing files"
-msgstr ""
+msgstr "примусово перезаписати існуючі файли"
 
 msgid "no warning for existing files and files not in index"
-msgstr ""
+msgstr "не попереджувати про існуючі файли та файли, яких немає в індексі"
 
 msgid "don't checkout new files"
-msgstr ""
+msgstr "не переключати стан для нових файлів"
 
 msgid "update stat information in the index file"
 msgstr "оновити статистичну інформацію в індексному файлі"
 
 msgid "read list of paths from the standard input"
-msgstr ""
+msgstr "зчитати список шляхів зі стандартного вводу"
 
 msgid "write the content to temporary files"
-msgstr ""
+msgstr "записати вміст у тимчасові файли"
 
 msgid "copy out the files from named stage"
-msgstr ""
+msgstr "скопіювати файли з іменованої стадії"
 
 msgid "git checkout [<options>] <branch>"
 msgstr "git checkout [<опції>] <гілка>"
@@ -3467,27 +3525,27 @@ msgstr "git restore [<опції>] [--source=<гілка>] <файл>..."
 
 #, c-format
 msgid "path '%s' does not have our version"
-msgstr "шлях '%s' не містить нашої версії"
+msgstr "шлях \"%s\" не містить нашої версії"
 
 #, c-format
 msgid "path '%s' does not have their version"
-msgstr "шлях '%s' не містить їхньої версії"
+msgstr "шлях \"%s\" не містить їхньої версії"
 
 #, c-format
 msgid "path '%s' does not have all necessary versions"
-msgstr "шлях '%s' не містить всіх необхідних версій"
+msgstr "шлях \"%s\" не містить всіх необхідних версій"
 
 #, c-format
 msgid "path '%s' does not have necessary versions"
-msgstr "шлях '%s' не містить необхідних версій"
+msgstr "шлях \"%s\" не містить необхідних версій"
 
 #, c-format
 msgid "path '%s': cannot merge"
-msgstr "шлях '%s': неможливо злити"
+msgstr "шлях \"%s\": неможливо злити"
 
 #, c-format
 msgid "Unable to add merge result for '%s'"
-msgstr "Неможливо додати результат злиття для '%s'"
+msgstr "Неможливо додати результат злиття для \"%s\""
 
 #, c-format
 msgid "Recreated %d merge conflict"
@@ -3512,23 +3570,23 @@ msgstr[2] "Оновлено %d шляхів з індексу"
 
 #, c-format
 msgid "'%s' cannot be used with updating paths"
-msgstr "'%s' не можна використовувати зі шляхами оновлення"
+msgstr "\"%s\" не можна використовувати зі шляхами оновлення"
 
 #, c-format
 msgid "Cannot update paths and switch to branch '%s' at the same time."
-msgstr "Неможливо одночасно оновити шляхи та переключитись на гілку '%s'."
+msgstr "Неможливо одночасно оновити шляхи та переключитись на гілку \"%s\"."
 
 #, c-format
 msgid "neither '%s' or '%s' is specified"
-msgstr "не вказано ні '%s', ні '%s'"
+msgstr "не вказано ні \"%s\", ні \"%s\""
 
 #, c-format
 msgid "'%s' must be used when '%s' is not specified"
-msgstr "'%s' повинен використовуватися, якщо не вказано '%s'"
+msgstr "\"%s\" повинен використовуватися, якщо не вказано \"%s\""
 
 #, c-format
 msgid "'%s' or '%s' cannot be used with %s"
-msgstr "'%s' або '%s' не можна використовувати з %s"
+msgstr "\"%s\" або \"%s\" не можна використовувати з %s"
 
 #, c-format
 msgid "path '%s' is unmerged"
@@ -3547,7 +3605,7 @@ msgstr ""
 
 #, c-format
 msgid "Can not do reflog for '%s': %s\n"
-msgstr "Неможливо виконати reflog для '%s': %s\n"
+msgstr "Неможливо виконати reflog для \"%s\": %s\n"
 
 msgid "HEAD is now at"
 msgstr "HEAD зараз на"
@@ -3557,11 +3615,11 @@ msgstr "не вдалося оновити HEAD"
 
 #, c-format
 msgid "Reset branch '%s'\n"
-msgstr "Скинути гілку '%s'\n"
+msgstr "Скинути гілку \"%s\"\n"
 
 #, c-format
 msgid "Already on '%s'\n"
-msgstr "Вже на '%s'\n"
+msgstr "Вже на \"%s\"\n"
 
 #, c-format
 msgid "Switched to and reset branch '%s'\n"
@@ -3569,11 +3627,11 @@ msgstr "Переключено на та скинуто гілку '%s'\n"
 
 #, c-format
 msgid "Switched to a new branch '%s'\n"
-msgstr "Переключено на нову гілку '%s'\n"
+msgstr "Переключено на нову гілку \"%s\"\n"
 
 #, c-format
 msgid "Switched to branch '%s'\n"
-msgstr "Переключено на гілку '%s'\n"
+msgstr "Переключено на гілку \"%s\"\n"
 
 #, c-format
 msgid " ... and %d more.\n"
@@ -3596,7 +3654,7 @@ msgstr[0] ""
 "\n"
 "%s\n"
 msgstr[1] ""
-"Ð\9fопеÑ\80едженнÑ\8f: Ð²Ð¸ Ð·Ð°Ð»Ð¸Ñ\88аÑ\94Ñ\82е Ð¿Ð¾Ð·Ð°Ð´Ñ\83 %d ÐºÐ¾Ð¼Ñ\96Ñ\82а, не підключених до\n"
+"Ð\9fопеÑ\80едженнÑ\8f: Ð²Ð¸ Ð·Ð°Ð»Ð¸Ñ\88аÑ\94Ñ\82е Ð¿Ð¾Ð·Ð°Ð´Ñ\83 %d ÐºÐ¾Ð¼Ñ\96Ñ\82и, не підключених до\n"
 "жодної з ваших гілок:\n"
 "\n"
 "%s\n"
@@ -3677,7 +3735,7 @@ msgstr ""
 
 #, c-format
 msgid "'%s' matched multiple (%d) remote tracking branches"
-msgstr "\"%s\" Ð²Ñ\96дповÑ\96даÑ\94 Ð´ÐµÐºÑ\96лÑ\8cком (%d) Ð³Ñ\96лкам Ð²Ñ\96ддаленого Ð²Ñ\96дÑ\81Ñ\82ежÑ\83ваннÑ\8f"
+msgstr "\"%s\" відповідає кільком (%d) гілкам віддаленого відстежування"
 
 msgid "only one reference expected"
 msgstr "очікувалось тільки одне посилання"
@@ -3696,19 +3754,19 @@ msgstr "посилання не є деревом: %s"
 
 #, c-format
 msgid "a branch is expected, got tag '%s'"
-msgstr "очікувалась гілка, надано тег '%s'"
+msgstr "очікувалась гілка, надано тег \"%s\""
 
 #, c-format
 msgid "a branch is expected, got remote branch '%s'"
-msgstr "очікувалась гілка, надана віддалена гілка '%s'"
+msgstr "очікувалась гілка, надана віддалена гілка \"%s\""
 
 #, c-format
 msgid "a branch is expected, got '%s'"
-msgstr "очікувалась гілка, надано '%s'"
+msgstr "очікувалась гілка, надано \"%s\""
 
 #, c-format
 msgid "a branch is expected, got commit '%s'"
-msgstr "очікувалась гілка, надано коміт '%s'"
+msgstr "очікувалась гілка, надано коміт \"%s\""
 
 msgid ""
 "If you want to detach HEAD at the commit, try again with the --detach option."
@@ -3804,17 +3862,17 @@ msgid "do not check if another worktree is holding the given ref"
 msgstr "не перевіряти, чи інше робоче дерево містить дане посилання"
 
 msgid "checkout our version for unmerged files"
-msgstr "використовувати нашу версію для незлитих файлів"
+msgstr "використовувати нашу версію для не злитих файлів"
 
 msgid "checkout their version for unmerged files"
-msgstr "використовувати їхню версію для незлитих файлів"
+msgstr "використовувати їхню версію для не злитих файлів"
 
 msgid "do not limit pathspecs to sparse entries only"
 msgstr "не обмежувати визначники шляхів лише розрідженими записами"
 
 #, c-format
 msgid "options '-%c', '-%c', and '%s' cannot be used together"
-msgstr "опції '-%c', '-%c' та '%s' не можуть використовуватись разом"
+msgstr "опції \"-%c\", \"-%c\" та \"%s\" не можна використовувати разом"
 
 msgid "--track needs a branch name"
 msgstr "--track потребує назви гілки"
@@ -3858,7 +3916,7 @@ msgid "create/reset and checkout a branch"
 msgstr "створити/скинути та перейти до нової гілки"
 
 msgid "create reflog for new branch"
-msgstr "створити reflog для нової гілки"
+msgstr "створити журнал посилань для нової гілки"
 
 msgid "second guess 'git checkout <no-such-branch>' (default)"
 msgstr "друга здогадка \"git checkout <гілка-не-існує>\" (за замовчуванням)"
@@ -3888,7 +3946,7 @@ msgid "restore the working tree (default)"
 msgstr "відновити робоче дерево (за замовчуванням)"
 
 msgid "ignore unmerged entries"
-msgstr "ігнорувати незлиті записи"
+msgstr "ігнорувати не злиті записи"
 
 msgid "use overlay mode"
 msgstr "використовувати режим накладення"
@@ -3897,6 +3955,8 @@ msgid ""
 "git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] "
 "[<pathspec>...]"
 msgstr ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <шаблон>] [-x | -X] [--] [<визначник "
+"шляху>...]"
 
 #, c-format
 msgid "Removing %s\n"
@@ -3923,10 +3983,10 @@ msgid "could not lstat %s\n"
 msgstr "не вдалося виконати lstat %s\n"
 
 msgid "Refusing to remove current working directory\n"
-msgstr "Ð\92Ñ\96дмова Ð² видаленні поточної робочої директорії\n"
+msgstr "Ð\92Ñ\96дмовлено Ñ\83 видаленні поточної робочої директорії\n"
 
 msgid "Would refuse to remove current working directory\n"
-msgstr "Було б відмовлено в видаленні поточної робочої директорії\n"
+msgstr "Було б відмовлено у видаленні поточної робочої директорії\n"
 
 #, c-format
 msgid ""
@@ -3935,6 +3995,10 @@ msgid ""
 "foo        - select item based on unique prefix\n"
 "           - (empty) select nothing\n"
 msgstr ""
+"Підказка по опціям:\n"
+"1          - вибрати пронумерований елемент\n"
+"foo        - вибрати елемент за унікальним префіксом\n"
+"           - (порожньо) - не вибирати нічого\n"
 
 #, c-format
 msgid ""
@@ -3947,27 +4011,35 @@ msgid ""
 "*          - choose all items\n"
 "           - (empty) finish selecting\n"
 msgstr ""
+"Підказка по опціям:\n"
+"1          - вибрати один елемент\n"
+"3-5        - вибрати діапазон елементів\n"
+"2-3,6-9    - вибрати кілька діапазонів\n"
+"foo        - вибрати елемент за унікальним префіксом\n"
+"-...       - скасувати вибір вказаних елементів\n"
+"*          - вибрати всі елементи\n"
+"           - (порожньо) завершити вибір\n"
 
 #, c-format
 msgid "Huh (%s)?\n"
-msgstr ""
+msgstr "Га (%s)?\n"
 
 #, c-format
 msgid "Input ignore patterns>> "
-msgstr ""
+msgstr "Введіть шаблони ігнорування>> "
 
 #, c-format
 msgid "WARNING: Cannot find items matched by: %s"
-msgstr ""
+msgstr "ПОПЕРЕДЖЕННЯ: Не вдалося знайти елементи, що відповідають: %s"
 
 msgid "Select items to delete"
-msgstr ""
+msgstr "Виберіть елементи для видалення"
 
 #. TRANSLATORS: Make sure to keep [y/N] as is
 
 #, c-format
 msgid "Remove %s [y/N]? "
-msgstr ""
+msgstr "Видалити %s [y/N]? "
 
 msgid ""
 "clean               - start cleaning\n"
@@ -3978,33 +4050,40 @@ msgid ""
 "help                - this screen\n"
 "?                   - help for prompt selection"
 msgstr ""
+"clean               - розпочати прибирання\n"
+"filter by pattern   - виключити елементи з прибирання\n"
+"select by numbers   - вибрати елементи для прибирання за номерами\n"
+"ask each            - підтверджувати кожне видалення (як \"rm -i\")\n"
+"quit                - припинити прибирання\n"
+"help                - показати цей екран\n"
+"?                   - підказка для швидкого вибору"
 
 msgid "Would remove the following item:"
 msgid_plural "Would remove the following items:"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Видалить наступний елемент:"
+msgstr[1] "Видалить наступні елементи:"
+msgstr[2] "Видалить наступні елементи:"
 
 msgid "No more files to clean, exiting."
-msgstr ""
+msgstr "Більше немає файлів для прибирання, вихід."
 
 msgid "do not print names of files removed"
-msgstr ""
+msgstr "не виводити назви видалених файлів"
 
 msgid "force"
-msgstr ""
+msgstr "примусово"
 
 msgid "interactive cleaning"
-msgstr ""
+msgstr "інтерактивне прибирання"
 
 msgid "remove whole directories"
-msgstr ""
+msgstr "видаляти цілі директорії"
 
 msgid "pattern"
-msgstr ""
+msgstr "шаблон"
 
 msgid "add <pattern> to ignore rules"
-msgstr ""
+msgstr "додати <шаблон> в правила ігнорування"
 
 msgid "remove ignored files, too"
 msgstr "видалити також ігноровані файли"
@@ -4016,11 +4095,15 @@ msgid ""
 "clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
 "clean"
 msgstr ""
+"clean.requireForce встановлено у true і не задано ні -i, ні -n, ні -f; "
+"відмовлено в прибиранні"
 
 msgid ""
 "clean.requireForce defaults to true and neither -i, -n, nor -f given; "
 "refusing to clean"
 msgstr ""
+"clean.requireForce встановлено у true за замовчуванням і не задано ні -i, ні "
+"-n, ні -f; відмовлено в прибиранні"
 
 msgid "-x and -X cannot be used together"
 msgstr "-x та -X не можна використовувати разом"
@@ -4032,7 +4115,7 @@ msgid "don't clone shallow repository"
 msgstr "не клонувати неглибоке сховище"
 
 msgid "don't create a checkout"
-msgstr "не Ð¿ÐµÑ\80еÑ\85одиÑ\82и Ð´Ð¾ Ð³Ñ\96лки"
+msgstr "не Ð¿ÐµÑ\80еÑ\85одиÑ\82и Ð½Ð° Ð³Ñ\96лкÑ\83"
 
 msgid "create a bare repository"
 msgstr "створити порожнє сховище"
@@ -4088,16 +4171,16 @@ msgid "depth"
 msgstr "глибина"
 
 msgid "create a shallow clone of that depth"
-msgstr "Ñ\81Ñ\82воÑ\80иÑ\82и Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невий клон вказаної глибини"
+msgstr "Ñ\81Ñ\82воÑ\80иÑ\82и Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºий клон вказаної глибини"
 
 msgid "create a shallow clone since a specific time"
-msgstr "Ñ\81Ñ\82воÑ\80иÑ\82и Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невий клон з певного часу"
+msgstr "Ñ\81Ñ\82воÑ\80иÑ\82и Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºий клон з певного часу"
 
 msgid "revision"
 msgstr "ревізія"
 
 msgid "deepen history of shallow clone, excluding rev"
-msgstr "поглибиÑ\82и Ñ\96Ñ\81Ñ\82оÑ\80Ñ\96Ñ\8e Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невого ÐºÐ»Ð¾Ð½Ñ\83, Ð·Ð° Ð²Ð¸Ð½Ñ\8fÑ\82ком rev"
+msgstr "поглибиÑ\82и Ñ\96Ñ\81Ñ\82оÑ\80Ñ\96Ñ\8e Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾ÐºÐ¾Ð³Ð¾ ÐºÐ»Ð¾Ð½Ñ\83, Ð·Ð° Ð²Ð¸Ð½Ñ\8fÑ\82ком Ñ\80евÑ\96зÑ\96Ñ\97"
 
 msgid "clone only one branch, HEAD or --branch"
 msgstr "клонувати лише одну гілку, HEAD або --branch"
@@ -4107,10 +4190,10 @@ msgstr ""
 "не клонувати жодних тегів і не слідувати за ними під час отримувань пізніше"
 
 msgid "any cloned submodules will be shallow"
-msgstr "бÑ\83дÑ\8c\8fкÑ\96 ÐºÐ»Ð¾Ð½Ð¾Ð²Ð°Ð½Ñ\96 Ð¿Ñ\96дмодÑ\83лÑ\96 Ð±Ñ\83дÑ\83Ñ\82Ñ\8c Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невими"
+msgstr "бÑ\83дÑ\8c\8fкÑ\96 ÐºÐ»Ð¾Ð½Ð¾Ð²Ð°Ð½Ñ\96 Ð¿Ñ\96дмодÑ\83лÑ\96 Ð±Ñ\83дÑ\83Ñ\82Ñ\8c Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºими"
 
 msgid "gitdir"
-msgstr "git-директорія"
+msgstr "git директорія"
 
 msgid "separate git dir from working tree"
 msgstr "відокремити git-директорію від робочого дерева"
@@ -4127,14 +4210,8 @@ msgstr "тільки для сервера"
 msgid "option to transmit"
 msgstr "опція для передачі"
 
-msgid "use IPv4 addresses only"
-msgstr "використовувати тільки IPv4 адреси"
-
-msgid "use IPv6 addresses only"
-msgstr "використовувати тільки IPv6 адреси"
-
 msgid "apply partial clone filters to submodules"
-msgstr "заÑ\81Ñ\82оÑ\81Ñ\83ваÑ\82и Ñ\87аÑ\81Ñ\82ковÑ\96 Ñ\84Ñ\96лÑ\8cÑ\82Ñ\80и ÐºÐ»Ð¾Ð½Ñ\96в до підмодулів"
+msgstr "заÑ\81Ñ\82оÑ\81Ñ\83ваÑ\82и Ñ\84Ñ\96лÑ\8cÑ\82Ñ\80и Ñ\87аÑ\81Ñ\82кового ÐºÐ»Ð¾Ð½Ñ\83ваннÑ\8f до підмодулів"
 
 msgid "any cloned submodules will use their remote-tracking branch"
 msgstr ""
@@ -4143,7 +4220,7 @@ msgstr ""
 
 msgid "initialize sparse-checkout file to include only files at root"
 msgstr ""
-"Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и, Ñ\89об Ñ\84айл Ñ\87аÑ\81Ñ\82кового переходу включав лише файли в корені"
+"Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и, Ñ\89об Ñ\84айл Ñ\80озÑ\80Ñ\96дженого переходу включав лише файли в корені"
 
 msgid "uri"
 msgstr "uri"
@@ -4153,11 +4230,11 @@ msgstr "URI для завантаження пакунків перед отри
 
 #, c-format
 msgid "info: Could not add alternate for '%s': %s\n"
-msgstr "инÑ\84о: Ð\9dе Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð´Ð¾Ð´Ð°Ñ\82и Ð°Ð»Ñ\8cÑ\82еÑ\80наÑ\82ивÑ\83 Ð´Ð»Ñ\8f '%s': %s\n"
+msgstr "инÑ\84о: Ð\9dе Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð´Ð¾Ð´Ð°Ñ\82и Ð·Ð°Ð¿Ð¾Ð·Ð¸Ñ\87ений Ð¾Ð±Ê¼Ñ\94кÑ\82 Ð´Ð»Ñ\8f \"%s\": %s\n"
 
 #, c-format
 msgid "failed to stat '%s'"
-msgstr "не вдалося виконати stat '%s'"
+msgstr "не вдалося виконати stat \"%s\""
 
 #, c-format
 msgid "%s exists and is not a directory"
@@ -4165,31 +4242,31 @@ msgstr "%s існує і не є директорією"
 
 #, c-format
 msgid "'%s' is a symlink, refusing to clone with --local"
-msgstr "\"%s\" Ñ\94 Ñ\81имволÑ\8cним Ð¿Ð¾Ñ\81иланнÑ\8fм, Ð²Ñ\96дмова Ð²Ñ\96д ÐºÐ»Ð¾Ð½Ñ\83ваннÑ\8f з --local"
+msgstr "\"%s\" Ñ\94 Ñ\81имволÑ\8cним Ð¿Ð¾Ñ\81иланнÑ\8fм, Ð²Ñ\96дмовлено Ð² ÐºÐ»Ð¾Ð½Ñ\83ваннÑ\96 з --local"
 
 #, c-format
 msgid "failed to start iterator over '%s'"
-msgstr "не вдалося запустити перебір для '%s'"
+msgstr "не вдалося запустити перебір для \"%s\""
 
 #, c-format
 msgid "symlink '%s' exists, refusing to clone with --local"
-msgstr "символьне посилання '%s' існує, не можу клонувати з --local"
+msgstr "символьне посилання \"%s\" існує, не можу клонувати з --local"
 
 #, c-format
 msgid "failed to unlink '%s'"
-msgstr "не вдалося розʼєднати '%s'"
+msgstr "не вдалося видалити \"%s\""
 
 #, c-format
 msgid "failed to create link '%s'"
-msgstr "не вдалося створити посилання '%s'"
+msgstr "не вдалося створити посилання \"%s\""
 
 #, c-format
 msgid "failed to copy file to '%s'"
-msgstr "не вдалося скопіювати файл у '%s'"
+msgstr "не вдалося скопіювати файл у \"%s\""
 
 #, c-format
 msgid "failed to iterate over '%s'"
-msgstr "не вдалося перебрати '%s'"
+msgstr "не вдалося перебрати \"%s\""
 
 #, c-format
 msgid "done.\n"
@@ -4200,7 +4277,7 @@ msgid ""
 "You can inspect what was checked out with 'git status'\n"
 "and retry with 'git restore --source=HEAD :/'\n"
 msgstr ""
-"Ð\9aлонÑ\83ваннÑ\8f Ð¿Ñ\80ойÑ\88ло Ñ\83Ñ\81пÑ\96Ñ\88но, Ð°Ð»Ðµ Ð½Ðµ Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð¿ÐµÑ\80ейÑ\82и Ð´Ð¾ Ð³Ñ\96лки.\n"
+"Ð\9aлонÑ\83ваннÑ\8f Ð¿Ñ\80ойÑ\88ло Ñ\83Ñ\81пÑ\96Ñ\88но, Ð°Ð»Ðµ Ð½Ðµ Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð¿ÐµÑ\80ейÑ\82и Ð½Ð° Ð³Ñ\96лкÑ\83.\n"
 "Ви можете перевірити, що було додано за допомогою 'git status'\n"
 "і повторити спробу за допомогою 'git restore --source=HEAD :/'\n"
 
@@ -4216,7 +4293,7 @@ msgid "unable to update %s"
 msgstr "не вдалося оновити %s"
 
 msgid "failed to initialize sparse-checkout"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и Ñ\87аÑ\81Ñ\82ковий перехід"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и Ñ\80озÑ\80Ñ\96джений перехід"
 
 msgid "remote HEAD refers to nonexistent ref, unable to checkout"
 msgstr "віддалений HEAD посилається на неіснуючого рефа, неможливо перейти"
@@ -4231,7 +4308,7 @@ msgid "cannot repack to clean up"
 msgstr "неможливо перепакувати, щоб очистити"
 
 msgid "cannot unlink temporary alternates file"
-msgstr "не вдається розʼєднати файл тимчасових альтернатив"
+msgstr "неможливо видалити тимчасовий файл запозичених обʼєктів"
 
 msgid "Too many arguments."
 msgstr "Забагато аргументів."
@@ -4247,7 +4324,7 @@ msgstr ""
 
 #, c-format
 msgid "repository '%s' does not exist"
-msgstr "сховище '%s' не існує"
+msgstr "сховище \"%s\" не існує"
 
 #, c-format
 msgid "depth %s is not a positive number"
@@ -4255,31 +4332,31 @@ msgstr "глибина %s не є додатнім числом"
 
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
-msgstr "шлях призначення '%s' вже існує і не є порожньою директорією."
+msgstr "шлях призначення \"%s\" вже існує і не є порожньою директорією."
 
 #, c-format
 msgid "repository path '%s' already exists and is not an empty directory."
-msgstr "шлях до сховища '%s' вже існує і не є порожньою директорією."
+msgstr "шлях до сховища \"%s\" вже існує і не є порожньою директорією."
 
 #, c-format
 msgid "working tree '%s' already exists."
-msgstr "робоче дерево '%s' вже існує."
+msgstr "робоче дерево \"%s\" вже існує."
 
 #, c-format
 msgid "could not create leading directories of '%s'"
-msgstr "не вдалося створити провідні директорії для '%s'"
+msgstr "не вдалося створити провідні директорії для \"%s\""
 
 #, c-format
 msgid "could not create work tree dir '%s'"
-msgstr "не вдалося створити директорію робочого дерева '%s'"
+msgstr "не вдалося створити директорію робочого дерева \"%s\""
 
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
-msgstr "Клонування у порожнє сховище '%s'...\n"
+msgstr "Клонування у порожнє сховище \"%s\"...\n"
 
 #, c-format
 msgid "Cloning into '%s'...\n"
-msgstr "Клонування в '%s'...\n"
+msgstr "Клонування в \"%s\"..\n"
 
 msgid ""
 "clone --recursive is not compatible with both --reference and --reference-if-"
@@ -4314,26 +4391,26 @@ msgid "source repository is shallow, reject to clone."
 msgstr "джерельне сховище є неглибоким, клонування відхилено."
 
 msgid "source repository is shallow, ignoring --local"
-msgstr "джерельне сховище є неглибоким, --local ігнорується"
+msgstr "джерельне сховище є неглибоким, --local ігноровано"
 
 msgid "--local is ignored"
-msgstr "--local ігнорується"
+msgstr "--local ігноровано"
 
 msgid "cannot clone from filtered bundle"
-msgstr "неможливо клонувати з відфільтрованого пакета"
+msgstr "неможливо клонувати з відфільтрованого пакунка"
 
 msgid "failed to initialize the repo, skipping bundle URI"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и Ñ\80епо, URI Ð¿Ð°ÐºÐµÑ\82а Ð¿Ñ\80опÑ\83Ñ\81каÑ\94Ñ\82Ñ\8cÑ\81Ñ\8f"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и Ñ\81Ñ\85овиÑ\89е, URI Ð¿Ð°ÐºÑ\83нка Ð¿Ñ\80опÑ\83Ñ\89ено"
 
 #, c-format
 msgid "failed to fetch objects from bundle URI '%s'"
-msgstr "не вдалося отримати об'єкти з пакету URI '%s'"
+msgstr "не вдалося отримати обʼєкти з пакунка URI '%s'"
 
 msgid "failed to fetch advertised bundles"
-msgstr "не вдалося отримати обіцяні пакети"
+msgstr "не вдалося отримати обіцяні пакунки"
 
 msgid "remote transport reported error"
-msgstr "опеÑ\80аÑ\86Ñ\96Ñ\8f Ð²Ñ\96ддаленного Ð¾Ñ\82Ñ\80иманнÑ\8f Ð¿Ð¾Ð²Ñ\96домила Ð¿Ñ\80о Ð¿Ð¾Ð¼Ð¸Ð»ÐºÑ\83"
+msgstr "операція віддаленого отримання повідомила про помилку"
 
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
@@ -4346,29 +4423,31 @@ msgid "git column [<options>]"
 msgstr "git column [<опції>]"
 
 msgid "lookup config vars"
-msgstr ""
+msgstr "пошук параметрів конфігурації"
 
 msgid "layout to use"
-msgstr ""
+msgstr "схема розташування"
 
 msgid "maximum width"
-msgstr ""
+msgstr "максимальна ширина"
 
 msgid "padding space on left border"
-msgstr ""
+msgstr "відступ по лівому краю"
 
 msgid "padding space on right border"
-msgstr ""
+msgstr "відступ по правому краю"
 
 msgid "padding space between columns"
-msgstr ""
+msgstr "відступ між стовпчиками"
 
 msgid "--command must be the first argument"
-msgstr ""
+msgstr "--command має бути першим аргументом"
 
 msgid ""
 "git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]"
 msgstr ""
+"git commit-graph verify [--object-dir <директорія>] [--shallow] [--"
+"[no-]progress]"
 
 msgid ""
 "git commit-graph write [--object-dir <dir>] [--append]\n"
@@ -4378,15 +4457,22 @@ msgid ""
 "[no-]progress]\n"
 "                       <split options>"
 msgstr ""
+"git commit-graph write [--object-dir <директорія>] [--append] [--object-dir "
+"<директорія>] [--append] [--object-dir <директорія>] [--append\n"
+"                       [--split[=<стратегія>]] [--reachable | --stdin-packs "
+"| --stdin-commits]\n"
+"                       [--changed-paths] [--[no-]max-new-filters <число>] [--"
+"[no-]progress]\n"
+"                       <опції розділення>"
 
 msgid "dir"
-msgstr "dir"
+msgstr "директорія"
 
 msgid "the object directory to store the graph"
-msgstr ""
+msgstr "директорія об’єктів для зберігання графу"
 
 msgid "if the commit-graph is split, only verify the tip file"
-msgstr ""
+msgstr "якщо коміт-граф розщеплено, перевіряти тільки файл підказок"
 
 #, c-format
 msgid "Could not open commit-graph '%s'"
@@ -4394,11 +4480,11 @@ msgstr "Не вдалося відкрити коміт-граф \"%s\""
 
 #, c-format
 msgid "unrecognized --split argument, %s"
-msgstr ""
+msgstr "нерозпізнаний --split аргумент, %s"
 
 #, c-format
 msgid "unexpected non-hex object ID: %s"
-msgstr ""
+msgstr "неочікуваний не hex ідентифікатор обʼєкта: %s"
 
 #, c-format
 msgid "invalid object: %s"
@@ -4406,55 +4492,60 @@ msgstr "неприпустимий об’єкт: %s"
 
 #, c-format
 msgid "option `%s' expects a numerical value"
-msgstr ""
+msgstr "опція \"%s\" очікує числове значення"
 
 msgid "start walk at all refs"
-msgstr ""
+msgstr "розпочати проходження по всім посиланням"
 
 msgid "scan pack-indexes listed by stdin for commits"
-msgstr ""
+msgstr "просканувати pack-indexes зазначені через stdin для комітів"
 
 msgid "start walk at commits listed by stdin"
-msgstr ""
+msgstr "розпочати проходження по всім комітам зазначеним через stdin"
 
 msgid "include all commits already in the commit-graph file"
-msgstr ""
+msgstr "включити всі коміти, які вже є у файлі коміт-графа"
 
 msgid "enable computation for changed paths"
-msgstr ""
+msgstr "увімкнути обчислення для змінених шляхів"
 
 msgid "allow writing an incremental commit-graph file"
-msgstr ""
+msgstr "дозволити запис інкрементного файлу коміт-графа"
 
 msgid "maximum number of commits in a non-base split commit-graph"
-msgstr ""
+msgstr "максимальна кількість комітів у безбазовому розщепленому коміт-графі"
 
 msgid "maximum ratio between two levels of a split commit-graph"
-msgstr ""
+msgstr "максимальне співвідношення між двома рівнями розщепленого коміт-графа"
 
 msgid "only expire files older than a given date-time"
-msgstr ""
+msgstr "видалити лише файли, старіші за вказану дату"
 
 msgid "maximum number of changed-path Bloom filters to compute"
-msgstr ""
+msgstr "максимальна кількість фільтрів Блума зміненого шляху для обчислення"
 
 msgid "use at most one of --reachable, --stdin-commits, or --stdin-packs"
 msgstr ""
+"використовувати щонайбільше один з --reachable, --stdin-commits або --stdin-"
+"packs"
 
 msgid "Collecting commits from input"
-msgstr ""
+msgstr "Збирання комітів з вхідних даних"
 
 msgid "git commit-tree <tree> [(-p <parent>)...]"
-msgstr ""
+msgstr "git commit-tree <дерево> [(-p <батько>)...]"
 
 msgid ""
 "git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
 "                [(-F <file>)...] <tree>"
 msgstr ""
+"git commit-tree [(-p <батько>)...] [-S[<ідентифікатор-ключа>]] [(-m "
+"<допис>)...]\n"
+"                [(-F <файл>)...] <дерево>"
 
 #, c-format
 msgid "duplicate parent %s ignored"
-msgstr ""
+msgstr "проігноровано дубльований батьківський %s"
 
 #, c-format
 msgid "not a valid object name %s"
@@ -4462,35 +4553,35 @@ msgstr "невірне ім’я об’єкта %s"
 
 #, c-format
 msgid "git commit-tree: failed to read '%s'"
-msgstr ""
+msgstr "git commit-tree: не вдалося прочитати \"%s\""
 
 #, c-format
 msgid "git commit-tree: failed to close '%s'"
-msgstr ""
+msgstr "git commit-tree: не вдалося закрити \"%s\""
 
 msgid "parent"
-msgstr ""
+msgstr "батько"
 
 msgid "id of a parent commit object"
-msgstr ""
+msgstr "ідентифікатор обʼєкта батьківського коміту"
 
 msgid "message"
-msgstr ""
+msgstr "допис"
 
 msgid "commit message"
-msgstr ""
+msgstr "допис до коміту"
 
 msgid "read commit log message from file"
-msgstr ""
+msgstr "читати допис до коміту з файлу"
 
 msgid "GPG sign commit"
 msgstr "підписати коміт за допомогою GPG"
 
 msgid "must give exactly one tree"
-msgstr ""
+msgstr "має бути надано лишень одне дерево"
 
 msgid "git commit-tree: failed to read"
-msgstr ""
+msgstr "git commit-tree: не вдалося прочитати"
 
 msgid ""
 "git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
@@ -4503,6 +4594,16 @@ msgid ""
 "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
 "           [--] [<pathspec>...]"
 msgstr ""
+"git commit [-a | --interactive | --patch] [-s] [-v] [-u<режим>] [--amend]\n"
+"           [--dry-run] [(-c | -C | --squash) <коміт> | --fixup [(amend|"
+"reword):]<коміт>)]\n"
+"           [-F <файл> | -m <допис>] [--reset-author] [--allow-empty]\n"
+"           [--allow-empty-message] [--no-verify] [-e] [--author=<автор>]\n"
+"           [--date=<дата>] [--cleanup=<режим>] [--[no-]status]\n"
+"           [-i | -o] [--pathspec-from-file=<файл> [--pathspec-file-nul]]\n"
+"           [(--trailer <токен>[(=|:)<значення>])...] [-S[<ідентифікатор "
+"ключа>]]\n"
+"           [--] [<визначник шляху>...]"
 
 msgid "git status [<options>] [--] [<pathspec>...]"
 msgstr "git status [<опції>] [--] [<визначник шляху>...]"
@@ -4512,6 +4613,9 @@ msgid ""
 "it empty. You can repeat your command with --allow-empty, or you can\n"
 "remove the commit entirely with \"git reset HEAD^\".\n"
 msgstr ""
+"Ви просили внести зміни до останнього коміту, але це зробить його\n"
+"порожнім. Ви можете повторити команду, скориставшись --allow-empty, або\n"
+"повністю видалити коміт за допомогою \"git reset HEAD^\".\n"
 
 msgid ""
 "The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
@@ -4520,12 +4624,17 @@ msgid ""
 "    git commit --allow-empty\n"
 "\n"
 msgstr ""
+"Попереднє висмикування зараз порожнє, можливо, через вирішення конфлікту.\n"
+"Якщо ви все одно бажаєте додати його, скористайтесь командою\n"
+"\n"
+"    git commit --allow-empty\n"
 
 msgid "Otherwise, please use 'git rebase --skip'\n"
-msgstr ""
+msgstr "В іншому випадку, будь ласка, скористайтесь \"git rebase --skip\"\n"
 
 msgid "Otherwise, please use 'git cherry-pick --skip'\n"
 msgstr ""
+"В іншому випадку, будь ласка, скористайтесь \"git cherry-pick --skip\"\n"
 
 msgid ""
 "and then use:\n"
@@ -4538,24 +4647,35 @@ msgid ""
 "    git cherry-pick --skip\n"
 "\n"
 msgstr ""
+"а потім скористайтесь:\n"
+"\n"
+"    git cherry-pick --continue\n"
+"\n"
+"щоб продовжити висмикування решти комітів.\n"
+"Якщо ви хочете пропустити цей коміт, скористайтесь\n"
+"\n"
+"    git cherry-pick --skip\n"
+
+msgid "updating files failed"
+msgstr "не вдалося оновити файли"
 
 msgid "failed to unpack HEAD tree object"
-msgstr ""
+msgstr "не вдалося розпакувати HEAD обʼєкт дерева"
 
 msgid "No paths with --include/--only does not make sense."
-msgstr ""
+msgstr "Ніякі шляхи з --include/--only не мають сенсу."
 
 msgid "unable to create temporary index"
 msgstr "не вдалося створити тимчасовий індекс"
 
 msgid "interactive add failed"
-msgstr ""
+msgstr "інтерактивне додавання не вдалося"
 
 msgid "unable to update temporary index"
 msgstr "не вдалося оновити тимчасовий індекс"
 
 msgid "Failed to update main cache tree"
-msgstr ""
+msgstr "Не вдалося оновити головне дерево кешу"
 
 msgid "unable to write new_index file"
 msgstr "не вдалося записати new_index файл"
@@ -4564,7 +4684,7 @@ msgid "cannot do a partial commit during a merge."
 msgstr "неможливо зробити частковий коміт під час злиття."
 
 msgid "cannot do a partial commit during a cherry-pick."
-msgstr ""
+msgstr "неможливо зробити частковий коміт під час висмикування."
 
 msgid "cannot do a partial commit during a rebase."
 msgstr "неможливо зробити частковий коміт під час перебазування."
@@ -4577,14 +4697,14 @@ msgstr "не вдалося записати тимчасовий файл ін
 
 #, c-format
 msgid "commit '%s' lacks author header"
-msgstr ""
+msgstr "у коміті \"%s\" немає заголовка автора"
 
 #, c-format
 msgid "commit '%s' has malformed author line"
-msgstr ""
+msgstr "у коміті \"%s\" невірно сформовано рядок автора"
 
 msgid "malformed --author parameter"
-msgstr ""
+msgstr "невірно сформований --author параметр"
 
 #, c-format
 msgid "invalid date format: %s"
@@ -4594,31 +4714,33 @@ msgid ""
 "unable to select a comment character that is not used\n"
 "in the current commit message"
 msgstr ""
+"не вдалося вибрати символ коментаря, який не використовується\n"
+"у поточному дописі до коміту"
 
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "не вдалося знайти коміт %s"
+msgid "could not lookup commit '%s'"
+msgstr "не вдалося знайти коміт \"%s\""
 
 #, c-format
 msgid "(reading log message from standard input)\n"
-msgstr ""
+msgstr "(читання допису журналу зі стандартного вводу)\n"
 
 msgid "could not read log from standard input"
-msgstr ""
+msgstr "не вдалося прочитати допис зі стандартного вводу"
 
 #, c-format
 msgid "could not read log file '%s'"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð¿Ñ\80оÑ\87иÑ\82аÑ\82и Ð»Ð¾Ð³ Ñ\84айл \"%s\""
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð¿Ñ\80оÑ\87иÑ\82аÑ\82и Ð´Ð¾Ð¿Ð¸Ñ\81 Ð· Ñ\84айлÑ\83 \"%s\""
 
 #, c-format
 msgid "options '%s' and '%s:%s' cannot be used together"
 msgstr "опції \"%s\" та \"%s:%s\" не можна використовувати разом"
 
 msgid "could not read SQUASH_MSG"
-msgstr ""
+msgstr "не вдалося прочитати SQUASH_MSG"
 
 msgid "could not read MERGE_MSG"
-msgstr ""
+msgstr "не вдалося прочитати MERGE_MSG"
 
 #, c-format
 msgid "could not open '%s'"
@@ -4632,18 +4754,24 @@ msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '%c' will be ignored.\n"
 msgstr ""
+"Будь ласка, введіть допис до коміту для ваших змін. Рядки, що починаються з\n"
+" \"%c\" будуть проігноровані.\n"
 
 #, c-format
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '%c' will be ignored, and an empty message aborts the commit.\n"
 msgstr ""
+"Будь ласка, введіть допис до коміту для ваших змін. Рядки, що починаються з\n"
+" \"%c\" будуть проігноровані, а порожній допис перерве коміт.\n"
 
 #, c-format
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '%c' will be kept; you may remove them yourself if you want to.\n"
 msgstr ""
+"Будь ласка, введіть допис до коміту для ваших змін. Рядки, що починаються з\n"
+" \"%c\" будуть збережені; ви можете вилучити їх самостійно, якщо захочете.\n"
 
 #, c-format
 msgid ""
@@ -4651,6 +4779,9 @@ msgid ""
 "with '%c' will be kept; you may remove them yourself if you want to.\n"
 "An empty message aborts the commit.\n"
 msgstr ""
+"Будь ласка, введіть допис до коміту для ваших змін. Рядки, що починаються з\n"
+" \"%c\" будуть збережені; ви можете вилучити їх самостійно, якщо захочете.\n"
+"Порожній допис перериває коміт.\n"
 
 msgid ""
 "\n"
@@ -4659,6 +4790,11 @@ msgid ""
 "\tgit update-ref -d MERGE_HEAD\n"
 "and try again.\n"
 msgstr ""
+"\n"
+"Схоже, що ви робите злиття.\n"
+"Якщо це не так, виконайте команду\n"
+"\tgit update-ref -d MERGE_HEAD\n"
+"і спробуйте ще раз.\n"
 
 msgid ""
 "\n"
@@ -4667,35 +4803,42 @@ msgid ""
 "\tgit update-ref -d CHERRY_PICK_HEAD\n"
 "and try again.\n"
 msgstr ""
+"\n"
+"Схоже, що ви робите висмикування.\n"
+"Якщо це не так, виконайте\n"
+"\tgit update-ref -d CHERRY_PICK_HEAD\n"
+"і спробуйте ще раз.\n"
 
 #, c-format
 msgid "%sAuthor:    %.*s <%.*s>"
-msgstr ""
+msgstr "%sАвтор:    %.*s <%.*s>"
 
 #, c-format
 msgid "%sDate:      %s"
-msgstr ""
+msgstr "%sДата:      %s"
 
 #, c-format
 msgid "%sCommitter: %.*s <%.*s>"
-msgstr ""
+msgstr "%sКомітер: %.*s <%.*s>"
 
 msgid "Cannot read index"
 msgstr "Неможливо прочитати індекс"
 
 msgid "unable to pass trailers to --trailers"
-msgstr "не вдалося передати trailers до --trailers"
+msgstr "не вдалося передати причепи до --trailers"
 
 msgid "Error building trees"
-msgstr ""
+msgstr "Помилка при побудові дерев"
 
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
-msgstr ""
+msgstr "Будь ласка, надайте допис, використовуючи опцію -m або -F.\n"
 
 #, c-format
 msgid "--author '%s' is not 'Name <email>' and matches no existing author"
 msgstr ""
+"--author \"%s\" не в форматі \"Імʼя <адреса електронної пошти>\" і не "
+"відповідає жодному існуючому автору"
 
 #, c-format
 msgid "Invalid ignored mode '%s'"
@@ -4706,55 +4849,54 @@ msgid "Invalid untracked files mode '%s'"
 msgstr "Неприпустимий режим невідстежуваних файлів \"%s\""
 
 msgid "You are in the middle of a merge -- cannot reword."
-msgstr "Ви перебуваєте в процесі злиття -- неможливо переформулювати."
+msgstr "Ви перебуваєте в процесі злиття -- неможливо перефразувати."
 
 msgid "You are in the middle of a cherry-pick -- cannot reword."
-msgstr ""
-"Ви перебуваєте в середині процесу висмикування -- неможливо переформулювати."
+msgstr "Ви перебуваєте в процесі висмикування -- неможливо перефразувати."
 
 #, c-format
 msgid "reword option of '%s' and path '%s' cannot be used together"
 msgstr ""
-"параметр переформулювання \"%s\" і шлях \"%s\" не можна використовувати разом"
+"параметр перефразування \"%s\" і шлях \"%s\" не можуть бути використані разом"
 
 #, c-format
 msgid "reword option of '%s' and '%s' cannot be used together"
-msgstr "опÑ\86Ñ\96Ñ\8f Ð¿ÐµÑ\80еÑ\84оÑ\80мÑ\83лÑ\8eваннÑ\8f \"%s\" Ñ\96 \"%s\" Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð±Ñ\83Ñ\82и Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82ана разом"
+msgstr "опÑ\86Ñ\96Ñ\8e Ð¿ÐµÑ\80еÑ\84Ñ\80азÑ\83ваннÑ\8f \"%s\" Ñ\96 \"%s\" Ð½Ðµ Ð¼Ð¾Ð¶Ð½Ð° Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82овÑ\83ваÑ\82и разом"
 
 msgid "You have nothing to amend."
-msgstr ""
+msgstr "Вам немає до чого вносити зміни."
 
 msgid "You are in the middle of a merge -- cannot amend."
-msgstr "Ви перебуваєте в процесі злиття -- не можна вносити зміни."
+msgstr "Ви перебуваєте в процесі злиття -- неможливо внести зміни."
 
 msgid "You are in the middle of a cherry-pick -- cannot amend."
-msgstr "Ви перебуваєте в процесі висмикування - не можна вносити зміни."
+msgstr "Ви перебуваєте в процесі висмикування - неможливо внести зміни."
 
 msgid "You are in the middle of a rebase -- cannot amend."
-msgstr "Ви перебуваєте в процесі перебазуавння -- не можна вносити зміни."
+msgstr "Ви перебуваєте в процесі перебазуавння -- неможливо внести зміни."
 
 msgid "--reset-author can be used only with -C, -c or --amend."
-msgstr ""
+msgstr "--reset-author можна використовувати лише з -C, -c або --amend."
 
 #, c-format
 msgid "unknown option: --fixup=%s:%s"
-msgstr ""
+msgstr "невідомий параметр: --fixup=%s:%s"
 
 #, c-format
 msgid "paths '%s ...' with -a does not make sense"
 msgstr "шляхи \"%s ...\" з -a не мають сенсу"
 
 msgid "show status concisely"
-msgstr ""
+msgstr "показувати статус стисло"
 
 msgid "show branch information"
 msgstr "показати інформацію про гілку"
 
 msgid "show stash information"
-msgstr ""
+msgstr "показати інформацію про схов"
 
 msgid "compute full ahead/behind values"
-msgstr ""
+msgstr "обчислювати повні попереду/позаду значення"
 
 msgid "version"
 msgstr "версія"
@@ -4763,315 +4905,335 @@ msgid "machine-readable output"
 msgstr "машинозчитуваний вивід"
 
 msgid "show status in long format (default)"
-msgstr ""
+msgstr "показувати статус у повному форматі (за замовчуванням)"
 
 msgid "terminate entries with NUL"
-msgstr ""
+msgstr "завершувати записи символом NUL"
 
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
+"показувати невідстежувані файли, варіанти режимів: all, normal, no (за "
+"замовчуванням: all)"
 
 msgid ""
 "show ignored files, optional modes: traditional, matching, no. (Default: "
 "traditional)"
 msgstr ""
+"показувати ігноровані файли, варіанти режимів: traditional, matching, no (за "
+"замовчуванням: traditional)."
 
 msgid "when"
-msgstr ""
+msgstr "коли"
 
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
 msgstr ""
+"ігнорувати зміни підмодулів, опціонально, якщо: all, dirty, untracked (за "
+"замовчуванням: all)."
 
 msgid "list untracked files in columns"
 msgstr "показати невідстежувані файли в стовпчиках"
 
 msgid "do not detect renames"
-msgstr ""
+msgstr "не виявляти перейменування"
 
 msgid "detect renames, optionally set similarity index"
-msgstr ""
+msgstr "виявляти перейменування, опціонально встановлювати індекс схожості"
 
 msgid "Unsupported combination of ignored and untracked-files arguments"
 msgstr ""
+"Непідтримувана комбінація аргументів для ігнорованих та невідстежуваних "
+"файлів"
 
 msgid "suppress summary after successful commit"
-msgstr ""
+msgstr "не показувати підсумок після успішного коміту"
 
 msgid "show diff in commit message template"
-msgstr ""
+msgstr "показувати різницю в шаблоні дописа до коміту"
 
 msgid "Commit message options"
-msgstr ""
+msgstr "Опції дописа до коміту"
 
 msgid "read message from file"
-msgstr ""
+msgstr "читати текст дописа з файлу"
 
 msgid "author"
-msgstr ""
+msgstr "автор"
 
 msgid "override author for commit"
-msgstr ""
+msgstr "перевизначити автора коміту"
 
 msgid "date"
-msgstr ""
+msgstr "дата"
 
 msgid "override date for commit"
-msgstr ""
+msgstr "перевизначити дату коміту"
 
 msgid "commit"
 msgstr "коміт"
 
 msgid "reuse and edit message from specified commit"
-msgstr ""
+msgstr "повторно використати та редагувати допис зі вказаного коміту"
 
 msgid "reuse message from specified commit"
-msgstr ""
+msgstr "повторно використати допис зі вказаного коміту"
 
 #. TRANSLATORS: Leave "[(amend|reword):]" as-is,
 #. and only translate <commit>.
 #.
 
 msgid "[(amend|reword):]commit"
-msgstr ""
+msgstr "[(amend|reword):]коміт"
 
 msgid ""
 "use autosquash formatted message to fixup or amend/reword specified commit"
 msgstr ""
+"використовувати допис у форматі autosquash для виправлення або зміни/"
+"редагування вказаного коміту"
 
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
+"використовувати допис у форматі autosquash для зчавлювання вказаного коміту"
 
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
-msgstr ""
+msgstr "автором коміту тепер є я (використовується з -C/-c/--amend)"
 
 msgid "trailer"
-msgstr ""
+msgstr "причіп"
 
 msgid "add custom trailer(s)"
-msgstr ""
+msgstr "додати нестандартний причіп"
 
 msgid "add a Signed-off-by trailer"
-msgstr ""
+msgstr "додати Signed-off-by причіп"
 
 msgid "use specified template file"
-msgstr ""
+msgstr "використати зазначений файл шаблону"
 
 msgid "force edit of commit"
 msgstr "редагувати коміт примусово"
 
 msgid "include status in commit message template"
-msgstr ""
+msgstr "включити статус у шаблон дописа до коміту"
 
 msgid "Commit contents options"
-msgstr ""
+msgstr "Опції вмісту коміту"
 
 msgid "commit all changed files"
-msgstr ""
+msgstr "закомітити всі змінені файли"
 
 msgid "add specified files to index for commit"
-msgstr ""
+msgstr "додати вказані файли до індексу для коміту"
 
 msgid "interactively add files"
 msgstr "додавати файли інтерактивно"
 
 msgid "interactively add changes"
-msgstr ""
+msgstr "додавати зміни інтерактивно"
 
 msgid "commit only specified files"
-msgstr ""
+msgstr "комітити лише вказані файли"
 
 msgid "bypass pre-commit and commit-msg hooks"
-msgstr ""
+msgstr "обходити pre-commit та commit-msg гачки"
 
 msgid "show what would be committed"
-msgstr "показаÑ\82и, Ñ\89о Ð±Ñ\83де Ð´Ð¾Ð´Ð°Ð½Ð¾ Ð´Ð¾ ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\83"
+msgstr "показаÑ\82и, Ñ\89о Ð±Ñ\83де Ð·Ð°ÐºÐ¾Ð¼Ñ\96Ñ\87ено"
 
 msgid "amend previous commit"
-msgstr ""
+msgstr "внести зміни до попереднього коміту"
 
 msgid "bypass post-rewrite hook"
 msgstr "обійти post-rewrite гачок"
 
 msgid "ok to record an empty change"
-msgstr ""
+msgstr "дозволити записати порожню зміну"
 
 msgid "ok to record a change with an empty message"
-msgstr ""
+msgstr "дозволити записати зміну з порожнім дописом"
 
 msgid "could not parse HEAD commit"
 msgstr "не вдалося розібрати HEAD коміт"
 
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
-msgstr ""
+msgstr "Пошкоджений MERGE_HEAD (%s)"
 
 msgid "could not read MERGE_MODE"
-msgstr ""
+msgstr "не вдалося прочитати MERGE_MODE"
 
 #, c-format
 msgid "could not read commit message: %s"
-msgstr "не вдалося прочитати допис до коміта: %s"
+msgstr "не вдалося прочитати допис до коміту: %s"
 
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
-msgstr ""
+msgstr "Переривання коміту через порожній допис до коміту.\n"
 
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
-msgstr ""
+msgstr "Переривання коміту; ви не відредагували допис.\n"
 
 #, c-format
 msgid "Aborting commit due to empty commit message body.\n"
-msgstr ""
+msgstr "Переривання коміту через порожнє тіло дописа до коміту.\n"
 
 msgid ""
 "repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full and quota is\n"
 "not exceeded, and then \"git restore --staged :/\" to recover."
 msgstr ""
+"сховище було оновлено, але не вдалося записати\n"
+"файл new_index. Переконайтеся, що диск не переповнений і квота\n"
+"не перевищена, а потім виконайте \"git restore --staged :/\" для відновлення."
 
 msgid "git config [<options>]"
 msgstr "git config [<опції>]"
 
 #, c-format
 msgid "unrecognized --type argument, %s"
-msgstr ""
+msgstr "нерозпізнаний аргумент --type, %s"
 
 msgid "only one type at a time"
-msgstr ""
+msgstr "лише один тип за раз"
 
 msgid "Config file location"
-msgstr ""
+msgstr "Розташування файлу конфігурації"
 
 msgid "use global config file"
-msgstr ""
+msgstr "використовувати глобальний файл конфігурації"
 
 msgid "use system config file"
-msgstr ""
+msgstr "використовувати файл конфігурації системи"
 
 msgid "use repository config file"
-msgstr "використовувати конфігураційний файл сховища"
+msgstr "використовувати файл конфігурації сховища"
 
 msgid "use per-worktree config file"
-msgstr "використовувати конфігураційний файл робочого дерева"
+msgstr "використовувати файл конфігурації робочого дерева"
 
 msgid "use given config file"
-msgstr ""
+msgstr "використовувати наданий файл конфігурації"
 
 msgid "blob-id"
-msgstr ""
+msgstr "blob-id"
 
 msgid "read config from given blob object"
-msgstr ""
+msgstr "прочитати конфігурацію з наданого blob-обʼєкту"
 
 msgid "Action"
-msgstr ""
+msgstr "Дія"
 
 msgid "get value: name [value-pattern]"
-msgstr ""
+msgstr "отримати значення: назва [шаблон-значення]"
 
 msgid "get all values: key [value-pattern]"
-msgstr ""
+msgstr "отримати всі значення: ключ [шаблон-значення]"
 
 msgid "get values for regexp: name-regex [value-pattern]"
-msgstr ""
+msgstr "отримати значення для регвиру: регвир-назви [шаблон-значення]"
 
 msgid "get value specific for the URL: section[.var] URL"
-msgstr ""
+msgstr "отримати значення для конкретної URL-адреси: розділ[.var] URL-адреса"
 
 msgid "replace all matching variables: name value [value-pattern]"
-msgstr ""
+msgstr "замінити всі відповідні змінні: назва значення [шаблон-значення]"
 
 msgid "add a new variable: name value"
-msgstr ""
+msgstr "додати нову змінну: назва значення"
 
 msgid "remove a variable: name [value-pattern]"
-msgstr ""
+msgstr "видалити змінну: назва [шаблон-значення]"
 
 msgid "remove all matches: name [value-pattern]"
-msgstr ""
+msgstr "видалити всі збіги: назва [шаблон-значення]"
 
 msgid "rename section: old-name new-name"
-msgstr ""
+msgstr "перейменувати розділ: стара-назва нова-назва"
 
 msgid "remove a section: name"
-msgstr ""
+msgstr "видалити розділ: назва"
 
 msgid "list all"
-msgstr ""
+msgstr "показати всі змінні"
 
 msgid "use string equality when comparing values to 'value-pattern'"
 msgstr ""
+"використовувати рівність строк при порівнянні значень з \"шаблон-значенням\""
 
 msgid "open an editor"
-msgstr ""
+msgstr "відкрити редактор"
 
 msgid "find the color configured: slot [default]"
-msgstr ""
+msgstr "знайти налаштований колір: слот [за замовчуванням]"
 
 msgid "find the color setting: slot [stdout-is-tty]"
-msgstr ""
+msgstr "знайти налаштування кольору: slot [stdout-is-tty]"
 
 msgid "Type"
-msgstr ""
+msgstr "Тип"
 
 msgid "type"
-msgstr ""
+msgstr "тип"
 
 msgid "value is given this type"
-msgstr ""
+msgstr "тип значення"
 
 msgid "value is \"true\" or \"false\""
-msgstr ""
+msgstr "значення \"true\" або \"false\""
 
 msgid "value is decimal number"
-msgstr ""
+msgstr "значення десяткове число"
 
 msgid "value is --bool or --int"
-msgstr ""
+msgstr "значення --bool або --int"
 
 msgid "value is --bool or string"
-msgstr ""
+msgstr "значення --bool або string"
 
 msgid "value is a path (file or directory name)"
-msgstr ""
+msgstr "значення шлях (файл або назва директорії)"
 
 msgid "value is an expiry date"
-msgstr ""
+msgstr "значення - дата закінчення терміну дії"
 
 msgid "Other"
-msgstr ""
+msgstr "Інше"
 
 msgid "terminate values with NUL byte"
-msgstr ""
+msgstr "завершити значення байтом NUL"
 
 msgid "show variable names only"
-msgstr ""
+msgstr "показувати тільки назви змінних"
 
 msgid "respect include directives on lookup"
-msgstr ""
+msgstr "дотримуватись директив включення при пошуку"
 
 msgid "show origin of config (file, standard input, blob, command line)"
 msgstr ""
+"показати походження конфігурації (файл, стандартний ввід, blob, командний "
+"рядок)"
 
 msgid "show scope of config (worktree, local, global, system, command)"
 msgstr ""
+"показати межі дії конфігурації (робоче дерево, локально, глобально, система, "
+"команда)"
 
 msgid "value"
 msgstr "значення"
 
 msgid "with --get, use default value when missing entry"
 msgstr ""
+"з --get використовувати значення за замовчуванням, якщо запис відсутній"
 
 #, c-format
 msgid "wrong number of arguments, should be %d"
-msgstr ""
+msgstr "невірна кількість аргументів, має бути %d"
 
 #, c-format
 msgid "wrong number of arguments, should be from %d to %d"
-msgstr ""
+msgstr "невірна кількість аргументів, має бути від %d до %d"
 
 #, c-format
 msgid "invalid key pattern: %s"
@@ -5093,13 +5255,13 @@ msgid "unable to parse default color value"
 msgstr "не вдалося розібрати початкове значення кольору"
 
 msgid "not in a git directory"
-msgstr "не в директорії git"
+msgstr "не в git директорії"
 
 msgid "writing to stdin is not supported"
-msgstr ""
+msgstr "запис до stdin не підтримується"
 
 msgid "writing config blobs is not supported"
-msgstr ""
+msgstr "запис blob конфігурації не підтримується"
 
 #, c-format
 msgid ""
@@ -5109,9 +5271,14 @@ msgid ""
 "#\tname = %s\n"
 "#\temail = %s\n"
 msgstr ""
+"# Це файл конфігурації Git для кожного користувача.\n"
+"[user]\n"
+"# Будь ласка, адаптуйте та розкоментуйте наступні рядки:\n"
+"# name = %s\n"
+"# email = %s\n"
 
 msgid "only one config file at a time"
-msgstr ""
+msgstr "лише один конфігураційний файл за раз"
 
 msgid "--local can only be used inside a git repository"
 msgstr "--local можна використовувати лише всередині git сховища"
@@ -5123,33 +5290,39 @@ msgid "--worktree can only be used inside a git repository"
 msgstr "--worktree можна використовувати лише всередині git сховища"
 
 msgid "$HOME not set"
-msgstr ""
+msgstr "$HOME не встановлено"
 
 msgid ""
 "--worktree cannot be used with multiple working trees unless the config\n"
 "extension worktreeConfig is enabled. Please read \"CONFIGURATION FILE\"\n"
 "section in \"git help worktree\" for details"
 msgstr ""
+"--worktree неможливо використовувати з кількома робочими деревами, якщо не "
+"увімкнено розширення\n"
+"конфігурації worktreeConfig. Будь ласка, прочитайте розділ \"КОНФІГУРАЦІЙНИЙ "
+"ФАЙЛ\"\n"
+"у \"git help worktree\" для більш детальної інформації"
 
 msgid "--get-color and variable type are incoherent"
-msgstr ""
+msgstr "--get-color і тип змінної не узгоджуються"
 
 msgid "only one action at a time"
-msgstr ""
+msgstr "лише одна дія за раз"
 
 msgid "--name-only is only applicable to --list or --get-regexp"
-msgstr ""
+msgstr "--name-only застосовується лише до --list або --get-regexp"
 
 msgid ""
 "--show-origin is only applicable to --get, --get-all, --get-regexp, and --"
 "list"
 msgstr ""
+"--show-origin застосовується лише до --get, --get-all, --get-regexp та --list"
 
 msgid "--default is only applicable to --get"
-msgstr ""
+msgstr "--default застосовується лише до --get"
 
 msgid "--fixed-value only applies with 'value-pattern'"
-msgstr ""
+msgstr "--fixed-value застосовується лише з \"шаблоном-значення\""
 
 #, c-format
 msgid "unable to read config file '%s'"
@@ -5159,10 +5332,10 @@ msgid "error processing config file(s)"
 msgstr "помилка при обробці файлу(ів) конфігурації"
 
 msgid "editing stdin is not supported"
-msgstr ""
+msgstr "редагування stdin не підтримується"
 
 msgid "editing blobs is not supported"
-msgstr ""
+msgstr "редагування blobs не підтримується"
 
 #, c-format
 msgid "cannot create configuration file %s"
@@ -5173,13 +5346,15 @@ msgid ""
 "cannot overwrite multiple values with a single value\n"
 "       Use a regexp, --add or --replace-all to change %s."
 msgstr ""
+"неможливо перезаписати кілька значень одним значенням\n"
+"       Використовуйте regexp, --add або --replace-all для зміни %s."
 
 #, c-format
 msgid "no such section: %s"
 msgstr "немає такого розділу: %s"
 
 msgid "print sizes in human readable format"
-msgstr ""
+msgstr "показувати розмір у зручному для читання форматі"
 
 #, c-format
 msgid ""
@@ -5188,85 +5363,100 @@ msgid ""
 "\n"
 "\tchmod 0700 %s"
 msgstr ""
+"Дозволи на вашу сокет директорію занадто вільні; інші\n"
+"користувачі можуть прочитати ваші кешовані облікові дані. Подумайте про "
+"запуск:\n"
+"\n"
+"\tchmod 0700 %s"
 
 msgid "print debugging messages to stderr"
-msgstr ""
+msgstr "виводити відлагоджувальні повідомлення в stderr"
 
 msgid "credential-cache--daemon unavailable; no unix socket support"
-msgstr ""
+msgstr "credential-cache--daemon недоступний; немає підтримки unix-сокетів"
 
 msgid "credential-cache unavailable; no unix socket support"
-msgstr ""
+msgstr "credential-cache недоступний; немає підтримки unix-сокетів"
 
 #, c-format
 msgid "unable to get credential storage lock in %d ms"
-msgstr ""
+msgstr "не вдалося отримати файл блокування сховища облікових даних за %d мс"
 
 msgid ""
 "git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"
 msgstr ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<н>] "
+"[<комітоподібне>...]"
 
 msgid ""
 "git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"
 msgstr ""
+"git describe [--all] [--tags] [--contains] [--abbrev=<н>] --"
+"dirty[=<позначка>]"
 
 msgid "git describe <blob>"
-msgstr ""
+msgstr "git describe <blob>"
 
 msgid "head"
 msgstr "head"
 
 msgid "lightweight"
-msgstr ""
+msgstr "lightweight"
 
 msgid "annotated"
-msgstr ""
+msgstr "annotated"
 
 #, c-format
 msgid "annotated tag %s not available"
-msgstr ""
+msgstr "анотований тег %s недоступний"
 
 #, c-format
 msgid "tag '%s' is externally known as '%s'"
-msgstr ""
+msgstr "тег \"%s\" відомий зовні як \"%s\""
 
 #, c-format
 msgid "no tag exactly matches '%s'"
-msgstr ""
+msgstr "жоден тег не збігається точно з \"%s\""
 
 #, c-format
 msgid "No exact match on refs or tags, searching to describe\n"
-msgstr ""
+msgstr "Немає точного збігу за посиланнями або тегами, пошук для опису\n"
 
 #, c-format
 msgid "finished search at %s\n"
-msgstr ""
+msgstr "пошук завершено на %s\n"
 
 #, c-format
 msgid ""
 "No annotated tags can describe '%s'.\n"
 "However, there were unannotated tags: try --tags."
 msgstr ""
+"Жоден анотований тег не може описати \"%s\".\n"
+"Однак існують неанотовані теги: спробуйте --tags."
 
 #, c-format
 msgid ""
 "No tags can describe '%s'.\n"
 "Try --always, or create some tags."
 msgstr ""
+"Жоден тег не може описати \"%s\".\n"
+"Спробуйте --always або створіть кілька тегів."
 
 #, c-format
 msgid "traversed %lu commits\n"
-msgstr ""
+msgstr "пройдено через %lu комітів\n"
 
 #, c-format
 msgid ""
 "more than %i tags found; listed %i most recent\n"
 "gave up search at %s\n"
 msgstr ""
+"знайдено більше %i тегів; показані %i останніх\n"
+"припинено пошук на %s\n"
 
 #, c-format
 msgid "describe %s\n"
-msgstr ""
+msgstr "описати %s\n"
 
 #, c-format
 msgid "Not a valid object name %s"
@@ -5274,53 +5464,56 @@ msgstr "Неприпустиме ім’я об’єкта %s"
 
 #, c-format
 msgid "%s is neither a commit nor blob"
-msgstr ""
+msgstr "%s не є commit чи blob"
 
 msgid "find the tag that comes after the commit"
-msgstr ""
+msgstr "знайти тег, що йде після коміту"
 
 msgid "debug search strategy on stderr"
-msgstr ""
+msgstr "виводити відлагоджувальні повідомлення стратегії пошуку в stderr"
 
 msgid "use any ref"
 msgstr "використати будь-яке посилання"
 
 msgid "use any tag, even unannotated"
-msgstr ""
+msgstr "використати будь-який тег, навіть неанотований"
 
 msgid "always use long format"
-msgstr ""
+msgstr "завжди використовувати довгий формат"
 
 msgid "only follow first parent"
-msgstr ""
+msgstr "слідувати тільки за першим з батьків"
 
 msgid "only output exact matches"
-msgstr ""
+msgstr "виводити лише точні збіги"
 
 msgid "consider <n> most recent tags (default: 10)"
-msgstr ""
+msgstr "враховувати <н> останніх тегів (за замовчуванням: 10)"
 
 msgid "only consider tags matching <pattern>"
-msgstr ""
+msgstr "враховувати лише теги, що відповідають <шаблону>"
 
 msgid "do not consider tags matching <pattern>"
-msgstr ""
+msgstr "не враховувати теги, що відповідають <шаблону>"
 
 msgid "show abbreviated commit object as fallback"
-msgstr ""
+msgstr "показувати скорочений обʼєкт коміту як запасний варіант"
 
 msgid "mark"
-msgstr ""
+msgstr "позначка"
 
 msgid "append <mark> on dirty working tree (default: \"-dirty\")"
 msgstr ""
-"додати <mark> на брудному робочому дереві (за замовчуванням: \\”-dirty\\”)"
+"додати <позначку> до брудного робочого дерева (за замовчуванням: \\”-"
+"dirty\\”)"
 
 msgid "append <mark> on broken working tree (default: \"-broken\")"
 msgstr ""
+"додати <позначку> до пошкодженого робочого дерева (за замовчуванням: \"-"
+"broken\")"
 
 msgid "No names found, cannot describe anything."
-msgstr ""
+msgstr "Назв не знайдено, неможливо нічого описати."
 
 #, c-format
 msgid "option '%s' and commit-ishes cannot be used together"
@@ -5330,25 +5523,27 @@ msgid ""
 "git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
 "             [--mode=<mode>]"
 msgstr ""
+"git diagnose [(-o | --output-directory) <шлях>] [(-s | --suffix) <формат>]\n"
+"             [--mode=<режим>]"
 
 msgid "specify a destination for the diagnostics archive"
-msgstr ""
+msgstr "вказати місце призначення архіву діагностики"
 
 msgid "specify a strftime format suffix for the filename"
-msgstr ""
+msgstr "вказати суфікс формату strftime для назви файлу"
 
 msgid "specify the content of the diagnostic archive"
-msgstr ""
+msgstr "вказати вміст архіву діагностики"
 
 msgid "--merge-base only works with two commits"
-msgstr ""
+msgstr "--merge-base працює лише з двома комітами"
 
 #, c-format
 msgid "'%s': not a regular file or symlink"
-msgstr ""
+msgstr "\"%s\": не звичайний файл або символьне посилання"
 
 msgid "no merge given, only parents."
-msgstr ""
+msgstr "злиття не надано, лише батьки."
 
 #, c-format
 msgid "invalid option: %s"
@@ -5356,7 +5551,7 @@ msgstr "неприпустима опція %s"
 
 #, c-format
 msgid "%s...%s: no merge base"
-msgstr ""
+msgstr "%s...%s: немає бази злиття"
 
 msgid "Not a git repository"
 msgstr "Не є git сховищем"
@@ -5367,7 +5562,7 @@ msgstr "надано неприпустимий об’єкт \"%s\"."
 
 #, c-format
 msgid "more than two blobs given: '%s'"
-msgstr ""
+msgstr "надано більше двох blob: \"%s\""
 
 #, c-format
 msgid "unhandled object '%s' given."
@@ -5375,10 +5570,10 @@ msgstr "надано необроблений об’єкт \"%s\"."
 
 #, c-format
 msgid "%s...%s: multiple merge bases, using %s"
-msgstr ""
+msgstr "%s...%s: кілька баз злиття, використання %s"
 
 msgid "git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"
-msgstr ""
+msgstr "git difftool [<опції>] [<коміт> [<коміт>]] [--] [<шлях>...]"
 
 #, c-format
 msgid "could not read symlink %s"
@@ -5396,13 +5591,15 @@ msgid ""
 "combined diff formats ('-c' and '--cc') are not supported in\n"
 "directory diff mode ('-d' and '--dir-diff')."
 msgstr ""
+"комбіновані формати diff (\"-c\" і \"--cc\") не підтримуються у\n"
+"режимі порівняння директорій (\"-d\" і \"--dir-diff\")."
 
 #, c-format
 msgid "both files modified: '%s' and '%s'."
-msgstr ""
+msgstr "обидва файли змінено: \"%s\" і \"%s\"."
 
 msgid "working tree file has been left."
-msgstr "залишено файл робочого дерева."
+msgstr "файл робочого дерева було залишено."
 
 #, c-format
 msgid "could not copy '%s' to '%s'"
@@ -5410,144 +5607,150 @@ msgstr "не вдалося скопіювати \"%s\" в \"%s\""
 
 #, c-format
 msgid "temporary files exist in '%s'."
-msgstr ""
+msgstr "тимчасові файли існують в \"%s\"."
 
 msgid "you may want to cleanup or recover these."
-msgstr ""
+msgstr "можливо, ви захочете очистити або відновити їх."
 
 #, c-format
 msgid "failed: %d"
-msgstr ""
+msgstr "завершилось невдало: %d"
 
 msgid "use `diff.guitool` instead of `diff.tool`"
-msgstr ""
+msgstr "використовувати \"diff.guitool\" замість \"diff.tool\""
 
 msgid "perform a full-directory diff"
-msgstr ""
+msgstr "виконати порівняння всіх директорій"
 
 msgid "do not prompt before launching a diff tool"
-msgstr ""
+msgstr "не запитувати перед запуском diff"
 
 msgid "use symlinks in dir-diff mode"
-msgstr ""
+msgstr "використовувати символьні посилання у режимі dir-diff"
 
 msgid "tool"
-msgstr ""
+msgstr "засіб"
 
 msgid "use the specified diff tool"
-msgstr ""
+msgstr "використовувати вказаний diff засіб"
 
 msgid "print a list of diff tools that may be used with `--tool`"
-msgstr ""
+msgstr "показати список diff засобів, які можна використовувати з \"--tool\""
 
 msgid ""
 "make 'git-difftool' exit when an invoked diff tool returns a non-zero exit "
 "code"
 msgstr ""
+"змусити \"git-difftool\" завершувати роботу, коли викликаний diff засіб "
+"повертає ненульовий код завершення"
 
 msgid "specify a custom command for viewing diffs"
-msgstr ""
+msgstr "вказати нестандартну команду для перегляду різниць"
 
 msgid "passed to `diff`"
-msgstr ""
+msgstr "передається до \"diff\""
 
 msgid "difftool requires worktree or --no-index"
-msgstr ""
+msgstr "difftool потребує worktree або --no-index"
 
 msgid "no <tool> given for --tool=<tool>"
-msgstr ""
+msgstr "не надано <засіб> для --tool=<засіб>"
 
 msgid "no <cmd> given for --extcmd=<cmd>"
-msgstr ""
+msgstr "не надана <команда> для --extcmd=<команда>"
 
 msgid "git fast-export [<rev-list-opts>]"
-msgstr ""
+msgstr "git fast-export [<rev-list-опції>]"
 
 msgid "Error: Cannot export nested tags unless --mark-tags is specified."
 msgstr ""
+"Помилка: неможливо експортувати вкладені теги, якщо не вказано --mark-tags."
 
 msgid "--anonymize-map token cannot be empty"
-msgstr ""
+msgstr "--anonymize-map токен не може бути порожнім"
 
 msgid "show progress after <n> objects"
-msgstr ""
+msgstr "показати прогрес після <н> обʼєктів"
 
 msgid "select handling of signed tags"
-msgstr ""
+msgstr "вибрати обробку підписаних тегів"
 
 msgid "select handling of tags that tag filtered objects"
-msgstr ""
+msgstr "вибрати обробку тегів, якими позначено відфільтровані обʼєкти"
 
 msgid "select handling of commit messages in an alternate encoding"
-msgstr ""
+msgstr "вибрати обробку дописів до комітів в іншому кодуванні"
 
 msgid "dump marks to this file"
-msgstr ""
+msgstr "експортувати позначки в цей файл"
 
 msgid "import marks from this file"
-msgstr ""
+msgstr "імпортувати позначки з цього файлу"
 
 msgid "import marks from this file if it exists"
-msgstr ""
+msgstr "імпортувати позначки з цього файлу, якщо він існує"
 
 msgid "fake a tagger when tags lack one"
-msgstr ""
+msgstr "підробляти теггера, коли його не вказано для тега"
 
 msgid "output full tree for each commit"
-msgstr ""
+msgstr "виводити повне дерево для кожного коміту"
 
 msgid "use the done feature to terminate the stream"
-msgstr ""
+msgstr "використовувати особливість done для завершення потоку"
 
 msgid "skip output of blob data"
-msgstr ""
+msgstr "пропускати виведення blob-даних"
 
 msgid "refspec"
-msgstr ""
+msgstr "визначник посилання"
 
 msgid "apply refspec to exported refs"
-msgstr ""
+msgstr "застосувати визначник посилання до експортованих посилань"
 
 msgid "anonymize output"
-msgstr ""
+msgstr "анонімізувати вивід"
 
 msgid "from:to"
-msgstr ""
+msgstr "від:до"
 
 msgid "convert <from> to <to> in anonymized output"
-msgstr ""
+msgstr "конвертувати <від> в <до> в анонімізованому виводі"
 
 msgid "reference parents which are not in fast-export stream by object id"
 msgstr ""
+"батьки посилання, яких не знайдено в fast-export потоці за ідентифікатором "
+"обʼєкта"
 
 msgid "show original object ids of blobs/commits"
-msgstr ""
+msgstr "показувати оригінальні ідентифікатори обʼєктів blob/комітів"
 
 msgid "label tags with mark ids"
-msgstr ""
+msgstr "позначати теги ідентифікаторами позначок"
 
 #, c-format
 msgid "Missing from marks for submodule '%s'"
-msgstr ""
+msgstr "Відсутні \"від\" позначки для підмодуля \"%s\""
 
 #, c-format
 msgid "Missing to marks for submodule '%s'"
-msgstr ""
+msgstr "Відсутні \"до\" позначки для підмодуля \"%s\""
 
 #, c-format
 msgid "Expected 'mark' command, got %s"
-msgstr ""
+msgstr "Очікувалась команда \"mark\", отримано %s"
 
 #, c-format
 msgid "Expected 'to' command, got %s"
-msgstr ""
+msgstr "Очікувалась команда \"to\", отримано %s"
 
 msgid "Expected format name:filename for submodule rewrite option"
-msgstr ""
+msgstr "Очікуваний формат назва:назва файлу для параметра перезапису підмодуля"
 
 #, c-format
 msgid "feature '%s' forbidden in input without --allow-unsafe-features"
 msgstr ""
+"особливість \"%s\" не можна використовувати без --allow-unsafe-features"
 
 #, c-format
 msgid "Lockfile created but not reported: %s"
@@ -5566,39 +5769,39 @@ msgid "git fetch --all [<options>]"
 msgstr "git fetch --all [<опції>]"
 
 msgid "fetch.parallel cannot be negative"
-msgstr ""
+msgstr "fetch.parallel не може бути відʼємним"
 
 msgid "couldn't find remote ref HEAD"
-msgstr "не вдалося знайти посилання віддаленого HEAD"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð½Ð°Ð¹Ñ\82и Ð¿Ð¾Ñ\81иланнÑ\8f Ð´Ð»Ñ\8f Ð²Ñ\96ддаленого HEAD"
 
 #, c-format
 msgid "From %.*s\n"
-msgstr ""
+msgstr "Від %.*s\n"
 
 #, c-format
 msgid "object %s not found"
 msgstr "об’єкт %s не знайдено"
 
 msgid "[up to date]"
-msgstr ""
+msgstr "[в актуальному стані]"
 
 msgid "[rejected]"
-msgstr ""
+msgstr "[відхилено]"
 
 msgid "can't fetch into checked-out branch"
 msgstr "неможливо виконати отримання в активну гілку"
 
 msgid "[tag update]"
-msgstr ""
+msgstr "[оновлення тегу]"
 
 msgid "unable to update local ref"
 msgstr "не вдалося оновити локальне посилання"
 
 msgid "would clobber existing tag"
-msgstr ""
+msgstr "зруйнує існуючий тег"
 
 msgid "[new tag]"
-msgstr ""
+msgstr "[новий тег]"
 
 msgid "[new branch]"
 msgstr "[нова гілка]"
@@ -5610,7 +5813,7 @@ msgid "forced update"
 msgstr "примусове оновлення"
 
 msgid "non-fast-forward"
-msgstr ""
+msgstr "без перемотування вперед"
 
 #, c-format
 msgid "cannot open '%s'"
@@ -5621,6 +5824,10 @@ msgid ""
 "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
 "flag or run 'git config fetch.showForcedUpdates true'"
 msgstr ""
+"fetch зазвичай показує, які гілки було примусово оновлено,\n"
+"але цю перевірку було вимкнено; щоб увімкнути її знову, скористайтесь \"--"
+"show-forced-updates\"\n"
+"або виконайте \"git config fetch.showForcedUpdates true\""
 
 #, c-format
 msgid ""
@@ -5629,46 +5836,52 @@ msgid ""
 "false'\n"
 "to avoid this check\n"
 msgstr ""
+"перевірка примусових оновлень зайняла %.2f секунд; ви можете скористатися\n"
+"\"--no-show-forced-updates\" або виконати \"git config fetch."
+"showForcedUpdates false\"\n"
+"щоб уникнути цієї перевірки\n"
 
 #, c-format
 msgid "%s did not send all necessary objects\n"
-msgstr "%s не надіслав всі необхідні обʼєкти\n"
+msgstr "%s не надіслав всіх необхідних обʼєктів\n"
 
 #, c-format
 msgid "rejected %s because shallow roots are not allowed to be updated"
-msgstr ""
+msgstr "відхилено %s, оскільки неглибокі корені не можна оновлювати"
 
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
 " 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
+"не вдалося оновити деякі локальні посилання; спробуйте виконати\n"
+" \"git remote prune %s\", щоб видалити всі старі конфліктні гілки"
 
 #, c-format
 msgid "   (%s will become dangling)"
-msgstr ""
+msgstr "   (%s стануть висячими)"
 
 #, c-format
 msgid "   (%s has become dangling)"
-msgstr ""
+msgstr "   (%s став висячим)"
 
 msgid "[deleted]"
 msgstr "[видалено]"
 
 msgid "(none)"
-msgstr ""
+msgstr "(нічого)"
 
 #, c-format
 msgid "refusing to fetch into branch '%s' checked out at '%s'"
-msgstr ""
+msgstr "відмовлено в отримані в гілку \"%s\", що знаходиться в \"%s\""
 
 #, c-format
 msgid "option \"%s\" value \"%s\" is not valid for %s"
-msgstr ""
+msgstr "значення \"%s\" опції \"%s\" неприпустиме для %s"
 
 #, c-format
 msgid "option \"%s\" is ignored for %s\n"
-msgstr ""
+msgstr "опція \"%s\" ігнорується для %s\n"
 
 #, c-format
 msgid "%s is not a valid object"
@@ -5679,13 +5892,15 @@ msgid "the object %s does not exist"
 msgstr "об’єкт %s не існує"
 
 msgid "multiple branches detected, incompatible with --set-upstream"
-msgstr ""
+msgstr "виявлено кілька гілок, несумісних з --set-upstream"
 
 #, c-format
 msgid ""
 "could not set upstream of HEAD to '%s' from '%s' when it does not point to "
 "any branch."
 msgstr ""
+"не вдалося встановити першоджерельне сховище для HEAD в \"%s\" з \"%s\", "
+"коли воно не вказує на жодну гілку."
 
 msgid "not setting upstream for a remote remote-tracking branch"
 msgstr ""
@@ -5701,6 +5916,8 @@ msgid ""
 "no source branch found;\n"
 "you need to specify exactly one branch with the --set-upstream option"
 msgstr ""
+"джерельна гілка не знайдена;\n"
+"потрібно вказати лишень одну гілку з опцією --set-upstream"
 
 #, c-format
 msgid "Fetching %s\n"
@@ -5712,24 +5929,26 @@ msgstr "не вдалося отримати %s"
 
 #, c-format
 msgid "could not fetch '%s' (exit code: %d)\n"
-msgstr ""
+msgstr "не вдалося отримати \"%s\" (код завершення: %d)\n"
 
 msgid ""
 "no remote repository specified; please specify either a URL or a\n"
 "remote name from which new revisions should be fetched"
 msgstr ""
+"віддалене сховище не вказано; будь ласка, вкажіть або URL або\n"
+"назву віддаленого сховища, з якого слід отримувати нові ревізії"
 
 msgid "you need to specify a tag name"
-msgstr ""
+msgstr "потрібно вказати назву тегу"
 
 msgid "fetch from all remotes"
-msgstr ""
+msgstr "отримати з усіх віддалених призначень"
 
 msgid "set upstream for git pull/fetch"
 msgstr "встановити першоджерельне сховище для git pull/fetch"
 
 msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr ""
+msgstr "додати до .git/FETCH_HEAD замість перезапису"
 
 msgid "use atomic transaction to update references"
 msgstr "використати атомарну транзакцію для оновлення посилань"
@@ -5738,99 +5957,108 @@ msgid "path to upload pack on remote end"
 msgstr "шлях для завантаження пакунка на віддаленій стороні"
 
 msgid "force overwrite of local reference"
-msgstr ""
+msgstr "примусовий перезапис локального посилання"
 
 msgid "fetch from multiple remotes"
-msgstr ""
+msgstr "отримати з кількох віддалених призначень"
 
 msgid "fetch all tags and associated objects"
-msgstr ""
+msgstr "отримати всі теги і повʼязані з ними обʼєкти"
 
 msgid "do not fetch all tags (--no-tags)"
-msgstr ""
+msgstr "не отримувати всі теги (--no-tags)"
 
 msgid "number of submodules fetched in parallel"
 msgstr "кількість підмодулів, що завантажуються паралельно"
 
 msgid "modify the refspec to place all refs within refs/prefetch/"
 msgstr ""
+"змінити визначник посилання, щоб помістити всі посилання в refs/prefetch/"
 
 msgid "prune remote-tracking branches no longer on remote"
 msgstr ""
+"видалити віддалено відстежувані гілки, що більше не існують у віддаленому "
+"призначенні"
 
 msgid "prune local tags no longer on remote and clobber changed tags"
 msgstr ""
+"видалити локальні теги, що більше не існують у віддаленому призначенні, і "
+"зруйнувати змінені теги"
 
 msgid "on-demand"
-msgstr ""
+msgstr "на вимогу"
 
 msgid "control recursive fetching of submodules"
 msgstr "контролювати рекурсивне отримання підмодулів"
 
 msgid "write fetched references to the FETCH_HEAD file"
-msgstr ""
+msgstr "записувати отримані посилання у файл FETCH_HEAD"
 
 msgid "keep downloaded pack"
-msgstr ""
+msgstr "зберегти завантажений пакунок"
 
 msgid "allow updating of HEAD ref"
-msgstr ""
+msgstr "дозволити оновлення HEAD посилання"
 
 msgid "deepen history of shallow clone"
-msgstr "поглибиÑ\82и Ñ\96Ñ\81Ñ\82оÑ\80Ñ\96Ñ\8e Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невого клону"
+msgstr "поглибиÑ\82и Ñ\96Ñ\81Ñ\82оÑ\80Ñ\96Ñ\8e Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºого клону"
 
 msgid "deepen history of shallow repository based on time"
-msgstr "поглибиÑ\82и Ñ\96Ñ\81Ñ\82оÑ\80Ñ\96Ñ\8e Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невого клону залежно від часу"
+msgstr "поглибиÑ\82и Ñ\96Ñ\81Ñ\82оÑ\80Ñ\96Ñ\8e Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºого клону залежно від часу"
 
 msgid "convert to a complete repository"
 msgstr "перетворити на повне сховище"
 
 msgid "re-fetch without negotiating common commits"
-msgstr ""
+msgstr "повторне отримання без узгодження спільних комітів"
 
 msgid "prepend this to submodule path output"
-msgstr ""
+msgstr "додавати це напочатку шляху до підмодуля при виведенні"
 
 msgid ""
 "default for recursive fetching of submodules (lower priority than config "
 "files)"
 msgstr ""
+"поведінка за замовчуванням для рекурсивного отримання підмодулів (нижчий "
+"пріоритет, ніж у конфігураційних файлів)"
 
 msgid "accept refs that update .git/shallow"
-msgstr ""
+msgstr "приймати посилання, які оновлюють .git/shallow"
 
 msgid "refmap"
-msgstr ""
+msgstr "refmap"
 
 msgid "specify fetch refmap"
-msgstr ""
+msgstr "вказати мапу посилань для fetch"
 
 msgid "report that we have only objects reachable from this object"
-msgstr ""
+msgstr "звітувати, що у нас є тільки обʼєкти, доступні з цього обʼєкта"
 
 msgid "do not fetch a packfile; instead, print ancestors of negotiation tips"
 msgstr ""
+"не отримувати файл пакунка; замість цього роздрукувати предків верхівок для "
+"узгодження"
 
 msgid "run 'maintenance --auto' after fetching"
-msgstr ""
+msgstr "виконати \"maintenance --auto\" після отримуваання"
 
 msgid "check for forced-updates on all updated branches"
-msgstr ""
+msgstr "перевірити на примусове оновлення для всіх оновлених гілок"
 
 msgid "write the commit-graph after fetching"
-msgstr ""
+msgstr "записати коміт-граф після отримання"
 
 msgid "accept refspecs from stdin"
-msgstr ""
+msgstr "приймати визначники посилань з stdin"
 
 msgid "--negotiate-only needs one or more --negotiation-tip=*"
-msgstr ""
+msgstr "--negotiate-only потребує одного або кількох --negotiation-tip=*"
 
 msgid "negative depth in --deepen is not supported"
-msgstr ""
+msgstr "відʼємна глибина в --deepen не підтримується"
 
 msgid "--unshallow on a complete repository does not make sense"
-msgstr ""
+msgstr "--unshallow на повному сховищі не має сенсу"
 
 #, c-format
 msgid "failed to fetch bundles from '%s'"
@@ -5844,21 +6072,24 @@ msgstr "fetch --all не має сенсу з визначниками поси
 
 #, c-format
 msgid "no such remote or remote group: %s"
-msgstr ""
+msgstr "немає такого віддаленого призначення або віддаленої групи: %s"
 
 msgid "fetching a group and specifying refspecs does not make sense"
-msgstr ""
+msgstr "отримання групи і вказівка визначників посилань не має сенсу"
 
 msgid "must supply remote when using --negotiate-only"
 msgstr ""
+"необхідно вказати віддалене призначення при використанні --negotiate-only"
 
 msgid "protocol does not support --negotiate-only, exiting"
-msgstr ""
+msgstr "протокол не підтримує --negotiate-only, вихід"
 
 msgid ""
 "--filter can only be used with the remote configured in extensions."
 "partialclone"
 msgstr ""
+"--filter можна використовувати лише з віддаленим призначенням, налаштованим "
+"у extensions.partialclone"
 
 msgid "--atomic can only be used when fetching from one remote"
 msgstr ""
@@ -5867,22 +6098,24 @@ msgstr ""
 
 msgid "--stdin can only be used when fetching from one remote"
 msgstr ""
+"--stdin можна використовувати лише при отриманні одного віддаленого джерела"
 
 msgid ""
 "git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"
 msgstr ""
+"git fmt-merge-msg [-m <допис>] [--log[=<н>] | --no-log] [--file <файл>]"
 
 msgid "populate log with at most <n> entries from shortlog"
-msgstr ""
+msgstr "заповнити журнал не більше ніж <н> записами з shortlog"
 
 msgid "alias for --log (deprecated)"
-msgstr ""
+msgstr "псевдонім для --log (застарілий)"
 
 msgid "text"
-msgstr ""
+msgstr "текст"
 
 msgid "use <text> as start of message"
-msgstr ""
+msgstr "використовувати <текст> як початок допису"
 
 msgid "use <name> instead of the real target branch"
 msgstr "використовувати <назва> замість реальної цільової гілки"
@@ -5894,68 +6127,68 @@ msgid "git for-each-ref [<options>] [<pattern>]"
 msgstr "git for-each-ref [<опції>] [<шаблон>]"
 
 msgid "git for-each-ref [--points-at <object>]"
-msgstr ""
+msgstr "git for-each-ref [--points-at <обʼєкт>]"
 
 msgid "git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"
-msgstr ""
+msgstr "git for-each-ref [--merged [<коміт>]] [--no-merged [<коміт>]]"
 
 msgid "git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"
-msgstr ""
+msgstr "git for-each-ref [--contains [<коміт>]] [--no-contains [<коміт>]]"
 
 msgid "quote placeholders suitably for shells"
-msgstr ""
+msgstr "заповнювачі лапок для shell"
 
 msgid "quote placeholders suitably for perl"
-msgstr ""
+msgstr "заповнювачі лапок для perl"
 
 msgid "quote placeholders suitably for python"
-msgstr ""
+msgstr "заповнювачі лапок для python"
 
 msgid "quote placeholders suitably for Tcl"
-msgstr ""
+msgstr "заповнювачі лапок для Tcl"
 
 msgid "show only <n> matched refs"
-msgstr ""
+msgstr "показати тільки <н> відповідних посилань"
 
 msgid "respect format colors"
-msgstr ""
+msgstr "дотримуватися кольорів формату"
 
 msgid "print only refs which points at the given object"
-msgstr ""
+msgstr "виводити тільки посилання, які вказують на заданий об’єкт"
 
 msgid "print only refs that are merged"
-msgstr ""
+msgstr "виводити тільки злиті посилання"
 
 msgid "print only refs that are not merged"
-msgstr ""
+msgstr "виводити тільки не злиті посилання"
 
 msgid "print only refs which contain the commit"
-msgstr ""
+msgstr "виводити тільки ті посилання, що містять коміт"
 
 msgid "print only refs which don't contain the commit"
-msgstr ""
+msgstr "виводити тільки ті посилання, що не містять коміту"
 
 msgid "read reference patterns from stdin"
 msgstr "читати шаблони посилань з stdin"
 
 msgid "unknown arguments supplied with --stdin"
-msgstr ""
+msgstr "невідомі аргументи надані через --stdin"
 
 msgid "git for-each-repo --config=<config> [--] <arguments>"
-msgstr ""
+msgstr "git for-each-repo --config=<конфіг> [--] <аргументи>"
 
 msgid "config"
-msgstr ""
+msgstr "конфіг"
 
 msgid "config key storing a list of repository paths"
-msgstr ""
+msgstr "ключ конфігурації, в якому зберігається список шляхів до сховищ"
 
 msgid "missing --config=<config>"
-msgstr ""
+msgstr "відсутній --config=<конфіг>"
 
 #, c-format
 msgid "got bad config --config=%s"
-msgstr ""
+msgstr "невірно задано параметр --config=%s"
 
 msgid "unknown"
 msgstr "невідомо"
@@ -5964,17 +6197,17 @@ msgstr "невідомо"
 
 #, c-format
 msgid "error in %s %s: %s"
-msgstr ""
+msgstr "помилка в %s %s: %s"
 
 #. TRANSLATORS: e.g. warning in tree 01bfda: <more explanation>
 
 #, c-format
 msgid "warning in %s %s: %s"
-msgstr ""
+msgstr "попередження в %s %s: %s"
 
 #, c-format
 msgid "broken link from %7s %s"
-msgstr ""
+msgstr "пошкоджене посилання з %7s %s"
 
 msgid "wrong object type in link"
 msgstr "невірний тип об’єкта в посиланні"
@@ -5984,21 +6217,23 @@ msgid ""
 "broken link from %7s %s\n"
 "              to %7s %s"
 msgstr ""
+"пошкоджене посилання з %7s %s\n"
+"                    на %7s %s"
 
 msgid "Checking connectivity"
 msgstr "Перевірка підключення"
 
 #, c-format
 msgid "missing %s %s"
-msgstr ""
+msgstr "відсутній %s %s"
 
 #, c-format
 msgid "unreachable %s %s"
-msgstr ""
+msgstr "недосяжний %s %s"
 
 #, c-format
 msgid "dangling %s %s"
-msgstr ""
+msgstr "висячий %s %s"
 
 msgid "could not create lost-found"
 msgstr "не вдалося створити lost-found"
@@ -6024,27 +6259,27 @@ msgid "Checking %s %s"
 msgstr "Перевірка %s %s"
 
 msgid "broken links"
-msgstr ""
+msgstr "пошкоджені посилання"
 
 #, c-format
 msgid "root %s"
-msgstr ""
+msgstr "корінь %s"
 
 #, c-format
 msgid "tagged %s %s (%s) in %s"
-msgstr ""
+msgstr "з тегом %s %s (%s) в %s"
 
 #, c-format
 msgid "%s: object corrupt or missing"
-msgstr ""
+msgstr "%s: об’єкт пошкоджений або відсутній"
 
 #, c-format
 msgid "%s: invalid reflog entry %s"
-msgstr "%s: неприпустимий запис reflog %s"
+msgstr "%s: неприпустимий запис журналу посилань %s"
 
 #, c-format
 msgid "Checking reflog %s->%s"
-msgstr ""
+msgstr "Перевірка журналу посилань %s->%s"
 
 #, c-format
 msgid "%s: invalid sha1 pointer %s"
@@ -6055,27 +6290,27 @@ msgid "%s: not a commit"
 msgstr "%s не є комітом"
 
 msgid "notice: No default references"
-msgstr ""
+msgstr "повідомлення: Немає посилань за замовчуванням"
 
 #, c-format
 msgid "%s: hash-path mismatch, found at: %s"
-msgstr ""
+msgstr "%s: невідповідність хеш/шлях знайдена в: %s"
 
 #, c-format
 msgid "%s: object corrupt or missing: %s"
-msgstr ""
+msgstr "%s: об’єкт пошкоджений або відсутній: %s"
 
 #, c-format
 msgid "%s: object is of unknown type '%s': %s"
-msgstr ""
+msgstr "%s: об’єкт невідомого типу \"%s\": %s"
 
 #, c-format
 msgid "%s: object could not be parsed: %s"
-msgstr ""
+msgstr "%s: неможливо розібрати об’єкт: %s"
 
 #, c-format
 msgid "bad sha1 file: %s"
-msgstr ""
+msgstr "невірний sha1 файл: %s"
 
 msgid "Checking object directory"
 msgstr "Перевірка директорії об’єкта"
@@ -6093,15 +6328,15 @@ msgstr "неприпустимий %s"
 
 #, c-format
 msgid "%s points to something strange (%s)"
-msgstr ""
+msgstr "%s вказує на щось дивне (%s)"
 
 #, c-format
 msgid "%s: detached HEAD points at nothing"
-msgstr ""
+msgstr "%s: відокремлений HEAD вказує на ніщо"
 
 #, c-format
 msgid "notice: %s points to an unborn branch (%s)"
-msgstr ""
+msgstr "повідомлення: %s вказує на ненароджену гілку (%s)"
 
 #, c-format
 msgid "Checking cache tree of %s"
@@ -6112,7 +6347,7 @@ msgid "%s: invalid sha1 pointer in cache-tree of %s"
 msgstr "%s: невірний sha1 вказівник в cache-tree для %s"
 
 msgid "non-tree in cache-tree"
-msgstr ""
+msgstr "non-tree в cache-tree"
 
 #, c-format
 msgid "%s: invalid sha1 pointer in resolve-undo of %s"
@@ -6120,11 +6355,11 @@ msgstr "%s: невірний sha1 вказівник в resolve-undo для %s"
 
 #, c-format
 msgid "unable to load rev-index for pack '%s'"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð²Ð°Ð½Ñ\82ажиÑ\82и rev-index Ð´Ð»Ñ\8f Ð¿Ð°ÐºÑ\83на \"%s\""
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð²Ð°Ð½Ñ\82ажиÑ\82и rev-index Ð´Ð»Ñ\8f Ð¿Ð°ÐºÑ\83нкÑ\83 \"%s\""
 
 #, c-format
 msgid "invalid rev-index for pack '%s'"
-msgstr "невÑ\96Ñ\80ний rev-index Ð´Ð»Ñ\8f Ð¿Ð°ÐºÑ\83на \"%s\""
+msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82имий rev-index Ð´Ð»Ñ\8f \"%s\""
 
 msgid ""
 "git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
@@ -6132,75 +6367,79 @@ msgid ""
 "         [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
 "         [--[no-]name-objects] [<object>...]"
 msgstr ""
+"git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
+"         [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
+"         [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
+"         [--[no-]name-objects] [<обʼєкт>...]"
 
 msgid "show unreachable objects"
-msgstr ""
+msgstr "показати недосяжні об’єкти"
 
 msgid "show dangling objects"
-msgstr "показувати висячі об’єкти"
+msgstr "показати висячі об’єкти"
 
 msgid "report tags"
-msgstr ""
+msgstr "звітувати про теги"
 
 msgid "report root nodes"
-msgstr ""
+msgstr "звітувати про кореневі вузли"
 
 msgid "make index objects head nodes"
-msgstr ""
+msgstr "побудувати головні вузли об’єктів індексу"
 
 msgid "make reflogs head nodes (default)"
-msgstr "зÑ\80обиÑ\82и reflogs Ð³Ð¾Ð»Ð¾Ð²Ð½Ð¸Ð¼Ð¸ Ð²Ñ\83злами (за замовчуванням)"
+msgstr "побÑ\83дÑ\83ваÑ\82и Ð³Ð¾Ð»Ð¾Ð²Ð½Ñ\96 Ð²Ñ\83зли Ð¶Ñ\83Ñ\80налÑ\83 Ð¿Ð¾Ñ\81иланÑ\8c (за замовчуванням)"
 
 msgid "also consider packs and alternate objects"
-msgstr ""
+msgstr "також розглядати пакунки та запозичені об’єкти"
 
 msgid "check only connectivity"
-msgstr ""
+msgstr "перевірити лише звʼязність"
 
 msgid "enable more strict checking"
-msgstr ""
+msgstr "увімкнути більш сувору перевірку"
 
 msgid "write dangling objects in .git/lost-found"
-msgstr ""
+msgstr "записувати висячі об’єкти в .git/lost-found"
 
 msgid "show progress"
-msgstr ""
+msgstr "показувати прогрес"
 
 msgid "show verbose names for reachable objects"
-msgstr ""
+msgstr "показувати докладні назви для доступних об’єктів"
 
 msgid "Checking objects"
 msgstr "Перевірка обʼєктів"
 
 #, c-format
 msgid "%s: object missing"
-msgstr ""
+msgstr "%s: об’єкт відсутній"
 
 #, c-format
 msgid "invalid parameter: expected sha1, got '%s'"
-msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82имий Ð¿Ð°Ñ\80амеÑ\82Ñ\80: Ð¾Ñ\87Ñ\96кÑ\83вавÑ\81Ñ\8f sha1, надано \"%s\""
+msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82имий Ð¿Ð°Ñ\80амеÑ\82Ñ\80: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c sha1, надано \"%s\""
 
 msgid "git fsmonitor--daemon start [<options>]"
-msgstr ""
+msgstr "git fsmonitor--daemon start [<опції>]"
 
 msgid "git fsmonitor--daemon run [<options>]"
-msgstr ""
+msgstr "git fsmonitor--daemon run [<опції>]"
 
 #, c-format
 msgid "value of '%s' out of range: %d"
-msgstr ""
+msgstr "значення \"%s\" за межами діапазону: %d"
 
 #, c-format
 msgid "value of '%s' not bool or int: %d"
-msgstr ""
+msgstr "значення \"%s\" не є bool або int: %d"
 
 #, c-format
 msgid "fsmonitor-daemon is watching '%s'\n"
-msgstr ""
+msgstr "fsmonitor-daemon стежить за \"%s\"\n"
 
 #, c-format
 msgid "fsmonitor-daemon is not watching '%s'\n"
-msgstr ""
+msgstr "fsmonitor-daemon не стежить за \"%s\"\n"
 
 #, c-format
 msgid "could not create fsmonitor cookie '%s'"
@@ -6208,23 +6447,23 @@ msgstr "не вдалося створити fsmonitor cookie \"%s\""
 
 #, c-format
 msgid "fsmonitor: cookie_result '%d' != SEEN"
-msgstr ""
+msgstr "fsmonitor: cookie_result \"%d\" != SEEN"
 
 #, c-format
 msgid "could not start IPC thread pool on '%s'"
 msgstr "не вдалося запустити пул потоків IPC на \"%s\""
 
 msgid "could not start fsmonitor listener thread"
-msgstr ""
+msgstr "не вдалося запустити потік слухача fsmonitor"
 
 msgid "could not start fsmonitor health thread"
-msgstr ""
+msgstr "не вдалося запустити потік стану fsmonitor"
 
 msgid "could not initialize listener thread"
-msgstr ""
+msgstr "не вдалося ініціалізувати потік слухача"
 
 msgid "could not initialize health thread"
-msgstr ""
+msgstr "не вдалося ініціалізувати потік стану"
 
 #, c-format
 msgid "could not cd home '%s'"
@@ -6232,33 +6471,33 @@ msgstr "не вдалося виконати cd home \"%s\""
 
 #, c-format
 msgid "fsmonitor--daemon is already running '%s'"
-msgstr ""
+msgstr "fsmonitor--daemon вже запущений \"%s\""
 
 #, c-format
 msgid "running fsmonitor-daemon in '%s'\n"
-msgstr ""
+msgstr "запуск fsmonitor-daemon в \"%s\"\n"
 
 #, c-format
 msgid "starting fsmonitor-daemon in '%s'\n"
-msgstr ""
+msgstr "старт fsmonitor-daemon в \"%s\"\n"
 
 msgid "daemon failed to start"
 msgstr "не вдалося запустити демон"
 
 msgid "daemon not online yet"
-msgstr ""
+msgstr "демон ще не онлайн"
 
 msgid "daemon terminated"
-msgstr ""
+msgstr "роботу демона припинено"
 
 msgid "detach from console"
 msgstr "від’єднати від консолі"
 
 msgid "use <n> ipc worker threads"
-msgstr ""
+msgstr "використовувати <н> потоків IPC працівника"
 
 msgid "max seconds to wait for background daemon startup"
-msgstr ""
+msgstr "максимальна кількість секунд для очікування запуску фонового демона"
 
 #, c-format
 msgid "invalid 'ipc-threads' value (%d)"
@@ -6266,10 +6505,10 @@ msgstr "невірне значення \"ipc-threads\" (%d)"
 
 #, c-format
 msgid "Unhandled subcommand '%s'"
-msgstr ""
+msgstr "Необроблена підкоманда \"%s\""
 
 msgid "fsmonitor--daemon not supported on this platform"
-msgstr ""
+msgstr "fsmonitor--daemon не підтримується на цій платформі"
 
 msgid "git gc [<options>]"
 msgstr "git gc [<опції>]"
@@ -6294,24 +6533,29 @@ msgid ""
 "\n"
 "%s"
 msgstr ""
+"Попередній запуск gc показав наступне. Будь ласка, виправте першопричину\n"
+"і видаліть %s\n"
+"Автоматичне очищення не буде виконано, доки файл не буде вилучено.\n"
+"\n"
+"%s"
 
 msgid "prune unreferenced objects"
-msgstr "видалити об’єкти без посилань"
+msgstr "видалити об’єкти, на які немає посилань"
 
 msgid "pack unreferenced objects separately"
-msgstr ""
+msgstr "пакувати об’єкти, на які немає посилань, окремо"
 
 msgid "be more thorough (increased runtime)"
-msgstr ""
+msgstr "працювати ретельніше (збільшує час виконання)"
 
 msgid "enable auto-gc mode"
-msgstr ""
+msgstr "увімкнути режим автоматичного збору сміття"
 
 msgid "force running gc even if there may be another gc running"
-msgstr ""
+msgstr "примусово запускати збирач сміття, навіть якщо інший збирач вже працює"
 
 msgid "repack all other packs except the largest pack"
-msgstr ""
+msgstr "перепакувати всі пакунки, крім найбільшого"
 
 #, c-format
 msgid "failed to parse gc.logExpiry value %s"
@@ -6320,38 +6564,47 @@ msgstr "не вдалося розібрати gc.logExpiry значення %s"
 #, c-format
 msgid "failed to parse prune expiry value %s"
 msgstr ""
+"не вдалося розібрати значення дати закінчення терміну дії для видалення %s"
 
 #, c-format
 msgid "Auto packing the repository in background for optimum performance.\n"
 msgstr ""
+"Автоматичне пакування сховища у фоновому режимі для оптимальної "
+"продуктивності.\n"
 
 #, c-format
 msgid "Auto packing the repository for optimum performance.\n"
-msgstr ""
+msgstr "Автоматичне пакування сховища для оптимальної продуктивності.\n"
 
 #, c-format
 msgid "See \"git help gc\" for manual housekeeping.\n"
 msgstr ""
+"Дивіться \"git help gc\" для отримання інформації про налагодження вручну.\n"
 
 #, c-format
 msgid ""
 "gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
 msgstr ""
+"збір сміття вже запущено на машині \"%s\" pid %<PRIuMAX> (скористайтесь --"
+"force, якщо ні)"
 
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
+"Занадто багато недосяжних вільних об’єктів; запустіть \"git prune\", щоб "
+"вилучити їх."
 
 msgid ""
 "git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"
 msgstr ""
+"git maintenance run [--auto] [--[no-]quiet] [--task=<завдання>] [--schedule]"
 
 msgid "--no-schedule is not allowed"
-msgstr ""
+msgstr "--no-schedule не дозволяється"
 
 #, c-format
 msgid "unrecognized --schedule argument '%s'"
-msgstr ""
+msgstr "нерозпізнаний аргумент --schedule \"%s\""
 
 msgid "failed to write commit-graph"
 msgstr "не вдалося записати граф комітів"
@@ -6360,31 +6613,32 @@ msgid "failed to prefetch remotes"
 msgstr "не вдалося виконати попереднє отримання з віддалених сховищ"
 
 msgid "failed to start 'git pack-objects' process"
-msgstr "не вдалося розпочати \"git pack-objects\" процес"
+msgstr "не вдалося запустити \"git pack-objects\" процес"
 
 msgid "failed to finish 'git pack-objects' process"
-msgstr ""
+msgstr "не вдалося завершити \"git pack-objects\" процес"
 
 msgid "failed to write multi-pack-index"
-msgstr ""
+msgstr "не вдалося записати multi-pack-index"
 
 msgid "'git multi-pack-index expire' failed"
-msgstr ""
+msgstr "\"git multi-pack-index expire\" завершився невдало"
 
 msgid "'git multi-pack-index repack' failed"
-msgstr ""
+msgstr "\"git multi-pack-index repack\" завершився невдало"
 
 msgid ""
 "skipping incremental-repack task because core.multiPackIndex is disabled"
 msgstr ""
+"пропуск incremental-repack завдання, оскільки core.multiPackIndex вимкнено"
 
 #, c-format
 msgid "lock file '%s' exists, skipping maintenance"
-msgstr ""
+msgstr "файл блокування \"%s\" існує, пропуск обслуговування"
 
 #, c-format
 msgid "task '%s' failed"
-msgstr ""
+msgstr "завдання \"%s\" завершилося невдало"
 
 #, c-format
 msgid "'%s' is not a valid task"
@@ -6395,36 +6649,36 @@ msgid "task '%s' cannot be selected multiple times"
 msgstr "завдання \"%s\" не можна вибрати кілька разів"
 
 msgid "run tasks based on the state of the repository"
-msgstr ""
+msgstr "запускати завдання на основі стану сховища"
 
 msgid "frequency"
-msgstr ""
+msgstr "частота"
 
 msgid "run tasks based on frequency"
-msgstr ""
+msgstr "запускати задачі на основі частоти"
 
 msgid "do not report progress or other information over stderr"
-msgstr ""
+msgstr "не показувати хід виконання та іншу інформацію в stderr"
 
 msgid "task"
-msgstr ""
+msgstr "завдання"
 
 msgid "run a specific task"
-msgstr ""
+msgstr "запустити певне завдання"
 
 msgid "use at most one of --auto and --schedule=<frequency>"
-msgstr ""
+msgstr "використовуйте щонайбільше одну з опцій --auto та --schedule=<частота>"
 
 #, c-format
 msgid "unable to add '%s' value of '%s'"
-msgstr "не вдалося додати значення \"%s\" до \"%s\""
+msgstr "не вдалося додати \"%s\" значення до \"%s\""
 
 msgid "return success even if repository was not registered"
-msgstr ""
+msgstr "повертати успіх, навіть якщо сховище не було зареєстровано"
 
 #, c-format
 msgid "unable to unset '%s' value of '%s'"
-msgstr "не вдалося скинути значення \"%s\" для \"%s\""
+msgstr "не вдалося скинути \"%s\" значення для \"%s\""
 
 #, c-format
 msgid "repository '%s' is not registered"
@@ -6453,6 +6707,8 @@ msgstr "не вдалося запустити schtasks"
 
 msgid "failed to run 'crontab -l'; your system might not support 'cron'"
 msgstr ""
+"не вдалося запустити \"crontab -l\"; можливо, ваша система не підтримує "
+"\"cron\""
 
 msgid "failed to create crontab temporary file"
 msgstr "не вдалося створити тимчасовий crontab файл"
@@ -6462,9 +6718,10 @@ msgstr "не вдалося відкрити тимчасовий файл"
 
 msgid "failed to run 'crontab'; your system might not support 'cron'"
 msgstr ""
+"не вдалося запустити \"crontab\"; можливо, ваша система не підтримує \"cron\""
 
 msgid "'crontab' died"
-msgstr ""
+msgstr "\"crontab\" завершився невдало"
 
 msgid "failed to start systemctl"
 msgstr "не вдалося стартувати systemctl"
@@ -6482,32 +6739,32 @@ msgstr "не вдалося очистити \"%s\""
 
 #, c-format
 msgid "unrecognized --scheduler argument '%s'"
-msgstr ""
+msgstr "нерозпізнаний --scheduler аргумент \"%s\""
 
 msgid "neither systemd timers nor crontab are available"
-msgstr ""
+msgstr "недоступні ні systemd таймери, ні crontab"
 
 #, c-format
 msgid "%s scheduler is not available"
-msgstr ""
+msgstr "%s планувальник недоступний"
 
 msgid "another process is scheduling background maintenance"
-msgstr ""
+msgstr "ще один процес планує фонове обслуговування"
 
 msgid "git maintenance start [--scheduler=<scheduler>]"
-msgstr ""
+msgstr "git maintenance start [--scheduler=<планувальник>]"
 
 msgid "scheduler"
-msgstr ""
+msgstr "планувальник"
 
 msgid "scheduler to trigger git maintenance run"
-msgstr ""
+msgstr "планувальник для запуску обслуговування git"
 
 msgid "failed to add repo to global config"
-msgstr ""
+msgstr "не вдалося додати сховище до глобальної конфігурації"
 
 msgid "git maintenance <subcommand> [<options>]"
-msgstr ""
+msgstr "git maintenance <підкоманда> [<опції>]"
 
 msgid "git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [<опції>] [-e] <шаблон> [<ревізія>...] [[--] <шлях>...]"
@@ -6518,7 +6775,7 @@ msgstr "grep: не вдалося створити потік: %s"
 
 #, c-format
 msgid "invalid number of threads specified (%d) for %s"
-msgstr "невÑ\96Ñ\80но Ð²ÐºÐ°Ð·Ð°Ð½Ð¾ кількість потоків (%d) для %s"
+msgstr "невÑ\96Ñ\80но Ð²ÐºÐ°Ð·Ð°Ð½Ð° кількість потоків (%d) для %s"
 
 #. TRANSLATORS: %s is the configuration
 #. variable for tweaking threads, currently
@@ -6527,7 +6784,7 @@ msgstr "невірно вказано кількість потоків (%d) д
 
 #, c-format
 msgid "no threads support, ignoring %s"
-msgstr "немає підтримки потоків, ігноруються %s"
+msgstr "немає підтримки потоків, ігнорування %s"
 
 #, c-format
 msgid "unable to read tree (%s)"
@@ -6535,155 +6792,155 @@ msgstr "не вдалося прочитати дерево (%s)"
 
 #, c-format
 msgid "unable to grep from object of type %s"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ\82и grep Ð· об’єкта типу %s"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ\82и grep Ð´Ð»Ñ\8f об’єкта типу %s"
 
 #, c-format
 msgid "switch `%c' expects a numerical value"
-msgstr ""
+msgstr "switch \"%c\" очікує числове значення"
 
 msgid "search in index instead of in the work tree"
 msgstr "шукати в індексі замість робочого дерева"
 
 msgid "find in contents not managed by git"
-msgstr ""
+msgstr "шукати у вмісті, не індексованому git"
 
 msgid "search in both tracked and untracked files"
 msgstr "шукати як у відстежуваних, так і в невідстежуваних файлах"
 
 msgid "ignore files specified via '.gitignore'"
-msgstr ""
+msgstr "ігнорувати файли, вказані через \".gitignore\""
 
 msgid "recursively search in each submodule"
 msgstr "шукати рекурсивно в кожному підмодулі"
 
 msgid "show non-matching lines"
-msgstr ""
+msgstr "показувати рядки, що не збігаються"
 
 msgid "case insensitive matching"
-msgstr ""
+msgstr "нечутливе до регістру зіставлення"
 
 msgid "match patterns only at word boundaries"
-msgstr ""
+msgstr "зіставляти шаблони тільки на межі слів"
 
 msgid "process binary files as text"
-msgstr ""
+msgstr "обробляти бінарні файли як текст"
 
 msgid "don't match patterns in binary files"
-msgstr ""
+msgstr "не зіставляти шаблони в бінарних файлах"
 
 msgid "process binary files with textconv filters"
-msgstr ""
+msgstr "обробляти бінарні файли за допомогою textconv фільтрів"
 
 msgid "search in subdirectories (default)"
-msgstr ""
+msgstr "шукати в піддиректоріях (за замовчуванням)"
 
 msgid "descend at most <depth> levels"
-msgstr ""
+msgstr "спускатися не більше ніж на <глибина> рівнів"
 
 msgid "use extended POSIX regular expressions"
-msgstr ""
+msgstr "використовувати розширені POSIX регулярні вирази"
 
 msgid "use basic POSIX regular expressions (default)"
-msgstr ""
+msgstr "використовувати базові регулярні вирази POSIX (за замовчуванням)"
 
 msgid "interpret patterns as fixed strings"
-msgstr ""
+msgstr "інтерпретувати шаблони як фіксовані строки"
 
 msgid "use Perl-compatible regular expressions"
-msgstr ""
+msgstr "використовувати Perl-сумісні регулярні вирази"
 
 msgid "show line numbers"
-msgstr ""
+msgstr "показувати номери рядків"
 
 msgid "show column number of first match"
-msgstr ""
+msgstr "показувати номер стовпця першого збігу"
 
 msgid "don't show filenames"
-msgstr ""
+msgstr "не показувати назви файлів"
 
 msgid "show filenames"
-msgstr ""
+msgstr "показувати назви файлів"
 
 msgid "show filenames relative to top directory"
-msgstr ""
+msgstr "показувати назви файлів відносно верхнього каталогу"
 
 msgid "show only filenames instead of matching lines"
-msgstr ""
+msgstr "показувати лише назви файлів замість відповідних рядків"
 
 msgid "synonym for --files-with-matches"
-msgstr ""
+msgstr "синонім для --files-with-matches"
 
 msgid "show only the names of files without match"
-msgstr ""
+msgstr "показувати лише назви файлів без збігу"
 
 msgid "print NUL after filenames"
-msgstr ""
+msgstr "друкувати NUL після назв файлів"
 
 msgid "show only matching parts of a line"
-msgstr ""
+msgstr "показувати лише частини рядка, що збігаються"
 
 msgid "show the number of matches instead of matching lines"
-msgstr ""
+msgstr "показувати кількість збігів замість рядків, що збігаються"
 
 msgid "highlight matches"
-msgstr ""
+msgstr "виділяти збіги"
 
 msgid "print empty line between matches from different files"
-msgstr ""
+msgstr "друкувати порожній рядок між збігами з різних файлів"
 
 msgid "show filename only once above matches from same file"
-msgstr ""
+msgstr "показувати назву файлу лише один раз над збігами з того файлу"
 
 msgid "show <n> context lines before and after matches"
-msgstr ""
+msgstr "показувати <н> рядків до і після збігу"
 
 msgid "show <n> context lines before matches"
-msgstr ""
+msgstr "показувати <н> рядків до збігу"
 
 msgid "show <n> context lines after matches"
-msgstr ""
+msgstr "показувати <н> рядків після збігу"
 
 msgid "use <n> worker threads"
-msgstr ""
+msgstr "використати <н> робочих потоків"
 
 msgid "shortcut for -C NUM"
-msgstr ""
+msgstr "скорочення для -C номер"
 
 msgid "show a line with the function name before matches"
-msgstr ""
+msgstr "показувати рядок з назвою функції перед збігами"
 
 msgid "show the surrounding function"
-msgstr ""
+msgstr "показати навколишню функцію"
 
 msgid "read patterns from file"
-msgstr ""
+msgstr "зчитувати шаблони з файлу"
 
 msgid "match <pattern>"
-msgstr ""
+msgstr "зіставляти <шаблон>"
 
 msgid "combine patterns specified with -e"
-msgstr ""
+msgstr "об’єднати шаблони, вказані через -e"
 
 msgid "indicate hit with exit status without output"
-msgstr ""
+msgstr "позначати збіг кодом виходу без виводу"
 
 msgid "show only matches from files that match all patterns"
-msgstr ""
+msgstr "показувати збіги лише з файлів, які відповідають усім шаблонам"
 
 msgid "pager"
-msgstr ""
+msgstr "пейджер"
 
 msgid "show matching files in the pager"
-msgstr ""
+msgstr "показати відповідні файли в пейджері"
 
 msgid "allow calling of grep(1) (ignored by this build)"
-msgstr ""
+msgstr "дозволяти виклик grep(1) (ігнорується у цій збірці)"
 
 msgid "maximum number of results per file"
-msgstr ""
+msgstr "максимальна кількість результатів у файлі"
 
 msgid "no pattern given"
-msgstr ""
+msgstr "шаблон не надано"
 
 msgid "--no-index or --untracked cannot be used with revs"
 msgstr "--no-index або --untracked не можна використовувати з ревізіями"
@@ -6693,10 +6950,10 @@ msgid "unable to resolve revision: %s"
 msgstr "не вдалося розвʼязати ревізію: %s"
 
 msgid "--untracked not supported with --recurse-submodules"
-msgstr ""
+msgstr "--untracked не підтримується з --recurse-submodules"
 
 msgid "invalid option combination, ignoring --threads"
-msgstr ""
+msgstr "неприпустима комбінація опцій, ігнорування --threads"
 
 msgid "no threads support, ignoring --threads"
 msgstr "немає підтримки потоків, ігнорування --threads"
@@ -6706,93 +6963,99 @@ msgid "invalid number of threads specified (%d)"
 msgstr "вказано неприпустиму кількість потоків (%d)"
 
 msgid "--open-files-in-pager only works on the worktree"
-msgstr ""
+msgstr "--open-files-in-pager працює тільки в робочому дереві"
 
 msgid "--[no-]exclude-standard cannot be used for tracked contents"
 msgstr ""
+"--[no-]exclude-standard не можна використовувати для відстежуваного вмісту"
 
 msgid "both --cached and trees are given"
-msgstr ""
+msgstr "надані як --cached, так і дерева"
 
 msgid ""
 "git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
 "                [--stdin [--literally]] [--] <file>..."
 msgstr ""
+"git hash-object [-t <тип>] [-w] [--path=<файл> | --no-filters]\n"
+"                [--stdin [--literally]] [--] <файл>..."
 
 msgid "git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"
-msgstr ""
+msgstr "git hash-object [-t <тип>] [-w] --stdin-paths [--no-filters]"
 
 msgid "object type"
 msgstr "тип обʼєкта"
 
 msgid "write the object into the object database"
-msgstr ""
+msgstr "записати об’єкт до бази даних об’єктів"
 
 msgid "read the object from stdin"
-msgstr ""
+msgstr "прочитати об’єкт з stdin"
 
 msgid "store file as is without filters"
-msgstr ""
+msgstr "зберегти файл як є без фільтрів"
 
 msgid ""
 "just hash any random garbage to create corrupt objects for debugging Git"
 msgstr ""
+"просто хешувати будь-який випадковий непотріб, щоб створити пошкоджені "
+"об’єкти для відлагодження Git"
 
 msgid "process file as it were from this path"
-msgstr ""
+msgstr "оброблювати файл, наче він з цього шляху"
 
 msgid "print all available commands"
-msgstr ""
+msgstr "показати всі доступні команди"
 
 msgid "show external commands in --all"
-msgstr ""
+msgstr "показати зовнішні команди в --all"
 
 msgid "show aliases in --all"
-msgstr ""
+msgstr "показати псевдоніми в --all"
 
 msgid "exclude guides"
-msgstr ""
+msgstr "виключити посібники"
 
 msgid "show man page"
-msgstr ""
+msgstr "показати сторінку керівництва користувача"
 
 msgid "show manual in web browser"
-msgstr ""
+msgstr "показати сторінку керівництва користувача в веб-браузері"
 
 msgid "show info page"
-msgstr ""
+msgstr "показати інформаційну сторінку"
 
 msgid "print command description"
-msgstr ""
+msgstr "показати опис команди"
 
 msgid "print list of useful guides"
-msgstr ""
+msgstr "показати список корисних посібників"
 
 msgid "print list of user-facing repository, command and file interfaces"
-msgstr ""
+msgstr "показати список інтерфейсів користувача для сховищ, команд та файлів"
 
 msgid "print list of file formats, protocols and other developer interfaces"
 msgstr ""
+"показати список форматів файлів, протоколів та інших інтерфейсів розробника"
 
 msgid "print all configuration variable names"
-msgstr ""
+msgstr "показати всі назви конфігураційних змінних"
 
 msgid "git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"
-msgstr ""
+msgstr "git help [[-i|--info] [-m|--man] [-w|--web]] [<команда>|<док>]"
 
 #, c-format
 msgid "unrecognized help format '%s'"
-msgstr ""
+msgstr "нерозпізнаний формат довідки \"%s\""
 
 msgid "Failed to start emacsclient."
-msgstr "Не вдалося запустити emacs клієнт."
+msgstr "Не вдалося запустити emacsclient."
 
 msgid "Failed to parse emacsclient version."
-msgstr "Не вдалося розібрати версію emacs клієнта."
+msgstr "Не вдалося розібрати версію emacsclient."
 
 #, c-format
 msgid "emacsclient version '%d' too old (< 22)."
-msgstr ""
+msgstr "версія emacsclient \"%d\" застаріла (< 22)."
 
 #, c-format
 msgid "failed to exec '%s'"
@@ -6803,22 +7066,26 @@ msgid ""
 "'%s': path for unsupported man viewer.\n"
 "Please consider using 'man.<tool>.cmd' instead."
 msgstr ""
+"\"%s\": шлях до непідтримуваного переглядача керівництва користувача.\n"
+"Будь ласка, скористайтесь \"man.<tool>.cmd\" замість цього."
 
 #, c-format
 msgid ""
 "'%s': cmd for supported man viewer.\n"
 "Please consider using 'man.<tool>.path' instead."
 msgstr ""
+"\"%s\": команда для підтримуваного переглядача керівництва користувача.\n"
+"Будь ласка, скористайтесь \"man.<tool>.path\" замість цього."
 
 #, c-format
 msgid "'%s': unknown man viewer."
-msgstr ""
+msgstr "\"%s\": невідомий переглядач керівництва користувача."
 
 msgid "no man viewer handled the request"
-msgstr ""
+msgstr "жоден з переглядачів керівництва користувача не обробив запит"
 
 msgid "no info viewer handled the request"
-msgstr ""
+msgstr "жоден з переглядачів інформації не обробив запит"
 
 #, c-format
 msgid "'%s' is aliased to '%s'"
@@ -6826,30 +7093,34 @@ msgstr "\"%s\" є псевдонімом для \"%s\""
 
 #, c-format
 msgid "bad alias.%s string: %s"
-msgstr ""
+msgstr "невірний псевдонім.%s рядок: %s"
 
 #, c-format
 msgid "the '%s' option doesn't take any non-option arguments"
-msgstr ""
+msgstr "опція \"%s\" не приймає жодних неопціональних аргументів"
 
 msgid ""
 "the '--no-[external-commands|aliases]' options can only be used with '--all'"
 msgstr ""
+"опції \"--no-[external-commands|aliases]\" можна використовувати лише з \"--"
+"all\""
 
 #, c-format
 msgid "usage: %s%s"
-msgstr ""
+msgstr "використання: %s%s"
 
 msgid "'git help config' for more information"
-msgstr ""
+msgstr "\"git help config\" для додаткової інформації"
 
 msgid ""
 "git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
 "args>]"
 msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<шлях>] <назва-гачка> [-- "
+"<аргументи-гачка>]"
 
 msgid "silently ignore missing requested <hook-name>"
-msgstr ""
+msgstr "мовчки ігнорувати відсутній <назва-гачка>"
 
 msgid "file to read into hooks' stdin"
 msgstr "файл, з якого читати stdin хука"
@@ -6999,9 +7270,9 @@ msgstr "Неочікувана контрольна сума наприкінц
 #, c-format
 msgid "pack has %d unresolved delta"
 msgid_plural "pack has %d unresolved deltas"
-msgstr[0] "пакунок має %d невирішену дельту"
-msgstr[1] "пакунок має %d невирішених дельти"
-msgstr[2] "пакунок має %d невирішених дельт"
+msgstr[0] "пакунок має %d нерозвʼязану дельту"
+msgstr[1] "пакунок має %d нерозвʼязаних дельти"
+msgstr[2] "пакунок має %d нерозвʼязаних дельт"
 
 #, c-format
 msgid "unable to deflate appended object (%d)"
@@ -7068,7 +7339,7 @@ msgid "unknown hash algorithm '%s'"
 msgstr "невідомий хеш-алгоритм '%s'"
 
 msgid "--stdin requires a git repository"
-msgstr "--stdin Ð²Ð¸Ð¼Ð°Ð³Ð°є наявності git сховища"
+msgstr "--stdin Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є наявності git сховища"
 
 msgid "--verify with no packfile name given"
 msgstr "--verify без зазначення имені файла пакунка"
@@ -7076,116 +7347,51 @@ msgstr "--verify без зазначення имені файла пакунк
 msgid "fsck error in pack objects"
 msgstr "помилка fsck в об’єктах пакунка"
 
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "неможливо виконати stat шаблона \"%s\""
-
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "неможливо виконати opendir \"%s\""
-
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "неможливо виконати readlink \"%s\""
-
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "неможливо виконати symlink \"%s\" \"%s\""
-
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "неможливо скопіювати \"%s\" до \"%s\""
-
-#, c-format
-msgid "ignoring template %s"
-msgstr ""
-
-#, c-format
-msgid "templates not found in %s"
-msgstr "шаблонів не знайдено в %s"
-
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "не копіюються шаблони з \"%s\": %s"
-
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "неприпустиме початкове ім’я гілки: \"%s\""
-
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "не вдалося обробити тип файлу %d"
-
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "не вдалося перемістити %s на %s"
-
-msgid "attempt to reinitialize repository with different hash"
-msgstr ""
-
-#, c-format
-msgid "%s already exists"
-msgstr "%s вже існує"
-
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr ""
-
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr ""
-
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr ""
-
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr ""
-
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr ""
-
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
 "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
 "         [-b <branch-name> | --initial-branch=<branch-name>]\n"
 "         [--shared[=<permissions>]] [<directory>]"
 msgstr ""
+"git init [-q | --quiet] [--bare] [--template=<шаблон-директорія>]\n"
+"         [--separate-git-dir <git-директорія>] [--object-format=<формат>]\n"
+"         [-b <назва-гілки> | --initial-branch=<назва-гілки>]\n"
+"         [--shared[=<дозволи>]] [<директорія>]"
 
 msgid "permissions"
-msgstr "пÑ\80ава Ð´Ð¾Ñ\81Ñ\82Ñ\83пÑ\83"
+msgstr "дозволи"
 
 msgid "specify that the git repository is to be shared amongst several users"
-msgstr ""
+msgstr "вказати, що git сховище буде спільним для кількох користувачів"
 
 msgid "override the name of the initial branch"
-msgstr ""
+msgstr "перевизначити назву початкової гілки"
 
 msgid "hash"
-msgstr ""
+msgstr "хеш"
 
 msgid "specify the hash algorithm to use"
-msgstr ""
+msgstr "вказати, який алгоритм хешування використовувати"
 
 #, c-format
 msgid "cannot mkdir %s"
-msgstr ""
+msgstr "не вдалося виконати mkdir %s"
 
 #, c-format
 msgid "cannot chdir to %s"
-msgstr ""
+msgstr "не вдалося виконати chdir %s"
 
 #, c-format
 msgid ""
 "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
 "dir=<directory>)"
 msgstr ""
+"%s (або --work-tree=<директорія>) не дозволено без вказівки %s (або --git-"
+"dir=<каталог>)"
 
 #, c-format
 msgid "Cannot access work tree '%s'"
-msgstr "Не вдається отримати доступ до робочого дерева \"%s\""
+msgstr "Неможливо отримати доступ до робочого дерева \"%s\""
 
 msgid "--separate-git-dir incompatible with bare repository"
 msgstr "--separate-git-dir несумісна з порожнім сховищем"
@@ -7195,45 +7401,48 @@ msgid ""
 "                       [(--trailer <token>[(=|:)<value>])...]\n"
 "                       [--parse] [<file>...]"
 msgstr ""
+"git interpret-trailers [--in-place] [--trim-empty]\n"
+"                       [(--trailer <токен>[(=|:)<значення>])...]\n"
+"                       [--parse] [<файл>...]"
 
 msgid "edit files in place"
-msgstr ""
+msgstr "редагувати файли на місцях"
 
 msgid "trim empty trailers"
-msgstr ""
+msgstr "обрізати порожні причепи"
 
 msgid "where to place the new trailer"
-msgstr ""
+msgstr "де розмістити новий причіп"
 
 msgid "action if trailer already exists"
-msgstr "що робити, якщо trailer вже існує"
+msgstr "що робити, якщо причіп вже існує"
 
 msgid "action if trailer is missing"
-msgstr ""
+msgstr "що робити, якщо причіп відсутній"
 
 msgid "output only the trailers"
-msgstr ""
+msgstr "виводити лише причепи"
 
 msgid "do not apply config rules"
-msgstr ""
+msgstr "не застосовувати правила конфігурації"
 
 msgid "join whitespace-continued values"
-msgstr ""
+msgstr "об’єднати значення, що продовжуються через пробіл"
 
 msgid "set parsing options"
-msgstr ""
+msgstr "встановити параметри розбору"
 
 msgid "do not treat --- specially"
-msgstr ""
+msgstr "не обробляти --- особливим чином"
 
 msgid "trailer(s) to add"
-msgstr ""
+msgstr "причіп(и) для додавання"
 
 msgid "--trailer with --only-input does not make sense"
-msgstr ""
+msgstr "--trailer з --only-input не має сенсу"
 
 msgid "no input file given for in-place editing"
-msgstr ""
+msgstr "не надано вхідного файлу для редагування на місці"
 
 msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
 msgstr "git log [<опції>] [<діапазон-ревізій>] [[--] <шлях>...]"
@@ -7246,45 +7455,47 @@ msgid "invalid --decorate option: %s"
 msgstr "неприпустима --decorate опція: %s"
 
 msgid "suppress diff output"
-msgstr ""
+msgstr "приховати вивід diff"
 
 msgid "show source"
-msgstr ""
+msgstr "показати джерело"
 
 msgid "clear all previously-defined decoration filters"
-msgstr ""
+msgstr "очистити всі раніше визначені фільтри оздоблення"
 
 msgid "only decorate refs that match <pattern>"
-msgstr ""
+msgstr "оздоблювати лише посилання, що відповідають <шаблону>"
 
 msgid "do not decorate refs that match <pattern>"
-msgstr ""
+msgstr "не оздоблювати посилання, що відповідають <шаблону>"
 
 msgid "decorate options"
-msgstr ""
+msgstr "опції оздоблення"
 
 msgid ""
 "trace the evolution of line range <start>,<end> or function :<funcname> in "
 "<file>"
 msgstr ""
+"простежити еволюцію діапазону рядків <початок>,<кінець> або функції :<назва-"
+"функції> в <файлі>"
 
 #, c-format
 msgid "unrecognized argument: %s"
-msgstr ""
+msgstr "нерозпізнаний аргумент: %s"
 
 msgid "-L<range>:<file> cannot be used with pathspec"
 msgstr "-L<діапазон>:<файл> не можна використовувати з визначником шляху"
 
 #, c-format
 msgid "Final output: %d %s\n"
-msgstr ""
+msgstr "Кінцевий результат: %d %s\n"
 
 msgid "unable to create temporary object directory"
 msgstr "не вдалося створити тимчасову директорію об’єкта"
 
 #, c-format
 msgid "git show %s: bad file"
-msgstr ""
+msgstr "git show %s: невірний файл"
 
 #, c-format
 msgid "could not read object %s"
@@ -7296,36 +7507,36 @@ msgstr "невідомий тип: %d"
 
 #, c-format
 msgid "%s: invalid cover from description mode"
-msgstr ""
+msgstr "%s: невірна обкладинка з режиму опису"
 
 msgid "format.headers without value"
-msgstr ""
+msgstr "format.headers без значення"
 
 #, c-format
 msgid "cannot open patch file %s"
 msgstr "не вдається відкрити файл латки %s"
 
 msgid "need exactly one range"
-msgstr ""
+msgstr "потрібен лишень один діапазон"
 
 msgid "not a range"
-msgstr ""
+msgstr "не діапазон"
 
 msgid "cover letter needs email format"
-msgstr ""
+msgstr "супровідний лист має бути у форматі електронної пошти"
 
 msgid "failed to create cover-letter file"
 msgstr "не вдалося створити файл супровідного листа"
 
 #, c-format
 msgid "insane in-reply-to: %s"
-msgstr ""
+msgstr "неприпустимий in-reply-to: %s"
 
 msgid "git format-patch [<options>] [<since> | <revision-range>]"
 msgstr "git format-patch [<опції>] [<відколи> | <діапазон-ревізій>]"
 
 msgid "two output directories?"
-msgstr ""
+msgstr "дві вихідні директорії?"
 
 #, c-format
 msgid "unknown commit %s"
@@ -7343,203 +7554,215 @@ msgid ""
 "please use git branch --set-upstream-to to track a remote branch.\n"
 "Or you could specify base commit by --base=<base-commit-id> manually"
 msgstr ""
+"не вдалося отримати першоджерельне сховище. Якщо ви хочете записати базовий "
+"коміт автоматично,\n"
+"будь ласка, скористайтесь git branch --set-upstream-to для відстежування "
+"віддаленої гілки.\n"
+"Або ви можете вказати базовий коміт вручну за допомогою --"
+"base=<ідентифікатор-базового-коміту>"
 
 msgid "failed to find exact merge base"
 msgstr "не вдалося знайти точну базу для злиття"
 
 msgid "base commit should be the ancestor of revision list"
-msgstr ""
+msgstr "базовий коміт має бути предком списку ревізій"
 
 msgid "base commit shouldn't be in revision list"
-msgstr ""
+msgstr "базового коміту не має бути в списку ревізій"
 
 msgid "cannot get patch id"
 msgstr "неможливо отримати ідентифікатор латки"
 
 msgid "failed to infer range-diff origin of current series"
-msgstr ""
+msgstr "не вдалося визначити походження різниці діапазонів поточного ряду"
 
 #, c-format
 msgid "using '%s' as range-diff origin of current series"
-msgstr ""
+msgstr "використання \"%s\" як походження різниці діапазонів поточного ряду"
 
 msgid "use [PATCH n/m] even with a single patch"
-msgstr ""
+msgstr "використовуйте [PATCH n/m] навіть з однією латкою"
 
 msgid "use [PATCH] even with multiple patches"
-msgstr ""
+msgstr "використовуйте [PATCH] навіть з кількома латками"
 
 msgid "print patches to standard out"
-msgstr ""
+msgstr "вивести латки на стандартний вивід"
 
 msgid "generate a cover letter"
-msgstr ""
+msgstr "скласти супровідний лист"
 
 msgid "use simple number sequence for output file names"
-msgstr ""
+msgstr "використати просту послідовність чисел для назв вихідних файлів"
 
 msgid "sfx"
-msgstr ""
+msgstr "суфікс"
 
 msgid "use <sfx> instead of '.patch'"
-msgstr ""
+msgstr "використати <суфікс> замість \".patch\""
 
 msgid "start numbering patches at <n> instead of 1"
-msgstr ""
+msgstr "почати нумерацію латок з <н> замість 1"
 
 msgid "reroll-count"
-msgstr ""
+msgstr "кількість перекидань"
 
 msgid "mark the series as Nth re-roll"
-msgstr ""
+msgstr "позначити ряд як N-не перекидання"
 
 msgid "max length of output filename"
-msgstr ""
+msgstr "максимальна довжина назви вихідного файлу"
 
 msgid "use [RFC PATCH] instead of [PATCH]"
-msgstr ""
+msgstr "використати [RFC PATCH] замість [PATCH]"
 
 msgid "cover-from-description-mode"
-msgstr ""
+msgstr "cover-from-description-mode"
 
 msgid "generate parts of a cover letter based on a branch's description"
-msgstr ""
+msgstr "скласти частини супровідного листа на основі опису гілки"
 
 msgid "use [<prefix>] instead of [PATCH]"
-msgstr ""
+msgstr "використати [<префікс>] замість [PATCH]"
 
 msgid "store resulting files in <dir>"
-msgstr ""
+msgstr "зберегти результуючі файли в <директорії>"
 
 msgid "don't strip/add [PATCH]"
-msgstr ""
+msgstr "не видаляти/додавати [PATCH]"
 
 msgid "don't output binary diffs"
-msgstr ""
+msgstr "не виводити бінарні різниці"
 
 msgid "output all-zero hash in From header"
-msgstr ""
+msgstr "вивести хеш з усіма нулями в заголовку From"
 
 msgid "don't include a patch matching a commit upstream"
 msgstr ""
+"не включати латки, які мають відповідні коміти в першоджерельному сховищі"
 
 msgid "show patch format instead of default (patch + stat)"
-msgstr ""
+msgstr "показати формат латки замість стандартного (латка + підсумок)"
 
 msgid "Messaging"
-msgstr ""
+msgstr "Повідомлення"
 
 msgid "header"
 msgstr "заголовок"
 
 msgid "add email header"
-msgstr ""
+msgstr "додати заголовок листа"
 
 msgid "email"
-msgstr ""
+msgstr "електронна адреса"
 
 msgid "add To: header"
-msgstr ""
+msgstr "додати To: заголовок"
 
 msgid "add Cc: header"
-msgstr ""
+msgstr "додати Cc: заголовок"
 
 msgid "ident"
-msgstr ""
+msgstr "особистість"
 
 msgid "set From address to <ident> (or committer ident if absent)"
 msgstr ""
+"встановити From адресу в <особистість> (або особистість комітера, якщо "
+"відсутня)"
 
 msgid "message-id"
-msgstr ""
+msgstr "ідентифікатор-повідомлення"
 
 msgid "make first mail a reply to <message-id>"
-msgstr ""
+msgstr "зробити перший лист відповіддю на <id-повідомлення>"
 
 msgid "boundary"
-msgstr ""
+msgstr "межа"
 
 msgid "attach the patch"
-msgstr ""
+msgstr "прикріпити латку"
 
 msgid "inline the patch"
-msgstr ""
+msgstr "вставити латку"
 
 msgid "enable message threading, styles: shallow, deep"
-msgstr ""
+msgstr "увімкнути потік повідомлень, стилі: дрібний, глибокий"
 
 msgid "signature"
-msgstr ""
+msgstr "підпис"
 
 msgid "add a signature"
-msgstr ""
+msgstr "додати підпис"
 
 msgid "base-commit"
-msgstr ""
+msgstr "базовий коміт"
 
 msgid "add prerequisite tree info to the patch series"
-msgstr ""
+msgstr "додати інформацію про дерево передумов до серії латок"
 
 msgid "add a signature from a file"
-msgstr ""
+msgstr "додати підпис з файлу"
 
 msgid "don't print the patch filenames"
-msgstr ""
+msgstr "не виводити назви файлів латок"
 
 msgid "show progress while generating patches"
-msgstr ""
+msgstr "показувати прогрес під час генерації патчів"
 
 msgid "show changes against <rev> in cover letter or single patch"
 msgstr ""
+"показувати зміни проти <ревізія> у супровідному листі або окремій латці"
 
 msgid "show changes against <refspec> in cover letter or single patch"
 msgstr ""
+"показувати зміни проти <визначник-посилання> у супровідному листі або "
+"окремій латці"
 
 msgid "percentage by which creation is weighted"
-msgstr ""
+msgstr "відсоток, за яким зважується створення"
 
 msgid "show in-body From: even if identical to the e-mail header"
-msgstr ""
+msgstr "показувати in-body From: навіть якщо він ідентичний заголовку листа"
 
 #, c-format
 msgid "invalid ident line: %s"
-msgstr "неприпустимий рядок ідентифікатора: %s"
+msgstr "неприпустимий рядок особистості: %s"
 
 msgid "--name-only does not make sense"
-msgstr ""
+msgstr "--name-only не має сенсу"
 
 msgid "--name-status does not make sense"
-msgstr ""
+msgstr "--name-status не має сенсу"
 
 msgid "--check does not make sense"
-msgstr ""
+msgstr "--check не має сенсу"
 
 msgid "--remerge-diff does not make sense"
-msgstr ""
+msgstr "--remerge-diff не має сенсу"
 
 #, c-format
 msgid "could not create directory '%s'"
 msgstr "не вдалося створити директорію \"%s\""
 
 msgid "--interdiff requires --cover-letter or single patch"
-msgstr ""
+msgstr "--interdiff вимагає --cover-letter або окремої латки"
 
 msgid "Interdiff:"
-msgstr ""
+msgstr "Різниця з попередньою серією латок:"
 
 #, c-format
 msgid "Interdiff against v%d:"
-msgstr ""
+msgstr "Різниця з v%d:"
 
 msgid "--range-diff requires --cover-letter or single patch"
-msgstr ""
+msgstr "--range-diff потребує --cover-letter або окремої латки"
 
 msgid "Range-diff:"
-msgstr ""
+msgstr "Різниця діапазону з попередньою серією латок:"
 
 #, c-format
 msgid "Range-diff against v%d:"
-msgstr ""
+msgstr "Різниця діапазону з v%d:"
 
 #, c-format
 msgid "unable to read signature file '%s'"
@@ -7552,192 +7775,202 @@ msgid "failed to create output files"
 msgstr "не вдалося створити вихідні файли"
 
 msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
-msgstr ""
+msgstr "git cherry [-v] [<першоджерельне-сховище> [<голова> [<ліміт>]]]]"
 
 #, c-format
 msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr ""
+"Не вдалося знайти віддалено відстежувану гілку, будь ласка, вкажіть "
+"<першоджерельне-сховище> вручну.\n"
+
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "не вдалося отримати інформацію про обʼєкт \"%s\""
 
 #, c-format
 msgid "bad ls-files format: element '%s' does not start with '('"
-msgstr "невірний формат ls-файлів: елемент \"%s\" не починається з \"(\""
+msgstr "невірний ls-files формат: елемент \"%s\" не починається з \"(\""
 
 #, c-format
 msgid "bad ls-files format: element '%s' does not end in ')'"
-msgstr "невірний формат ls-файлів: елемент \"%s\" не закінчується на \")\""
+msgstr "невірний ls-files формат: елемент \"%s\" не закінчується на \")\""
 
 #, c-format
 msgid "bad ls-files format: %%%.*s"
-msgstr ""
+msgstr "невірний ls-files формат: %%%.*s"
 
 msgid "git ls-files [<options>] [<file>...]"
 msgstr "git ls-files [<опції>] [<файл>...]"
 
 msgid "separate paths with the NUL character"
-msgstr ""
+msgstr "відокремити шляхи символом NUL"
 
 msgid "identify the file status with tags"
-msgstr ""
+msgstr "визначити стан файлу за допомогою тегів"
 
 msgid "use lowercase letters for 'assume unchanged' files"
-msgstr ""
+msgstr "використати малі літери для \"вважати незмінними\" файлів"
 
 msgid "use lowercase letters for 'fsmonitor clean' files"
-msgstr ""
+msgstr "використати малі літери для \"fsmonitor clean\" файлів"
 
 msgid "show cached files in the output (default)"
-msgstr ""
+msgstr "показати кешовані файли у виводі (за замовчуванням)"
 
 msgid "show deleted files in the output"
-msgstr ""
+msgstr "показати видалені файли у виводі"
 
 msgid "show modified files in the output"
-msgstr ""
+msgstr "показати змінені файли у виводі"
 
 msgid "show other files in the output"
-msgstr ""
+msgstr "показати інші файли у виводі"
 
 msgid "show ignored files in the output"
-msgstr ""
+msgstr "показати ігноровані файли у виводі"
 
 msgid "show staged contents' object name in the output"
-msgstr ""
+msgstr "показати назву обʼєкта індексованого вмісту у виводі"
 
 msgid "show files on the filesystem that need to be removed"
-msgstr ""
+msgstr "показати файли файлової системи, які потрібно видалити"
 
 msgid "show 'other' directories' names only"
-msgstr ""
+msgstr "показати тільки назви \"інших\" директорій"
 
 msgid "show line endings of files"
-msgstr ""
+msgstr "показати закінчення рядків файлів"
 
 msgid "don't show empty directories"
-msgstr ""
+msgstr "не показувати порожні директорії"
 
 msgid "show unmerged files in the output"
-msgstr ""
+msgstr "показати не злиті файли у виводі"
 
 msgid "show resolve-undo information"
-msgstr ""
+msgstr "показати resolve-undo інформацію"
 
 msgid "skip files matching pattern"
-msgstr ""
+msgstr "пропустити файли, які відповідають шаблону"
 
 msgid "read exclude patterns from <file>"
-msgstr ""
+msgstr "читати шаблони виключення з <файлу>"
 
 msgid "read additional per-directory exclude patterns in <file>"
-msgstr ""
+msgstr "читати додаткові шаблони виключення для кожної директорії з <файлу>"
 
 msgid "add the standard git exclusions"
-msgstr ""
+msgstr "додати стандартні git виключення"
 
 msgid "make the output relative to the project top directory"
-msgstr ""
+msgstr "зробити виведення відносно верхньої директорії проекту"
 
 msgid "if any <file> is not in the index, treat this as an error"
-msgstr ""
+msgstr "якщо якогось <файлу> немає в індексі, вважати це помилкою"
 
 msgid "tree-ish"
-msgstr ""
+msgstr "деревоподібне-джерело"
 
 msgid "pretend that paths removed since <tree-ish> are still present"
 msgstr ""
+"вдавати, що шляхи, видалені після <деревоподібного-джерела>, все ще присутні"
 
 msgid "show debugging data"
-msgstr ""
+msgstr "показати дані відлагодження"
 
 msgid "suppress duplicate entries"
-msgstr ""
+msgstr "не показувати дублікати записів"
 
 msgid "show sparse directories in the presence of a sparse index"
-msgstr ""
+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] [--sort=<key>]\n"
 "              [--symref] [<repository> [<patterns>...]]"
 msgstr ""
+"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<виконавчий-файл>]\n"
+"              [-q | --quiet] [--exit-code] [--get-url] [--sort=<ключ>]\n"
+"              [--symref] [<сховище> [<шаблони>...]]"
 
 msgid "do not print remote URL"
-msgstr ""
+msgstr "не виводити віддалену URL-адресу"
 
 msgid "exec"
-msgstr ""
+msgstr "виконавчий файл"
 
 msgid "path of git-upload-pack on the remote host"
 msgstr "шлях до git-upload-pack на віддаленому сервері"
 
 msgid "limit to tags"
-msgstr ""
+msgstr "обмежити до тегів"
 
 msgid "limit to heads"
-msgstr ""
+msgstr "обмежити до голів"
 
 msgid "do not show peeled tags"
-msgstr ""
+msgstr "не показувати очищені теги"
 
 msgid "take url.<base>.insteadOf into account"
-msgstr ""
+msgstr "враховувати url.<база>.insteadOf"
 
 msgid "exit with exit code 2 if no matching refs are found"
-msgstr ""
+msgstr "вийти з кодом виходу 2, якщо не знайдено відповідних посилань"
 
 msgid "show underlying ref in addition to the object pointed by it"
-msgstr ""
+msgstr "показувати базове посилання на додаток до об’єкта, на який воно вказує"
 
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<опції>] <деревоподібне-джерело> [<шлях>...]"
 
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "не вдалося отримати інформацію про обʼєкт \"%s\""
-
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
-msgstr "невірний формат ls-дерева: елемент \"%s\" не починається з \"(\""
+msgstr "невірний формат ls-tree: елемент \"%s\" не починається з \"(\""
 
 #, c-format
 msgid "bad ls-tree format: element '%s' does not end in ')'"
-msgstr "невірний формат ls-дерева: елемент \"%s\" не закінчується на \")\""
+msgstr "невірний формат ls-tree: елемент \"%s\" не закінчується на \")\""
 
 #, c-format
 msgid "bad ls-tree format: %%%.*s"
-msgstr ""
+msgstr "невірний формат ls-tree: %%%.*s"
 
 msgid "only show trees"
-msgstr ""
+msgstr "показувати тільки дерева"
 
 msgid "recurse into subtrees"
-msgstr ""
+msgstr "рекурсивно в піддеревах"
 
 msgid "show trees when recursing"
-msgstr ""
+msgstr "відображати дерева при рекурсії"
 
 msgid "terminate entries with NUL byte"
-msgstr ""
+msgstr "завершувати записи байтом NUL"
 
 msgid "include object size"
 msgstr "включити розмір об’єкта"
 
 msgid "list only filenames"
-msgstr ""
+msgstr "показувати лише назви файлів"
 
 msgid "list only objects"
 msgstr "показати лише обʼєкти"
 
 msgid "use full path names"
-msgstr ""
+msgstr "використовувати повні назви шляхів"
 
 msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
+"показувати все дерево, а не лише поточну директорію (мається на увазі --full-"
+"name)."
 
 msgid "--format can't be combined with other format-altering options"
 msgstr "--format не можна комбінувати з іншими опціями зміни формату"
@@ -7745,109 +7978,111 @@ msgstr "--format не можна комбінувати з іншими опці
 #. TRANSLATORS: keep <> in "<" mail ">" info.
 
 msgid "git mailinfo [<options>] <msg> <patch> < mail >info"
-msgstr ""
+msgstr "git mailinfo [<опції>] <допис> <латка> < mail >info"
 
 msgid "keep subject"
-msgstr ""
+msgstr "не змінювати тему"
 
 msgid "keep non patch brackets in subject"
-msgstr ""
+msgstr "зберігати дужки, що не стосуються латок, в темі"
 
 msgid "copy Message-ID to the end of commit message"
-msgstr ""
+msgstr "копіювати Message-ID в кінець допису до коміту"
 
 msgid "re-code metadata to i18n.commitEncoding"
-msgstr ""
+msgstr "перекодувати метадані в i18n.commitEncoding"
 
 msgid "disable charset re-coding of metadata"
-msgstr ""
+msgstr "вимкнути перекодування метаданих"
 
 msgid "encoding"
-msgstr ""
+msgstr "кодування"
 
 msgid "re-code metadata to this encoding"
-msgstr ""
+msgstr "перекодувати метадані в це кодування"
 
 msgid "use scissors"
-msgstr ""
+msgstr "використовувати ножиці"
 
 msgid "<action>"
-msgstr ""
+msgstr "<дія>"
 
 msgid "action when quoted CR is found"
-msgstr ""
+msgstr "дія при знаходженні цитованого CR"
 
 msgid "use headers in message's body"
-msgstr ""
+msgstr "використовувати заголовки в тілі повідомлення"
 
 msgid "reading patches from stdin/tty..."
-msgstr ""
+msgstr "читання латок з stdin/tty..."
 
 #, c-format
 msgid "empty mbox: '%s'"
-msgstr ""
+msgstr "порожній mbox: \"%s\""
 
 msgid "git merge-base [-a | --all] <commit> <commit>..."
-msgstr ""
+msgstr "git merge-base [-a | --all] <коміт> <коміт>..."
 
 msgid "git merge-base [-a | --all] --octopus <commit>..."
-msgstr ""
+msgstr "git merge-base [-a | --all] --octopus <коміт>..."
 
 msgid "git merge-base --is-ancestor <commit> <commit>"
-msgstr ""
+msgstr "git merge-base --is-ancestor <коміт> <коміт>"
 
 msgid "git merge-base --independent <commit>..."
-msgstr ""
+msgstr "git merge-base --independent <коміт>..."
 
 msgid "git merge-base --fork-point <ref> [<commit>]"
-msgstr ""
+msgstr "git merge-base --fork-point <посилання> [<коміт>]"
 
 msgid "output all common ancestors"
-msgstr ""
+msgstr "вивести всіх спільних предків"
 
 msgid "find ancestors for a single n-way merge"
-msgstr ""
+msgstr "знайти предків для одного n-стороннього злиття"
 
 msgid "list revs not reachable from others"
-msgstr ""
+msgstr "показати ревізії, недоступні з інших джерел"
 
 msgid "is the first one ancestor of the other?"
-msgstr ""
+msgstr "чи є перша з них предком другої?"
 
 msgid "find where <commit> forked from reflog of <ref>"
-msgstr ""
+msgstr "знайти, де <коміт> відгалузився від журналу посилань <посилання>"
 
 msgid ""
 "git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> "
 "<orig-file> <file2>"
 msgstr ""
+"git merge-file [<опції>] [-L <назва1> [-L <оріг> [-L <назва2>]]] <файл1> "
+"<оріг-файл> <файл2>"
 
 msgid "send results to standard output"
-msgstr ""
+msgstr "надсилати результати до стандартного виводу"
 
 msgid "use a diff3 based merge"
-msgstr ""
+msgstr "використовувати злиття на основі diff3"
 
 msgid "use a zealous diff3 based merge"
-msgstr ""
+msgstr "використовувати ретельне злиття на основі diff3"
 
 msgid "for conflicts, use our version"
-msgstr ""
+msgstr "у разі конфліктів використовувати нашу версію"
 
 msgid "for conflicts, use their version"
-msgstr ""
+msgstr "у разі конфліктів використовувати їхню версію"
 
 msgid "for conflicts, use a union version"
-msgstr ""
+msgstr "у разі конфліктів використовувати об’єднану версію"
 
 msgid "for conflicts, use this marker size"
-msgstr ""
+msgstr "у разі конфліктів використовувати цей розмір маркера"
 
 msgid "do not warn about conflicts"
-msgstr ""
+msgstr "не попереджати про конфлікти"
 
 msgid "set labels for file1/orig-file/file2"
-msgstr ""
+msgstr "встановити мітки для файл1/оріг-файл/файл2"
 
 #, c-format
 msgid "unknown option %s"
@@ -7860,12 +8095,12 @@ msgstr "не вдалося розібрати обʼєкт \"%s\""
 #, 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[2] ""
+msgstr[0] "неможливо обробити більш ніж %d базу. Ігнорування %s."
+msgstr[1] "неможливо обробити більш ніж %d бази. Ігнорування %s."
+msgstr[2] "неможливо обробити більш ніж %d баз. Ігнорування %s."
 
 msgid "not handling anything other than two heads merge."
-msgstr ""
+msgstr "не оброблюється нічого, окрім злиття двох верхівок."
 
 #, c-format
 msgid "could not resolve ref '%s'"
@@ -7873,49 +8108,49 @@ msgstr "не вдалося розвʼязати посилання \"%s\""
 
 #, c-format
 msgid "Merging %s with %s\n"
-msgstr ""
+msgstr "Злиття %s з %s\n"
 
 msgid "not something we can merge"
-msgstr ""
+msgstr "не те, що ми в змозі об’єднати"
 
 msgid "refusing to merge unrelated histories"
-msgstr ""
+msgstr "відмовлено в об’єднанні непов’язаних історій"
 
 msgid "failure to merge"
-msgstr ""
+msgstr "не вдалося злити"
 
 msgid "git merge-tree [--write-tree] [<options>] <branch1> <branch2>"
-msgstr ""
+msgstr "git merge-tree [--write-tree] [<опції>] <гілка1> <гілка2>"
 
 msgid "git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"
-msgstr ""
+msgstr "git merge-tree [--trivial-merge] <базове-дерево> <гілка1> <гілка2>"
 
 msgid "do a real merge instead of a trivial merge"
-msgstr ""
+msgstr "зробити справжнє злиття замість тривіального злиття"
 
 msgid "do a trivial merge only"
-msgstr ""
+msgstr "зробити лише тривіальне злиття"
 
 msgid "also show informational/conflict messages"
-msgstr ""
+msgstr "також показувати інформаційні/конфліктні повідомлення"
 
 msgid "list filenames without modes/oids/stages"
-msgstr ""
+msgstr "вивести назви файлів без режимів/oid/стадій"
 
 msgid "allow merging unrelated histories"
-msgstr ""
+msgstr "дозволити злиття непов’язаних історій"
 
 msgid "perform multiple merges, one per line of input"
-msgstr ""
+msgstr "виконати кілька злиттів, по одному на кожен рядок вводу"
 
 msgid "specify a merge-base for the merge"
 msgstr "вказати базу для злиття"
 
 msgid "--trivial-merge is incompatible with all other options"
-msgstr ""
+msgstr "--trivial-merge несумісна з усіма іншими опціями"
 
 msgid "--merge-base is incompatible with --stdin"
-msgstr ""
+msgstr "--merge-base несумісна з --stdin"
 
 #, c-format
 msgid "malformed input line: '%s'."
@@ -7923,17 +8158,17 @@ msgstr "невірно сформований рядок вводу: \"%s\"."
 
 #, c-format
 msgid "merging cannot continue; got unclean result of %d"
-msgstr ""
+msgstr "неможливо продовжити злиття; отримано брудний результат для %d"
 
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<опції>] [<коміт>...]"
 
 msgid "switch `m' requires a value"
-msgstr ""
+msgstr "перемикач \"m\" потребує значення"
 
 #, c-format
 msgid "option `%s' requires a value"
-msgstr "опÑ\86Ñ\96Ñ\8f \"%s\" Ð²Ð¸Ð¼Ð°Ð³Ð°є значення"
+msgstr "опÑ\86Ñ\96Ñ\8f \"%s\" Ð¿Ð¾Ñ\82Ñ\80ебÑ\83є значення"
 
 #, c-format
 msgid "Could not find merge strategy '%s'.\n"
@@ -7941,98 +8176,99 @@ msgstr "Не вдалося знайти стратегію злиття \"%s\".
 
 #, c-format
 msgid "Available strategies are:"
-msgstr ""
+msgstr "Доступні стратегії:"
 
 #, c-format
 msgid "Available custom strategies are:"
-msgstr ""
+msgstr "Доступні спеціальні стратегії:"
 
 msgid "do not show a diffstat at the end of the merge"
-msgstr ""
+msgstr "не показувати diffstat наприкінці злиття"
 
 msgid "show a diffstat at the end of the merge"
-msgstr ""
+msgstr "показувати diffstat наприкінці злиття"
 
 msgid "(synonym to --stat)"
-msgstr ""
+msgstr "(синонім до --stat)"
 
 msgid "add (at most <n>) entries from shortlog to merge commit message"
 msgstr ""
+"додати (не більше <н>) записів з короткого журналу у допис до коміту злиття"
 
 msgid "create a single commit instead of doing a merge"
-msgstr ""
+msgstr "створити єдиний коміт замість злиття"
 
 msgid "perform a commit if the merge succeeds (default)"
-msgstr ""
+msgstr "виконати коміт, якщо злиття пройшло успішно (за замовчуванням)"
 
 msgid "edit message before committing"
-msgstr "Ñ\80едагÑ\83ваÑ\82и Ð¿Ð¾Ð²Ñ\96домленнÑ\8f перед комітом"
+msgstr "Ñ\80едагÑ\83ваÑ\82и Ð´Ð¾Ð¿Ð¸Ñ\81 перед комітом"
 
 msgid "allow fast-forward (default)"
-msgstr ""
+msgstr "дозволити перемотування вперед (за замовчуванням)"
 
 msgid "abort if fast-forward is not possible"
-msgstr ""
+msgstr "перервати, якщо перемотування вперед неможливе"
 
 msgid "verify that the named commit has a valid GPG signature"
-msgstr ""
+msgstr "перевіряти, чи має коміт дійсний GPG-підпис"
 
 msgid "strategy"
-msgstr ""
+msgstr "стратегія"
 
 msgid "merge strategy to use"
-msgstr ""
+msgstr "яку стратегію злиття використовувати"
 
 msgid "option=value"
-msgstr ""
+msgstr "опція=значення"
 
 msgid "option for selected merge strategy"
-msgstr ""
+msgstr "опція для обраної стратегії злиття"
 
 msgid "merge commit message (for a non-fast-forward merge)"
-msgstr ""
+msgstr "допис до коміту злиття (для злиття без перемотування вперед)"
 
 msgid "use <name> instead of the real target"
-msgstr "використовувати <назва> замість реальної цілі"
+msgstr "використовувати <назву> замість реальної цілі"
 
 msgid "abort the current in-progress merge"
 msgstr "перервати поточне злиття"
 
 msgid "--abort but leave index and working tree alone"
-msgstr "--abort, але зберегти стан індекса і робочого дерева"
+msgstr "--abort, але зберегти стан індексу і робочого дерева"
 
 msgid "continue the current in-progress merge"
 msgstr "продовжити поточний процес злиття"
 
 msgid "bypass pre-merge-commit and commit-msg hooks"
-msgstr ""
+msgstr "обходити pre-merge-commit та commit-msg гачки"
 
 msgid "could not run stash."
 msgstr "не вдалося виконати stash."
 
 msgid "stash failed"
-msgstr ""
+msgstr "не вдалося додати до схову"
 
 #, c-format
 msgid "not a valid object: %s"
 msgstr "не є припустимим обʼєктом: %s"
 
 msgid "read-tree failed"
-msgstr ""
+msgstr "read-tree завершився невдало"
 
 msgid "Already up to date. (nothing to squash)"
-msgstr ""
+msgstr "Вже в актуальному стані. (нічого зчавлювати)"
 
 msgid "Already up to date."
-msgstr ""
+msgstr "Вже в актуальному стані."
 
 #, c-format
 msgid "Squash commit -- not updating HEAD\n"
-msgstr ""
+msgstr "Коміт зчавлювання -- HEAD не оновлюється\n"
 
 #, c-format
 msgid "No merge message -- not updating HEAD\n"
-msgstr ""
+msgstr "Немає допису до злиття -- HEAD не оновлюється\n"
 
 #, c-format
 msgid "'%s' does not point to a commit"
@@ -8040,17 +8276,17 @@ msgstr "\"%s\" не вказує на коміт"
 
 #, c-format
 msgid "Bad branch.%s.mergeoptions string: %s"
-msgstr ""
+msgstr "Невірна branch.%s.mergeoptions строка: %s"
 
 msgid "Unable to write index."
 msgstr "Не вдалося записати індекс."
 
 msgid "Not handling anything other than two heads merge."
-msgstr ""
+msgstr "Не оброблюється нічого, окрім злиття двох верхівок."
 
 #, c-format
 msgid "unknown strategy option: -X%s"
-msgstr ""
+msgstr "невідомий варіант стратегії: -X%s"
 
 #, c-format
 msgid "unable to write %s"
@@ -8063,33 +8299,41 @@ msgstr "Не вдалося прочитати з \"%s\""
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
-"Ð\9dе Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ð·Ð»Ð¸Ñ\82Ñ\82Ñ\8f; Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82овÑ\83йÑ\82е \"git commit\" Ð´Ð»Ñ\8f Ð·Ð°Ð²ÐµÑ\80Ñ\88еннÑ\8f злиття.\n"
+"Ð\9dе Ð´Ð¾Ð´Ð°Ð½Ð¾ ÐºÐ¾Ð¼Ñ\96Ñ\82 Ð·Ð»Ð¸Ñ\82Ñ\82Ñ\8f; Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8c \"git commit\", Ñ\89об Ð·Ð°Ð²ÐµÑ\80Ñ\88иÑ\82и злиття.\n"
 
 msgid ""
 "Please enter a commit message to explain why this merge is necessary,\n"
 "especially if it merges an updated upstream into a topic branch.\n"
 "\n"
 msgstr ""
+"Будь ласка, введіть допис до коміту, щоб пояснити, чому це злиття є "
+"необхідним,\n"
+"особливо якщо воно об’єднує першоджерельні оновлення з тематичною гілкою.\n"
 
 msgid "An empty message aborts the commit.\n"
-msgstr ""
+msgstr "Порожній допис перерве процес коміту.\n"
 
 #, c-format
 msgid ""
 "Lines starting with '%c' will be ignored, and an empty message aborts\n"
 "the commit.\n"
 msgstr ""
+"Рядки, що починаються з \"%c\", будуть проігноровані, а порожній допис "
+"перерве\n"
+"процес коміту.\n"
 
 msgid "Empty commit message."
-msgstr ""
+msgstr "Порожній допис до коміту."
 
 #, c-format
 msgid "Wonderful.\n"
-msgstr ""
+msgstr "Чудово.\n"
 
 #, c-format
 msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
 msgstr ""
+"Автоматичне злиття не вдалося; виправте конфлікти і потім зробіть коміт "
+"результату.\n"
 
 msgid "No current branch."
 msgstr "Немає поточної гілки."
@@ -8099,14 +8343,15 @@ msgstr "Немає віддаленого призначення для пото
 
 msgid "No default upstream defined for the current branch."
 msgstr ""
+"Для поточної гілки не визначено першоджерельне сховище за замовчуванням."
 
 #, c-format
 msgid "No remote-tracking branch for %s from %s"
-msgstr ""
+msgstr "Немає віддалено відстежуваної гілки для %s з %s"
 
 #, c-format
 msgid "Bad value '%s' in environment '%s'"
-msgstr ""
+msgstr "Невірне значення \"%s\" в оточенні \"%s\""
 
 #, c-format
 msgid "could not close '%s'"
@@ -8114,109 +8359,117 @@ msgstr "не вдалося закрити \"%s\""
 
 #, c-format
 msgid "not something we can merge in %s: %s"
-msgstr ""
+msgstr "не те, що можна злити в %s: %s"
 
 msgid "--abort expects no arguments"
-msgstr ""
+msgstr "--abort не очікує жодних аргументів"
 
 msgid "There is no merge to abort (MERGE_HEAD missing)."
-msgstr ""
+msgstr "Неможливо перервати злиття (відсутній MERGE_HEAD)."
 
 msgid "--quit expects no arguments"
-msgstr ""
+msgstr "--quit не очікує жодних аргументів"
 
 msgid "--continue expects no arguments"
-msgstr ""
+msgstr "--continue не очікує жодних аргументів"
 
 msgid "There is no merge in progress (MERGE_HEAD missing)."
-msgstr ""
+msgstr "Злиття не виконується (відсутній MERGE_HEAD)."
 
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you merge."
 msgstr ""
+"Ви не завершили злиття (існує MERGE_HEAD).\n"
+"Будь ласка, зробіть коміт для ваших змін перед злиттям."
 
 msgid ""
 "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 "Please, commit your changes before you merge."
 msgstr ""
+"Ви не завершили висмикування (існує CHERRY_PICK_HEAD).\n"
+"Будь ласка, зробіть коміт для ваших змін перед злиттям."
 
 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
-msgstr ""
+msgstr "Ви не завершили висмикування (існує CHERRY_PICK_HEAD)."
 
 msgid "No commit specified and merge.defaultToUpstream not set."
-msgstr ""
+msgstr "Не вказано коміт і не встановлено merge.defaultToUpstream."
 
 msgid "Squash commit into empty head not supported yet"
-msgstr ""
+msgstr "Поки що немає підтримки комітів зчавлювання в порожню верхівку"
 
 msgid "Non-fast-forward commit does not make sense into an empty head"
-msgstr "Ð\9dе fast-forward ÐºÐ¾Ð¼Ñ\96Ñ\82 Ð½Ðµ Ð¼Ð°Ñ\94 Ñ\81енÑ\81Ñ\83 Ð· Ð¿Ð¾Ñ\80ожнÑ\96м HEAD"
+msgstr "Ð\9aомÑ\96Ñ\82 Ð±ÐµÐ· Ð¿ÐµÑ\80емоÑ\82Ñ\83ваннÑ\8f Ð²Ð¿ÐµÑ\80ед Ñ\83 Ð¿Ð¾Ñ\80ожнÑ\8e Ð²ÐµÑ\80Ñ\85Ñ\96вкÑ\83 Ð½Ðµ Ð¼Ð°Ñ\94 Ñ\81енÑ\81Ñ\83"
 
 #, c-format
 msgid "%s - not something we can merge"
-msgstr ""
+msgstr "%s - не те, що можна злити"
 
 msgid "Can merge only exactly one commit into empty head"
-msgstr ""
+msgstr "Можна злити лишень один коміт у порожню верхівку"
 
 #, c-format
 msgid "Updating %s..%s\n"
-msgstr ""
+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 ""
+msgstr "Спроба справді тривіального внутрішньо-індексного злиття...\n"
 
 #, c-format
 msgid "Nope.\n"
-msgstr ""
+msgstr "Ні.\n"
 
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
-msgstr ""
+msgstr "Приведення дерева до початкового стану...\n"
 
 #, c-format
 msgid "Trying merge strategy %s...\n"
-msgstr ""
+msgstr "Спроба стратегії злиття %s...\n"
 
 #, c-format
 msgid "No merge strategy handled the merge.\n"
-msgstr ""
+msgstr "Жодна стратегія злиття не впоралася зі злиттям.\n"
 
 #, c-format
 msgid "Merge with strategy %s failed.\n"
-msgstr ""
+msgstr "Злиття зі стратегією %s не вдалося.\n"
 
 #, c-format
 msgid "Using the %s strategy to prepare resolving by hand.\n"
-msgstr ""
+msgstr "Використання стратегії %s для підготовки вирішення вручну.\n"
 
 #, c-format
 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 ""
+msgstr "попередження: вхідний тег не пройшов fsck: %s"
 
 #, c-format
 msgid "error: tag input does not pass fsck: %s"
-msgstr ""
+msgstr "помилка: вхідний тег не пройшов fsck: %s"
 
 #, c-format
 msgid "%d (FSCK_IGNORE?) should never trigger this callback"
-msgstr ""
+msgstr "%d (FSCK_IGNORE?) ніколи не мав спричинити цей зворотній виклик"
 
 #, c-format
 msgid "could not read tagged object '%s'"
@@ -8224,33 +8477,35 @@ msgstr "не вдалося прочитати тегований об’єкт
 
 #, c-format
 msgid "object '%s' tagged as '%s', but is a '%s' type"
-msgstr ""
+msgstr "об’єкт \"%s\", позначений як \"%s\", але має тип \"%s\""
 
 msgid "could not read from stdin"
 msgstr "не вдалося прочитати з stdin"
 
 msgid "tag on stdin did not pass our strict fsck check"
-msgstr ""
+msgstr "тег з stdin не пройшов нашу сувору перевірку fsck"
 
 msgid "tag on stdin did not refer to a valid object"
-msgstr ""
+msgstr "тег з stdin не посилався на дійсний об’єкт"
 
 msgid "unable to write tag file"
 msgstr "не вдалося записати файл тегів"
 
 msgid "input is NUL terminated"
-msgstr ""
+msgstr "ввід завершено символом NUL"
 
 msgid "allow missing objects"
-msgstr "дозволити відсутні об’єкти"
+msgstr "дозволяти відсутні об’єкти"
 
 msgid "allow creation of more than one tree"
-msgstr ""
+msgstr "дозволяти створення більш ніж одного дерева"
 
 msgid ""
 "git multi-pack-index [<options>] write [--preferred-pack=<pack>][--refs-"
 "snapshot=<path>]"
 msgstr ""
+"git multi-pack-index [<опції>] write [--preferred-pack=<пакунок>] [--refs-"
+"snapshot=<шлях>]"
 
 msgid "git multi-pack-index [<options>] verify"
 msgstr "git multi-pack-index [<опції>] verify"
@@ -8259,53 +8514,58 @@ msgid "git multi-pack-index [<options>] expire"
 msgstr "git multi-pack-index [<опції>] expire"
 
 msgid "git multi-pack-index [<options>] repack [--batch-size=<size>]"
-msgstr ""
+msgstr "git multi-pack-index [<опції>] repack [--batch-size=<розмір>]"
 
 msgid "directory"
 msgstr "директорія"
 
 msgid "object directory containing set of packfile and pack-index pairs"
-msgstr ""
+msgstr "директорія об’єктів, що містить набір packfile та pack-index пар"
 
 msgid "preferred-pack"
-msgstr ""
+msgstr "preferred-pack"
 
 msgid "pack for reuse when computing a multi-pack bitmap"
 msgstr ""
+"пакунок для повторного використання під час обчислення multi-pack bitmap"
 
 msgid "write multi-pack bitmap"
-msgstr ""
+msgstr "записати multi-pack bitmap"
 
 msgid "write multi-pack index containing only given indexes"
-msgstr ""
+msgstr "записати multi-pack індекс, що містить лише задані індекси"
 
 msgid "refs snapshot for selecting bitmap commits"
-msgstr ""
+msgstr "знімок посилань для вибору bitmap комітів"
 
 msgid ""
 "during repack, collect pack-files of smaller size into a batch that is "
 "larger than this size"
 msgstr ""
+"під час перепакування збирати пакувальні файли меншого розміру в партію, "
+"більшу за цей розмір"
 
 msgid "git mv [<options>] <source>... <destination>"
 msgstr "git mv [<опції>] <джерело>... <призначення>"
 
 #, c-format
 msgid "Directory %s is in index and no submodule?"
-msgstr ""
+msgstr "Директорія %s в індексі, але без підмодуля?"
 
 msgid "Please stage your changes to .gitmodules or stash them to proceed"
 msgstr ""
+"Будь ласка, додайте змінений .gitmodules до індексу або до схову, щоб "
+"продовжити"
 
 #, c-format
 msgid "%.*s is in index"
-msgstr ""
+msgstr "%.*s в індексі"
 
 msgid "force move/rename even if target exists"
-msgstr ""
+msgstr "примусово переміщувати/перейменовувати, навіть якщо ціль існує"
 
 msgid "skip move/rename errors"
-msgstr ""
+msgstr "пропускати помилки переміщення/перейменування"
 
 #, c-format
 msgid "destination '%s' is not a directory"
@@ -8313,38 +8573,38 @@ msgstr "місце призначення \"%s\" не є директорією"
 
 #, c-format
 msgid "Checking rename of '%s' to '%s'\n"
-msgstr ""
+msgstr "Перевірка перейменування \"%s\" на \"%s\"\n"
 
 msgid "bad source"
 msgstr "невірне джерело"
 
 msgid "destination exists"
-msgstr ""
+msgstr "призначення існує"
 
 msgid "can not move directory into itself"
-msgstr ""
+msgstr "неможливо перемістити директорію в саму себе"
 
 msgid "cannot move directory over file"
-msgstr ""
+msgstr "неможливо перемістити директорію поверх файлу"
 
 msgid "source directory is empty"
-msgstr ""
+msgstr "директорія джерела порожня"
 
 msgid "not under version control"
-msgstr ""
+msgstr "не під контролем версій"
 
 msgid "conflicted"
-msgstr ""
+msgstr "конфлікт"
 
 #, c-format
 msgid "overwriting '%s'"
-msgstr ""
+msgstr "перезапис \"%s\""
 
 msgid "Cannot overwrite"
-msgstr ""
+msgstr "Неможливо перезаписати"
 
 msgid "multiple sources for the same target"
-msgstr ""
+msgstr "кілька джерел для однієї цілі"
 
 msgid "destination directory does not exist"
 msgstr "директорія призначення не існує"
@@ -8354,7 +8614,7 @@ msgstr "призначення існує в індексі"
 
 #, c-format
 msgid "%s, source=%s, destination=%s"
-msgstr ""
+msgstr "%s, джерело=%s, призначення=%s"
 
 #, c-format
 msgid "Renaming %s to %s\n"
@@ -8362,7 +8622,7 @@ msgstr "Перейменування %s на %s\n"
 
 #, c-format
 msgid "renaming '%s' failed"
-msgstr ""
+msgstr "перейменування \"%s\" завершилося невдало"
 
 msgid "git name-rev [<options>] <commit>..."
 msgstr "git name-rev [<опції>] <коміт>..."
@@ -8371,108 +8631,119 @@ msgid "git name-rev [<options>] --all"
 msgstr "git name-rev [<опції>] --all"
 
 msgid "git name-rev [<options>] --annotate-stdin"
-msgstr ""
+msgstr "git name-rev [<опції>] --annotate-stdin"
 
 msgid "print only ref-based names (no object names)"
-msgstr ""
+msgstr "виводити тільки назви на основі посилань (без назв об’єктів)"
 
 msgid "only use tags to name the commits"
-msgstr ""
+msgstr "використовувати теги лише для назв комітів"
 
 msgid "only use refs matching <pattern>"
-msgstr ""
+msgstr "використовувати лише посилання, що збігаються з <шаблоном>"
 
 msgid "ignore refs matching <pattern>"
-msgstr ""
+msgstr "ігнорувати посилання, що збігаються з <шаблоном>"
 
 msgid "list all commits reachable from all refs"
-msgstr ""
+msgstr "вивести всі коміти, доступні з усіх посилань"
 
 msgid "deprecated: use --annotate-stdin instead"
-msgstr ""
+msgstr "застаріле: замість цього використовуйте --annotate-stdin"
 
 msgid "annotate text from stdin"
-msgstr ""
+msgstr "анотувати текст зі stdin"
 
 msgid "allow to print `undefined` names (default)"
-msgstr ""
+msgstr "дозволити виводити \"невизначені\" назви (за замовчуванням)"
 
 msgid "dereference tags in the input (internal use)"
-msgstr ""
+msgstr "розіменувати теги на вході (внутрішнє використання)"
 
 msgid "git notes [--ref <notes-ref>] [list [<object>]]"
-msgstr ""
+msgstr "git notes [--ref <посилання-нотатки>] [list [<об’єкт>]]"
 
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
+"git notes [--ref <посилання-нотатки>] add [-f] [--allow-empty] [--"
+"[no-]separator|--separator=<розділювач-абзаців>] [--[no-]stripspace] [-m "
+"<допис> | -F <файл> | (-c | -C) <обʼєкт>] [<обʼєкт>]"
 
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
+"git notes [--ref <посилання-нотатки>] copy [-f] <з-об’єкта> <до-об’єкта>"
 
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
+"git notes [--ref <посилання-нотатки>] append [--allow-empty] [--"
+"[no-]separator|--separator=<розділювач-абзаців>] [--[no-]stripspace] [-m "
+"<допис> | -F <файл> | (-c | -C) <обʼєкт>] [<обʼєкт>]"
 
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
-msgstr ""
+msgstr "git notes [--ref <посилання-нотатки>] edit [--allow-empty] [<об’єкт>]"
 
 msgid "git notes [--ref <notes-ref>] show [<object>]"
-msgstr ""
+msgstr "git notes [--ref <посилання-нотатки>] show [<об’єкт>]"
 
 msgid ""
 "git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"
 msgstr ""
+"git notes [--ref <посилання-нотатки>] merge [-v | -q] [-s <стратегія>] "
+"<посилання-нотатки>"
 
 msgid "git notes [--ref <notes-ref>] remove [<object>...]"
-msgstr ""
+msgstr "git notes [--ref <посилання-нотатки>] remove [<об’єкт>...]"
 
 msgid "git notes [--ref <notes-ref>] prune [-n] [-v]"
-msgstr ""
+msgstr "git notes [--ref <посилання-нотатки>] prune [-n] [-v]."
 
 msgid "git notes [--ref <notes-ref>] get-ref"
-msgstr ""
+msgstr "git notes [--ref <посилання-нотатки>] get-ref"
 
 msgid "git notes [list [<object>]]"
-msgstr ""
+msgstr "git notes [list [<об’єкт>]]"
 
 msgid "git notes add [<options>] [<object>]"
 msgstr "git notes add [<опції>] [<обʼєкт>]"
 
 msgid "git notes copy [<options>] <from-object> <to-object>"
-msgstr ""
+msgstr "git notes copy [<опції>] <з-об’єкта> <до-об’єкта"
 
 msgid "git notes copy --stdin [<from-object> <to-object>]..."
-msgstr ""
+msgstr "git notes copy --stdin [<з-об’єкта> <до-об’єкта>]..."
 
 msgid "git notes append [<options>] [<object>]"
 msgstr "git notes append [<опції>] [<обʼєкт>]"
 
 msgid "git notes edit [<object>]"
-msgstr ""
+msgstr "git notes edit [<об’єкт>]"
 
 msgid "git notes show [<object>]"
-msgstr ""
+msgstr "git notes show [<об’єкт>]"
 
 msgid "git notes merge [<options>] <notes-ref>"
 msgstr "git notes merge [<опції>] <посилання-нотатки>"
 
 msgid "git notes merge --commit [<options>]"
-msgstr ""
+msgstr "git notes merge --commit [<опції>]"
 
 msgid "git notes merge --abort [<options>]"
-msgstr ""
+msgstr "git notes merge --abort [<опції>]"
 
 msgid "git notes remove [<object>]"
-msgstr ""
+msgstr "git notes remove [<об’єкт>]"
 
 msgid "git notes prune [<options>]"
 msgstr "git notes prune [<опції>]"
 
 msgid "Write/edit the notes for the following object:"
-msgstr ""
+msgstr "Записати/відредагувати нотатки для наступного обʼєкта:"
 
 #, c-format
 msgid "unable to start 'show' for object '%s'"
@@ -8486,14 +8757,14 @@ msgid "failed to finish 'show' for object '%s'"
 msgstr "не вдалося завершити \"show\" для об’єкта \"%s\""
 
 msgid "please supply the note contents using either -m or -F option"
-msgstr ""
+msgstr "будь ласка, надайте зміст нотатки, використовуючи опцію -m або -F"
 
 msgid "unable to write note object"
 msgstr "не вдалося записати об’єкт нотатки"
 
 #, c-format
 msgid "the note contents have been left in %s"
-msgstr ""
+msgstr "вміст нотатки залишено в %s"
 
 #, c-format
 msgid "could not open or read '%s'"
@@ -8521,49 +8792,61 @@ msgstr "не вдалося скопіювати нотатки з \"%s\" в \"%
 
 #, c-format
 msgid "refusing to %s notes in %s (outside of refs/notes/)"
-msgstr ""
+msgstr "відмовлено в %s нотаток у %s (за межами refs/notes/)"
 
 #, c-format
 msgid "no note found for object %s."
 msgstr "для обʼєкта %s не знайдено жодної нотатки."
 
 msgid "note contents as a string"
-msgstr ""
+msgstr "вміст нотатки як строка"
 
 msgid "note contents in a file"
-msgstr ""
+msgstr "вміст нотатки у файлі"
 
 msgid "reuse and edit specified note object"
-msgstr ""
+msgstr "повторно використати та редагувати вказаний обʼєкт нотатки"
 
 msgid "reuse specified note object"
-msgstr ""
+msgstr "повторно використати вказаний обʼєкт нотатки"
 
 msgid "allow storing empty note"
-msgstr ""
+msgstr "дозволити збереження порожньої нотатки"
 
 msgid "replace existing notes"
 msgstr "замінити існуючі нотатки"
 
+msgid "<paragraph-break>"
+msgstr "<розділювач-абзаців>"
+
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "вставити <розділювач-абзаців> між абзацами"
+
+msgid "remove unnecessary whitespace"
+msgstr "видалити зайві пробіли"
+
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
 "existing notes"
 msgstr ""
+"Неможливо додати нотатки. Знайдено існуючі нотатки для обʼєкта %s. "
+"Скористайтесь \"-f\" для перезапису існуючих нотаток"
 
 #, c-format
 msgid "Overwriting existing notes for object %s\n"
-msgstr ""
+msgstr "Перезапис існуючих нотаток для обʼєкта %s\n"
 
 #, c-format
 msgid "Removing note for object %s\n"
 msgstr "Видалення нотатки для обʼєкта %s\n"
 
 msgid "read objects from stdin"
-msgstr ""
+msgstr "зчитати обʼєкти з stdin"
 
 msgid "load rewriting config for <command> (implies --stdin)"
 msgstr ""
+"завантажити перезапис конфігурації для <команда> (мається на увазі --stdin)"
 
 msgid "too few arguments"
 msgstr "замало аргументів"
@@ -8573,81 +8856,87 @@ msgid ""
 "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
 "existing notes"
 msgstr ""
+"Неможливо скопіювати нотатки. Знайдено існуючі нотатки для обʼєкта %s. "
+"Скористайтесь \"-f\", щоб перезаписати існуючі нотатки"
 
 #, c-format
 msgid "missing notes on source object %s. Cannot copy."
-msgstr ""
+msgstr "нотатки джерельного обʼєкта %s відсутні. Неможливо скопіювати."
 
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
 "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
 msgstr ""
+"Опції -m/-F/-c/-C застаріли для підкоманди \"edit\".\n"
+"Будь ласка, скористайтесь \"git notes add -f -m/-F/-c/-C\" замість цього.\n"
 
 msgid "failed to delete ref NOTES_MERGE_PARTIAL"
-msgstr ""
+msgstr "не вдалося видалити посилання NOTES_MERGE_PARTIAL"
 
 msgid "failed to delete ref NOTES_MERGE_REF"
-msgstr ""
+msgstr "не вдалося видалити посилання NOTES_MERGE_REF"
 
 msgid "failed to remove 'git notes merge' worktree"
-msgstr ""
+msgstr "не вдалося видалити \"git notes merge\" робоче дерево"
 
 msgid "failed to read ref NOTES_MERGE_PARTIAL"
-msgstr ""
+msgstr "не вдалося прочитати посилання NOTES_MERGE_PARTIAL"
 
 msgid "could not find commit from NOTES_MERGE_PARTIAL."
-msgstr ""
+msgstr "не вдалося знайти коміт з NOTES_MERGE_PARTIAL."
 
 msgid "could not parse commit from NOTES_MERGE_PARTIAL."
-msgstr ""
+msgstr "не вдалося розібрати коміт з NOTES_MERGE_PARTIAL."
 
 msgid "failed to resolve NOTES_MERGE_REF"
-msgstr ""
+msgstr "не вдалося розвʼязати NOTES_MERGE_REF"
 
 msgid "failed to finalize notes merge"
 msgstr "не вдалося завершити злиття нотаток"
 
 #, c-format
 msgid "unknown notes merge strategy %s"
-msgstr ""
+msgstr "невідома стратегія злиття нотаток %s"
 
 msgid "General options"
-msgstr ""
+msgstr "Основні опції"
 
 msgid "Merge options"
-msgstr ""
+msgstr "Опції злиття"
 
 msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
 "cat_sort_uniq)"
 msgstr ""
+"вирішити конфлікти нотаток, використовуючи задану стратегію (manual/our/"
+"their/union/cat_sort_uniq)"
 
 msgid "Committing unmerged notes"
-msgstr "Виконнання коміту незлитих нотаток"
+msgstr "Виконнання коміту не злитих нотаток"
 
 msgid "finalize notes merge by committing unmerged notes"
-msgstr ""
+msgstr "завершити злиття комітом не злитих нотаток"
 
 msgid "Aborting notes merge resolution"
-msgstr ""
+msgstr "Переривання злиття нотаток"
 
 msgid "abort notes merge"
 msgstr "перервати злиття нотаток"
 
 msgid "cannot mix --commit, --abort or -s/--strategy"
-msgstr ""
+msgstr "не можна змішувати --commit, --abort або -s/--strategy"
 
 msgid "must specify a notes ref to merge"
 msgstr "необхідно вказати посилання нотаток для злиття"
 
 #, c-format
 msgid "unknown -s/--strategy: %s"
-msgstr ""
+msgstr "невідома -s/--strategy: %s"
 
 #, c-format
 msgid "a notes merge into %s is already in-progress at %s"
-msgstr ""
+msgstr "злиття нотаток у %s вже виконується в %s"
 
 #, c-format
 msgid "failed to store link to current notes ref (%s)"
@@ -8659,6 +8948,9 @@ msgid ""
 "'git notes merge --commit', or abort the merge with 'git notes merge --"
 "abort'.\n"
 msgstr ""
+"Автоматичне злиття нотаток не вдалося. Виправте конфлікти у %s і зробіть "
+"коміт змін командою \"git notes merge --commit\" або перервіть злиття "
+"командою \"git notes merge --abort\".\n"
 
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
@@ -8666,46 +8958,52 @@ msgstr "Не вдалося розвʼязати \"%s\" як припустим
 
 #, c-format
 msgid "Object %s has no note\n"
-msgstr ""
+msgstr "Обʼєкт %s не має нотатки\n"
 
 msgid "attempt to remove non-existent note is not an error"
-msgstr ""
+msgstr "спроба видалити неіснуючу нотатку не є помилкою"
 
 msgid "read object names from the standard input"
-msgstr ""
+msgstr "зчитати імена обʼєктів зі стандартного вводу"
 
 msgid "do not remove, show only"
-msgstr ""
+msgstr "не видаляти, тільки показувати"
 
 msgid "report pruned notes"
-msgstr ""
+msgstr "звітувати про видалені нотатки"
 
 msgid "notes-ref"
-msgstr ""
+msgstr "посилання-нотатки"
 
 msgid "use notes from <notes-ref>"
-msgstr ""
+msgstr "використовувати нотатки з <посилання-нотатки>"
 
 #, c-format
 msgid "unknown subcommand: `%s'"
-msgstr ""
+msgstr "невідома підкоманда: \"%s\""
 
 msgid "git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"
 msgstr ""
+"git pack-objects --stdout [<опції>] [< <список-посилань> | < <список-"
+"обʼєктів>]"
 
 msgid ""
 "git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"
 msgstr ""
+"git pack-objects [<опції>] <базова-назва> [< <список-посилань> | < <список-"
+"обʼєктів>]"
 
 #, c-format
 msgid ""
 "write_reuse_object: could not locate %s, expected at offset %<PRIuMAX> in "
 "pack %s"
 msgstr ""
+"write_reuse_object: не вдалося знайти %s, очікуваний зі зміщенням %<PRIuMAX> "
+"у пакунку %s"
 
 #, c-format
 msgid "bad packed object CRC for %s"
-msgstr ""
+msgstr "невірна CRC запакованого обʼєкта %s"
 
 #, c-format
 msgid "corrupt packed object for %s"
@@ -8717,7 +9015,7 @@ msgstr "виявлено рекурсивну дельту для обʼєкта
 
 #, c-format
 msgid "ordered %u objects, expected %<PRIu32>"
-msgstr ""
+msgstr "замовлено %u обʼєктів, очікувалось %<PRIu32>"
 
 #, c-format
 msgid "expected object at offset %<PRIuMAX> in pack %s"
@@ -8725,6 +9023,8 @@ msgstr "очікувався обʼєкт на зміщенні %<PRIuMAX> па
 
 msgid "disabling bitmap writing, packs are split due to pack.packSizeLimit"
 msgstr ""
+"вимкнення bitmap запису, пакунки розбиваються на частини через pack."
+"packSizeLimit"
 
 msgid "Writing objects"
 msgstr "Запис обʼєктів"
@@ -8742,10 +9042,10 @@ msgstr "не вдалося записати bitmap індекс"
 
 #, c-format
 msgid "wrote %<PRIu32> objects while expecting %<PRIu32>"
-msgstr ""
+msgstr "записано %<PRIu32> обʼєкти при очікуванні %<PRIu32>"
 
 msgid "disabling bitmap writing, as some objects are not being packed"
-msgstr ""
+msgstr "вимкнення bitmap запису, оскільки деякі обʼєкти не упаковуються"
 
 #, c-format
 msgid "delta base offset overflow in pack for %s"
@@ -8772,14 +9072,14 @@ msgstr "обʼєкт %s не може бути прочитаний"
 
 #, c-format
 msgid "object %s inconsistent object length (%<PRIuMAX> vs %<PRIuMAX>)"
-msgstr ""
+msgstr "обʼєкт %s має невідповідну довжину (%<PRIuMAX> проти %<PRIuMAX>)"
 
 msgid "suboptimal pack - out of memory"
-msgstr ""
+msgstr "неоптимальний пакунок - не вистачає памʼяті"
 
 #, c-format
 msgid "Delta compression using up to %d threads"
-msgstr ""
+msgstr "Дельта компресія з використанням до %d потоків"
 
 #, c-format
 msgid "unable to pack objects reachable from tag %s"
@@ -8793,18 +9093,22 @@ msgid "Compressing objects"
 msgstr "Компресія обʼєктів"
 
 msgid "inconsistency with delta count"
-msgstr ""
+msgstr "неспівпадіння з підрахунком дельти"
 
 #, c-format
 msgid ""
 "value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-"
 "hash> <uri>' (got '%s')"
 msgstr ""
+"значення uploadpack.blobpackfileuri повинно мати вигляд \"<хеш-обʼєкта> <хеш-"
+"пакунка> <uri>\" (отримано \"%s\")"
 
 #, c-format
 msgid ""
 "object already configured in another uploadpack.blobpackfileuri (got '%s')"
 msgstr ""
+"обʼєкт вже сконфігуровано в іншому uploadpack.blobpackfileuri (отримано "
+"\"%s\")"
 
 #, c-format
 msgid "could not get type of object %s in pack %s"
@@ -8816,7 +9120,7 @@ msgstr "не вдалося знайти пакунок \"%s\""
 
 #, c-format
 msgid "packfile %s cannot be accessed"
-msgstr ""
+msgstr "неможливо отримати доступ до файлу пакунку %s"
 
 msgid "Enumerating cruft objects"
 msgstr "Перерахування марних обʼєктів"
@@ -8832,29 +9136,33 @@ msgid ""
 "expected edge object ID, got garbage:\n"
 " %s"
 msgstr ""
+"очікувався ідентифікатор реберного обʼєкту, отримано непотріб:\n"
+" %s"
 
 #, c-format
 msgid ""
 "expected object ID, got garbage:\n"
 " %s"
 msgstr ""
+"очікувався ідентифікатор обʼєкта, отримано непотріб:\n"
+" %s"
 
 msgid "could not load cruft pack .mtimes"
-msgstr ""
+msgstr "не вдалося завантажити марний пакунок .mtimes"
 
 msgid "cannot open pack index"
 msgstr "не вдалося відкрити індекс пакунка"
 
 #, c-format
 msgid "loose object at %s could not be examined"
-msgstr ""
+msgstr "не вдалося розглянути вільний обʼєкт у %s"
 
 msgid "unable to force loose object"
 msgstr "не вдалося примусово вивільнити обʼєкт"
 
 #, c-format
 msgid "not a rev '%s'"
-msgstr ""
+msgstr "не є ревізією \"%s\""
 
 #, c-format
 msgid "bad revision '%s'"
@@ -8865,41 +9173,41 @@ msgstr "не вдалося додати нещодавні обʼєкти"
 
 #, c-format
 msgid "unsupported index version %s"
-msgstr ""
+msgstr "непідтримувана версія індексу %s"
 
 #, c-format
 msgid "bad index version '%s'"
 msgstr "невірна версія індексу \"%s\""
 
 msgid "show progress meter during object writing phase"
-msgstr ""
+msgstr "показувати хід виконання під час фази запису обʼєкта"
 
 msgid "similar to --all-progress when progress meter is shown"
-msgstr ""
+msgstr "подібно до --all-progress, коли показано хід виконання"
 
 msgid "<version>[,<offset>]"
-msgstr ""
+msgstr "<версія>[, <зміщення>]"
 
 msgid "write the pack index file in the specified idx format version"
-msgstr ""
+msgstr "записати індексний файл пакунка у вказаній версії idx формату"
 
 msgid "maximum size of each output pack file"
-msgstr ""
+msgstr "максимальний розмір кожного файлу вихідного пакунку"
 
 msgid "ignore borrowed objects from alternate object store"
-msgstr ""
+msgstr "ігнорувати запозичені обʼєкти з місця збереження запозичених об’єктів"
 
 msgid "ignore packed objects"
 msgstr "ігнорувати запаковані обʼєкти"
 
 msgid "limit pack window by objects"
-msgstr ""
+msgstr "обмежити вікно пакування за обʼєктами"
 
 msgid "limit pack window by memory in addition to object limit"
-msgstr ""
+msgstr "обмежити вікно пакування за памʼяттю на додаток до ліміту обʼєкта"
 
 msgid "maximum length of delta chain allowed in the resulting pack"
-msgstr ""
+msgstr "максимальна довжина дельта ланцюжка, дозволена в результуючому пакунку"
 
 msgid "reuse existing deltas"
 msgstr "повторно використати існуючі дельти"
@@ -8908,136 +9216,140 @@ msgid "reuse existing objects"
 msgstr "повторно використати існуючі обʼєкти"
 
 msgid "use OFS_DELTA objects"
-msgstr ""
+msgstr "використати OFS_DELTA обʼєкти"
 
 msgid "use threads when searching for best delta matches"
-msgstr ""
+msgstr "використовувати потоки під час пошуку найкращих дельта збігів"
 
 msgid "do not create an empty pack output"
 msgstr "не створювати вивід порожнього пакунка"
 
 msgid "read revision arguments from standard input"
-msgstr ""
+msgstr "зчитувати аргументи ревізії зі стандартного вводу"
 
 msgid "limit the objects to those that are not yet packed"
-msgstr ""
+msgstr "обмежувати обʼєкти тільки тими, які ще не запаковані"
 
 msgid "include objects reachable from any reference"
-msgstr ""
+msgstr "включати обʼєкти, досяжні з будь-якого посилання"
 
 msgid "include objects referred by reflog entries"
-msgstr ""
+msgstr "включати обʼєкти, на які посилаються записи журналу посилань"
 
 msgid "include objects referred to by the index"
-msgstr ""
+msgstr "включати обʼєкти, на які посилається індекс"
 
 msgid "read packs from stdin"
-msgstr ""
+msgstr "прочитати пакунки з stdin"
 
 msgid "output pack to stdout"
-msgstr ""
+msgstr "вивести пакунок у stdout"
 
 msgid "include tag objects that refer to objects to be packed"
 msgstr ""
+"включати обʼєкти тегів, які посилаються на обʼєкти, що будуть запаковані"
 
 msgid "keep unreachable objects"
-msgstr ""
+msgstr "зберігати недосяжні обʼєкти"
 
 msgid "pack loose unreachable objects"
-msgstr ""
+msgstr "запакувати вільні недосяжні обʼєкти"
 
 msgid "unpack unreachable objects newer than <time>"
-msgstr ""
+msgstr "розпакувати недосяжні обʼєкти, новіші за <час>"
 
 msgid "create a cruft pack"
-msgstr ""
+msgstr "створити марний пакунок"
 
 msgid "expire cruft objects older than <time>"
-msgstr ""
+msgstr "видалити марні обʼєкти старіші за <час>"
 
 msgid "use the sparse reachability algorithm"
-msgstr ""
+msgstr "використовувати алгоритм розрідженої досяжності"
 
 msgid "create thin packs"
 msgstr "створити тонкі пакунки"
 
 msgid "create packs suitable for shallow fetches"
-msgstr ""
+msgstr "створювати пакунки, придатні для неглибокого отримання"
 
 msgid "ignore packs that have companion .keep file"
-msgstr ""
+msgstr "ігнорувати пакунки, які мають супровідний .keep файл"
 
 msgid "ignore this pack"
 msgstr "ігнорувати цей пакунок"
 
 msgid "pack compression level"
-msgstr ""
+msgstr "рівень стиснення пакунка"
 
 msgid "do not hide commits by grafts"
-msgstr ""
+msgstr "не приховувати коміти через прищепи"
 
 msgid "use a bitmap index if available to speed up counting objects"
 msgstr ""
+"використовувати bitmap індекс, якщо він доступний, для прискорення "
+"підрахунку обʼєктів"
 
 msgid "write a bitmap index together with the pack index"
-msgstr ""
+msgstr "записати bitmap індекс разом з індексом пакунка"
 
 msgid "write a bitmap index if possible"
-msgstr ""
+msgstr "записати bitmap індекс, якщо це можливо"
 
 msgid "handling for missing objects"
 msgstr "обробка для відсутніх обʼєктів"
 
 msgid "do not pack objects in promisor packfiles"
-msgstr ""
+msgstr "не пакувати обʼєкти у promisor пакунки"
 
 msgid "respect islands during delta compression"
-msgstr ""
+msgstr "поважати острови під час дельта компресії"
 
 msgid "protocol"
-msgstr ""
+msgstr "протокол"
 
 msgid "exclude any configured uploadpack.blobpackfileuri with this protocol"
-msgstr ""
+msgstr "вилучити всі налаштовані uploadpack.blobpackfileuri з цим протоколом"
 
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
-msgstr ""
+msgstr "глибина дельта ланцюжка %d занадто глибока, примусове %d"
 
 #, c-format
 msgid "pack.deltaCacheLimit is too high, forcing %d"
-msgstr ""
+msgstr "pack.deltaCacheLimit занадто великий, примусове %d"
 
 #, c-format
 msgid "bad pack compression level %d"
-msgstr ""
+msgstr "невірний рівень стиснення пакунка %d"
 
 msgid "--max-pack-size cannot be used to build a pack for transfer"
 msgstr ""
+"--max-pack-size не можна використовувати для створення пакунка для передачі"
 
 msgid "minimum pack size limit is 1 MiB"
-msgstr ""
+msgstr "мінімальний розмір пакунка - 1 МіБ"
 
 msgid "--thin cannot be used to build an indexable pack"
-msgstr ""
+msgstr "--thin не можна використовувати для створення індексованого пакунка"
 
 msgid "cannot use --filter without --stdout"
-msgstr ""
+msgstr "неможливо використовувати --filter без --stdout"
 
 msgid "cannot use --filter with --stdin-packs"
-msgstr ""
+msgstr "неможливо використовувати --filter з --stdin-packs"
 
 msgid "cannot use internal rev list with --stdin-packs"
-msgstr ""
+msgstr "неможливо використовувати внутрішній список ревізій з --stdin-packs"
 
 msgid "cannot use internal rev list with --cruft"
-msgstr ""
+msgstr "неможливо використовувати внутрішній список ревізій з --cruft"
 
 msgid "cannot use --stdin-packs with --cruft"
-msgstr ""
+msgstr "неможливо використовувати --stdin-packs з --cruft"
 
 msgid "cannot use --max-pack-size with --cruft"
-msgstr ""
+msgstr "неможливо використовувати --max-pack-size з --cruft"
 
 msgid "Enumerating objects"
 msgstr "Перерахування обʼєктів"
@@ -9047,6 +9359,8 @@ msgid ""
 "Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-"
 "reused %<PRIu32>"
 msgstr ""
+"Всього %<PRIu32> (дельта %<PRIu32>), повторно використано %<PRIu32> (дельта "
+"%<PRIu32>), повторно використано пакунків %<PRIu32>"
 
 msgid ""
 "'git pack-redundant' is nominated for removal.\n"
@@ -9055,42 +9369,57 @@ 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\" номіновано на вилучення.\n"
+"Якщо ви все ще використовуєте цю команду, будь ласка, додайте додатковий "
+"параметр\n"
+"\"--i-still-use-this\" у командному рядку\n"
+"і повідомте нам, що ви все ще використовуєте її, надіславши листа\n"
+"на адресу <git@vger.kernel.org>.  Дякуємо.\n"
 
 msgid "refusing to run without --i-still-use-this"
-msgstr ""
+msgstr "відмовлено в запуску без --i-still-use-this"
 
-msgid "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
 msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <шаблон>] [--exclude <шаблон>]"
 
 msgid "pack everything"
-msgstr ""
+msgstr "запакувати все"
 
 msgid "prune loose refs (default)"
 msgstr "видалити вивільнені посилання (за замовчуванням)"
 
+msgid "references to include"
+msgstr "посилання для включення"
+
+msgid "references to exclude"
+msgstr "посилання для виключення"
+
 msgid "git patch-id [--stable | --unstable | --verbatim]"
-msgstr ""
+msgstr "git patch-id [--stable | --unstable | --verbatim]"
 
 msgid "use the unstable patch-id algorithm"
-msgstr ""
+msgstr "використовувати нестабільний алгоритм ідентифікатора латки"
 
 msgid "use the stable patch-id algorithm"
-msgstr ""
+msgstr "використовувати стабільний алгоритм ідентифікатора латки"
 
 msgid "don't strip whitespace from the patch"
-msgstr ""
+msgstr "не прибирати пробіли з латки"
 
 msgid "git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"
-msgstr ""
+msgstr "git prune [-n] [-v] [--progress] [--expire <час>] [--] [<верхівка>...]"
 
 msgid "report pruned objects"
-msgstr ""
+msgstr "повідомляти про видалені обʼєкти"
 
 msgid "expire objects older than <time>"
-msgstr ""
+msgstr "видалити обʼєкти старіші за <час>"
 
 msgid "limit traversal to objects outside promisor packfiles"
-msgstr ""
+msgstr "обмежити обхід об’єктами за межами promisor пакунків"
 
 msgid "cannot prune in a precious-objects repo"
 msgstr "неможливо виконати видалення в precious-objects сховищі"
@@ -9102,42 +9431,52 @@ msgid "control for recursive fetching of submodules"
 msgstr "управління рекурсивним отриманням підмодулів"
 
 msgid "Options related to merging"
-msgstr ""
+msgstr "Опції, повʼязані зі злиттям"
 
 msgid "incorporate changes by rebasing rather than merging"
-msgstr ""
+msgstr "вносити зміни через перебазування, а не злиття"
 
 msgid "allow fast-forward"
-msgstr ""
+msgstr "дозволити перемотування вперед"
 
 msgid "control use of pre-merge-commit and commit-msg hooks"
-msgstr ""
+msgstr "контролювати використання гачків pre-merge-commit та commit-msg"
 
 msgid "automatically stash/stash pop before and after"
-msgstr ""
+msgstr "автоматично додавати до та забирати зі схову перед і після"
 
 msgid "Options related to fetching"
-msgstr ""
+msgstr "Опції, пов’язані з отриманням"
 
 msgid "force overwrite of local branch"
-msgstr ""
+msgstr "примусовий перезапис локальної гілки"
 
 msgid "number of submodules pulled in parallel"
 msgstr "кількість підмодулів, що затягуються паралельно"
 
+msgid "use IPv4 addresses only"
+msgstr "використовувати тільки IPv4 адреси"
+
+msgid "use IPv6 addresses only"
+msgstr "використовувати тільки IPv6 адреси"
+
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
 "fetched."
 msgstr ""
+"Серед щойно отриманих посилань немає кандидата, відносно якого можна "
+"виконати перебазування."
 
 msgid ""
 "There are no candidates for merging among the refs that you just fetched."
-msgstr ""
+msgstr "Серед щойно отриманих посилань немає кандидатів на злиття."
 
 msgid ""
 "Generally this means that you provided a wildcard refspec which had no\n"
 "matches on the remote end."
 msgstr ""
+"Зазвичай це означає, що для визначника посилання, ви ввели символ "
+"підстановки, який не має збігів на віддаленому призначені."
 
 #, c-format
 msgid ""
@@ -9145,44 +9484,52 @@ msgid ""
 "a branch. Because this is not the default configured remote\n"
 "for your current branch, you must specify a branch on the command line."
 msgstr ""
+"Ви попросили затягнути з віддаленого \"%s\", але не вказали\n"
+"гілку. Оскільки це не типове віддалене призначення\n"
+"для вашої поточної гілки, вам треба вказати гілку у командному рядку."
 
 msgid "You are not currently on a branch."
 msgstr "Наразі ви не на гілці."
 
 msgid "Please specify which branch you want to rebase against."
 msgstr ""
+"Будь ласка, вкажіть, відносно якої гілки ви хочете виконати перебазування."
 
 msgid "Please specify which branch you want to merge with."
-msgstr ""
+msgstr "Будь ласка, вкажіть, з якою гілкою ви хочете виконати злиття."
 
 msgid "See git-pull(1) for details."
-msgstr ""
+msgstr "Дивіться git-pull(1) для більш детальної інформації."
 
 msgid "<remote>"
-msgstr ""
+msgstr "<віддалене-призначення>"
 
 msgid "<branch>"
 msgstr "<гілка>"
 
 msgid "There is no tracking information for the current branch."
-msgstr ""
+msgstr "Немає інформації для відстежування поточної гілки."
 
 msgid ""
 "If you wish to set tracking information for this branch you can do so with:"
 msgstr ""
+"Якщо ви бажаєте встановити інформацію для відстежування цієї гілки, ви "
+"можете зробити це за допомогою:"
 
 #, c-format
 msgid ""
 "Your configuration specifies to merge with the ref '%s'\n"
 "from the remote, but no such ref was fetched."
 msgstr ""
+"У вашій конфігурації вказано робити злиття з посиланням \"%s\"\n"
+"з віддаленого призначення, але такого посилання не було отримано."
 
 #, c-format
 msgid "unable to access commit %s"
 msgstr "не вдалося отримати доступ до коміту %s"
 
 msgid "ignoring --verify-signatures for rebase"
-msgstr ""
+msgstr "ігнорування --verify-signatures для перебазування"
 
 msgid ""
 "You have divergent branches and need to specify how to reconcile them.\n"
@@ -9199,15 +9546,29 @@ msgid ""
 "or --ff-only on the command line to override the configured default per\n"
 "invocation.\n"
 msgstr ""
+"У вас є розбіжні гілки, і вам потрібно вказати, як їх узгодити.\n"
+"Ви можете зробити це, виконавши одну з наступних команд \n"
+"до вашого наступного затягування:\n"
+"\n"
+"  git config pull.rebase false # merge\n"
+"  git config pull.rebase true # rebase\n"
+"  git config pull.ff only # fast-forward only\n"
+"\n"
+"Ви можете замінити \"git config\" на \"git config --global\", щоб встановити "
+"налаштування за замовчуванням\n"
+"для всіх сховищ. Ви також можете передати --rebase, --no-rebase,\n"
+"або --ff-only у командному рядку, щоб перевизначити налаштування за "
+"замовчуванням для кожного\n"
+"виклику.\n"
 
 msgid "Updating an unborn branch with changes added to the index."
-msgstr ""
+msgstr "Оновлення ненародженої гілки зі змінами, доданими до індексу."
 
 msgid "pull with rebase"
-msgstr ""
+msgstr "затягнути з перебазуванням"
 
 msgid "Please commit or stash them."
-msgstr ""
+msgstr "Будь ласка, зробіть коміт або додайте зміни до схову."
 
 #, c-format
 msgid ""
@@ -9215,6 +9576,9 @@ msgid ""
 "fast-forwarding your working tree from\n"
 "commit %s."
 msgstr ""
+"отримання оновило верхівку поточної гілки.\n"
+"перемотування вперед вашого робочого дерева з\n"
+"коміту %s."
 
 #, c-format
 msgid ""
@@ -9225,21 +9589,27 @@ msgid ""
 "$ git reset --hard\n"
 "to recover."
 msgstr ""
+"Неможливо перемотати вперед ваше робоче дерево.\n"
+"Переконавшись, що ви зберегли все цінне з\n"
+"$ git diff %s\n"
+"виводу, виконайте\n"
+"$ git reset --hard\n"
+"для відновлення."
 
 msgid "Cannot merge multiple branches into empty head."
-msgstr ""
+msgstr "Неможливо злити кілька гілок до порожньої верхівки."
 
 msgid "Cannot rebase onto multiple branches."
-msgstr ""
+msgstr "Неможливо перебазувати на кілька гілок."
 
 msgid "Cannot fast-forward to multiple branches."
-msgstr ""
+msgstr "Неможливо перемотати вперед кілька гілок."
 
 msgid "Need to specify how to reconcile divergent branches."
-msgstr ""
+msgstr "Потрібно вказати, як узгоджувати розбіжні гілки."
 
 msgid "cannot rebase with locally recorded submodule modifications"
-msgstr ""
+msgstr "неможливо перебазувати з локально записаними модифікаціями підмодуля"
 
 msgid "git push [<options>] [<repository> [<refspec>...]]"
 msgstr "git push [<опції>] [<сховище> [<визначник посилання>...]]"
@@ -9265,8 +9635,7 @@ msgid ""
 "in 'git help config'.\n"
 msgstr ""
 "\n"
-"Щоб уникнути автоматичного налаштування гілки перводжерельного сховища, якщо "
-"її назва\n"
+"Щоб уникнути автоматичного налаштування висхідної гілки, якщо її назва\n"
 "не збігається з назвою локальної гілки, скористайтесь опцією 'simple' для "
 "branch.autoSetupMerge\n"
 "у “git help config”.\n"
@@ -9284,10 +9653,9 @@ msgid ""
 "    git push %s HEAD\n"
 "%s%s"
 msgstr ""
-"Назва гілки перводжерельного сховища для вашої поточної гілки не збігається "
-"з\n"
-"назвою вашої поточної гілки.  Щоб надіслати до гілки\n"
-"першоджерельного сховища, скористайтесь командою\n"
+"Назва висхідної гілки для вашої поточної гілки не збігається з\n"
+"назвою вашої поточної гілки.  Щоб надіслати до висхідної гілки,\n"
+"скористайтесь командою\n"
 "\n"
 "    git push %s HEAD:%s\n"
 "\n"
@@ -9328,16 +9696,16 @@ msgid ""
 "    git push --set-upstream %s %s\n"
 "%s"
 msgstr ""
-"Ð\9fоÑ\82оÑ\87на Ð³Ñ\96лка %s Ð½Ðµ Ð¼Ð°Ñ\94 Ð³Ñ\96лки Ñ\83 Ð¿ÐµÑ\80Ñ\88оджeÑ\80елÑ\8cномÑ\83 Ñ\81Ñ\85овиÑ\89Ñ\96.\n"
+"Ð\9fоÑ\82оÑ\87на Ð³Ñ\96лка %s Ð½Ðµ Ð¼Ð°Ñ\94 Ð²Ð¸Ñ\81Ñ\85Ñ\96дноÑ\97 Ð³Ñ\96лки.\n"
 "Щоб надіслати поточну гілку і встановити віддалене призначення "
-"пеÑ\80Ñ\88оджеÑ\80елÑ\8cним Ñ\81Ñ\85овиÑ\89ем, Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8f\n"
+"пеÑ\80Ñ\88оджеÑ\80елÑ\8cним Ñ\81Ñ\85овиÑ\89ем, Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8c\n"
 "\n"
 "    git push --set-upstream %s %s\n"
 "%s"
 
 #, c-format
 msgid "The current branch %s has multiple upstream branches, refusing to push."
-msgstr "Ð\9fоÑ\82оÑ\87на Ð³Ñ\96лка %s Ð¼Ð°Ñ\94 Ð´ÐµÐºÑ\96лÑ\8cка Ð²Ð¸Ñ\81Ñ\85Ñ\96дниÑ\85 Ð³Ñ\96лок, Ð²Ñ\96дмова Ð½Ð°Ð´Ñ\81иланнÑ\8f."
+msgstr "Ð\9fоÑ\82оÑ\87на Ð³Ñ\96лка %s Ð¼Ð°Ñ\94 ÐºÑ\96лÑ\8cка Ð²Ð¸Ñ\81Ñ\85Ñ\96дниÑ\85 Ð³Ñ\96лок, Ð²Ñ\96дмовлено Ð² Ð½Ð°Ð´Ñ\81иланнÑ\96."
 
 msgid ""
 "You didn't specify any refspecs to push, and push.default is \"nothing\"."
@@ -9351,52 +9719,55 @@ msgid ""
 "your current branch '%s', without telling me what to push\n"
 "to update which remote branch."
 msgstr ""
-"Ви надсилаєте до віддаленої гілки '%s', яка не є першоджерелом\n"
-"вашої поточної гілки '%s', не кажучі мені, що надсилати\n"
+"Ви надсилаєте до віддаленої гілки \"%s\", яка не є першоджерелом\n"
+"вашої поточної гілки \"%s\", не кажучі мені, що надсилати\n"
 "і яку віддалену гілку оновлювати."
 
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Ð\9eновленнÑ\8f Ð±Ñ\83ло Ð²Ñ\96дÑ\85илено, оскільки верхівка вашої поточної гілки знаходиться "
+"Ð\9eновленнÑ\8f Ð±Ñ\83ли Ð²Ñ\96дÑ\85иленÑ\96, оскільки верхівка вашої поточної гілки знаходиться "
 "позаду\n"
-"її віддаленого аналога. Інтегруйте віддалені зміни (наприклад, через\n"
-"'git pull ...') перед повторним надсиланням.\n"
-"Докладніше у \"Примітці про перемотування\" команди \"git push --help\"."
+"її віддаленого аналога. Якщо ви хочете інтегрувати віддалені зміни,\n"
+"скористайтесь командою \"git pull\" перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
 
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Ð\9eновленнÑ\8f Ð±Ñ\83ло Ð²Ñ\96дÑ\85илено, Ð¾Ñ\81кÑ\96лÑ\8cки Ð²ÐµÑ\80Ñ\85Ñ\96вка Ð²Ð°Ñ\88оÑ\97 Ð¿Ð¾Ñ\82оÑ\87ної гілки знаходиться "
+"Ð\9eновленнÑ\8f Ð±Ñ\83ли Ð²Ñ\96дÑ\85иленÑ\96, Ð¾Ñ\81кÑ\96лÑ\8cки Ð²ÐµÑ\80Ñ\85Ñ\96вка Ð½Ð°Ð´Ñ\96Ñ\81ланої гілки знаходиться "
 "позаду\n"
-"її віддаленого аналога. Стягнить цю гілку та інтегруйте віддалені зміни\n"
-"(наприклад, через 'git pull...') перед повторним надсиланням.\n"
-"Докладніше у \"Примітці про перемотування\" команди \"git push --help\"."
+"її віддаленого аналога. Якщо ви хочете інтегрувати віддалені зміни, "
+"скористайтесь командою \"git pull\"\n"
+"перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
 
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Ð\9eновленнÑ\8f Ð±Ñ\83ло Ð²Ñ\96дÑ\85илено, оскільки у віддаленому сховищі міститься робота, "
+"Ð\9eновленнÑ\8f Ð±Ñ\83ли Ð²Ñ\96дÑ\85иленÑ\96, оскільки у віддаленому сховищі міститься робота, "
 "якої\n"
 "немає локально. Зазвичай це стається, коли інше сховище надсилає\n"
-"до Ñ\82ого Ñ\81амого Ð¿Ð¾Ñ\81иланнÑ\8f. Ð\9cожливо, Ð²Ð°Ð¼ Ñ\81лÑ\96д Ñ\81поÑ\87аÑ\82кÑ\83 Ñ\96нÑ\82егÑ\80Ñ\83ваÑ\82и Ð²Ñ\96ддаленÑ\96 "
-"зміни\n"
-"(наприклад, через 'git pull ...') перед повторним надсиланням.\n"
-"Ð\94окладнÑ\96Ñ\88е Ñ\83 \"Ð\9fÑ\80имÑ\96Ñ\82Ñ\86Ñ\96 Ð¿Ñ\80о Ð¿ÐµÑ\80емоÑ\82Ñ\83ваннÑ\8f\" команди \"git push --help\"."
+"до Ñ\82ого Ñ\81амого Ð¿Ð¾Ñ\81иланнÑ\8f. Ð¯ÐºÑ\89о Ð²Ð¸ Ñ\85оÑ\87еÑ\82е Ñ\96нÑ\82егÑ\80Ñ\83ваÑ\82и Ð²Ñ\96ддаленÑ\96 Ð·Ð¼Ñ\96ни,\n"
+"скористайтесь командою \"git pull\" перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"впеÑ\80ед\" команди \"git push --help\"."
 
 msgid "Updates were rejected because the tag already exists in the remote."
 msgstr ""
-"Ð\9eновленнÑ\8f Ð±Ñ\83ло Ð²Ñ\96дÑ\85илено, оскільки тег вже існує на віддаленому сховищі."
+"Ð\9eновленнÑ\8f Ð±Ñ\83ли Ð²Ñ\96дÑ\85иленÑ\96, оскільки тег вже існує на віддаленому сховищі."
 
 msgid ""
 "You cannot update a remote ref that points at a non-commit object,\n"
@@ -9407,18 +9778,21 @@ msgstr ""
 "об’єктом коміту,\n"
 "або оновити віддалене посилання так, щоб воно вказувало на об’єкт, що не є "
 "об’єктом коміту,\n"
-"без використання опції '--force'.\n"
+"без використання опції \"--force\".\n"
 
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"Оновлення було відхилено, оскільки верхівка віддалено відстежуваної \n"
-"гілки була оновлена з моменту останнього стягування. Можливо, ви захочете\n"
-"інтегрувати ці зміни локально (наприклад, через 'git pull ...')\n"
-"перед примусовим оновленням.\n"
+"Оновлення були відхилені, оскільки верхівка віддалено відстежуваної гілки "
+"була\n"
+"оновлена з часу останньої синхронізації. Якщо ви хочете інтегрувати "
+"віддалені зміни,\n"
+"скористайтесь командою \"git pull\" перед повторним надсиланням.\n"
+"Докладні відомості наведено у розділі \"Зауваження щодо перемотування "
+"вперед\" команди \"git push --help\"."
 
 #, c-format
 msgid "Pushing to %s\n"
@@ -9452,7 +9826,8 @@ msgid "delete refs"
 msgstr "видалити посилання"
 
 msgid "push tags (can't be used with --all or --branches or --mirror)"
-msgstr "надіслати теги (не може бути використано з --all, --branches або --mirror)"
+msgstr ""
+"надіслати теги (не можна використовувати з --all, --branches або --mirror)"
 
 msgid "force updates"
 msgstr "оновити примусово"
@@ -9470,7 +9845,7 @@ msgid "control recursive pushing of submodules"
 msgstr "контролювати рекурсивне надсилання підмодулів"
 
 msgid "use thin pack"
-msgstr "викоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е тонке пакування"
+msgstr "викоÑ\80иÑ\81Ñ\82овÑ\83ваÑ\82и тонке пакування"
 
 msgid "receive pack program"
 msgstr "отримати пакетну програму"
@@ -9494,7 +9869,7 @@ msgid "request atomic transaction on remote side"
 msgstr "запросити атомарну транзакцію на віддаленій стороні"
 
 msgid "--delete doesn't make sense without any refs"
-msgstr "--delete не має сенсу без рефів"
+msgstr "--delete не має сенсу без посилань"
 
 #, c-format
 msgid "bad repository '%s'"
@@ -9532,27 +9907,29 @@ msgstr "опції push не можуть містити символи ново
 
 msgid "git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"
 msgstr ""
+"git range-diff [<опції>] <стара-база>..<стара-верхівка> <нова-база>..<нова-"
+"верхівка>"
 
 msgid "git range-diff [<options>] <old-tip>...<new-tip>"
-msgstr ""
+msgstr "git range-diff [<опції>] <стара-верхівка>...<нова-верхівка>"
 
 msgid "git range-diff [<options>] <base> <old-tip> <new-tip>"
-msgstr ""
+msgstr "git range-diff [<опції>] <база> <стара-верхівка> <нова-верхівка>"
 
 msgid "use simple diff colors"
-msgstr ""
+msgstr "використовувати прості кольори diff"
 
 msgid "notes"
-msgstr ""
+msgstr "нотатки"
 
 msgid "passed to 'git log'"
-msgstr ""
+msgstr "передано до \"git log\""
 
 msgid "only emit output related to the first range"
-msgstr ""
+msgstr "видати тільки вивід, що відноситься до першого діапазону"
 
 msgid "only emit output related to the second range"
-msgstr ""
+msgstr "видати тільки вивід, що відноситься до другого діапазону"
 
 #, c-format
 msgid "not a revision: '%s'"
@@ -9575,57 +9952,62 @@ msgid ""
 "              [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]\n"
 "              (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
 msgstr ""
+"git read-tree [(-m [--trivial] [--aggressive] | --reset | --"
+"prefix=<префікс>)\n"
+"              [-u | -i]] [--index-output=<файл>] [--no-sparse-checkout]\n"
+"              (--empty | <деревоподібне-джерело1> [<деревоподібне-джерело2> "
+"[<деревоподібне-джерело3>]])"
 
 msgid "write resulting index to <file>"
-msgstr ""
+msgstr "записати отриманий індекс у <файл>"
 
 msgid "only empty the index"
 msgstr "тільки очистити індекс"
 
 msgid "Merging"
-msgstr ""
+msgstr "Злиття"
 
 msgid "perform a merge in addition to a read"
 msgstr "виконати злиття на додачу до читання"
 
 msgid "3-way merge if no file level merging required"
-msgstr ""
+msgstr "3-стороннє злиття, при відсутності потреби в злитті на рівні файлів"
 
 msgid "3-way merge in presence of adds and removes"
-msgstr ""
+msgstr "3-стороннє злиття за наявності додавання та видалення"
 
 msgid "same as -m, but discard unmerged entries"
-msgstr "те саме, що й -m, але відкидає незлиті записи"
+msgstr "те саме, що й -m, але відкидає не злиті записи"
 
 msgid "<subdirectory>/"
-msgstr ""
+msgstr "<піддиректорія>/"
 
 msgid "read the tree into the index under <subdirectory>/"
-msgstr ""
+msgstr "зчитати дерево в індекс під <піддиректорію>/"
 
 msgid "update working tree with merge result"
-msgstr ""
+msgstr "оновити робоче дерево результатом злиття"
 
 msgid "gitignore"
-msgstr ""
+msgstr "gitignore"
 
 msgid "allow explicitly ignored files to be overwritten"
-msgstr ""
+msgstr "дозволити перезапис явно проігнорованих файлів"
 
 msgid "don't check the working tree after merging"
 msgstr "не перевіряти робоче дерево після злиття"
 
 msgid "don't update the index or the work tree"
-msgstr ""
+msgstr "не оновлювати індекс або робоче дерево"
 
 msgid "skip applying sparse checkout filter"
 msgstr "пропустити застосування sparse checkout фільтра"
 
 msgid "debug unpack-trees"
-msgstr ""
+msgstr "відлагодити unpack-trees"
 
 msgid "suppress feedback messages"
-msgstr ""
+msgstr "не показувати повідомлення зворотного звʼязку"
 
 msgid "You need to resolve your current index first"
 msgstr "Спочатку вам потрібно розвʼязати поточний індекс"
@@ -9634,10 +10016,14 @@ msgid ""
 "git rebase [-i] [options] [--exec <cmd>] [--onto <newbase> | --keep-base] "
 "[<upstream> [<branch>]]"
 msgstr ""
+"git rebase [-i] [опції] [--exec <команда>] [--onto <нова-база> | --keep-"
+"base] [<першоджерельне-сховище> [<гілка>]]"
 
 msgid ""
 "git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]"
 msgstr ""
+"git rebase [-i] [опції] [--exec <команда>] [--onto <нова-база>] --root "
+"[<гілка>]"
 
 #, c-format
 msgid "could not read '%s'."
@@ -9654,11 +10040,11 @@ msgid "could not generate todo list"
 msgstr "не вдалося створити список справ"
 
 msgid "a base commit must be provided with --upstream or --onto"
-msgstr ""
+msgstr "базовий коміт має бути наданий з --upstream або --onto"
 
 #, c-format
 msgid "%s requires the merge backend"
-msgstr ""
+msgstr "%s потребує обробника злиття"
 
 #, c-format
 msgid "invalid onto: '%s'"
@@ -9670,7 +10056,7 @@ msgstr "неприпустимий orig-head: \"%s\""
 
 #, c-format
 msgid "ignoring invalid allow_rerere_autoupdate: '%s'"
-msgstr ""
+msgstr "ігнорування неприпустимого allow_rerere_autoupdate: \"%s\""
 
 #, c-format
 msgid "could not remove '%s'"
@@ -9683,6 +10069,13 @@ msgid ""
 "To abort and get back to the state before \"git rebase\", run \"git rebase --"
 "abort\"."
 msgstr ""
+"Вирішіть усі конфлікти вручну, позначте їх як вирішені за допомогою\n"
+"\"git add/rm <конфліктні_файли>\", а потім виконайте \"git rebase --"
+"continue\".\n"
+"Замість цього ви можете пропустити цей коміт: виконайте \"git rebase --"
+"skip\".\n"
+"Щоб перервати процес і повернутися до стану перед \"git rebase\", виконайте "
+"\"git rebase --abort\"."
 
 #, c-format
 msgid ""
@@ -9694,10 +10087,17 @@ msgid ""
 "\n"
 "As a result, git cannot rebase them."
 msgstr ""
+"\n"
+"git зіткнувся з помилкою під час підготовки латок для відтворення\n"
+"цих ревізій:\n"
+"\n"
+"    %s\n"
+"\n"
+"Внаслідок цього git не може їх перебазувати."
 
 #, c-format
 msgid "Unknown rebase-merges mode: %s"
-msgstr ""
+msgstr "Невідомий режим перебазування-злиття: %s"
 
 #, c-format
 msgid "could not switch to %s"
@@ -9711,12 +10111,17 @@ msgid ""
 "unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
 "\"ask\"."
 msgstr ""
+"нерозпізнаний порожній тип \"%s\"; припустимими значеннями є \"drop\", "
+"\"keep\" та \"ask\"."
 
 msgid ""
 "--rebase-merges with an empty string argument is deprecated and will stop "
 "working in a future version of Git. Use --rebase-merges without an argument "
 "instead, which does the same thing."
 msgstr ""
+"Команда --rebase-merges з порожнім строковим аргументом є застарілою і "
+"перестане працювати у наступній версії Git. Замість цього скористайтесь "
+"командою --rebase-merges без аргументу, який робить те саме."
 
 #, c-format
 msgid ""
@@ -9727,6 +10132,13 @@ msgid ""
 "    git rebase '<branch>'\n"
 "\n"
 msgstr ""
+"%s\n"
+"Будь ласка, вкажіть гілку, відносно якої ви хочете виконати перебазування.\n"
+"Дивіться git-rebase(1) для детальної інформації.\n"
+"\n"
+"    git rebase \"<гілка>\"\n"
+"\n"
+"\n"
 
 #, c-format
 msgid ""
@@ -9742,152 +10154,169 @@ msgstr ""
 "\n"
 
 msgid "exec commands cannot contain newlines"
-msgstr ""
+msgstr "команди exec не можуть містити символи нового рядка"
 
 msgid "empty exec command"
-msgstr ""
+msgstr "порожня команда exec"
 
 msgid "rebase onto given branch instead of upstream"
-msgstr ""
+msgstr "перебазувати на задану гілку замість першоджерельного сховища"
 
 msgid "use the merge-base of upstream and branch as the current base"
 msgstr ""
+"використовувати базу злиття першоджерельного сховища та гілки як поточну базу"
 
 msgid "allow pre-rebase hook to run"
-msgstr ""
+msgstr "дозволити запуск pre-rebase гачка"
 
 msgid "be quiet. implies --no-stat"
-msgstr ""
+msgstr "працювати тихесенько. Мається на увазі --no-stat"
 
 msgid "display a diffstat of what changed upstream"
-msgstr ""
+msgstr "відображати diffstat того, що змінилося у першоджерельному сховищі"
 
 msgid "do not show diffstat of what changed upstream"
-msgstr ""
+msgstr "не відображати diffstat того, що змінилося у першоджерельному сховищі"
 
 msgid "add a Signed-off-by trailer to each commit"
-msgstr ""
+msgstr "додати Signed-off-by причіп до кожного коміту"
 
 msgid "make committer date match author date"
-msgstr ""
+msgstr "зробити так, щоб дата комітера збігалася з датою автора"
 
 msgid "ignore author date and use current date"
-msgstr ""
+msgstr "ігнорувати дату автора та використати поточну дату"
 
 msgid "synonym of --reset-author-date"
-msgstr ""
+msgstr "синонім --reset-author-date"
 
 msgid "passed to 'git apply'"
-msgstr ""
+msgstr "передано в \"git apply\""
 
 msgid "ignore changes in whitespace"
-msgstr ""
+msgstr "ігнорувати зміни в пробілах"
 
 msgid "cherry-pick all commits, even if unchanged"
-msgstr ""
+msgstr "висмикнути всі коміти, навіть якщо вони не змінені"
 
 msgid "continue"
-msgstr ""
+msgstr "продовжити"
 
 msgid "skip current patch and continue"
-msgstr ""
+msgstr "пропустити поточну латку і продовжити"
 
 msgid "abort and check out the original branch"
 msgstr "перервати і перейти до початкової гілки"
 
 msgid "abort but keep HEAD where it is"
-msgstr ""
+msgstr "перервати, але залишити HEAD на місці"
 
 msgid "edit the todo list during an interactive rebase"
-msgstr ""
+msgstr "редагувати список справ під час інтерактивного перебазування"
 
 msgid "show the patch file being applied or merged"
-msgstr ""
+msgstr "показати файл латки, який застосовується або зливається"
 
 msgid "use apply strategies to rebase"
-msgstr ""
+msgstr "використовувати стратегії застосування для перебазування"
 
 msgid "use merging strategies to rebase"
-msgstr ""
+msgstr "використовувати стратегії злиття для перебазування"
 
 msgid "let the user edit the list of commits to rebase"
-msgstr ""
+msgstr "дозволити користувачеві редагувати список комітів для перебазування"
 
 msgid "(REMOVED) was: try to recreate merges instead of ignoring them"
 msgstr ""
+"(ВИДАЛЕНО) було: спробувати відтворити злиття замість того, щоб ігнорувати їх"
 
 msgid "how to handle commits that become empty"
-msgstr ""
+msgstr "як обробляти порожні коміти"
 
 msgid "keep commits which start empty"
-msgstr ""
+msgstr "зберігати коміти, які починаються порожніми"
 
 msgid "move commits that begin with squash!/fixup! under -i"
-msgstr ""
+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 ""
+msgstr "додати exec рядки після кожного коміту редагованого списку"
 
 msgid "allow rebasing commits with empty messages"
-msgstr ""
+msgstr "дозволити перебазування комітів з порожніми дописами"
 
 msgid "try to rebase merges instead of skipping them"
-msgstr ""
+msgstr "спробувати перебазувати злиття замість того, щоб пропускати їх"
 
 msgid "use 'merge-base --fork-point' to refine upstream"
 msgstr ""
-"використовуйте \"merge-base --fork-point\" для уточнення першоджерельного "
-"Ñ\81Ñ\85овиÑ\89а"
+"скористайтесь \"merge-base --fork-point\", щоб зазначиити першоджерельне "
+"Ñ\81Ñ\85овиÑ\89е"
 
 msgid "use the given merge strategy"
-msgstr ""
+msgstr "використати задану стратегію злиття"
 
 msgid "option"
-msgstr ""
+msgstr "опція"
 
 msgid "pass the argument through to the merge strategy"
-msgstr ""
+msgstr "передати аргумент до стратегії злиття"
 
 msgid "rebase all reachable commits up to the root(s)"
-msgstr ""
+msgstr "перебазувати всі доступні коміти до кореня(ів)."
 
 msgid "automatically re-schedule any `exec` that fails"
-msgstr ""
+msgstr "автоматично переносити будь-який \"exec\", який завершився невдало"
 
 msgid "apply all changes, even those already present upstream"
 msgstr ""
+"застосовувати всі зміни, навіть ті, що вже існують у першоджерельному сховищі"
 
 msgid "It looks like 'git am' is in progress. Cannot rebase."
-msgstr ""
+msgstr "Схоже, що виконується команда \"git am\". Неможливо перебазувати."
 
 msgid ""
 "`rebase --preserve-merges` (-p) is no longer supported.\n"
 "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) більше не підтримується.\n"
+"Скористайтесь \"git rebase --abort\" для завершення поточного "
+"перебазування.\n"
+"Або поверніться до v2.33 або більш ранньої версії, щоб завершити "
+"перебазування."
 
 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 було замінено на --rebase-merges\n"
+"Примітка: У вашій конфігурації \"pull.rebase\" також може бути встановлено у "
+"значення \"preserve\",\n"
+"який більше не підтримується; натомість використовуйте \"merges\""
 
 msgid "No rebase in progress?"
 msgstr "Перебазування не відбувається?"
 
 msgid "The --edit-todo action can only be used during interactive rebase."
 msgstr ""
+"Дію --edit-todo можна використовувати лише під час інтерактивного "
+"перебазування."
 
 msgid "Cannot read HEAD"
-msgstr ""
+msgstr "Неможливо прочитати HEAD"
 
 msgid ""
 "You must edit all merge conflicts and then\n"
 "mark them as resolved using git add"
 msgstr ""
+"Ви повинні відредагувати всі конфлікти злиття, а потім\n"
+"позначити їх як вирішені за допомогою git add"
 
 msgid "could not discard worktree changes"
 msgstr "не вдалося відкинути зміни робочого дерева"
@@ -9907,34 +10336,49 @@ msgid ""
 "and run me again.  I am stopping in case you still have something\n"
 "valuable there.\n"
 msgstr ""
+"Здається, що директорія %s вже існує, і\n"
+"можливо, ви перебуваєте у процесі іншого перебазування.  Якщо це так,\n"
+"будь ласка, спробуйте\n"
+"\t%s\n"
+"Якщо це не так, спробуйте\n"
+"\t%s\n"
+"і запустіть команду ще раз.  Зупинка на випадок, якщо там у вас все ще є "
+"щось\n"
+"цінне.\n"
 
 msgid "switch `C' expects a numerical value"
-msgstr ""
+msgstr "перемикач \"C\" очікує числове значення"
 
 msgid "--strategy requires --merge or --interactive"
-msgstr ""
+msgstr "--strategy потребує --merge або --interactive"
 
 msgid ""
 "apply options are incompatible with rebase.autoSquash.  Consider adding --no-"
 "autosquash"
 msgstr ""
+"apply опції несумісні з rebase.autoSquash.  Розгляньте можливість додавання "
+"--no-autosquash"
 
 msgid ""
 "apply options are incompatible with rebase.rebaseMerges.  Consider adding --"
 "no-rebase-merges"
 msgstr ""
+"apply опції несумісні з rebase.rebaseMerges.  Розгляньте можливість "
+"додавання --no-rebase-merges"
 
 msgid ""
 "apply options are incompatible with rebase.updateRefs.  Consider adding --no-"
 "update-refs"
 msgstr ""
+"apply опції несумісні з rebase.updateRefs.  Розгляньте можливість додавання "
+"--no-update-refs"
 
 #, c-format
 msgid "Unknown rebase backend: %s"
-msgstr ""
+msgstr "Невідомий обробник перебазування: %s"
 
 msgid "--reschedule-failed-exec requires --exec or --interactive"
-msgstr ""
+msgstr "--reschedule-failed-exec потребує --exec або --interactive"
 
 #, c-format
 msgid "invalid upstream '%s'"
@@ -9956,11 +10400,11 @@ msgstr "Не вдалося розвʼязати HEAD у коміт"
 
 #, c-format
 msgid "'%s': need exactly one merge base with branch"
-msgstr ""
+msgstr "\"%s\": потрібна лишень одна база злиття з гілкою"
 
 #, c-format
 msgid "'%s': need exactly one merge base"
-msgstr ""
+msgstr "\"%s\": потрібна лишень одна база злиття"
 
 #, c-format
 msgid "Does not point to a valid commit '%s'"
@@ -9974,7 +10418,7 @@ msgid "Current branch %s is up to date.\n"
 msgstr "Поточна гілка %s знаходиться в актуальному стані.\n"
 
 msgid "HEAD is up to date, rebase forced."
-msgstr ""
+msgstr "HEAD знаходиться в актуальному стані, примусове перебазування."
 
 #, c-format
 msgid "Current branch %s is up to date, rebase forced.\n"
@@ -9982,7 +10426,7 @@ msgstr ""
 "Поточна гілка %s знаходиться в актуальному стані, перебазовуйте примусово.\n"
 
 msgid "The pre-rebase hook refused to rebase."
-msgstr ""
+msgstr "Гачок pre-rebase відмовився перебазувати."
 
 #, c-format
 msgid "Changes to %s:\n"
@@ -9990,18 +10434,18 @@ msgstr "Зміни у %s:\n"
 
 #, c-format
 msgid "Changes from %s to %s:\n"
-msgstr ""
+msgstr "Зміна з %s на %s:\n"
 
 #, c-format
 msgid "First, rewinding head to replay your work on top of it...\n"
-msgstr ""
+msgstr "Спочатку перемотуємо HEAD, щоб відтворити вашу роботу поверх того...\n"
 
 msgid "Could not detach HEAD"
 msgstr "Не вдалося відʼєднати HEAD"
 
 #, c-format
 msgid "Fast-forwarded %s to %s.\n"
-msgstr ""
+msgstr "Перемотано вперед %s на %s.\n"
 
 msgid "git receive-pack <git-dir>"
 msgstr "git receive-pack <git-директорія>"
@@ -10021,7 +10465,20 @@ msgid ""
 "To squelch this message and still keep the default behaviour, set\n"
 "'receive.denyCurrentBranch' configuration variable to 'refuse'."
 msgstr ""
-
+"За замовчуванням, оновлення поточної гілки у непустому сховищі\n"
+"заборонено, оскільки це зробить індекс і робоче дерево невідповідними\n"
+"з тим, що ви надіслали, і вимагатиме виконання команди \"git reset --hard\" "
+"щоб співставити робоче дерево і HEAD.\n"
+"\n"
+"Ви можете встановити конфігураційну змінну \"receive.denyCurrentBranch\"\n"
+"на \"ignore\" або \"warn\" у віддаленому сховищі, щоб дозволити надсилання "
+"до поточної гілки; однак, це не рекомендується, якщо ви не\n"
+"налагодили оновлення його робочого дерева відповідно до того, що ви "
+"надіслали якимось іншим способом.\n"
+"\n"
+"Щоб ігнорувати це повідомлення і зберегти поведінку за замовчуванням, "
+"встановіть параметр \"receive.denyCurrentBranch\" у значення \"refuse\"."
+
 msgid ""
 "By default, deleting the current branch is denied, because the next\n"
 "'git clone' won't result in any file checked out, causing confusion.\n"
@@ -10032,9 +10489,19 @@ msgid ""
 "\n"
 "To squelch this message, you can set it to 'refuse'."
 msgstr ""
+"За замовчуванням, видалення поточної гілки заборонено, оскільки наступний\n"
+"\"git clone\" не призведе до переключення стану жодного файлу, що спричинить "
+"плутанину.\n"
+"\n"
+"Ви можете встановити конфігураційну змінну \"receive.denyDeleteCurrent\" у "
+"значення\n"
+"\"warn\" або \"ignore\" у віддаленому сховищі, щоб дозволити видалення\n"
+"поточної гілки, з попереджувальним повідомленням або без нього.\n"
+"\n"
+"Щоб ігнорувати це повідомлення, ви можете встановити значення \"refuse\"."
 
 msgid "quiet"
-msgstr ""
+msgstr "тихо"
 
 msgid "you must specify a directory"
 msgstr "необхідно вказати директорію"
@@ -10048,62 +10515,70 @@ msgid ""
 "                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
 "<refs>...]"
 msgstr ""
+"git reflog expire [--expire=<час>] [--expire-unreachable=<час>]\n"
+"                  [--rewrite] [--updateref] [--stale-fix]\n"
+"                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | "
+"<посилання>...]"
 
 msgid ""
 "git reflog delete [--rewrite] [--updateref]\n"
 "                  [--dry-run | -n] [--verbose] <ref>@{<specifier>}..."
 msgstr ""
+"git reflog delete [--rewrite] [--updateref]\n"
+"                  [--dry-run | -n] [--verbose] <посилання>@{<визначник>}..."
 
 msgid "git reflog exists <ref>"
-msgstr ""
+msgstr "git reflog exists <посилання>"
 
 #, c-format
 msgid "invalid timestamp '%s' given to '--%s'"
 msgstr "неприпустима позначка часу \"%s\" передана до \"--%s\""
 
 msgid "do not actually prune any entries"
-msgstr ""
+msgstr "насправді не видаляти жодного запису"
 
 msgid ""
 "rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"
-msgstr ""
+msgstr "перезаписати старий SHA1 на новий SHA1 запису, який тепер передує йому"
 
 msgid "update the reference to the value of the top reflog entry"
-msgstr ""
+msgstr "оновити посилання на значення верхнього запису журналу посилань"
 
 msgid "print extra information on screen"
-msgstr ""
+msgstr "вивести додаткову інформацію на екран"
 
 msgid "timestamp"
 msgstr "позначка часу"
 
 msgid "prune entries older than the specified time"
-msgstr ""
+msgstr "видалити записи, старіші за вказаний час"
 
 msgid ""
 "prune entries older than <time> that are not reachable from the current tip "
 "of the branch"
 msgstr ""
+"видалити записи, старіші за <час>, які недоступні з поточної верхівки гілки"
 
 msgid "prune any reflog entries that point to broken commits"
 msgstr ""
+"видалити всі записи журналу посилань, які вказують на пошкоджені коміти"
 
 msgid "process the reflogs of all references"
-msgstr ""
+msgstr "обробляти журнали посилань всіх посилань"
 
 msgid "limits processing to reflogs from the current worktree only"
-msgstr ""
+msgstr "обмежити обробку журналами посилань лише з поточного робочого дерева"
 
 #, c-format
 msgid "Marking reachable objects..."
-msgstr ""
+msgstr "Позначення досяжних обʼєктів..."
 
 #, c-format
 msgid "%s points nowhere!"
-msgstr ""
+msgstr "%s вказує в нікуди!"
 
 msgid "no reflog specified to delete"
-msgstr ""
+msgstr "не вказано журнал посилань для видалення"
 
 #, c-format
 msgid "invalid ref format: %s"
@@ -10113,49 +10588,54 @@ msgid ""
 "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--"
 "mirror=<fetch|push>] <name> <url>"
 msgstr ""
+"git remote add [-t <гілка>] [-m <мастер>] [-f] [--tags | --no-tags] [--"
+"mirror=<fetch|push>] <назва> <URL-адреса>"
 
 msgid "git remote rename [--[no-]progress] <old> <new>"
-msgstr ""
+msgstr "git remote rename [--[no-]progress] <стара-назва> <нова-назва>"
 
 msgid "git remote remove <name>"
-msgstr ""
+msgstr "git remote remove <назвa>"
 
 msgid "git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"
-msgstr ""
+msgstr "git remote set-head <назва> (-a | --auto | -d | --delete | <гілка>)"
 
 msgid "git remote [-v | --verbose] show [-n] <name>"
-msgstr ""
+msgstr "git remote [-v | --verbose] show [-n] <назва>"
 
 msgid "git remote prune [-n | --dry-run] <name>"
-msgstr ""
+msgstr "git remote prune [-n | --dry-run] <назва>"
 
 msgid ""
 "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
 msgstr ""
+"git remote [-v | --verbose] update [-p | --prune] [(<група> | <віддалене-"
+"призначення>)...]"
 
 msgid "git remote set-branches [--add] <name> <branch>..."
-msgstr ""
+msgstr "git remote set-branches [--add] <назва> <гілка>..."
 
 msgid "git remote get-url [--push] [--all] <name>"
-msgstr ""
+msgstr "git remote get-url [--push] [--all] <назва>"
 
 msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
 msgstr ""
+"git remote set-url [--push] <назва> <нова-url-адреса> [<стара-url-адреса>]"
 
 msgid "git remote set-url --add <name> <newurl>"
-msgstr ""
+msgstr "git remote set-url --add <назва> <нова-url-адреса>"
 
 msgid "git remote set-url --delete <name> <url>"
-msgstr ""
+msgstr "git remote set-url --delete <назва> <url-адреса>"
 
 msgid "git remote add [<options>] <name> <url>"
 msgstr "git remote add [<опції>] <назва> <url>"
 
 msgid "git remote set-branches <name> <branch>..."
-msgstr ""
+msgstr "git remote set-branches <назва> <гілка>..."
 
 msgid "git remote set-branches --add <name> <branch>..."
-msgstr ""
+msgstr "git remote set-branches --add <назва> <гілка>..."
 
 msgid "git remote show [<options>] <name>"
 msgstr "git remote show [<опції>] <назва>"
@@ -10168,7 +10648,7 @@ msgstr "git remote update [<опції>] [<група> | <віддаленe-пр
 
 #, c-format
 msgid "Updating %s"
-msgstr ""
+msgstr "Оновлення %s"
 
 #, c-format
 msgid "Could not fetch %s"
@@ -10178,34 +10658,40 @@ msgid ""
 "--mirror is dangerous and deprecated; please\n"
 "\t use --mirror=fetch or --mirror=push instead"
 msgstr ""
+"--mirror небезпечний і застарілий; будь ласка, \n"
+"\t скористайтесь --mirror=fetch або --mirror=push"
 
 #, c-format
 msgid "unknown mirror argument: %s"
-msgstr ""
+msgstr "невідомий аргумент дзеркала: %s"
 
 msgid "fetch the remote branches"
-msgstr ""
-
-msgid "import all tags and associated objects when fetching"
-msgstr ""
+msgstr "отримати віддалені гілки"
 
-msgid "or do not fetch any tag at all (--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
 msgstr ""
+"імпортувати всі теги та повʼязані з ними обʼєкти під час отримання\n"
+"або не отримувати жодного тегу (--no-tags)"
 
 msgid "branch(es) to track"
-msgstr ""
+msgstr "гілка(и) для відстежування"
 
 msgid "master branch"
 msgstr "master гілка"
 
 msgid "set up remote as a mirror to push to or fetch from"
 msgstr ""
+"налаштувати віддалене призначення як дзеркало, щоб надсилати до нього або "
+"отримувати з нього дані"
 
 msgid "specifying a master branch makes no sense with --mirror"
-msgstr ""
+msgstr "вказівка головної гілки не має сенсу з --mirror"
 
 msgid "specifying branches to track makes sense only with fetch mirrors"
 msgstr ""
+"вказівка гілок для відстежування має сенс тільки з дзеркалами отримання"
 
 #, c-format
 msgid "remote %s already exists."
@@ -10217,18 +10703,18 @@ msgstr "Не вдалося налаштувати master \"%s\""
 
 #, c-format
 msgid "more than one %s"
-msgstr ""
+msgstr "більше одного %s"
 
 #, c-format
 msgid "unhandled branch.%s.rebase=%s; assuming 'true'"
-msgstr ""
+msgstr "unhandled branch.%s.rebase=%s; припускаю \"true\""
 
 #, c-format
 msgid "Could not get fetch map for refspec %s"
 msgstr "Не вдалося забрати карту отримання для визначника посилання %s"
 
 msgid "(matching)"
-msgstr ""
+msgstr "(збіг)"
 
 msgid "(delete)"
 msgstr "(видалити)"
@@ -10247,6 +10733,9 @@ msgid ""
 "\t%s:%d\n"
 "now names the non-existent remote '%s'"
 msgstr ""
+"Конфігурація %s remote.pushDefault in:\n"
+"\t%s:%d\n"
+"тепер називає неіснуюче віддалене посилання \"%s\""
 
 #, c-format
 msgid "No such remote: '%s'"
@@ -10262,17 +10751,20 @@ msgid ""
 "\t%s\n"
 "\tPlease update the configuration manually if necessary."
 msgstr ""
+"Не оновлюється нестандартний визначник отримання посилань\n"
+"%s\n"
+"Будь ласка, за потреби оновіть конфігурацію вручну."
 
 msgid "Renaming remote references"
-msgstr ""
+msgstr "Перейменування віддалених посилань"
 
 #, c-format
 msgid "deleting '%s' failed"
-msgstr ""
+msgstr "не вдалося видалити \"%s\""
 
 #, c-format
 msgid "creating '%s' failed"
-msgstr ""
+msgstr "не вдалося створити \"%s\""
 
 msgid ""
 "Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
@@ -10281,8 +10773,14 @@ msgid_plural ""
 "Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
 "to delete them, use:"
 msgstr[0] ""
+"Примітка: гілка поза межами refs/remotes/ ієрархії не була видалена;\n"
+"щоб видалити її, скористайтесь:"
 msgstr[1] ""
+"Примітка: деякі гілки поза межами refs/remotes/ ієрархії не були видалені;\n"
+"щоб видалити їх, скористайтесь:"
 msgstr[2] ""
+"Примітка: деякі гілки поза межами refs/remotes/ ієрархії не були видалені;\n"
+"щоб видалити їх, скористайтесь:"
 
 #, c-format
 msgid "Could not remove config section '%s'"
@@ -10290,50 +10788,50 @@ msgstr "Не вдалося видалити секцію конфігураці
 
 #, c-format
 msgid " new (next fetch will store in remotes/%s)"
-msgstr ""
+msgstr " нова (наступне отримання зберігатиметься у віддалених remotes/%s)"
 
 msgid " tracked"
 msgstr " відстежується"
 
 msgid " skipped"
-msgstr ""
+msgstr " пропущена"
 
 msgid " stale (use 'git remote prune' to remove)"
-msgstr ""
+msgstr " застаріла (скористайтесь \"git remote prune\", щоб видалити)"
 
 msgid " ???"
-msgstr ""
+msgstr " ???"
 
 #, c-format
 msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
-msgstr ""
+msgstr "неприпустиме branch.%s.merge; неможливо перебазувати на > 1 гілку"
 
 #, c-format
 msgid "rebases interactively onto remote %s"
-msgstr "перебазувати інтерактивно у віддалену %s"
+msgstr "перебазувати інтерактивно на віддалене призначення %s"
 
 #, c-format
 msgid "rebases interactively (with merges) onto remote %s"
-msgstr ""
+msgstr "перебазувати інтерактивно (зі злиттям) на віддалене призначення %s"
 
 #, c-format
 msgid "rebases onto remote %s"
-msgstr ""
+msgstr "перебазувати на віддалене призначення %s"
 
 #, c-format
 msgid " merges with remote %s"
-msgstr ""
+msgstr " зливається з віддаленим призначенням %s"
 
 #, c-format
 msgid "merges with remote %s"
-msgstr ""
+msgstr "зливається з віддаленим призначенням %s"
 
 #, c-format
 msgid "%-*s    and with remote %s\n"
-msgstr ""
+msgstr "%-*s    та з віддаленим призначенням %s\n"
 
 msgid "create"
-msgstr ""
+msgstr "створити"
 
 msgid "delete"
 msgstr "видалити"
@@ -10342,40 +10840,40 @@ msgid "up to date"
 msgstr "в актуальному стані"
 
 msgid "fast-forwardable"
-msgstr ""
+msgstr "з можливістю перемотування вперед"
 
 msgid "local out of date"
-msgstr ""
+msgstr "локальне сховище застаріло"
 
 #, c-format
 msgid "    %-*s forces to %-*s (%s)"
-msgstr ""
+msgstr "    %-*s примусово надіслати до %-*s (%s)"
 
 #, c-format
 msgid "    %-*s pushes to %-*s (%s)"
-msgstr ""
+msgstr "    %-*s надіслати до %-*s (%s)"
 
 #, c-format
 msgid "    %-*s forces to %s"
-msgstr ""
+msgstr "    %-*s примусово надіслати до %s"
 
 #, c-format
 msgid "    %-*s pushes to %s"
-msgstr ""
+msgstr "    %-*s надіслати до %s"
 
 msgid "do not query remotes"
-msgstr ""
+msgstr "не запитувати віддалені призначення"
 
 #, c-format
 msgid "* remote %s"
-msgstr ""
+msgstr "* віддалене %s"
 
 #, c-format
 msgid "  Fetch URL: %s"
-msgstr ""
+msgstr "  URL-адреса отримання: %s"
 
 msgid "(no URL)"
-msgstr ""
+msgstr "(без URL-адреси)"
 
 #. TRANSLATORS: the colon ':' should align
 #. with the one in " Fetch URL: %s"
@@ -10384,14 +10882,14 @@ msgstr ""
 
 #, c-format
 msgid "  Push  URL: %s"
-msgstr ""
+msgstr "  URL-адреса надсилання: %s"
 
 #, c-format
 msgid "  HEAD branch: %s"
 msgstr "  HEAD гілка: %s"
 
 msgid "(not queried)"
-msgstr ""
+msgstr "(не запитувалось)"
 
 msgid "(unknown)"
 msgstr "(невідомо)"
@@ -10400,6 +10898,7 @@ msgstr "(невідомо)"
 msgid ""
 "  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
 msgstr ""
+"  HEAD гілка (віддалений HEAD неоднозначний, може бути одним з наступних):\n"
 
 #, c-format
 msgid "  Remote branch:%s"
@@ -10409,16 +10908,16 @@ msgstr[1] " Віддалені гілки:%s"
 msgstr[2] " Віддалених гілок:%s"
 
 msgid " (status not queried)"
-msgstr ""
+msgstr " (статус не запитувався)"
 
 msgid "  Local branch configured for 'git pull':"
 msgid_plural "  Local branches configured for 'git pull':"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "  Локальну гілку налаштовано на \"git pull\":"
+msgstr[1] "  Локальні гілки налаштовано на \"git pull\":"
+msgstr[2] "  Локальних гілок налаштовано на \"git pull\":"
 
 msgid "  Local refs will be mirrored by 'git push'"
-msgstr ""
+msgstr "  Локальні посилання будуть віддзеркалені за допомогою \"git push\""
 
 #, c-format
 msgid "  Local ref configured for 'git push'%s:"
@@ -10429,15 +10928,18 @@ msgstr[2] "  Локальних посилань налаштовано для \
 
 msgid "set refs/remotes/<name>/HEAD according to remote"
 msgstr ""
+"встановити refs/remotes/<назва>/HEAD відповідно до віддаленого призначення"
 
 msgid "delete refs/remotes/<name>/HEAD"
-msgstr ""
+msgstr "видалити refs/remotes/<назва>/HEAD"
 
 msgid "Cannot determine remote HEAD"
-msgstr ""
+msgstr "Не вдалося визначити віддалений HEAD"
 
 msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
 msgstr ""
+"Існує кілька віддалених HEAD гілок. Будь ласка, виберіть одну з них, "
+"скориставшись:"
 
 #, c-format
 msgid "Could not delete %s"
@@ -10453,11 +10955,11 @@ msgstr "Не вдалося налаштувати %s"
 
 #, c-format
 msgid " %s will become dangling!"
-msgstr ""
+msgstr " %s стануть висячими!"
 
 #, c-format
 msgid " %s has become dangling!"
-msgstr ""
+msgstr " %s став висячим!"
 
 #, c-format
 msgid "Pruning %s"
@@ -10465,18 +10967,18 @@ msgstr "Видалення %s"
 
 #, c-format
 msgid "URL: %s"
-msgstr ""
+msgstr "URL-адреса: %s"
 
 #, c-format
 msgid " * [would prune] %s"
-msgstr ""
+msgstr " * [буде видалено] %s"
 
 #, c-format
 msgid " * [pruned] %s"
-msgstr ""
+msgstr " * [видалено] %s"
 
 msgid "prune remotes after fetching"
-msgstr ""
+msgstr "видалити віддалені призначення після отримання"
 
 #, c-format
 msgid "No such remote '%s'"
@@ -10486,23 +10988,23 @@ msgid "add branch"
 msgstr "додати гілку"
 
 msgid "no remote specified"
-msgstr ""
+msgstr "віддалене призначення не вказано"
 
 msgid "query push URLs rather than fetch URLs"
-msgstr ""
+msgstr "запитувати URL-адреси надсилань замість URL-адрес отримання"
 
 msgid "return all URLs"
-msgstr ""
+msgstr "повернути всі URL-адреси"
 
 #, c-format
 msgid "no URLs configured for remote '%s'"
 msgstr "не налаштовано URL-адреси для віддаленого \"%s\""
 
 msgid "manipulate push URLs"
-msgstr ""
+msgstr "маніпулювати URL-адресами надсилання"
 
 msgid "add URL"
-msgstr ""
+msgstr "додати URL-адресу"
 
 msgid "delete URLs"
 msgstr "видалити URL-адреси"
@@ -10512,17 +11014,17 @@ msgstr "--add --delete не має сенсу"
 
 #, c-format
 msgid "Invalid old URL pattern: %s"
-msgstr ""
+msgstr "Неприпустимий шаблон старої URL-адреси: %s"
 
 #, c-format
 msgid "No such URL found: %s"
-msgstr ""
+msgstr "Такої URL-адреси не знайдено: %s"
 
 msgid "Will not delete all non-push URLs"
-msgstr ""
+msgstr "Не видалятиме всі URL-адреси, що не є призначенням надсилань"
 
 msgid "be verbose; must be placed before a subcommand"
-msgstr ""
+msgstr "розгорнутий вивід; має стояти перед підкомандою"
 
 msgid "git repack [<options>]"
 msgstr "git repack [<опції>]"
@@ -10531,15 +11033,20 @@ msgid ""
 "Incremental repacks are incompatible with bitmap indexes.  Use\n"
 "--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
 msgstr ""
+"Поступові перепакування несумісні з bitmap індексами.  Скористайтесь "
+"параметром\n"
+"--no-write-bitmap-index або вимкніть конфігурацію pack.writeBitmaps."
 
 msgid "could not start pack-objects to repack promisor objects"
-msgstr ""
+msgstr "не вдалося розпочати pack-objects для перепакування promisor обʼєктів"
 
 msgid "repack: Expecting full hex object ID lines only from pack-objects."
 msgstr ""
+"перепакування: очікуються повні рядки hex ідентифікаторів обʼєктів тільки "
+"від pack-objects."
 
 msgid "could not finish pack-objects to repack promisor objects"
-msgstr ""
+msgstr "не вдалося завершити pack-objects для перепакування promisor обʼєктів"
 
 #, c-format
 msgid "cannot open index for %s"
@@ -10547,103 +11054,104 @@ msgstr "неможливо відкрити індекс для %s"
 
 #, c-format
 msgid "pack %s too large to consider in geometric progression"
-msgstr ""
+msgstr "пакунок %s занадто великий, щоб враховувати в геометричній прогресії"
 
 #, c-format
 msgid "pack %s too large to roll up"
-msgstr ""
+msgstr "пакунок %s занадто великий для згортання"
 
 #, c-format
 msgid "could not open tempfile %s for writing"
-msgstr ""
+msgstr "не вдалося відкрити тимчасовий файл %s для запису"
 
 msgid "could not close refs snapshot tempfile"
-msgstr ""
+msgstr "не вдалося закрити тимчасовий файл знімка посилань"
 
 #, c-format
 msgid "could not remove stale bitmap: %s"
 msgstr "не вдалося видалити застарілий bitmap: %s"
 
 msgid "pack everything in a single pack"
-msgstr ""
+msgstr "запакувати все в один пакунок"
 
 msgid "same as -a, and turn unreachable objects loose"
-msgstr ""
+msgstr "те саме, що й -a, та звільняє недосяжні обʼєкти"
 
 msgid "same as -a, pack unreachable cruft objects separately"
-msgstr ""
+msgstr "те саме, що й -a, пакує недосяжні марні обʼєкти окремо"
 
 msgid "approxidate"
-msgstr ""
+msgstr "приблизна дата"
 
 msgid "with --cruft, expire objects older than this"
-msgstr ""
+msgstr "з --cruft видалити обʼєкти, старіші за цей термін"
 
 msgid "remove redundant packs, and run git-prune-packed"
-msgstr ""
+msgstr "видалити зайві пакунки і запустити git-prune-packed"
 
 msgid "pass --no-reuse-delta to git-pack-objects"
-msgstr ""
+msgstr "передати --no-reuse-delta до git-pack-objects"
 
 msgid "pass --no-reuse-object to git-pack-objects"
-msgstr ""
+msgstr "передати --no-reuse-object до git-pack-objects"
 
 msgid "do not run git-update-server-info"
-msgstr ""
+msgstr "не запускати git-update-server-info"
 
 msgid "pass --local to git-pack-objects"
-msgstr ""
+msgstr "передати --local до git-pack-objects"
 
 msgid "write bitmap index"
 msgstr "записати bitmap індекс"
 
 msgid "pass --delta-islands to git-pack-objects"
-msgstr ""
+msgstr "передати --delta-islands до git-pack-objects"
 
 msgid "with -A, do not loosen objects older than this"
-msgstr ""
+msgstr "з -A, не послабляти обʼєкти, старіші за це значення"
 
 msgid "with -a, repack unreachable objects"
-msgstr ""
+msgstr "з -a, перепакувати недоступні обʼєкти"
 
 msgid "size of the window used for delta compression"
-msgstr ""
+msgstr "розмір вікна, що використовується для дельта компресії"
 
 msgid "bytes"
-msgstr ""
+msgstr "байти"
 
 msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
+"те саме, що й вище, але обмежує розмір памʼяті замість кількості записів"
 
 msgid "limits the maximum delta depth"
-msgstr ""
+msgstr "обмежує максимальну глибину дельти"
 
 msgid "limits the maximum number of threads"
-msgstr ""
+msgstr "обмежує максимальну кількість потоків"
 
 msgid "maximum size of each packfile"
-msgstr ""
+msgstr "максимальний розмір кожного файла пакунка"
 
 msgid "repack objects in packs marked with .keep"
-msgstr ""
+msgstr "перепакувати обʼєкти в пакунках, позначених .keep"
 
 msgid "do not repack this pack"
-msgstr ""
+msgstr "не перепаковувати цей пакунок"
 
 msgid "find a geometric progression with factor <N>"
-msgstr ""
+msgstr "знайти геометричну прогресію з фактором <Н>"
 
 msgid "write a multi-pack index of the resulting packs"
-msgstr ""
+msgstr "записати multi-pack-index результуючих пакунків"
 
 msgid "pack prefix to store a pack containing pruned objects"
-msgstr ""
+msgstr "префікс пакунка для зберігання пакунка з обрізаними обʼєктами"
 
 msgid "cannot delete packs in a precious-objects repo"
-msgstr ""
+msgstr "неможливо видалити пакунки в precious-objects сховищі"
 
 msgid "Nothing new to pack."
-msgstr ""
+msgstr "Немає нічого нового для пакування."
 
 #, c-format
 msgid "pack prefix %s does not begin with objdir %s"
@@ -10651,44 +11159,46 @@ msgstr "префікс пакунку %s не починається з objdir %
 
 #, c-format
 msgid "renaming pack to '%s' failed"
-msgstr ""
+msgstr "перейменування пакунка на \"%s\" завершилося невдало"
 
 #, c-format
 msgid "pack-objects did not write a '%s' file for pack %s-%s"
-msgstr ""
+msgstr "pack-objects не записав файл \"%s\" для пакунка %s-%s"
 
 #, c-format
 msgid "could not unlink: %s"
-msgstr "не вдалося відʼєднати %s"
+msgstr "не вдалося видалити: %s"
 
 msgid "git replace [-f] <object> <replacement>"
-msgstr ""
+msgstr "git replace [-f] <обʼєкт> <заміна>"
 
 msgid "git replace [-f] --edit <object>"
-msgstr ""
+msgstr "git replace [-f] --edit <обʼєкт>"
 
 msgid "git replace [-f] --graft <commit> [<parent>...]"
-msgstr ""
+msgstr "git replace [-f] --graft <коміт> [<батько>...]"
 
 msgid "git replace -d <object>..."
-msgstr ""
+msgstr "git replace -d <обʼєкт>..."
 
 msgid "git replace [--format=<format>] [-l [<pattern>]]"
-msgstr ""
+msgstr "git replace [--format=<формат>] [-l [<шаблон>]]"
 
 #, c-format
 msgid ""
 "invalid replace format '%s'\n"
 "valid formats are 'short', 'medium' and 'long'"
 msgstr ""
+"невірний формат заміни \"%s\"\n"
+"допустимі формати \"short\", \"medium\" та \"long\""
 
 #, c-format
 msgid "replace ref '%s' not found"
-msgstr ""
+msgstr "заміна посилання \"%s\" не знайдена"
 
 #, c-format
 msgid "Deleted replace ref '%s'"
-msgstr ""
+msgstr "Видалена заміна посилання \"%s\""
 
 #, c-format
 msgid "'%s' is not a valid ref name"
@@ -10696,7 +11206,7 @@ msgstr "\"%s\" не є припустимою назвою посилання"
 
 #, c-format
 msgid "replace ref '%s' already exists"
-msgstr "змÑ\96нний ref \"%s\" вже існує"
+msgstr "замÑ\96на Ð¿Ð¾Ñ\81иланнÑ\8f \"%s\" вже існує"
 
 #, c-format
 msgid ""
@@ -10704,13 +11214,16 @@ msgid ""
 "'%s' points to a replaced object of type '%s'\n"
 "while '%s' points to a replacement object of type '%s'."
 msgstr ""
+"Обʼєкти повинні бути одного типу.\n"
+"\"%s\" вказує на замінений обʼєкт типу \"%s\", \n"
+"тоді як \"%s\" вказує на обʼєкт заміни типу \"%s\"."
 
 #, c-format
 msgid "unable to open %s for writing"
 msgstr "не вдалося відкрити %s для запису"
 
 msgid "cat-file reported failure"
-msgstr ""
+msgstr "cat-file повідомила про збій"
 
 #, c-format
 msgid "unable to open %s for reading"
@@ -10723,7 +11236,7 @@ msgid "unable to read from mktree"
 msgstr "не вдалося прочитати з mktree"
 
 msgid "mktree reported failure"
-msgstr ""
+msgstr "mktree повідомила про збій"
 
 msgid "mktree did not return an object name"
 msgstr "mktree не повернув назву обʼєкта"
@@ -10740,11 +11253,11 @@ msgid "unable to get object type for %s"
 msgstr "не вдалося отримати тип обʼєкта для %s"
 
 msgid "editing object file failed"
-msgstr ""
+msgstr "редагування файла обʼєкта завершилося невдало"
 
 #, c-format
 msgid "new object is the same as the old one: '%s'"
-msgstr ""
+msgstr "новий обʼєкт такий самий, як і старий: \"%s\""
 
 #, c-format
 msgid "could not parse %s as a commit"
@@ -10752,24 +11265,26 @@ msgstr "не вдалося розібрати %s як коміт"
 
 #, c-format
 msgid "bad mergetag in commit '%s'"
-msgstr "непÑ\80авилÑ\8cний mergetag в коміті \"%s\""
+msgstr "невÑ\96Ñ\80ний mergetag в коміті \"%s\""
 
 #, c-format
 msgid "malformed mergetag in commit '%s'"
-msgstr ""
+msgstr "невірно сформований тег злиття у коміті \"%s\""
 
 #, c-format
 msgid ""
 "original commit '%s' contains mergetag '%s' that is discarded; use --edit "
 "instead of --graft"
 msgstr ""
+"початковий коміт \"%s\" містить тег злиття \"%s\", який було відкинуто; "
+"скористайтесь --edit замість --graft"
 
 #, c-format
 msgid "the original commit '%s' has a gpg signature"
-msgstr ""
+msgstr "оригінальний коміт \"%s\" має підпис gpg"
 
 msgid "the signature will be removed in the replacement commit!"
-msgstr ""
+msgstr "підпис буде видалено в коміті заміни!"
 
 #, c-format
 msgid "could not write replacement commit for: '%s'"
@@ -10777,38 +11292,40 @@ msgstr "не вдалося записати коміт заміни для: \"%
 
 #, c-format
 msgid "graft for '%s' unnecessary"
-msgstr ""
+msgstr "прищепа для \"%s\" не потрібна"
 
 #, c-format
 msgid "new commit is the same as the old one: '%s'"
-msgstr ""
+msgstr "новий коміт такий самий, як і старий: \"%s\""
 
 #, c-format
 msgid ""
 "could not convert the following graft(s):\n"
 "%s"
 msgstr ""
+"не вдалося конвертувати наступні прищепи:\n"
+"%s"
 
 msgid "list replace refs"
-msgstr ""
+msgstr "показати заміни посилань"
 
 msgid "delete replace refs"
-msgstr "видалиÑ\82и Ð·Ð¼Ñ\96ннÑ\96 Ð¿Ð¾Ñ\81иланнÑ\8f"
+msgstr "видалиÑ\82и Ð·Ð°Ð¼Ñ\96ни Ð¿Ð¾Ñ\81иланнÑ\8c"
 
 msgid "edit existing object"
 msgstr "редагувати існуючий обʼєкт"
 
 msgid "change a commit's parents"
-msgstr ""
+msgstr "змінити батьків коміту"
 
 msgid "convert existing graft file"
-msgstr ""
+msgstr "конвертувати існуючий файл щеплення"
 
 msgid "replace the ref if it exists"
-msgstr ""
+msgstr "замінити посилання, якщо воно існує"
 
 msgid "do not pretty-print contents for --edit"
-msgstr ""
+msgstr "не прикрашати вивід вмісту для --edit"
 
 msgid "use this format"
 msgstr "використати цей формат"
@@ -10817,38 +11334,40 @@ msgid "--format cannot be used when not listing"
 msgstr "--format не можна використовувати без list"
 
 msgid "-f only makes sense when writing a replacement"
-msgstr ""
+msgstr "-f має сенс тільки при записі заміни"
 
 msgid "--raw only makes sense with --edit"
-msgstr ""
+msgstr "--raw має сенс тільки з --edit"
 
 msgid "-d needs at least one argument"
-msgstr ""
+msgstr "-d потребує принаймні одного аргументу"
 
 msgid "bad number of arguments"
-msgstr ""
+msgstr "невірна кількість аргументів"
 
 msgid "-e needs exactly one argument"
-msgstr ""
+msgstr "-e потребує лишень один аргумент"
 
 msgid "-g needs at least one argument"
-msgstr ""
+msgstr "-g потребує принаймні одного аргументу"
 
 msgid "--convert-graft-file takes no argument"
-msgstr ""
+msgstr "--convert-graft-file не потребує аргументів"
 
 msgid "only one pattern can be given with -l"
-msgstr ""
+msgstr "тільки один шаблон може бути заданий з -l"
 
 msgid ""
 "git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"
 msgstr ""
+"git rerere [clear | forget <визначник-шляху>... | diff | status | remaining "
+"| gc]"
 
 msgid "register clean resolutions in index"
-msgstr ""
+msgstr "зареєструвати чисті вирішення в індексі"
 
 msgid "'git rerere forget' without paths is deprecated"
-msgstr ""
+msgstr "команда \"git rerere forget\" без шляхів застаріла"
 
 #, c-format
 msgid "unable to generate diff for '%s'"
@@ -10860,17 +11379,17 @@ msgstr ""
 "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"
 
 msgid "git reset [-q] [<tree-ish>] [--] <pathspec>..."
-msgstr "git reset [-q] [<деревоподібне джерело>] [--] <визначник шляху>..."
+msgstr "git reset [-q] [<деревоподібне-джерело>] [--] <визначник шляху>..."
 
 msgid ""
 "git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"
 msgstr ""
-"git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<деревоподібне "
+"git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<деревоподібне-"
 "джерело>]"
 
 msgid "git reset --patch [<tree-ish>] [--] [<pathspec>...]"
 msgstr ""
-"git reset --patch [<деревоподібне джерело>] [--] [<визначник шляху>...]"
+"git reset --patch [<деревоподібне-джерело>] [--] [<визначник шляху>...]"
 
 msgid "mixed"
 msgstr "змішане"
@@ -10973,9 +11492,10 @@ msgstr "не вдалося отримати дані про використа
 #, 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 ""
+msgstr "rev-list не підтримує відображення нотаток"
 
 #, c-format
 msgid "marked counting and '%s' cannot be used together"
@@ -10985,25 +11505,25 @@ msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
 msgstr "git rev-parse --parseopt [<опції>] -- [<аргументи>...]"
 
 msgid "keep the `--` passed as an arg"
-msgstr ""
+msgstr "залишити \"--\" переданим як аргумент"
 
 msgid "stop parsing after the first non-option argument"
-msgstr ""
+msgstr "зупинити розбір після першого неопціонального аргументу"
 
 msgid "output in stuck long form"
-msgstr ""
+msgstr "виведення в застряглій довгій формі"
 
 msgid "premature end of input"
 msgstr "передчасне закінчення вхідних даних"
 
 msgid "no usage string given before the `--' separator"
-msgstr ""
+msgstr "не вказана строка використання перед \"--\" розділювачем"
 
 msgid "missing opt-spec before option flags"
-msgstr ""
+msgstr "відсутній opt-spec перед прапорцями опції"
 
 msgid "Needed a single revision"
-msgstr ""
+msgstr "Необхідна одна ревізія"
 
 msgid ""
 "git rev-parse --parseopt [<options>] -- [<args>...]\n"
@@ -11012,133 +11532,147 @@ msgid ""
 "\n"
 "Run \"git rev-parse --parseopt -h\" for more information on the first usage."
 msgstr ""
+"git rev-parse --parseopt [<опції>] -- [<аргументи>...]\n"
+"   або: git rev-parse --sq-quote [<аргумент>...]\n"
+"   або: git rev-parse [<опції>] [<аргумент>...]\n"
+"\n"
+"Запустіть \"git rev-parse --parseopt -h\" для отримання додаткової "
+"інформації про перше використання."
 
 msgid "--resolve-git-dir requires an argument"
-msgstr ""
+msgstr "--resolve-git-dir потребує аргументу"
 
 #, c-format
 msgid "not a gitdir '%s'"
-msgstr ""
+msgstr "не є git директорією \"%s\""
 
 msgid "--git-path requires an argument"
-msgstr ""
+msgstr "--git-path потребує аргументу"
 
 msgid "-n requires an argument"
-msgstr "-n потребує аргумент"
+msgstr "-n потребує аргументу"
 
 msgid "--path-format requires an argument"
-msgstr ""
+msgstr "--path-format потребує аргументу"
 
 #, c-format
 msgid "unknown argument to --path-format: %s"
-msgstr ""
+msgstr "невідомий аргумент до --path-format: %s"
 
 msgid "--default requires an argument"
-msgstr ""
+msgstr "--default потребує аргументу"
 
 msgid "--prefix requires an argument"
-msgstr ""
+msgstr "--prefix потребує аргументу"
 
 #, c-format
 msgid "unknown mode for --abbrev-ref: %s"
-msgstr ""
+msgstr "невідомий режим для --abbrev-ref: %s"
 
 msgid "--exclude-hidden cannot be used together with --branches"
-msgstr "--exclude-hidden неможливо використати разом з --branches"
+msgstr "--exclude-hidden не можна використовувати разом з --branches"
 
 msgid "--exclude-hidden cannot be used together with --tags"
-msgstr ""
+msgstr "--exclude-hidden неможливо використовувати разом з --tags"
 
 msgid "--exclude-hidden cannot be used together with --remotes"
-msgstr ""
+msgstr "--exclude-hidden неможливо використовувати разом з --remotes"
 
 msgid "this operation must be run in a work tree"
-msgstr ""
+msgstr "цю операцію треба виконувати в робочому дереві"
 
 #, c-format
 msgid "unknown mode for --show-object-format: %s"
-msgstr ""
+msgstr "невідомий режим для --show-object-format: %s"
 
 msgid ""
 "git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] "
 "<commit>..."
 msgstr ""
+"git revert [--[no-]edit] [-n] [-m <номер-батька>] [-s] [-S[<ідентифікатор-"
+"ключа>]] <коміт>..."
 
 msgid "git revert (--continue | --skip | --abort | --quit)"
-msgstr ""
+msgstr "git revert (--continue | --skip | --abort | --quit)"
 
 msgid ""
 "git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
 "                [-S[<keyid>]] <commit>..."
 msgstr ""
+"git cherry-pick [--edit] [-n] [-m <номер-батька>] [-s] [-x] [--ff].\n"
+"                [-S[<ідентифікатор-ключа>]] <коміт>..."
 
 msgid "git cherry-pick (--continue | --skip | --abort | --quit)"
 msgstr "git cherry-pick (--continue | --skip | --abort | --quit)"
 
 #, c-format
 msgid "option `%s' expects a number greater than zero"
-msgstr ""
+msgstr "опція \"%s\" очікує число більше нуля"
 
 #, c-format
 msgid "%s: %s cannot be used with %s"
 msgstr "%s: %s неможливо використовувати з %s"
 
 msgid "end revert or cherry-pick sequence"
-msgstr ""
+msgstr "завершити процес вивертання або висмикування"
 
 msgid "resume revert or cherry-pick sequence"
-msgstr ""
+msgstr "відновити процес вивертання або висмикування"
 
 msgid "cancel revert or cherry-pick sequence"
-msgstr ""
+msgstr "скасувати процес вивертання або висмикування"
 
 msgid "skip current commit and continue"
-msgstr ""
+msgstr "пропустити поточний коміт і продовжити"
 
 msgid "don't automatically commit"
 msgstr "не комітити автоматично"
 
 msgid "edit the commit message"
-msgstr ""
+msgstr "редагувати допис до коміту"
 
 msgid "parent-number"
-msgstr ""
+msgstr "номер батька"
 
 msgid "select mainline parent"
-msgstr ""
+msgstr "вибрати основну батьківську лінію"
 
 msgid "merge strategy"
-msgstr ""
+msgstr "стратегія злиття"
 
 msgid "option for merge strategy"
 msgstr "опція для стратегії злиття"
 
 msgid "append commit name"
-msgstr ""
+msgstr "додати назву коміту"
 
 msgid "preserve initially empty commits"
-msgstr ""
+msgstr "зберігати первинно порожні коміти"
 
 msgid "allow commits with empty messages"
-msgstr ""
+msgstr "дозволити коміти з порожніми дописами"
 
 msgid "keep redundant, empty commits"
-msgstr ""
+msgstr "зберігати зайві порожні коміти"
 
 msgid "use the 'reference' format to refer to commits"
-msgstr ""
+msgstr "використовувати \"reference\" формат для посилань на коміти"
 
 msgid "revert failed"
 msgstr "вивертання не вдалося"
 
 msgid "cherry-pick failed"
-msgstr ""
+msgstr "висмикування не вдалося"
 
 msgid ""
 "git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
 "       [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
 "       [--] [<pathspec>...]"
 msgstr ""
+"git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--ignore-"
+"unmatch\n"
+"       [--quiet] [--pathspec-from-file=<файл> [--pathspec-file-nul]]\n"
+"       [--] [<визначник-шляху>...]"
 
 msgid ""
 "the following file has staged content different from both the\n"
@@ -11147,24 +11681,34 @@ msgid_plural ""
 "the following files have staged content different from both the\n"
 "file and the HEAD:"
 msgstr[0] ""
+"наступний файл має доданий до індексу вміст, відмінний як від файла\n"
+"так й від HEAD:"
 msgstr[1] ""
+"наступні файли мають доданий до індексу вміст, відмінний як від файла\n"
+"так й від HEAD:"
 msgstr[2] ""
+"наступні файли мають доданий до індексу вміст, відмінний як від файла\n"
+"так й від HEAD:"
 
 msgid ""
 "\n"
 "(use -f to force removal)"
 msgstr ""
+"\n"
+"(використовуйте -f щоб видалити примусово)"
 
 msgid "the following file has changes staged in the index:"
 msgid_plural "the following files have changes staged in the index:"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "у наступному файлі є зміни, додані до індексу:"
+msgstr[1] "у наступних файлах є зміни, додані до індексу:"
+msgstr[2] "у наступних файлах є зміни, додані до індексу:"
 
 msgid ""
 "\n"
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
+"\n"
+"(використовуйте --cached, щоб зберегти файл, або -f, щоб видалити примусово)"
 
 msgid "the following file has local modifications:"
 msgid_plural "the following files have local modifications:"
@@ -11173,29 +11717,30 @@ msgstr[1] "наступні файли мають локальні зміни:"
 msgstr[2] "наступних файлів мають локальні зміни:"
 
 msgid "do not list removed files"
-msgstr ""
+msgstr "не показувати видалені файли"
 
 msgid "only remove from the index"
 msgstr "видалити тільки з індексу"
 
 msgid "override the up-to-date check"
-msgstr ""
+msgstr "перевизначити перевірку на актуальність"
 
 msgid "allow recursive removal"
-msgstr ""
+msgstr "дозволити рекурсивне видалення"
 
 msgid "exit with a zero status even if nothing matched"
-msgstr ""
+msgstr "виходити з нульовим статусом, навіть якщо нічого не збігається"
 
 msgid "No pathspec was given. Which files should I remove?"
-msgstr ""
+msgstr "Не було вказано визначник шляху. Які файли слід видалити?"
 
 msgid "please stage your changes to .gitmodules or stash them to proceed"
 msgstr ""
+"будь ласка, додайте ваші зміни до .gitmodules або схову, щоб продовжити"
 
 #, c-format
 msgid "not removing '%s' recursively without -r"
-msgstr ""
+msgstr "не видалено \"%s\" рекурсивно без -r"
 
 #, c-format
 msgid "git rm: unable to remove %s"
@@ -11208,6 +11753,11 @@ msgid ""
 "              [--[no-]signed | --signed=(true|false|if-asked)]\n"
 "              [<host>:]<directory> (--all | <ref>...)"
 msgstr ""
+"git send-pack [--mirror] [--dry-run] [--force]\n"
+"              [--receive-pack=<git-пакунок-отримання>]\n"
+"              [--verbose] [--thin] [--atomic]\n"
+"              [--[no-]signed | --signed=(true|false|if-asked)]\n"
+"              [<хост>:]<директорія> (--all | <посилання>...)"
 
 msgid "remote name"
 msgstr "віддалена назва"
@@ -11216,57 +11766,57 @@ msgid "push all refs"
 msgstr "надіслати всі посилання"
 
 msgid "use stateless RPC protocol"
-msgstr ""
+msgstr "використовувати протокол RPC без збереження стану"
 
 msgid "read refs from stdin"
-msgstr ""
+msgstr "прочитати посилання з stdin"
 
 msgid "print status from remote helper"
-msgstr ""
+msgstr "вивести статус з віддаленого помічника"
 
 msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
 msgstr "git shortlog [<опції>] [<діапазон-ревізій>] [[--] <шлях>...]"
 
 msgid "git log --pretty=short | git shortlog [<options>]"
-msgstr ""
+msgstr "git log --pretty=short | git shortlog [<опції>]"
 
 msgid "using multiple --group options with stdin is not supported"
-msgstr ""
+msgstr "використання кількох --group опцій з stdin не підтримується"
 
 #, c-format
 msgid "using %s with stdin is not supported"
-msgstr ""
+msgstr "використання %s з stdin не підтримується"
 
 #, c-format
 msgid "unknown group type: %s"
 msgstr "невідомий тип групи: %s"
 
 msgid "group by committer rather than author"
-msgstr ""
+msgstr "групувати за комітером, а не за автором"
 
 msgid "sort output according to the number of commits per author"
-msgstr ""
+msgstr "сортувати виведення за кількістю комітів на автора"
 
 msgid "suppress commit descriptions, only provides commit count"
-msgstr ""
+msgstr "приховати описи комітів, показати лише кількість комітів"
 
 msgid "show the email address of each author"
-msgstr ""
+msgstr "показати адресу електронної пошти кожного автора"
 
 msgid "<w>[,<i1>[,<i2>]]"
-msgstr ""
+msgstr "<w>[,<i1>[,<i2>]]"
 
 msgid "linewrap output"
 msgstr "обгортати рядки виводу"
 
 msgid "field"
-msgstr ""
+msgstr "поле"
 
 msgid "group by field"
-msgstr ""
+msgstr "групувати за полем"
 
 msgid "too many arguments given outside repository"
-msgstr ""
+msgstr "занадто багато аргументів надано поза сховищем"
 
 msgid ""
 "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
@@ -11275,35 +11825,40 @@ msgid ""
 "                [--no-name | --sha1-name] [--topics]\n"
 "                [(<rev> | <glob>)...]"
 msgstr ""
+"git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
+"                [--current] [--color[=<коли>] | --no-color] [--sparse]\n"
+"                [--more=<н> | --list | --independent | --merge-base]\n"
+"                [--no-name | --sha1-name] [--topics]\n"
+"                [(<ревізія> | <глоб>)...]"
 
 msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
-msgstr ""
+msgstr "git show-branch (-g | --reflog)[=<н>[,<база>]] [--list] [<посилання>]"
 
 #, c-format
 msgid "ignoring %s; cannot handle more than %d ref"
 msgid_plural "ignoring %s; cannot handle more than %d refs"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "ігнорування %s; неможливо обробити більше %d посилання"
+msgstr[1] "ігнорування %s; неможливо обробити більше %d посилань"
+msgstr[2] "ігнорування %s; неможливо обробити більше %d посилань"
 
 #, c-format
 msgid "no matching refs with %s"
-msgstr ""
+msgstr "немає співпадаючих посилань з %s"
 
 msgid "show remote-tracking and local branches"
-msgstr ""
+msgstr "показати віддалено відстежувані та локальні гілки"
 
 msgid "show remote-tracking branches"
 msgstr "показати віддалено відстежувані гілки"
 
 msgid "color '*!+-' corresponding to the branch"
-msgstr ""
+msgstr "колір \"*!+-\" відповідно на гілку"
 
 msgid "show <n> more commits after the common ancestor"
-msgstr ""
+msgstr "показати ще <н> комітів після спільного предка"
 
 msgid "synonym to more=-1"
-msgstr ""
+msgstr "синонім до more=-1"
 
 msgid "suppress naming strings"
 msgstr "не показувати назву"
@@ -11312,34 +11867,34 @@ msgid "include the current branch"
 msgstr "включити поточну гілку"
 
 msgid "name commits with their object names"
-msgstr ""
+msgstr "називати коміти за іменами обʼєктів"
 
 msgid "show possible merge bases"
-msgstr ""
+msgstr "показати можливі бази злиття"
 
 msgid "show refs unreachable from any other ref"
-msgstr ""
+msgstr "показати посилання, недосяжні з жодного іншого посилання"
 
 msgid "show commits in topological order"
-msgstr ""
+msgstr "показати коміти в топологічному порядку"
 
 msgid "show only commits not on the first branch"
-msgstr ""
+msgstr "показати лише коміти не з найпершої гілки"
 
 msgid "show merges reachable from only one tip"
-msgstr ""
+msgstr "показати злиття досяжні лише з однієї верхівки"
 
 msgid "topologically sort, maintaining date order where possible"
-msgstr ""
+msgstr "сортувати топологічно, зберігаючи порядок дат, якщо це можливо"
 
 msgid "<n>[,<base>]"
-msgstr ""
+msgstr "<н>[,<база>]"
 
 msgid "show <n> most recent ref-log entries starting at base"
-msgstr ""
+msgstr "показати <н> останніх записів лога посилань, починаючи з бази"
 
 msgid "no branches given, and HEAD is not valid"
-msgstr ""
+msgstr "не надано гілок, і HEAD не є дійсним"
 
 msgid "--reflog option needs one branch name"
 msgstr "--reflog потребує одну назву гілки"
@@ -11347,9 +11902,9 @@ msgstr "--reflog потребує одну назву гілки"
 #, c-format
 msgid "only %d entry can be shown at one time."
 msgid_plural "only %d entries can be shown at one time."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "одночасно може бути показаний лише %d запис."
+msgstr[1] "одночасно можуть бути показані лише %d записи."
+msgstr[2] "одночасно можуть бути показані лише %d записів."
 
 #, c-format
 msgid "no such ref %s"
@@ -11358,9 +11913,9 @@ msgstr "немає такого посилання %s"
 #, c-format
 msgid "cannot handle more than %d rev."
 msgid_plural "cannot handle more than %d revs."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "неможливо обробити більше %d ревізії."
+msgstr[1] "неможливо обробити більше %d ревізій."
+msgstr[2] "неможливо обробити більше %d ревізій."
 
 #, c-format
 msgid "'%s' is not a valid ref."
@@ -11368,7 +11923,7 @@ msgstr "\"%s\" не є припустимим посиланням."
 
 #, c-format
 msgid "cannot find commit %s (%s)"
-msgstr ""
+msgstr "не вдалося знайти коміт %s (%s)"
 
 msgid "hash-algorithm"
 msgstr "хеш-алгоритм"
@@ -11381,30 +11936,34 @@ msgid ""
 "             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
 "             [--heads] [--] [<pattern>...]"
 msgstr ""
+"git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-d | --"
+"dereference]\n"
+"             [-s | --hash[=<н>]] [--abbrev[=<н>]] [--tags]\n"
+"             [--heads] [--] [<шаблон>...]"
 
 msgid "git show-ref --exclude-existing[=<pattern>]"
-msgstr ""
+msgstr "git show-ref --exclude-existing[=<шаблон>]"
 
 msgid "only show tags (can be combined with heads)"
-msgstr "показати тільки теги (можна комбінувати з heads)"
+msgstr "показати тільки теги (можна комбінувати з верхівками)"
 
 msgid "only show heads (can be combined with tags)"
-msgstr "показати тільки верхівки (можна комбінувати з tags)"
+msgstr "показати тільки верхівки (можна комбінувати з тегами)"
 
 msgid "stricter reference checking, requires exact ref path"
-msgstr ""
+msgstr "більш сувора перевірка посилань, потребує точного шляху до посилання"
 
 msgid "show the HEAD reference, even if it would be filtered out"
-msgstr ""
+msgstr "показати HEAD посилання, навіть якщо воно було б відфільтроване"
 
 msgid "dereference tags into object IDs"
 msgstr "розіменувати теги в ідентифікатори обʼєктів"
 
 msgid "only show SHA1 hash using <n> digits"
-msgstr ""
+msgstr "показати тільки SHA1 хеш з використанням <н> цифр"
 
 msgid "do not print results to stdout (useful with --verify)"
-msgstr ""
+msgstr "не виводити результати у stdout (корисно з --verify)"
 
 msgid "show refs from stdin that aren't in local repository"
 msgstr "показати посилання з stdin, яких немає в локальному сховищі"
@@ -11413,25 +11972,31 @@ msgid ""
 "git sparse-checkout (init | list | set | add | reapply | disable | check-"
 "rules) [<options>]"
 msgstr ""
+"git sparse-checkout (init | list | set | add | reapply | disable | check-"
+"rules) [<опції>]"
 
 msgid "this worktree is not sparse"
-msgstr ""
+msgstr "це робоче дерево не є розрідженим"
 
 msgid "this worktree is not sparse (sparse-checkout file may not exist)"
 msgstr ""
+"це робоче дерево не є розрідженим (файл розрідженого переходу може не "
+"існувати)"
 
 #, c-format
 msgid ""
 "directory '%s' contains untracked files, but is not in the sparse-checkout "
 "cone"
 msgstr ""
+"директорія \"%s\" містить невідстежувані файли, але не входить до конуса "
+"розрідженого переходу"
 
 #, c-format
 msgid "failed to remove directory '%s'"
 msgstr "не вдалося видалити директорію \"%s\""
 
 msgid "failed to create directory for sparse-checkout file"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\81Ñ\82воÑ\80иÑ\82и Ð´Ð¸Ñ\80екÑ\82оÑ\80Ñ\96Ñ\8e Ð´Ð»Ñ\8f Ñ\84айлÑ\83 Ñ\87аÑ\81Ñ\82кового переходу"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\81Ñ\82воÑ\80иÑ\82и Ð´Ð¸Ñ\80екÑ\82оÑ\80Ñ\96Ñ\8e Ð´Ð»Ñ\8f Ñ\84айлÑ\83 Ñ\80озÑ\80Ñ\96дженого переходу"
 
 msgid "failed to initialize worktree config"
 msgstr "не вдалося ініціалізувати конфігурацію робочого дерева"
@@ -11440,10 +12005,10 @@ msgid "failed to modify sparse-index config"
 msgstr "не вдалося змінити sparse-index конфігурацію"
 
 msgid "initialize the sparse-checkout in cone mode"
-msgstr "Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и Ñ\87аÑ\81Ñ\82ковий перехід в режимі конуса"
+msgstr "Ñ\96нÑ\96Ñ\86Ñ\96алÑ\96зÑ\83ваÑ\82и Ñ\80озÑ\80Ñ\96джений перехід в режимі конуса"
 
 msgid "toggle the use of a sparse index"
-msgstr ""
+msgstr "перемкнути використання розрідженого індексу"
 
 #, c-format
 msgid "unable to create leading directories of %s"
@@ -11459,62 +12024,77 @@ msgstr "не вдалося нормалізувати шлях %s"
 
 #, c-format
 msgid "unable to unquote C-style string '%s'"
-msgstr ""
+msgstr "неможливо прибрати лапки з C-style строки \"%s\""
 
 msgid "unable to load existing sparse-checkout patterns"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð²Ð°Ð½Ñ\82ажиÑ\82и Ñ\96Ñ\81нÑ\83Ñ\8eÑ\87Ñ\96 Ñ\88аблони Ñ\87аÑ\81Ñ\82кових переходів"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð²Ð°Ð½Ñ\82ажиÑ\82и Ñ\96Ñ\81нÑ\83Ñ\8eÑ\87Ñ\96 Ñ\88аблони Ñ\80озÑ\80Ñ\96джених переходів"
 
 msgid "existing sparse-checkout patterns do not use cone mode"
-msgstr ""
+msgstr "існуючі шаблони розрідженого переходу не використовують режим конуса"
 
 msgid "please run from the toplevel directory in non-cone mode"
 msgstr ""
+"будь ласка, запускайте з директорії верхнього рівня в не конусномі режимі"
 
 msgid "specify directories rather than patterns (no leading slash)"
-msgstr ""
+msgstr "вказати директорії замість шаблонів (без першого слешу)"
 
 msgid ""
 "specify directories rather than patterns.  If your directory starts with a "
 "'!', pass --skip-checks"
 msgstr ""
+"вказати директорії замість шаблонів.  Якщо ваша директорія починається з \"!"
+"\", додайте --skip-checks"
 
 msgid ""
 "specify directories rather than patterns.  If your directory really has any "
 "of '*?[]\\' in it, pass --skip-checks"
 msgstr ""
+"вказати директорії замість шаблонів.  Якщо в назві вашої директорії дійсно є "
+"символи \"*?[]\\\", додайте --skip-checks"
 
 #, c-format
 msgid ""
 "'%s' is not a directory; to treat it as a directory anyway, rerun with --"
 "skip-checks"
 msgstr ""
+"\"%s\" не є директорією; щоб вважати його директорією, повторіть запуск з --"
+"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 ""
+"додайте перший слеш перед такими шляхами, як \"%s\", якщо вам потрібен один "
+"файл (див. розділ НЕ КОНУСНІ ПРОБЛЕМИ у посібнику з git-sparse-checkout)."
 
 msgid "git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"
-msgstr ""
+msgstr "git sparse-checkout add [--skip-checks] (--stdin | <шаблони>)"
 
 msgid ""
 "skip some sanity checks on the given paths that might give false positives"
 msgstr ""
+"пропустити деякі перевірки на заданих шляхах, які можуть давати хибні "
+"результати"
 
 msgid "read patterns from standard in"
-msgstr ""
+msgstr "читати шаблони зі стандартного вводу"
 
 msgid "no sparse-checkout to add to"
-msgstr ""
+msgstr "немає розрідженого переходу для додавання"
 
 msgid ""
 "git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
 "(--stdin | <patterns>)"
 msgstr ""
+"git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] "
+"(--stdin | <шаблони>)"
 
 msgid "must be in a sparse-checkout to reapply sparsity patterns"
 msgstr ""
+"має перебувати в розрідженому переході для повторного застосування шаблонів "
+"розрідженості"
 
 msgid "error while refreshing working directory"
 msgstr "помилка під час оновлення робочої директорії"
@@ -11523,12 +12103,16 @@ msgid ""
 "git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
 "file <file>]"
 msgstr ""
+"git sparse-checkout check-rules [-z] [--skip-checks][--[no-]cone] [--rules-"
+"file <файл>]"
 
 msgid "terminate input and output files by a NUL character"
-msgstr ""
+msgstr "завершити вхідні та вихідні файли символом NUL"
 
 msgid "when used with --rules-file interpret patterns as cone mode patterns"
 msgstr ""
+"при використанні з --rules-file інтерпретувати шаблони як шаблони конусного "
+"режиму"
 
 msgid "use patterns in <file> instead of the current ones."
 msgstr "використовувати шаблони з <file> замість поточних."
@@ -11540,21 +12124,23 @@ msgid ""
 "git stash show [-u | --include-untracked | --only-untracked] [<diff-"
 "options>] [<stash>]"
 msgstr ""
+"git stash show [-u | --include-untracked | --only-untracked] [<опції-"
+"різниці>] [<схов>]"
 
 msgid "git stash drop [-q | --quiet] [<stash>]"
-msgstr ""
+msgstr "git stash drop [-q | --quiet] [<схов>]"
 
 msgid "git stash pop [--index] [-q | --quiet] [<stash>]"
-msgstr ""
+msgstr "git stash pop [--index] [-q | --quiet] [<схов>]"
 
 msgid "git stash apply [--index] [-q | --quiet] [<stash>]"
-msgstr ""
+msgstr "git stash apply [--index] [-q | --quiet] [<схов>]"
 
 msgid "git stash branch <branchname> [<stash>]"
-msgstr ""
+msgstr "git stash branch <назва-гілки> [<схов>]"
 
 msgid "git stash store [(-m | --message) <message>] [-q | --quiet] <commit>"
-msgstr ""
+msgstr "git stash store [(-m | --message) <допис>] [-q | --quiet] <коміт>"
 
 msgid ""
 "git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
@@ -11564,15 +12150,24 @@ msgid ""
 "          [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
 "          [--] [<pathspec>...]]"
 msgstr ""
+"git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q "
+"| --quiet]\n"
+"          [-u | --include-untracked] [-a | --all] [(-m | --message) "
+"<допис>]\n"
+"          [--pathspec-from-file=<файл> [--pathspec-file-nul]]\n"
+"          [--] [<визначник-шляху>...]]"
 
 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] [-S | --staged] [-k | --[no-]keep-index] [-q | "
+"--quiet]\n"
+"          [-u | --include-untracked] [-a | --all] [<допис>]"
 
 msgid "git stash create [<message>]"
-msgstr ""
+msgstr "git stash create [<допис>]"
 
 #, c-format
 msgid "'%s' is not a stash-like commit"
@@ -11580,17 +12175,17 @@ msgstr "\"%s\" не є сховоподібним комітом"
 
 #, c-format
 msgid "Too many revisions specified:%s"
-msgstr ""
+msgstr "Вказано забагато ревізій:%s"
 
 msgid "No stash entries found."
-msgstr ""
+msgstr "Записи схова не знайдені."
 
 #, c-format
 msgid "%s is not a valid reference"
 msgstr "%s не є припустимим посиланням"
 
 msgid "git stash clear with arguments is unimplemented"
-msgstr ""
+msgstr "git stash clear з аргументами не реалізовано"
 
 #, c-format
 msgid ""
@@ -11598,6 +12193,9 @@ msgid ""
 "            %s -> %s\n"
 "         to make room.\n"
 msgstr ""
+"ПОПЕРЕДЖЕННЯ: Невідстежуваний файл на шляху відстежуваного!  Перейменування\n"
+"            %s -> %s\n"
+"         щоб звільнити місце.\n"
 
 msgid "cannot apply a stash in the middle of a merge"
 msgstr "неможливо застосувати схов посеред злиття"
@@ -11607,17 +12205,17 @@ msgid "could not generate diff %s^!."
 msgstr "не вдалося згенерувати різницю %s^!."
 
 msgid "conflicts in index. Try without --index."
-msgstr ""
+msgstr "конфлікти в індексі. Спробуйте без --index."
 
 msgid "could not save index tree"
 msgstr "не вдалося зберегти дерево індекса"
 
 #, c-format
 msgid "Merging %s with %s"
-msgstr ""
+msgstr "Злиття %s з %s"
 
 msgid "Index was not unstashed."
-msgstr ""
+msgstr "Індекс не було вилучено зі схову."
 
 msgid "could not restore untracked files from stash"
 msgstr "не вдалося відновити невідстежувані файли зі схову"
@@ -11627,21 +12225,21 @@ msgstr "спроба відтворити індекс"
 
 #, c-format
 msgid "Dropped %s (%s)"
-msgstr ""
+msgstr "Скинуто %s (%s)"
 
 #, c-format
 msgid "%s: Could not drop stash entry"
-msgstr ""
+msgstr "%s: Не вдалося скинути запис схову"
 
 #, c-format
 msgid "'%s' is not a stash reference"
 msgstr "\"%s\" не є посиланням схова"
 
 msgid "The stash entry is kept in case you need it again."
-msgstr ""
+msgstr "Запис схову збережено на випадок, якщо він вам знову знадобиться."
 
 msgid "No branch name specified"
-msgstr ""
+msgstr "Не вказана назва гілки"
 
 msgid "failed to parse tree"
 msgstr "не вдалося розібрати дерево"
@@ -11660,10 +12258,10 @@ msgid "Cannot update %s with %s"
 msgstr "Неможливо оновити %s з %s"
 
 msgid "stash message"
-msgstr ""
+msgstr "допис до запису схова"
 
 msgid "\"git stash store\" requires one <commit> argument"
-msgstr ""
+msgstr "\"git stash store\" потребує одного <коміт> аргументу"
 
 msgid "No staged changes"
 msgstr "Немає індексованих змін"
@@ -11681,7 +12279,7 @@ msgid "Cannot save the untracked files"
 msgstr "Неможливо зберегти невідстежувані файли"
 
 msgid "Cannot save the current worktree state"
-msgstr ""
+msgstr "Не вдалося зберегти поточний стан робочого дерева"
 
 msgid "Cannot save the current staged state"
 msgstr "Неможливо зберегти поточний індексований стан"
@@ -11695,37 +12293,38 @@ msgstr ""
 
 msgid "Can't use --staged and --include-untracked or --all at the same time"
 msgstr ""
+"Не можна використовувати --staged і --include-untracked або --all одночасно"
 
 msgid "Did you forget to 'git add'?"
-msgstr ""
+msgstr "Ви забули \"git add\"?"
 
 msgid "No local changes to save"
-msgstr ""
+msgstr "Немає локальних змін для збереження"
 
 msgid "Cannot initialize stash"
 msgstr "Неможливо ініціалізувати схов"
 
 msgid "Cannot save the current status"
-msgstr ""
+msgstr "Неможливо зберегти поточний стан"
 
 #, c-format
 msgid "Saved working directory and index state %s"
-msgstr ""
+msgstr "Збережено робочу директорію та стан індексу %s"
 
 msgid "Cannot remove worktree changes"
-msgstr ""
+msgstr "Неможливо видалити зміни робочого дерева"
 
 msgid "keep index"
-msgstr ""
+msgstr "зберегти індекс"
 
 msgid "stash staged changes only"
-msgstr ""
+msgstr "додати до схову тільки індексовані зміни"
 
 msgid "stash in patch mode"
-msgstr ""
+msgstr "додати до схову у режимі латання"
 
 msgid "quiet mode"
-msgstr ""
+msgstr "тихий режим"
 
 msgid "include untracked files in stash"
 msgstr "в тому числі невідстежувані файли схову"
@@ -11734,38 +12333,42 @@ msgid "include ignore files"
 msgstr "в тому числи файли ігнорування"
 
 msgid "skip and remove all lines starting with comment character"
-msgstr ""
+msgstr "пропустити та видалити всі рядки, що починаються з символу коментаря"
 
 msgid "prepend comment character and space to each line"
-msgstr ""
+msgstr "додати символ коментаря та пробіл до кожного рядка"
 
 #, c-format
 msgid "Expecting a full ref name, got %s"
-msgstr ""
+msgstr "Очікувалась повна назва посилання, отримано %s"
 
 #, c-format
 msgid "could not get a repository handle for submodule '%s'"
-msgstr ""
+msgstr "не вдалося отримати обʼєкт сховища для підмодуля \"%s\""
 
 #, c-format
 msgid ""
 "could not look up configuration '%s'. Assuming this repository is its own "
 "authoritative upstream."
 msgstr ""
+"не вдалося знайти конфігурацію \"%s\". Мабуть, це сховище має власне "
+"першоджерельне сховище."
 
 #, c-format
 msgid "No url found for submodule path '%s' in .gitmodules"
-msgstr ""
+msgstr "Не знайдено URL для шляху підмодуля \"%s\" у .gitmodules"
 
 #, c-format
 msgid "Entering '%s'\n"
-msgstr ""
+msgstr "Введення \"%s\"\n"
 
 #, c-format
 msgid ""
 "run_command returned non-zero status for %s\n"
 "."
 msgstr ""
+"run_command повернула ненульовий статус для %s\n"
+"."
 
 #, c-format
 msgid ""
@@ -11773,15 +12376,18 @@ msgid ""
 "submodules of %s\n"
 "."
 msgstr ""
+"run_command повернула ненульовий статус під час рекурсії у вкладених "
+"підмодулях %s\n"
+"."
 
 msgid "suppress output of entering each submodule command"
-msgstr ""
+msgstr "приховати вивід введення кожної команди підмодуля"
 
 msgid "recurse into nested submodules"
 msgstr "рекурсивно у вкладених підмодулях"
 
 msgid "git submodule foreach [--quiet] [--recursive] [--] <command>"
-msgstr ""
+msgstr "git submodule foreach [--quiet] [--recursive] [--] <команда>"
 
 #, c-format
 msgid "Failed to register url for submodule path '%s'"
@@ -11789,11 +12395,12 @@ msgstr "Не вдалося зареєструвати url для підмоду
 
 #, c-format
 msgid "Submodule '%s' (%s) registered for path '%s'\n"
-msgstr ""
+msgstr "Підмодуль \"%s\" (%s) зареєстровано для шляху \"%s\"\n"
 
 #, c-format
 msgid "warning: command update mode suggested for submodule '%s'\n"
 msgstr ""
+"попередження: запропоновано режим оновлення команд для підмодуля \"%s\"\n"
 
 #, c-format
 msgid "Failed to register update mode for submodule path '%s'"
@@ -11801,7 +12408,7 @@ msgstr ""
 "Не вдалося зареєструвати режим оновлення для підмодуля за шляхом \"%s\""
 
 msgid "suppress output for initializing a submodule"
-msgstr ""
+msgstr "приховати вивід для ініціалізації підмодуля"
 
 msgid "git submodule init [<options>] [<path>]"
 msgstr "git submodule init [<опції>] [<шлях>]"
@@ -11809,37 +12416,40 @@ msgstr "git submodule init [<опції>] [<шлях>]"
 #, c-format
 msgid "no submodule mapping found in .gitmodules for path '%s'"
 msgstr ""
+"відповідне відображення підмодуля не знайдено у .gitmodules для шляху \"%s\""
 
 #, c-format
 msgid "could not resolve HEAD ref inside the submodule '%s'"
-msgstr ""
+msgstr "не вдалося розвʼязати HEAD посилання всередині підмодуля \"%s\""
 
 #, c-format
 msgid "failed to recurse into submodule '%s'"
 msgstr "не вдалося обробити рекурсивно підмодуль \"%s\""
 
 msgid "suppress submodule status output"
-msgstr ""
+msgstr "приховати вивід стану підмодуля"
 
 msgid ""
 "use commit stored in the index instead of the one stored in the submodule "
 "HEAD"
 msgstr ""
+"використати коміт, що зберігається в індексі, замість того, що зберігається "
+"в HEAD підмодуля"
 
 msgid "git submodule status [--quiet] [--cached] [--recursive] [<path>...]"
-msgstr ""
+msgstr "git submodule status [--quiet] [--cached] [--recursive] [<шлях>...]"
 
 #, c-format
 msgid "* %s %s(blob)->%s(submodule)"
-msgstr ""
+msgstr "* %s %s(blob)->%s(підмодуль)"
 
 #, c-format
 msgid "* %s %s(submodule)->%s(blob)"
-msgstr ""
+msgstr "* %s %s(підмодуль)->%s(blob)"
 
 #, c-format
 msgid "%s"
-msgstr ""
+msgstr "%s"
 
 #, c-format
 msgid "couldn't hash object from '%s'"
@@ -11847,29 +12457,30 @@ msgstr "не вдалося хешувати обʼєкт з \"%s\""
 
 #, c-format
 msgid "unexpected mode %o\n"
-msgstr ""
+msgstr "неочікуваний режим %o\n"
 
 msgid "use the commit stored in the index instead of the submodule HEAD"
 msgstr "використати коміт, збережений в індексі, замість підмодуля HEAD"
 
 msgid "compare the commit in the index with that in the submodule HEAD"
-msgstr ""
+msgstr "порівняти коміт в індексі з комітом у HEAD підмодуля"
 
 msgid "skip submodules with 'ignore_config' value set to 'all'"
 msgstr ""
+"пропускати підмодулі зі значенням \"ignore_config\" встановленим у \"all\""
 
 msgid "limit the summary size"
-msgstr ""
+msgstr "обмежити розмір підсумку"
 
 msgid "git submodule summary [<options>] [<commit>] [--] [<path>]"
-msgstr ""
+msgstr "git summary submodule [<опції>] [<коміт>] [--] [<шлях>]"
 
 msgid "could not fetch a revision for HEAD"
-msgstr ""
+msgstr "не вдалося отримати ревізію для HEAD"
 
 #, c-format
 msgid "Synchronizing submodule url for '%s'\n"
-msgstr ""
+msgstr "Синхронізація url підмодуля для \"%s\"\n"
 
 #, c-format
 msgid "failed to register url for submodule path '%s'"
@@ -11880,22 +12491,26 @@ msgid "failed to update remote for submodule '%s'"
 msgstr "не вдалося оновити віддалене призначення для підмодуля \"%s\""
 
 msgid "suppress output of synchronizing submodule url"
-msgstr ""
+msgstr "приховати вивід процесу синхронізації url-адреси підмодуля"
 
 msgid "git submodule sync [--quiet] [--recursive] [<path>]"
-msgstr ""
+msgstr "git submodule sync [--quiet] [--recursive] [<шлях>]"
 
 #, c-format
 msgid ""
 "Submodule work tree '%s' contains a .git directory. This will be replaced "
 "with a .git file by using absorbgitdirs."
 msgstr ""
+"Робоче дерево підмодуля \"%s\" містить директорію .git. Її буде замінено на ."
+"git файл за допомогою absorbgitdirs."
 
 #, c-format
 msgid ""
 "Submodule work tree '%s' contains local modifications; use '-f' to discard "
 "them"
 msgstr ""
+"Робоче дерево підмодуля \"%s\" містить локальні модифікації; скористайтесь "
+"\"-f\", щоб скасувати їх"
 
 #, c-format
 msgid "Cleared directory '%s'\n"
@@ -11911,20 +12526,23 @@ msgstr "не вдалося створити порожню директорію
 
 #, c-format
 msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
-msgstr ""
+msgstr "Підмодуль \"%s\" (%s) не зареєстровано за шляхом \"%s\"\n"
 
 msgid "remove submodule working trees even if they contain local changes"
 msgstr ""
+"видалити робочі дерева підмодулів, навіть якщо вони містять локальні зміни"
 
 msgid "unregister all submodules"
-msgstr ""
+msgstr "скасувати реєстрацію всіх підмодулів"
 
 msgid ""
 "git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"
 msgstr ""
+"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<шлях>...]]"
 
 msgid "Use '--all' if you really want to deinitialize all submodules"
 msgstr ""
+"Скористайтесь \"--all\", якщо ви дійсно хочете деініціалізувати всі підмодулі"
 
 msgid ""
 "An alternate computed from a superproject's alternate is invalid.\n"
@@ -11932,65 +12550,76 @@ msgid ""
 "submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
 "'--reference-if-able' instead of '--reference'."
 msgstr ""
+"Запозичений обʼєкт, обчислений з запозиченого обʼєкту батьківського проекту, "
+"не є дійсним.\n"
+"Щоб дозволити Git клонувати без запозиченого обʼєкту в такому випадку, "
+"встановіть\n"
+"submodule.alternateErrorStrategy на \"info\" або, що еквівалентно, клонуйте "
+"з\n"
+"\"--reference-if-able\" замість \"--reference\"."
 
 #, c-format
 msgid "could not get a repository handle for gitdir '%s'"
-msgstr "не вдалося отримати дескриптор сховища для gitdir \"%s\""
+msgstr "не вдалося отримати дескриптор сховища для git директорії \"%s\""
 
 #, c-format
 msgid "submodule '%s' cannot add alternate: %s"
-msgstr "підмодуль \"%s\" не може додати спільний обʼєкт: %s"
+msgstr "підмодуль \"%s\" не може додати запозичених обʼєкт: %s"
 
 #, c-format
 msgid "Value '%s' for submodule.alternateErrorStrategy is not recognized"
-msgstr ""
+msgstr "Значення \"%s\" для submodule.alternateErrorStrategy не розпізнано"
 
 #, c-format
 msgid "Value '%s' for submodule.alternateLocation is not recognized"
-msgstr ""
+msgstr "Значення \"%s\" для submodule.alternateLocation не розпізнано"
 
 #, c-format
 msgid "refusing to create/use '%s' in another submodule's git dir"
 msgstr ""
+"відмовлено в створенні/використанні \"%s\" у git директорії іншого підмодуля"
 
 #, c-format
 msgid "clone of '%s' into submodule path '%s' failed"
-msgstr ""
+msgstr "не вдалося клонувати \"%s\" у шлях підмодуля \"%s\""
 
 #, c-format
 msgid "directory not empty: '%s'"
-msgstr ""
+msgstr "директорія не порожня: \"%s\""
 
 #, c-format
 msgid "could not get submodule directory for '%s'"
 msgstr "не вдалося отримати директорію підмодуля для \"%s\""
 
 msgid "alternative anchor for relative paths"
-msgstr ""
+msgstr "альтернативний якір для відносних шляхів"
 
 msgid "where the new submodule will be cloned to"
 msgstr "куди буде клоновано новий підмодуль"
 
 msgid "name of the new submodule"
-msgstr ""
+msgstr "назва нового підмодуля"
 
 msgid "url where to clone the submodule from"
-msgstr ""
+msgstr "url адреса, звідки клонувати підмодуль"
 
 msgid "depth for shallow clones"
-msgstr ""
+msgstr "глибина для неглибоких клонів"
 
 msgid "force cloning progress"
 msgstr "примусово звітувати прогрес клонування"
 
 msgid "disallow cloning into non-empty directory"
-msgstr ""
+msgstr "заборонити клонування у непорожню директорію"
 
 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=<шлях>] [--quiet] [--reference "
+"<сховище>] [--name <назва>] [--depth <глибина>] [--single-branch] [--filter "
+"<визначник-фільтру>] --url <url> --path <шлях>"
 
 #, c-format
 msgid "Invalid update mode '%s' configured for submodule path '%s'"
@@ -12000,30 +12629,34 @@ msgstr ""
 
 #, c-format
 msgid "Submodule path '%s' not initialized"
-msgstr ""
+msgstr "Підмодуль за шляхом \"%s\" не ініціалізовано"
 
 msgid "Maybe you want to use 'update --init'?"
-msgstr ""
+msgstr "Можливо, ви хочете скористатись командою \"update --init\"?"
 
 #, c-format
 msgid "Skipping unmerged submodule %s"
-msgstr ""
+msgstr "Пропуск незлитого підмодуля %s"
 
 #, c-format
 msgid "Skipping submodule '%s'"
-msgstr ""
+msgstr "Пропуск підмодуля \"%s\""
+
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "неможливо клонувати підмодуль \"%s\" без URL-адреси"
 
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
-msgstr ""
+msgstr "Не вдалося клонувати \"%s\". Запланована повторна спроба"
 
 #, c-format
 msgid "Failed to clone '%s' a second time, aborting"
-msgstr ""
+msgstr "Не вдалося клонувати \"%s\" вдруге, переривання"
 
 #, c-format
 msgid "Unable to checkout '%s' in submodule path '%s'"
-msgstr ""
+msgstr "Не вдалося переключитися на \"%s\" у підмодулі за шляхом \"%s\""
 
 #, c-format
 msgid "Unable to rebase '%s' in submodule path '%s'"
@@ -12035,33 +12668,37 @@ msgstr "Не вдалося злити \"%s\" в підмодулі за шля
 
 #, c-format
 msgid "Execution of '%s %s' failed in submodule path '%s'"
-msgstr ""
+msgstr "Не вдалося виконати \"%s %s\" у шляху підмодуля \"%s\""
 
 #, c-format
 msgid "Submodule path '%s': checked out '%s'\n"
-msgstr ""
+msgstr "Шлях підмодуля \"%s\": переключено стан \"%s\"\n"
 
 #, c-format
 msgid "Submodule path '%s': rebased into '%s'\n"
-msgstr ""
+msgstr "Шлях підмодуля \"%s\": перебазовано в \"%s\"\n"
 
 #, c-format
 msgid "Submodule path '%s': merged in '%s'\n"
-msgstr ""
+msgstr "Шлях підмодуля \"%s\": злито в \"%s\"\n"
 
 #, c-format
 msgid "Submodule path '%s': '%s %s'\n"
-msgstr ""
+msgstr "Шлях підмодуля \"%s\": \"%s %s\"\n"
 
 #, c-format
 msgid "Unable to fetch in submodule path '%s'; trying to directly fetch %s:"
 msgstr ""
+"Неможливо виконати отримання шляху підмодуля \"%s\"; спроба отримати напряму "
+"%s:"
 
 #, c-format
 msgid ""
 "Fetched in submodule path '%s', but it did not contain %s. Direct fetching "
 "of that commit failed."
 msgstr ""
+"Отримано у шляху до підмодуля \"%s\", але він не містить %s. Пряме отримання "
+"цього коміту не вдалося."
 
 #, c-format
 msgid "could not initialize submodule at path '%s'"
@@ -12072,18 +12709,20 @@ msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
 "the superproject is not on any branch"
 msgstr ""
+"Гілку підмодуля (%s) налаштовано на успадкування гілки від суперпроекту, але "
+"суперпроект не знаходиться у жодній гілці"
 
 #, c-format
 msgid "Unable to find current revision in submodule path '%s'"
-msgstr ""
+msgstr "Не вдалося знайти поточну ревізію у шляху підмодуля \"%s\""
 
 #, c-format
 msgid "Unable to fetch in submodule path '%s'"
-msgstr ""
+msgstr "Не вдалося отримати шлях підмодуля \"%s\""
 
 #, c-format
 msgid "Unable to find %s revision in submodule path '%s'"
-msgstr ""
+msgstr "Не вдалося знайти ревізію %s у шляху підмодуля \"%s\""
 
 #, c-format
 msgid "Failed to recurse into submodule path '%s'"
@@ -12099,34 +12738,34 @@ msgid "use SHA-1 of submodule's remote tracking branch"
 msgstr "використовувати SHA-1 гілки віддаленого відстежування підмодуля"
 
 msgid "traverse submodules recursively"
-msgstr ""
+msgstr "обходити підмодулі рекурсивно"
 
 msgid "don't fetch new objects from the remote site"
-msgstr ""
+msgstr "не отримувати нові обʼєкти з віддаленої сторони"
 
 msgid "use the 'checkout' update strategy (default)"
-msgstr ""
+msgstr "використати стратегію оновлення \"checkout \" (за замовчуванням)"
 
 msgid "use the 'merge' update strategy"
-msgstr ""
+msgstr "використати стратегію оновлення \"merge\""
 
 msgid "use the 'rebase' update strategy"
-msgstr ""
+msgstr "використати стратегію оновлення \"rebase\""
 
 msgid "create a shallow clone truncated to the specified number of revisions"
-msgstr "Ñ\81Ñ\82воÑ\80иÑ\82и Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невий клон, урізаний до вказаної кількості ревізій"
+msgstr "Ñ\81Ñ\82воÑ\80иÑ\82и Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºий клон, урізаний до вказаної кількості ревізій"
 
 msgid "parallel jobs"
-msgstr ""
+msgstr "паралельні потоки"
 
 msgid "whether the initial clone should follow the shallow recommendation"
-msgstr ""
+msgstr "чи повинен початковий клон слідувати неглибоким рекомендаціям"
 
 msgid "don't print cloning progress"
-msgstr ""
+msgstr "не виводити хід клонування"
 
 msgid "disallow cloning into non-empty directory, implies --init"
-msgstr ""
+msgstr "заборонити клонування у непорожній каталог, мається на увазі --init"
 
 msgid ""
 "git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] "
@@ -12134,44 +12773,50 @@ msgid ""
 "shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] "
 "[--] [<path>...]"
 msgstr ""
+"git submodule [--quiet] update [--init [--filter=<визначник-фільтру>]] [--"
+"remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--"
+"[no-]recommend-shallow] [--reference <сховище>] [--recursive] [--[no-]single-"
+"branch] [--] [<шлях>...]"
 
 msgid "git submodule absorbgitdirs [<options>] [<path>...]"
 msgstr "git submodule absorbgitdirs [<опції>] [<шлях>...]"
 
 msgid "suppress output for setting url of a submodule"
-msgstr ""
+msgstr "приховати вивід при встановленні url підмодуля"
 
 msgid "git submodule set-url [--quiet] <path> <newurl>"
-msgstr ""
+msgstr "git submodule set-url [--quiet] <шлях> <новий-url>"
 
 msgid "set the default tracking branch to master"
-msgstr ""
+msgstr "встановити гілку відстежування за замовчуванням на master"
 
 msgid "set the default tracking branch"
 msgstr "встановити гілку відстежування за замовчуванням"
 
 msgid "git submodule set-branch [-q|--quiet] (-d|--default) <path>"
-msgstr ""
+msgstr "git submodule set-branch [-q|--quiet] (-d|--default) <шлях>"
 
 msgid "git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"
-msgstr ""
+msgstr "git submodule set-branch [-q|--quiet] (-b|--branch) <гілка> <шлях>"
 
 msgid "--branch or --default required"
-msgstr ""
+msgstr "Потрібно вказати --branch або --default"
 
 msgid "print only error messages"
-msgstr ""
+msgstr "виводити тільки повідомлення про помилки"
 
 msgid "force creation"
-msgstr ""
+msgstr "примусове створення"
 
 msgid "show whether the branch would be created"
-msgstr ""
+msgstr "показати, чи буде створено гілку"
 
 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] <назва> <початковий-oid> <початкова-назва>"
 
 #, c-format
 msgid "creating branch '%s'"
@@ -12179,7 +12824,7 @@ msgstr "створення гілки \"%s\""
 
 #, c-format
 msgid "Adding existing repo at '%s' to the index\n"
-msgstr ""
+msgstr "Додавання існуючого сховища за адресою \"%s\" до індексу\n"
 
 #, c-format
 msgid "'%s' already exists and is not a valid git repo"
@@ -12188,6 +12833,8 @@ msgstr "\"%s\" вже існує і не є припустимим git схов
 #, c-format
 msgid "A git directory for '%s' is found locally with remote(s):\n"
 msgstr ""
+"Git директорію для \"%s\" знайдено локально з віддаленим(и) "
+"призначенням(и):\n"
 
 #, c-format
 msgid ""
@@ -12198,10 +12845,17 @@ msgid ""
 "or you are unsure what this means choose another name with the '--name' "
 "option."
 msgstr ""
+"Якщо ви хочете повторно використати цю локальну git директорію замість того, "
+"щоб знову клонувати з\n"
+"  %s\n"
+"скористайтесь опцією \"--force\". Якщо локальна директорія git не є "
+"правильним сховищем\n"
+"або ви не впевнені, що це означає, виберіть іншу назву за допомогою опції "
+"\"--name\"."
 
 #, c-format
 msgid "Reactivating local git directory for submodule '%s'\n"
-msgstr ""
+msgstr "Повторна активація локальної git директорії для підмодуля \"%s\"\n"
 
 #, c-format
 msgid "unable to checkout submodule '%s'"
@@ -12209,6 +12863,7 @@ msgstr "не вдалося переключитись на підмодуль \
 
 msgid "please make sure that the .gitmodules file is in the working tree"
 msgstr ""
+"будь ласка, переконайтеся, що файл .gitmodules знаходиться у робочому дереві"
 
 #, c-format
 msgid "Failed to add submodule '%s'"
@@ -12220,81 +12875,88 @@ msgstr "Не вдалося зареєструвати підмодуль \"%s\"
 
 #, c-format
 msgid "'%s' already exists in the index"
-msgstr ""
+msgstr "\"%s\" вже існує в індексі"
 
 #, c-format
 msgid "'%s' already exists in the index and is not a submodule"
-msgstr ""
+msgstr "\"%s\" вже існує в індексі і не є підмодулем"
 
 #, c-format
 msgid "'%s' does not have a commit checked out"
 msgstr "\"%s\" не має активного коміту"
 
 msgid "branch of repository to add as submodule"
-msgstr ""
+msgstr "гілка сховища, яку потрібно додати як підмодуль"
 
 msgid "allow adding an otherwise ignored submodule path"
-msgstr ""
+msgstr "дозволити додавання шляху до підмодуля, який інакше ігнорується"
 
 msgid "borrow the objects from reference repositories"
-msgstr ""
+msgstr "запозичити обʼєкти з репозиторіїв посилань"
 
 msgid ""
 "sets the submodule's name to the given string instead of defaulting to its "
 "path"
 msgstr ""
+"встановлює назву підмодуля на вказане значення замість використання його "
+"шляху"
 
 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 ""
+"Відносний шлях можна використовувати лише з верхнього рівня робочого дерева"
 
 #, c-format
 msgid "repo URL: '%s' must be absolute or begin with ./|../"
-msgstr ""
+msgstr "URL сховища: \"%s\" має бути абсолютним або починатися з ./|../."
 
 #, c-format
 msgid "'%s' is not a valid submodule name"
 msgstr "\"%s\" не є припустимою назвою підмодуля"
 
 msgid "git submodule--helper <command>"
-msgstr ""
+msgstr "git submodule--helper <команда>"
 
 msgid "git symbolic-ref [-m <reason>] <name> <ref>"
-msgstr ""
+msgstr "git symbolic-ref [-m <причина>] <назва> <посилання>"
 
 msgid "git symbolic-ref [-q] [--short] [--no-recurse] <name>"
-msgstr ""
+msgstr "git symbolic-ref [-q] [--short] [--no-recurse] <назва>"
 
 msgid "git symbolic-ref --delete [-q] <name>"
-msgstr ""
+msgstr "git symbolic-ref --delete [-q] <назва>"
 
 msgid "suppress error message for non-symbolic (detached) refs"
 msgstr ""
+"приховати повідомлення про помилку для несимвольних (відокремлених) посилань"
 
 msgid "delete symbolic ref"
 msgstr "видалити символьне посилання"
 
 msgid "shorten ref output"
-msgstr ""
+msgstr "скоротити вивід посилань"
 
 msgid "recursively dereference (default)"
 msgstr "рекурсивне розіменування (за замовчуванням)"
 
 msgid "reason"
-msgstr ""
+msgstr "причина"
 
 msgid "reason of the update"
-msgstr ""
+msgstr "причина оновлення"
 
 msgid ""
 "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
 "        <tagname> [<commit> | <object>]"
 msgstr ""
+"git tag [-a | -s | -u <ідентифікатор-ключа>] [-f] [-m <допис> | -F <файл>] [-"
+"e]\n"
+"        <назва-тегу> [<коміт> | <об’єкт>]"
 
 msgid "git tag -d <tagname>..."
-msgstr ""
+msgstr "git tag -d <назва-тега>..."
 
 msgid ""
 "git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
@@ -12302,17 +12964,21 @@ msgid ""
 "        [--create-reflog] [--sort=<key>] [--format=<format>]\n"
 "        [--merged <commit>] [--no-merged <commit>] [<pattern>...]"
 msgstr ""
+"git tag [-n[<число>]] -l [--contains <коміт>] [--no-contains <коміт>]\n"
+"        [--points-at <обʼєкт>] [--column[=<опціі>] | --no-column]\n"
+"        [--create-reflog] [--sort=<ключ>] [--format=<формат>]\n"
+"        [--merged <коміт>] [--no-merged <коміт>] [<шаблон>...]"
 
 msgid "git tag -v [--format=<format>] <tagname>..."
-msgstr ""
+msgstr "git tag -v [--format=<формат>] <назва-тега>..."
 
 #, c-format
 msgid "tag '%s' not found."
-msgstr ""
+msgstr "тег \"%s\" не знайдено."
 
 #, c-format
 msgid "Deleted tag '%s' (was %s)\n"
-msgstr ""
+msgstr "Видалено тег \"%s\" (було %s)\n"
 
 #, c-format
 msgid ""
@@ -12321,6 +12987,10 @@ msgid ""
 "  %s\n"
 "Lines starting with '%c' will be ignored.\n"
 msgstr ""
+"\n"
+"Напишіть допис до тегу:\n"
+"  %s\n"
+"Рядки, що починаються з \"%c\", будуть проігноровані.\n"
 
 #, c-format
 msgid ""
@@ -12330,6 +13000,11 @@ msgid ""
 "Lines starting with '%c' will be kept; you may remove them yourself if you "
 "want to.\n"
 msgstr ""
+"\n"
+"Напишіть допис до тегу:\n"
+"  %s\n"
+"Рядки, що починаються з \"%c\", будуть збережені; ви можете вилучити їх "
+"самостійно, якщо захочете.\n"
 
 msgid "unable to sign the tag"
 msgstr "не вдалося підписати тег"
@@ -12341,77 +13016,82 @@ msgid ""
 "\n"
 "\tgit tag -f %s %s^{}"
 msgstr ""
+"Ви створили вкладений тег. Обʼєкт, на який посилається ваш новий тег\n"
+"вже є тегом. Якщо ви хотіли позначити обʼєкт, на який він вказує, "
+"скористайтесь\n"
+"\n"
+"\tgit tag -f %s %s^{}"
 
 msgid "bad object type."
 msgstr "невірний тип обʼєкта."
 
 msgid "no tag message?"
-msgstr ""
+msgstr "немає допису до тегу?"
 
 #, c-format
 msgid "The tag message has been left in %s\n"
-msgstr ""
+msgstr "Допис до тегу було залишено в %s\n"
 
 msgid "list tag names"
-msgstr ""
+msgstr "показати назви тегів"
 
 msgid "print <n> lines of each tag message"
-msgstr ""
+msgstr "вивести <н> рядків кожного допису до тегу"
 
 msgid "delete tags"
 msgstr "видалити теги"
 
 msgid "verify tags"
-msgstr ""
+msgstr "перевірити теги"
 
 msgid "Tag creation options"
-msgstr ""
+msgstr "Опції створення тегів"
 
 msgid "annotated tag, needs a message"
-msgstr ""
+msgstr "анотований тег потребує допису"
 
 msgid "tag message"
-msgstr ""
+msgstr "допис до тегу"
 
 msgid "force edit of tag message"
-msgstr ""
+msgstr "примусове редагування допису до тегу"
 
 msgid "annotated and GPG-signed tag"
-msgstr ""
+msgstr "анотований та підписаний GPG-підписом тег"
 
 msgid "use another key to sign the tag"
-msgstr ""
+msgstr "використати інший ключ для підпису тегу"
 
 msgid "replace the tag if exists"
-msgstr ""
+msgstr "замінити тег, якщо він існує"
 
 msgid "create a reflog"
-msgstr "створити reflog"
+msgstr "створити журнал посилань"
 
 msgid "Tag listing options"
-msgstr ""
+msgstr "Опції виводу тегів"
 
 msgid "show tag list in columns"
-msgstr ""
+msgstr "показати список тегів в стовпчиках"
 
 msgid "print only tags that contain the commit"
-msgstr ""
+msgstr "вивести тільки теги, що містять коміти"
 
 msgid "print only tags that don't contain the commit"
-msgstr ""
+msgstr "вивести тільки теги, що не містять комітів"
 
 msgid "print only tags that are merged"
-msgstr ""
+msgstr "вивести тільки злиті теги"
 
 msgid "print only tags that are not merged"
-msgstr ""
+msgstr "вивести тільки не злиті теги"
 
 msgid "print only tags of the object"
-msgstr ""
+msgstr "вивести тільки теги обʼєкта"
 
 #, c-format
 msgid "the '%s' option is only allowed in list mode"
-msgstr ""
+msgstr "опція \"%s\" дозволена лише в режимі виводу"
 
 #, c-format
 msgid "'%s' is not a valid tag name."
@@ -12427,7 +13107,7 @@ msgstr "Неприпустимий режим очищення %s"
 
 #, c-format
 msgid "Updated tag '%s' (was %s)\n"
-msgstr ""
+msgstr "Оновлено тег \"%s\" (було %s)\n"
 
 msgid "pack exceeds maximum allowed size"
 msgstr "пакунок перевищує максимально дозволений розмір"
@@ -12459,34 +13139,39 @@ msgstr "не вдалося видалити директорію %s"
 
 #, c-format
 msgid "Testing mtime in '%s' "
-msgstr ""
+msgstr "Тестування mtime в \"%s\" "
 
 msgid "directory stat info does not change after adding a new file"
 msgstr ""
+"статистична інформація директорії не змінилась після додання нового файла"
 
 msgid "directory stat info does not change after adding a new directory"
 msgstr ""
+"статистична інформація директорії не змінилась після додання нової директорії"
 
 msgid "directory stat info changes after updating a file"
-msgstr ""
+msgstr "статистична інформація директорії змінилась після оновлення файла"
 
 msgid "directory stat info changes after adding a file inside subdirectory"
 msgstr ""
+"статистична інформація директорії змінилась після додання файла до "
+"піддиректорії"
 
 msgid "directory stat info does not change after deleting a file"
-msgstr ""
+msgstr "статистична інформація директорії не змінилась після видалення файла"
 
 msgid "directory stat info does not change after deleting a directory"
 msgstr ""
+"статистична інформація директорії не змінилась після видалення директорії"
 
 msgid " OK"
-msgstr ""
+msgstr " OK"
 
 msgid "git update-index [<options>] [--] [<file>...]"
 msgstr "git update-index [<опції>] [--] [<файл>...]"
 
 msgid "continue refresh even when index needs update"
-msgstr ""
+msgstr "продовжити оновлення, навіть якщо індекс потребує змін"
 
 msgid "refresh: ignore submodules"
 msgstr "оновити: ігнорувати підмодулі"
@@ -12495,112 +13180,118 @@ msgid "do not ignore new files"
 msgstr "не ігнорувати нові файли"
 
 msgid "let files replace directories and vice-versa"
-msgstr ""
+msgstr "дозволити файлам замінювати директорії і навпаки"
 
 msgid "notice files missing from worktree"
-msgstr ""
+msgstr "повідомляти про файли, відсутні в робочому дереві"
 
 msgid "refresh even if index contains unmerged entries"
-msgstr ""
+msgstr "оновити, навіть якщо індекс містить не злиті записи"
 
 msgid "refresh stat information"
-msgstr ""
+msgstr "оновити статистичну інформацію"
 
 msgid "like --refresh, but ignore assume-unchanged setting"
-msgstr ""
+msgstr "на кшталт --refresh, але ігнорує assume-unchanged опцію"
 
 msgid "<mode>,<object>,<path>"
-msgstr ""
+msgstr "<режим>,<обʼєкт>,<шлях>"
 
 msgid "add the specified entry to the index"
 msgstr "додати вказаний запис до індексу"
 
 msgid "mark files as \"not changing\""
-msgstr ""
+msgstr "позначити файли як \"не змінені\""
 
 msgid "clear assumed-unchanged bit"
-msgstr ""
+msgstr "очистити assumed-unchanged біт"
 
 msgid "mark files as \"index-only\""
-msgstr ""
+msgstr "позначити файли як \"тільки для індексу\""
 
 msgid "clear skip-worktree bit"
-msgstr ""
+msgstr "очистити skip-worktree біт"
 
 msgid "do not touch index-only entries"
-msgstr ""
+msgstr "ігнорувати файли, призначені тільки для індексу"
 
 msgid "add to index only; do not add content to object database"
-msgstr ""
+msgstr "додати лише до індексу; не додавати вміст до бази даних обʼєкта"
 
 msgid "remove named paths even if present in worktree"
-msgstr ""
+msgstr "видалити іменовані шляхи, навіть якщо вони присутні у робочому дереві"
 
 msgid "with --stdin: input lines are terminated by null bytes"
-msgstr ""
+msgstr "з --stdin: вхідні рядки завершуються нульовими байтами"
 
 msgid "read list of paths to be updated from standard input"
-msgstr ""
+msgstr "прочитати список шляхів для оновлення зі стандартного вводу"
 
 msgid "add entries from standard input to the index"
-msgstr ""
+msgstr "додати записи зі стандартного вводу до індексу"
 
 msgid "repopulate stages #2 and #3 for the listed paths"
-msgstr ""
+msgstr "перезаповнити етапи №2 і №3 для перелічених шляхів"
 
 msgid "only update entries that differ from HEAD"
-msgstr ""
+msgstr "оновити тільки ті записи, які відрізняються від HEAD"
 
 msgid "ignore files missing from worktree"
-msgstr ""
+msgstr "ігнорувати файли відсутні в робочому дереві"
 
 msgid "report actions to standard output"
-msgstr ""
+msgstr "звітувати про дії на стандартний вивід"
 
 msgid "(for porcelains) forget saved unresolved conflicts"
-msgstr ""
+msgstr "(для високорівневих команд) забути збережені невирішені конфлікти"
 
 msgid "write index in this format"
-msgstr ""
+msgstr "записати індекс у цьому форматі"
 
 msgid "enable or disable split index"
-msgstr ""
+msgstr "увімкнути або вимкнути розщеплений індекс"
 
 msgid "enable/disable untracked cache"
-msgstr ""
+msgstr "увімкнути/вимкнути невідстежуваний кеш"
 
 msgid "test if the filesystem supports untracked cache"
-msgstr ""
+msgstr "перевірити, чи підтримує файлова система невідстежуваний кеш"
 
 msgid "enable untracked cache without testing the filesystem"
-msgstr ""
+msgstr "увімкнути невідстежуваний кеш без тестування файлової системи"
 
 msgid "write out the index even if is not flagged as changed"
-msgstr ""
+msgstr "записати індекс, навіть якщо він не позначений як змінений"
 
 msgid "enable or disable file system monitor"
-msgstr ""
+msgstr "увімкнути або вимкнути монітор файлової системи"
 
 msgid "mark files as fsmonitor valid"
-msgstr ""
+msgstr "позначити файли придатними для fsmonitor"
 
 msgid "clear fsmonitor valid bit"
-msgstr ""
+msgstr "очистити біт придатності для fsmonitor"
 
 msgid ""
 "core.splitIndex is set to false; remove or change it, if you really want to "
 "enable split index"
 msgstr ""
+"core.splitIndex встановлено в false; видаліть або змініть його, якщо ви "
+"дійсно хочете увімкнути розщеплений індекс"
 
 msgid ""
 "core.splitIndex is set to true; remove or change it, if you really want to "
 "disable split index"
 msgstr ""
+"core.splitIndex встановлено в true; видаліть або змініть його, якщо ви "
+"дійсно хочете вимкнути розщеплений індекс"
 
 msgid ""
 "core.untrackedCache is set to true; remove or change it, if you really want "
 "to disable the untracked cache"
 msgstr ""
+"core.untrackedCache встановлено в true; видаліть або змініть його, якщо ви "
+"дійсно хочете вимкнути невідстежуваний кеш"
 
 msgid "Untracked cache disabled"
 msgstr "Невідстежуваний кеш вимкнено"
@@ -12609,6 +13300,8 @@ msgid ""
 "core.untrackedCache is set to false; remove or change it, if you really want "
 "to enable the untracked cache"
 msgstr ""
+"core.untrackedCache встановлено в false; видаліть або змініть його, якщо ви "
+"дійсно хочете увімкнути невідстежуваний кеш"
 
 #, c-format
 msgid "Untracked cache enabled for '%s'"
@@ -12616,37 +13309,42 @@ msgstr "Увімкнено невідстежуваний кеш для \"%s\""
 
 msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor"
 msgstr ""
+"core.fsmonitor не встановлено; встановіть його, якщо ви дійсно хочете "
+"увімкнути fsmonitor"
 
 msgid "fsmonitor enabled"
-msgstr ""
+msgstr "fsmonitor увімкнено"
 
 msgid ""
 "core.fsmonitor is set; remove it if you really want to disable fsmonitor"
 msgstr ""
+"core.fsmonitor встановлено; видаліть його, якщо ви дійсно хочете вимкнути "
+"fsmonitor"
 
 msgid "fsmonitor disabled"
-msgstr ""
+msgstr "fsmonitor вимкнено"
 
 msgid "git update-ref [<options>] -d <refname> [<old-val>]"
 msgstr "git update-ref [<опції>] -d <назва посилання> [<старе значення>]"
 
 msgid "git update-ref [<options>]    <refname> <new-val> [<old-val>]"
 msgstr ""
+"git update-ref [<опції>] <назва-посилання> <нове-значення> [<старе-значення>]"
 
 msgid "git update-ref [<options>] --stdin [-z]"
-msgstr ""
+msgstr "git update-ref [<опції>] --stdin [-z]"
 
 msgid "delete the reference"
 msgstr "видалити посилання"
 
 msgid "update <refname> not the one it points to"
-msgstr ""
+msgstr "оновити <назвау-посилання>, а не те, на яке воно вказує"
 
 msgid "stdin has NUL-terminated arguments"
-msgstr ""
+msgstr "stdin має аргументи, що закінчуються NUL"
 
 msgid "read updates from stdin"
-msgstr ""
+msgstr "читати оновлення з stdin"
 
 msgid "update the info files from scratch"
 msgstr "оновити інформаційні файли з чистого аркуша"
@@ -12655,78 +13353,115 @@ msgid ""
 "git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
 "                [--advertise-refs] <directory>"
 msgstr ""
+"git-upload-pack [--[no-]strict] [--timeout=<н>] [--stateless-rpc]\n"
+"                [--advertise-refs] <директорія>"
 
 msgid "quit after a single request/response exchange"
-msgstr ""
+msgstr "припинити роботу після першого запит/відповідь обміну"
 
 msgid "serve up the info/refs for git-http-backend"
-msgstr ""
+msgstr "надати info/refs для git-http-backend"
 
 msgid "do not try <directory>/.git/ if <directory> is no Git directory"
 msgstr ""
+"не пробувати <директорія>/.git/, якщо <директорія> не є директорією Git"
 
 msgid "interrupt transfer after <n> seconds of inactivity"
-msgstr ""
+msgstr "перервати передачу після <н> секунд неактивності"
 
 msgid "git verify-commit [-v | --verbose] [--raw] <commit>..."
-msgstr ""
+msgstr "git verify-commit [-v | —verbose] [--raw] <коміт>..."
 
 msgid "print commit contents"
-msgstr ""
+msgstr "показати вміст коміту"
 
 msgid "print raw gpg status output"
-msgstr ""
+msgstr "показати необроблений вивід стану gpg"
 
 msgid "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."
 msgstr ""
+"git verify-pack [-v | --verbose] [-s | --stat-only] [--] <пакунок>.idx..."
 
 msgid "verbose"
-msgstr ""
+msgstr "розгорнутий вивід"
 
 msgid "show statistics only"
-msgstr ""
+msgstr "показати тільки статистику"
 
 msgid "git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."
-msgstr ""
+msgstr "git verify-tag [-v | --verbose] [--format=<формат>] [--raw] <тег>..."
 
 msgid "print tag contents"
-msgstr ""
+msgstr "показати вміст тегу"
 
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
+"git worktree add [-f] [--detach] [--checkout] [--lock [--reason <строка>]]\n"
+"                 [--orphan] [(-b | -B) <нова-гілка>] <шлях> [<комітоподібне>]"
 
 msgid "git worktree list [-v | --porcelain [-z]]"
-msgstr ""
+msgstr "git worktree list [-v | --porcelain [-z]]"
 
 msgid "git worktree lock [--reason <string>] <worktree>"
-msgstr ""
+msgstr "git worktree lock [--reason <строка>] <робоче дерево>"
 
 msgid "git worktree move <worktree> <new-path>"
-msgstr ""
+msgstr "git worktree move <робоче-дерево> <новий-шлях>"
 
 msgid "git worktree prune [-n] [-v] [--expire <expire>]"
-msgstr ""
+msgstr "git worktree prune [-n] [-v] [--expire <термін-дії>]"
 
 msgid "git worktree remove [-f] <worktree>"
-msgstr ""
+msgstr "git worktree remove [-f] <робоче дерево>"
 
 msgid "git worktree repair [<path>...]"
-msgstr ""
+msgstr "git worktree repair [<шлях>...]"
 
 msgid "git worktree unlock <worktree>"
+msgstr "git worktree unlock <робоче дерево>"
+
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "Немає можливої джерельної гілки, що означає \"--orphan\""
+
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
 msgstr ""
+"Якщо ви хочете створити робоче дерево, що містить нову сирітську гілку\n"
+"(гілку без комітів) для цього сховища, ви можете зробити це\n"
+"за допомогою прапорця --orphan:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
 
 #, c-format
-msgid "Removing %s/%s: %s"
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
 msgstr ""
+"Якщо ви хочете створити робоче дерево, що містить нову сирітську гілку\n"
+"(гілку без комітів) для цього сховища, ви можете зробити це\n"
+"за допомогою прапорця --orphan:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
+#, c-format
+msgid "Removing %s/%s: %s"
+msgstr "Видалення %s/%s: %s"
 
 msgid "report pruned working trees"
 msgstr "звітувати про видалення робочих дерев"
 
 msgid "expire working trees older than <time>"
-msgstr ""
+msgstr "видалити робочі дерева, старіші за <час>"
 
 #, c-format
 msgid "'%s' already exists"
@@ -12741,16 +13476,24 @@ msgid ""
 "'%s' is a missing but locked worktree;\n"
 "use '%s -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"
 msgstr ""
+"\"%s\" - є відсутнім, але заблокованим робочим деревом;\n"
+"скористайтесь командою \"%s -f -f\", щоб перевизначити або \"unlock\" і "
+"\"prune\" або \"remove\", щоб очистити"
 
 #, c-format
 msgid ""
 "'%s' is a missing but already registered worktree;\n"
 "use '%s -f' to override, or 'prune' or 'remove' to clear"
 msgstr ""
+"\"%s\" - є відсутнім, але вже зареєстрованим робочим деревом;\n"
+"скористайтесь командою \"%s -f\", щоб перевизначити, або \"prune\" чи "
+"\"remove\", щоб очистити"
 
 #, c-format
 msgid "failed to copy '%s' to '%s'; sparse-checkout may not work correctly"
 msgstr ""
+"не вдалося скопіювати \"%s\" в \"%s\"; розріджений перехід може працювати "
+"некоректно"
 
 #, c-format
 msgid "failed to copy worktree config from '%s' to '%s'"
@@ -12765,26 +13508,54 @@ msgid "could not create directory of '%s'"
 msgstr "не вдалося створити директорію \"%s\""
 
 msgid "initializing"
-msgstr ""
+msgstr "ініціалізація"
 
 #, c-format
 msgid "Preparing worktree (new branch '%s')"
-msgstr ""
+msgstr "Підготовка робочого дерева (нова гілка \"%s\")"
 
 #, c-format
 msgid "Preparing worktree (resetting branch '%s'; was at %s)"
-msgstr ""
+msgstr "Підготовка робочого дерева (скидання гілки \"%s\"; була на %s)"
 
 #, c-format
 msgid "Preparing worktree (checking out '%s')"
-msgstr ""
+msgstr "Підготовка робочого дерева (перехід до \"%s\")"
+
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "недосяжне: неприпустиме посилання: %s"
 
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
+msgstr "Підготовка робочого дерева (відокремлений HEAD %s)"
+
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
 msgstr ""
+"HEAD вказує на неприпустиме (або осиротіле) посилання.\n"
+"HEAD шлях: \"%s\"\n"
+"HEAD вміст: \"%s\""
+
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"Не існує локальних або віддалених посилань, незважаючи на наявність "
+"принаймні одного віддаленого\n"
+"призначення, зупинка; скористайтесь \"add -f\", щоб перевизначити або "
+"спочатку отримати віддалене посилання"
+
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "\"%s\" і \"%s\" не можна використовувати разом"
 
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
+"перейти на <гілку>, навіть якщо вона вже активна в іншому робочому дереві"
 
 msgid "create a new branch"
 msgstr "створити нову гілку"
@@ -12792,6 +13563,9 @@ msgstr "створити нову гілку"
 msgid "create or reset a branch"
 msgstr "створити або скинути гілку"
 
+msgid "create unborn/orphaned branch"
+msgstr "створити ненароджену/сирітську гілку"
+
 msgid "populate the new working tree"
 msgstr "заповнити нове робоче дерево"
 
@@ -12799,10 +13573,10 @@ msgid "keep the new working tree locked"
 msgstr "зберегти нове робоче дерево зафіксованим"
 
 msgid "reason for locking"
-msgstr ""
+msgstr "причина блокування"
 
 msgid "set up tracking mode (see git-branch(1))"
-msgstr ""
+msgstr "налаштувати режим відстежування (дивіться git-branch(1))"
 
 msgid "try to match the new branch name with a remote-tracking branch"
 msgstr ""
@@ -12812,35 +13586,42 @@ msgstr ""
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "опції \"%s\", \"%s\" та \"%s\" не можна використовувати разом"
 
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "опції \"%s\" і \"%s\" не можна використовувати разом"
+
+msgid "<commit-ish>"
+msgstr "<комітоподібне>"
+
 msgid "added with --lock"
-msgstr ""
+msgstr "додано з --lock"
 
 msgid "--[no-]track can only be used if a new branch is created"
-msgstr ""
+msgstr "--[no-]track можна використовувати лише при створенні нової гілки"
 
 msgid "show extended annotations and reasons, if available"
-msgstr ""
+msgstr "показувати розширені анотації та причини, якщо вони доступні"
 
 msgid "add 'prunable' annotation to worktrees older than <time>"
-msgstr ""
+msgstr "додати анотацію \"prunable\" до робочих дерев, старіших за <час>"
 
 msgid "terminate records with a NUL character"
-msgstr ""
+msgstr "завершувати записи символом NUL"
 
 #, c-format
 msgid "'%s' is not a working tree"
 msgstr "\"%s\" не є робочим деревом"
 
 msgid "The main working tree cannot be locked or unlocked"
-msgstr ""
+msgstr "Головне робоче дерево неможливо заблокувати або розблокувати"
 
 #, c-format
 msgid "'%s' is already locked, reason: %s"
-msgstr ""
+msgstr "\"%s\" вже заблоковано, причина: %s"
 
 #, c-format
 msgid "'%s' is already locked"
-msgstr ""
+msgstr "\"%s\" вже заблоковано"
 
 #, c-format
 msgid "'%s' is not locked"
@@ -12848,9 +13629,11 @@ msgstr "\"%s\" не зафіксовано"
 
 msgid "working trees containing submodules cannot be moved or removed"
 msgstr ""
+"робочі дерева, що містять підмодулі, не можуть бути переміщені або видалені"
 
 msgid "force move even if worktree is dirty or locked"
 msgstr ""
+"перемістити примусово, навіть якщо робоче дерево забруднене або заблоковане"
 
 #, c-format
 msgid "'%s' is a main working tree"
@@ -12858,22 +13641,28 @@ msgstr "\"%s\" є головним робочим деревом"
 
 #, c-format
 msgid "could not figure out destination name from '%s'"
-msgstr ""
+msgstr "не вдалося визначити назву призначення з \"%s\""
 
 #, c-format
 msgid ""
 "cannot move a locked working tree, lock reason: %s\n"
 "use 'move -f -f' to override or unlock first"
 msgstr ""
+"неможливо перемістити заблоковане робоче дерево, причина блокування: %s\n"
+"скористайтесь командою \"move -f -f\", щоб спочатку перевизначити або "
+"розблокувати його"
 
 msgid ""
 "cannot move a locked working tree;\n"
 "use 'move -f -f' to override or unlock first"
 msgstr ""
+"неможливо перемістити заблоковане робоче дерево;\n"
+"скористайтесь командою \"move -f -f\", щоб спочатку перевизначити або "
+"розблокувати його"
 
 #, c-format
 msgid "validation failed, cannot move working tree: %s"
-msgstr ""
+msgstr "валідація завершилася невдало, неможливо перемістити робоче дерево: %s"
 
 #, c-format
 msgid "failed to move '%s' to '%s'"
@@ -12886,6 +13675,8 @@ msgstr "не вдалося виконати \"git status\" на \"%s\""
 #, c-format
 msgid "'%s' contains modified or untracked files, use --force to delete it"
 msgstr ""
+"\"%s\" містить змінені або невідстежувані файли, скористайтесь --force, щоб "
+"видалити їх"
 
 #, c-format
 msgid "failed to run 'git status' on '%s', code %d"
@@ -12893,44 +13684,49 @@ msgstr "не вдалося виконати \"git status\" на \"%s\", код
 
 msgid "force removal even if worktree is dirty or locked"
 msgstr ""
+"видалити примусово, навіть якщо робоче дерево забруднене або заблоковане"
 
 #, c-format
 msgid ""
 "cannot remove a locked working tree, lock reason: %s\n"
 "use 'remove -f -f' to override or unlock first"
 msgstr ""
+"неможливо видалити заблоковане робоче дерево, причина блокування: %s\n"
+"скористайтесь \"remove -f -f\", щоб перевизначити або розблокувати"
 
 msgid ""
 "cannot remove a locked working tree;\n"
 "use 'remove -f -f' to override or unlock first"
 msgstr ""
+"неможливо видалити заблоковане робоче дерево;\n"
+"скористайтесь \"remove -f -f\", щоб перевизначити або розблокувати"
 
 #, c-format
 msgid "validation failed, cannot remove working tree: %s"
-msgstr ""
+msgstr "валідація завершилася невдало, неможливо видалити робоче дерево: %s"
 
 #, c-format
 msgid "repair: %s: %s"
-msgstr ""
+msgstr "відремонтувати: %s: %s"
 
 #, c-format
 msgid "error: %s: %s"
-msgstr ""
+msgstr "помилка: %s: %s"
 
 msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
-msgstr ""
+msgstr "git write-tree [--missing-ok] [--prefix=<префікс>/]"
 
 msgid "<prefix>/"
-msgstr ""
+msgstr "<префікс>/"
 
 msgid "write tree object for a subdirectory <prefix>"
-msgstr ""
+msgstr "записати обʼєкт дерева для піддиректорії <префікс>"
 
 msgid "only useful for debugging"
-msgstr ""
+msgstr "корисно лише для відлагодження"
 
 msgid "core.fsyncMethod = batch is unsupported on this platform"
-msgstr ""
+msgstr "core.fsyncMethod = batch не підтримується на цій платформі"
 
 #, c-format
 msgid "could not parse bundle list key %s with value '%s'"
@@ -12938,13 +13734,13 @@ msgstr "не вдалося розібрати ключ списку пакун
 
 #, c-format
 msgid "bundle list at '%s' has no mode"
-msgstr ""
+msgstr "список пакунків на \"%s\" не має режиму"
 
 msgid "failed to create temporary file"
 msgstr "не вдалося створити тимчасовий файл"
 
 msgid "insufficient capabilities"
-msgstr ""
+msgstr "недостатні здібності"
 
 #, c-format
 msgid "file downloaded from '%s' is not a bundle"
@@ -12955,11 +13751,11 @@ msgstr "не вдалося зберегти токен максимальног
 
 #, c-format
 msgid "unrecognized bundle mode from URI '%s'"
-msgstr ""
+msgstr "нерозпізнаний режим пакунка з URI \"%s\""
 
 #, c-format
 msgid "exceeded bundle URI recursion limit (%d)"
-msgstr ""
+msgstr "перевищено ліміт рекурсії URI пакунка (%d)"
 
 #, c-format
 msgid "failed to download bundle from URI '%s'"
@@ -12967,23 +13763,23 @@ msgstr "не вдалося завантажити пакунок з URI \"%s\""
 
 #, c-format
 msgid "file at URI '%s' is not a bundle or bundle list"
-msgstr ""
+msgstr "файл з URI \"%s\" не є пакунком або списком пакунків"
 
 #, c-format
 msgid "bundle-uri: unexpected argument: '%s'"
-msgstr ""
+msgstr "bundle-uri: неочікуваний аргумент: \"%s\""
 
 msgid "bundle-uri: expected flush after arguments"
-msgstr ""
+msgstr "bundle-uri: очікувалось flush після аргументів"
 
 msgid "bundle-uri: got an empty line"
-msgstr ""
+msgstr "bundle-uri: отримано порожній рядок"
 
 msgid "bundle-uri: line is not of the form 'key=value'"
-msgstr ""
+msgstr "bundle-uri: рядок не відповідає формату \"key=value\""
 
 msgid "bundle-uri: line has empty key or value"
-msgstr ""
+msgstr "bundle-uri: рядок має порожній ключ або значення"
 
 #, c-format
 msgid "unrecognized bundle hash algorithm: %s"
@@ -12995,39 +13791,49 @@ msgstr "невідома властивість \"%s\""
 
 #, c-format
 msgid "'%s' does not look like a v2 or v3 bundle file"
-msgstr ""
+msgstr "\"%s\" не схожий на файл пакунка v2 або v3"
 
 #, c-format
 msgid "unrecognized header: %s%s (%d)"
-msgstr ""
+msgstr "нерозпізнаний заголовок: %s%s (%d)"
 
 msgid "Repository lacks these prerequisite commits:"
-msgstr ""
+msgstr "У сховищі не вистачає обовʼязкових комітів:"
 
 msgid "need a repository to verify a bundle"
-msgstr ""
+msgstr "потрібне сховище для перевірки пакунка"
 
 msgid ""
 "some prerequisite commits exist in the object store, but are not connected "
 "to the repository's history"
 msgstr ""
+"деякі попередні коміти існують у місці збереження обʼєктів, але не повʼязані "
+"з історією сховища"
 
 #, c-format
 msgid "The bundle contains this ref:"
 msgid_plural "The bundle contains these %<PRIuMAX> refs:"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Пакунок містить це %<PRIuMAX> посилання:"
+msgstr[1] "Пакунок містить ці %<PRIuMAX> посилання:"
+msgstr[2] "Пакунок містить ці %<PRIuMAX> посилань:"
 
 msgid "The bundle records a complete history."
-msgstr ""
+msgstr "Пакунок записує повну історію."
 
 #, c-format
 msgid "The bundle requires this ref:"
 msgid_plural "The bundle requires these %<PRIuMAX> refs:"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Пакунок потребує це %<PRIuMAX> посилання:"
+msgstr[1] "Пакунок потребує ці %<PRIuMAX> посилання:"
+msgstr[2] "Пакунок потребує ці %<PRIuMAX> посилань:"
+
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "Пакунок використовує такий алгоритм хешування: %s"
+
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "Пакунок використовує такий фільтр: %s"
 
 msgid "unable to dup bundle descriptor"
 msgstr "не вдалося продублювати дескриптор пакунка"
@@ -13036,44 +13842,44 @@ msgid "Could not spawn pack-objects"
 msgstr "Не вдалося розмножити об’єкти пакунків"
 
 msgid "pack-objects died"
-msgstr ""
+msgstr "pack-objects завершився невдало"
 
 #, c-format
 msgid "ref '%s' is excluded by the rev-list options"
-msgstr ""
+msgstr "посилання \"%s\" виключено опціями rev-list"
 
 #, c-format
 msgid "unsupported bundle version %d"
-msgstr ""
+msgstr "непідтримувана версія пакунка %d"
 
 #, c-format
 msgid "cannot write bundle version %d with algorithm %s"
-msgstr ""
+msgstr "неможливо записати версію пакунка %d з алгоритмом %s"
 
 msgid "Refusing to create empty bundle."
-msgstr ""
+msgstr "Відмовлено в створенні порожнього пакунка."
 
 #, c-format
 msgid "cannot create '%s'"
 msgstr "неможливо створити \"%s\""
 
 msgid "index-pack died"
-msgstr ""
+msgstr "index-pack завершився невдало"
 
 msgid "terminating chunk id appears earlier than expected"
-msgstr ""
+msgstr "ідентифікатор завершення фрагмента зʼявився раніше, ніж очікувалось"
 
 #, c-format
 msgid "improper chunk offset(s) %<PRIx64> and %<PRIx64>"
-msgstr ""
+msgstr "невірне зміщення шматка(ів) %<PRIx64> та %<PRIx64>"
 
 #, c-format
 msgid "duplicate chunk ID %<PRIx32> found"
-msgstr ""
+msgstr "знайдено дубльований шматок з ідентифікатором %<PRIx32>"
 
 #, c-format
 msgid "final chunk has non-zero id %<PRIx32>"
-msgstr ""
+msgstr "заключний шматок має ненульовий ідентифікатор %<PRIx32>"
 
 msgid "invalid hash version"
 msgstr "неприпустима версія хешу"
@@ -13083,373 +13889,377 @@ msgid "invalid color value: %.*s"
 msgstr "неприпустиме значення кольору: %.*s"
 
 msgid "Add file contents to the index"
-msgstr ""
+msgstr "Додати вміст файлу до індексу"
 
 msgid "Apply a series of patches from a mailbox"
-msgstr ""
+msgstr "Застосувати серію латок з поштової скриньки"
 
 msgid "Annotate file lines with commit information"
-msgstr ""
+msgstr "Анотувати рядки файлів з інформацією про коміти"
 
 msgid "Apply a patch to files and/or to the index"
-msgstr ""
+msgstr "Застосувати латку до файлів та/або до індексу"
 
 msgid "Import a GNU Arch repository into Git"
-msgstr ""
+msgstr "Імпортувати GNU Arch сховище до Git"
 
 msgid "Create an archive of files from a named tree"
-msgstr ""
+msgstr "Створити архів файлів з названого дерева"
 
 msgid "Use binary search to find the commit that introduced a bug"
-msgstr ""
+msgstr "Використати бінарний пошук, щоб знайти коміт, який вніс помилку"
 
 msgid "Show what revision and author last modified each line of a file"
-msgstr ""
+msgstr "Показати, яка ревізія та автор востаннє змінювали кожен рядок файлу"
 
 msgid "List, create, or delete branches"
 msgstr "Показати, створити або видалити гілки"
 
 msgid "Collect information for user to file a bug report"
-msgstr ""
+msgstr "Зібрати інформацію, щоб користувач міг подати звіт про помилку"
 
 msgid "Move objects and refs by archive"
-msgstr ""
+msgstr "Перенести архів обʼєктів та посилань"
 
 msgid "Provide content or type and size information for repository objects"
-msgstr ""
+msgstr "Показати вміст або інформацію про тип і розмір обʼєктів сховища"
 
 msgid "Display gitattributes information"
-msgstr ""
+msgstr "Відобразити інформацію про gitattributes"
 
 msgid "Debug gitignore / exclude files"
-msgstr ""
+msgstr "Відлагодити gitignore / вилучити файли"
 
 msgid "Show canonical names and email addresses of contacts"
-msgstr ""
+msgstr "Показати канонічні імена та адреси електронної пошти контактів"
 
 msgid "Ensures that a reference name is well formed"
-msgstr ""
+msgstr "Забезпечує правильне формування назви посилання"
 
 msgid "Switch branches or restore working tree files"
 msgstr "Перемкнути гілки або відновити файли робочого дерева"
 
 msgid "Copy files from the index to the working tree"
-msgstr ""
+msgstr "Скопіювати файли з індексу в робоче дерево"
 
 msgid "Find commits yet to be applied to upstream"
-msgstr ""
+msgstr "Знайти коміти, які ще не були застосовані до першоджерельного сховища"
 
 msgid "Apply the changes introduced by some existing commits"
-msgstr ""
+msgstr "Застосувати зміни, внесені деякими існуючими комітами"
 
 msgid "Graphical alternative to git-commit"
-msgstr ""
+msgstr "Графічна альтернатива git-commit"
 
 msgid "Remove untracked files from the working tree"
 msgstr "Видалити невідстежувані файли з робочого дерева"
 
 msgid "Clone a repository into a new directory"
-msgstr ""
+msgstr "Клонувати сховище в нову директорію"
 
 msgid "Display data in columns"
-msgstr ""
+msgstr "Відобразити дані в стовпчиках"
 
 msgid "Record changes to the repository"
 msgstr "Записати зміни у сховище"
 
 msgid "Write and verify Git commit-graph files"
-msgstr ""
+msgstr "Записати та перевірити файли коміт-графа Git"
 
 msgid "Create a new commit object"
-msgstr ""
+msgstr "Створити новий обʼєкт коміту"
 
 msgid "Get and set repository or global options"
-msgstr ""
+msgstr "Отримати та встановити параметри сховища або глобальні параметри"
 
 msgid "Count unpacked number of objects and their disk consumption"
-msgstr ""
+msgstr "Підрахувати кількість розпакованих обʼєктів та їхнє використання диска"
 
 msgid "Retrieve and store user credentials"
-msgstr ""
+msgstr "Отримати та зберегти облікові дані користувача"
 
 msgid "Helper to temporarily store passwords in memory"
-msgstr ""
+msgstr "Помічник для тимчасового зберігання паролів у памʼяті"
 
 msgid "Helper to store credentials on disk"
-msgstr ""
+msgstr "Помічник для зберігання облікових даних на диску"
 
 msgid "Export a single commit to a CVS checkout"
-msgstr ""
+msgstr "Експортувати окремий коміт до CVS стану"
 
 msgid "Salvage your data out of another SCM people love to hate"
-msgstr ""
+msgstr "Врятувати свої дані з іншої SCM, яку всі так неполюбляють"
 
 msgid "A CVS server emulator for Git"
-msgstr ""
+msgstr "Емулятор CVS сервера для Git"
 
 msgid "A really simple server for Git repositories"
-msgstr ""
+msgstr "Дуже простий сервер для Git сховищ"
 
 msgid "Give an object a human readable name based on an available ref"
 msgstr ""
+"Надати обʼєкту читабельну для людини назву на основі наявного посилання"
 
 msgid "Generate a zip archive of diagnostic information"
-msgstr ""
+msgstr "Згенерувати zip-архів з діагностичною інформацією"
 
 msgid "Show changes between commits, commit and working tree, etc"
 msgstr "Показати зміни між комітами, комітом та робочим деревом, тощо"
 
 msgid "Compares files in the working tree and the index"
-msgstr ""
+msgstr "Порівнює файли в робочому дереві та індексі"
 
 msgid "Compare a tree to the working tree or index"
 msgstr "Порівняти дерево з робочим деревом або індексом"
 
 msgid "Compares the content and mode of blobs found via two tree objects"
 msgstr ""
+"Порівнює вміст та режим blob обʼєктів, знайдених у двох обʼєктах дерева"
 
 msgid "Show changes using common diff tools"
-msgstr ""
+msgstr "Показати зміни за допомогою звичайних diff засобів"
 
 msgid "Git data exporter"
-msgstr ""
+msgstr "Експортер даних Git"
 
 msgid "Backend for fast Git data importers"
-msgstr ""
+msgstr "Обробник для швидких імпортерів даних Git"
 
 msgid "Download objects and refs from another repository"
-msgstr ""
+msgstr "Завантажити обʼєкти та посилання з іншого сховища"
 
 msgid "Receive missing objects from another repository"
-msgstr ""
+msgstr "Отримати відсутні обʼєкти з іншого сховища"
 
 msgid "Rewrite branches"
 msgstr "Перезаписати гілки"
 
 msgid "Produce a merge commit message"
-msgstr ""
+msgstr "Створити допис до коміту злиття"
 
 msgid "Output information on each ref"
-msgstr ""
+msgstr "Вивести інформацію про кожне посилання"
 
 msgid "Run a Git command on a list of repositories"
-msgstr ""
+msgstr "Запустити команду Git на списку сховищ"
 
 msgid "Prepare patches for e-mail submission"
-msgstr ""
+msgstr "Підготувати латки для надсилання електронною поштою"
 
 msgid "Verifies the connectivity and validity of the objects in the database"
-msgstr ""
+msgstr "Перевіряє звʼязність та валідність обʼєктів у базі даних"
 
 msgid "Cleanup unnecessary files and optimize the local repository"
-msgstr ""
+msgstr "Видалити непотрібні файли та оптимізувати локальне сховище"
 
 msgid "Extract commit ID from an archive created using git-archive"
 msgstr ""
+"Витягти ідентифікатор коміту з архіву, створеного за допомогою git-archive"
 
 msgid "Print lines matching a pattern"
-msgstr ""
+msgstr "Вивести рядки, що відповідають шаблону"
 
 msgid "A portable graphical interface to Git"
-msgstr ""
+msgstr "Портативний графічний інтерфейс до Git"
 
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr ""
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "Обчислити ідентифікатор обʼєкта та за бажанням створити обʼєкт з файлу"
 
 msgid "Display help information about Git"
-msgstr ""
+msgstr "Відобразити довідкову інформацію про Git"
 
 msgid "Run git hooks"
-msgstr ""
+msgstr "Запустити git гачки"
 
 msgid "Server side implementation of Git over HTTP"
-msgstr ""
+msgstr "Серверна реалізація Git через HTTP"
 
 msgid "Download from a remote Git repository via HTTP"
-msgstr ""
+msgstr "Завантажити з віддаленого Git сховища через HTTP"
 
 msgid "Push objects over HTTP/DAV to another repository"
-msgstr ""
+msgstr "Надіслати обʼєкти через HTTP/DAV до іншого сховища"
 
 msgid "Send a collection of patches from stdin to an IMAP folder"
-msgstr ""
+msgstr "Надіслати збірку латок з stdin до теки IMAP"
 
 msgid "Build pack index file for an existing packed archive"
-msgstr ""
+msgstr "Побудувати індексний файл пакунка для існуючого запакованого архіву"
 
 msgid "Create an empty Git repository or reinitialize an existing one"
-msgstr ""
+msgstr "Створити порожнє Git сховище або переініціалізувати існуюче"
 
 msgid "Instantly browse your working repository in gitweb"
-msgstr ""
+msgstr "Миттєво переглянути своє робоче сховище в gitweb"
 
 msgid "Add or parse structured information in commit messages"
-msgstr ""
+msgstr "Додати або розібрати структуровану інформацію в дописах до комітів"
 
 msgid "Show commit logs"
-msgstr "Ð\9fоказаÑ\82и Ð»Ð¾Ð³ ÐºÐ¾Ð¼Ñ\96Ñ\82а"
+msgstr "Ð\9fоказаÑ\82и Ð¶Ñ\83Ñ\80нал ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\83"
 
 msgid "Show information about files in the index and the working tree"
-msgstr ""
+msgstr "Показати інформацію про файли в індексі та робочому дереві"
 
 msgid "List references in a remote repository"
 msgstr "Показати посилання у віддаленому сховищі"
 
 msgid "List the contents of a tree object"
-msgstr ""
+msgstr "Показати вміст обʼєкта дерева"
 
 msgid "Extracts patch and authorship from a single e-mail message"
-msgstr ""
+msgstr "Витягує латку та авторство з одного повідомлення електронної пошти"
 
 msgid "Simple UNIX mbox splitter program"
-msgstr ""
+msgstr "Проста програма-розщеплювач UNIX mbox"
 
 msgid "Run tasks to optimize Git repository data"
-msgstr ""
+msgstr "Запустити завдання для оптимізації даних Git сховища"
 
 msgid "Join two or more development histories together"
-msgstr ""
+msgstr "Обʼєднати дві або більше історій розробки"
 
 msgid "Find as good common ancestors as possible for a merge"
-msgstr ""
+msgstr "Знайти якомога кращого спільного предка для злиття"
 
 msgid "Run a three-way file merge"
-msgstr ""
+msgstr "Запустити тристороннє злиття файлів"
 
 msgid "Run a merge for files needing merging"
-msgstr ""
+msgstr "Запустити злиття для файлів, які потрібно обʼєднати"
 
 msgid "The standard helper program to use with git-merge-index"
-msgstr ""
+msgstr "Стандартна допоміжна програма для використання з git-merge-index"
 
 msgid "Perform merge without touching index or working tree"
-msgstr ""
+msgstr "Виконати злиття, не торкаючись індексу або робочого дерева"
 
 msgid "Run merge conflict resolution tools to resolve merge conflicts"
 msgstr ""
+"Запустити інструменти вирішення конфліктів, щоб вирішити конфлікти злиття"
 
 msgid "Creates a tag object with extra validation"
-msgstr ""
+msgstr "Створює обʼєкт тегу з додатковою перевіркою"
 
 msgid "Build a tree-object from ls-tree formatted text"
-msgstr ""
+msgstr "Побудувати обʼєкт дерева з ls-tree форматованого тексту"
 
 msgid "Write and verify multi-pack-indexes"
-msgstr ""
+msgstr "Записати і перевірити multi-pack-indexes"
 
 msgid "Move or rename a file, a directory, or a symlink"
-msgstr ""
+msgstr "Перемістити або перейменувати файл, директорію або символьне посилання"
 
 msgid "Find symbolic names for given revs"
-msgstr ""
+msgstr "Знайти символьни назви для заданих ревізій"
 
 msgid "Add or inspect object notes"
-msgstr "Додайте або перевірте нотатки до обʼєктів"
+msgstr "Додати або перевірити нотатки до обʼєктів"
 
 msgid "Import from and submit to Perforce repositories"
-msgstr ""
+msgstr "Імпортувати з та надсилати до Perforce сховищ"
 
 msgid "Create a packed archive of objects"
-msgstr ""
+msgstr "Створити запакований архів обʼєктів"
 
 msgid "Find redundant pack files"
 msgstr "Знайти зайві файли пакунків"
 
 msgid "Pack heads and tags for efficient repository access"
-msgstr ""
+msgstr "Запакувати верхівки та теги для ефективного доступу до сховища"
 
 msgid "Compute unique ID for a patch"
-msgstr ""
+msgstr "Обчислити унікальний ідентифікатор для патчу"
 
 msgid "Prune all unreachable objects from the object database"
-msgstr ""
+msgstr "Видалити всі недосяжні обʼєкти з бази даних обʼєктів"
 
 msgid "Remove extra objects that are already in pack files"
-msgstr ""
+msgstr "Видалити зайві обʼєкти, які вже є у файлах пакунків"
 
 msgid "Fetch from and integrate with another repository or a local branch"
-msgstr ""
+msgstr "Отримати та інтегрувати з іншим сховищем або локальною гілкою"
 
 msgid "Update remote refs along with associated objects"
-msgstr ""
+msgstr "Оновити віддалені посилання разом з асоційованими обʼєктами"
 
 msgid "Applies a quilt patchset onto the current branch"
-msgstr ""
+msgstr "Застосовує набір латок до поточної гілки"
 
 msgid "Compare two commit ranges (e.g. two versions of a branch)"
-msgstr ""
+msgstr "Порівняти два діапазони комітів (наприклад, дві версії гілки)"
 
 msgid "Reads tree information into the index"
-msgstr ""
+msgstr "Зчитує інформацію про дерево в індекс"
 
 msgid "Reapply commits on top of another base tip"
-msgstr ""
+msgstr "Застосувати коміти поверх іншої верхівки бази"
 
 msgid "Receive what is pushed into the repository"
-msgstr ""
+msgstr "Отримати те, що надсилається до сховища"
 
 msgid "Manage reflog information"
-msgstr ""
+msgstr "Керування інформацією журналу посилань"
 
 msgid "Manage set of tracked repositories"
 msgstr "Керувати набором відстежуваних сховищ"
 
 msgid "Pack unpacked objects in a repository"
-msgstr ""
+msgstr "Запакувати розпаковані обʼєкти у сховищі"
 
 msgid "Create, list, delete refs to replace objects"
-msgstr ""
+msgstr "Створити, показати, видалити посилання для об’єктів заміни"
 
 msgid "Generates a summary of pending changes"
-msgstr ""
+msgstr "Створює підсумок змін для розгляду"
 
 msgid "Reuse recorded resolution of conflicted merges"
-msgstr ""
+msgstr "Використати повторно записане розв’язання конфліктних злиттів"
 
 msgid "Reset current HEAD to the specified state"
-msgstr ""
+msgstr "Скинути поточний HEAD до вказаного стану"
 
 msgid "Restore working tree files"
 msgstr "Відновити файли робочого дерева"
 
 msgid "Lists commit objects in reverse chronological order"
-msgstr ""
+msgstr "Показувати обʼєкти коміту у зворотному хронологічному порядку"
 
 msgid "Pick out and massage parameters"
-msgstr ""
+msgstr "Визначення та обробка параметрів"
 
 msgid "Revert some existing commits"
-msgstr ""
+msgstr "Вивернути деякі існуючі коміти"
 
 msgid "Remove files from the working tree and from the index"
-msgstr ""
+msgstr "Видалити файли з робочого дерева та з індексу"
 
 msgid "Send a collection of patches as emails"
-msgstr ""
+msgstr "Надіслати колекцію латок у вигляді електронних листів"
 
 msgid "Push objects over Git protocol to another repository"
-msgstr ""
+msgstr "Надіслати обʼєкти за протоколом Git до іншого сховища"
 
 msgid "Git's i18n setup code for shell scripts"
-msgstr ""
+msgstr "Код налаштування i18n у Git для скриптів оболонки"
 
 msgid "Common Git shell script setup code"
-msgstr ""
+msgstr "Загальний код налаштування скриптів оболонки Git"
 
 msgid "Restricted login shell for Git-only SSH access"
-msgstr ""
+msgstr "Обмежений логін оболонки для доступу по SSH лише для Git"
 
 msgid "Summarize 'git log' output"
-msgstr ""
+msgstr "Підсумувати вивід \"git log\""
 
 msgid "Show various types of objects"
-msgstr ""
+msgstr "Показати різні типи об’єктів"
 
 msgid "Show branches and their commits"
 msgstr "Показати гілки та їхні коміти"
 
 msgid "Show packed archive index"
-msgstr ""
+msgstr "Показати індекс запакованого архіву"
 
 msgid "List references in a local repository"
 msgstr "Показати посилання у локальному сховищі"
@@ -13458,251 +14268,256 @@ msgid "Reduce your working tree to a subset of tracked files"
 msgstr "Скоротити робоче дерево до підмножини відстежуваних файлів"
 
 msgid "Add file contents to the staging area"
-msgstr ""
+msgstr "Додати вміст файлу до області індексації"
 
 msgid "Stash the changes in a dirty working directory away"
-msgstr ""
+msgstr "Перенести зміни в брудній робочій директорії до схову"
 
 msgid "Show the working tree status"
 msgstr "Показати стан робочого дерева"
 
 msgid "Remove unnecessary whitespace"
-msgstr ""
+msgstr "Видалити зайві пробіли"
 
 msgid "Initialize, update or inspect submodules"
-msgstr ""
+msgstr "Ініціалізувати, оновити або перевірити підмодулі"
 
 msgid "Bidirectional operation between a Subversion repository and Git"
-msgstr ""
+msgstr "Двонаправлена операція між Subversion сховищем та Git"
 
 msgid "Switch branches"
 msgstr "Переключити гілки"
 
 msgid "Read, modify and delete symbolic refs"
-msgstr ""
+msgstr "Прочитати, змінити та видалити символьні посилання"
 
 msgid "Create, list, delete or verify a tag object signed with GPG"
 msgstr ""
+"Створити, показати, видалити або перевірити обʼєкт тегу, підписаний GPG"
 
 msgid "Creates a temporary file with a blob's contents"
-msgstr ""
+msgstr "Створює тимчасовий файл із вмістом blob"
 
 msgid "Unpack objects from a packed archive"
-msgstr ""
+msgstr "Розпакувати обʼєкти із запакованого архіву"
 
 msgid "Register file contents in the working tree to the index"
-msgstr ""
+msgstr "Зареєструвати вміст файлу робочого дерева в індексі"
 
 msgid "Update the object name stored in a ref safely"
-msgstr ""
+msgstr "Безпечно оновити назву обʼєкта, що зберігається в посиланні"
 
 msgid "Update auxiliary info file to help dumb servers"
-msgstr ""
+msgstr "Оновити додатковий інформаційний файл для допомоги \"тупим\" серверам"
 
 msgid "Send archive back to git-archive"
-msgstr ""
+msgstr "Надіслати архів назад до git-archive"
 
 msgid "Send objects packed back to git-fetch-pack"
-msgstr ""
+msgstr "Надіслати запаковані обʼєкти назад до git-fetch-pack"
 
 msgid "Show a Git logical variable"
-msgstr ""
+msgstr "Показати логічну змінну Git"
 
 msgid "Check the GPG signature of commits"
-msgstr ""
+msgstr "Перевірити GPG-підпис комітів"
 
 msgid "Validate packed Git archive files"
-msgstr ""
+msgstr "Перевірити запаковані файли Git архіву"
 
 msgid "Check the GPG signature of tags"
-msgstr ""
+msgstr "Перевірити GPG-підпис тегів"
 
 msgid "Display version information about Git"
-msgstr ""
+msgstr "Показати інформацію про версію Git"
 
 msgid "Show logs with difference each commit introduces"
-msgstr ""
+msgstr "Показати журнал з різницею, яку вносить кожен коміт"
 
 msgid "Manage multiple working trees"
 msgstr "Керувати кількома робочими деревами"
 
 msgid "Create a tree object from the current index"
-msgstr ""
+msgstr "Створити обʼєкт дерева з поточного індексу"
 
 msgid "Defining attributes per path"
-msgstr ""
+msgstr "Визначення атрибутів для кожного шляху"
 
 msgid "Git command-line interface and conventions"
-msgstr ""
+msgstr "Інтерфейс та конвенції командного рядка Git"
 
 msgid "A Git core tutorial for developers"
-msgstr ""
+msgstr "Інструкція по ядру Git для розробників"
 
 msgid "Providing usernames and passwords to Git"
-msgstr ""
+msgstr "Надання імен користувачів та паролів до Git"
 
 msgid "Git for CVS users"
-msgstr ""
+msgstr "Git для користувачів CVS"
 
 msgid "Tweaking diff output"
-msgstr ""
+msgstr "Налаштування виводу різниці"
 
 msgid "A useful minimum set of commands for Everyday Git"
-msgstr ""
+msgstr "Корисний мінімальний набір команд для повсякденного використання Git"
 
 msgid "Frequently asked questions about using Git"
-msgstr ""
+msgstr "Поширені запитання про використання Git"
 
 msgid "The bundle file format"
-msgstr "Формат файлу пакета"
+msgstr "Формат файлу пакунка"
 
 msgid "Chunk-based file formats"
-msgstr ""
+msgstr "Файлові формати на основі шматків"
 
 msgid "Git commit-graph format"
-msgstr ""
+msgstr "Формат Git коміт-графа"
 
 msgid "Git index format"
-msgstr ""
+msgstr "Формат Git індекса"
 
 msgid "Git pack format"
-msgstr ""
+msgstr "Формат Git пакунка"
 
 msgid "Git cryptographic signature formats"
-msgstr ""
+msgstr "Формати криптографічного підпису Git"
 
 msgid "A Git Glossary"
-msgstr ""
+msgstr "Git словник"
 
 msgid "Hooks used by Git"
-msgstr ""
+msgstr "Гачки, що використовує Git"
 
 msgid "Specifies intentionally untracked files to ignore"
-msgstr ""
+msgstr "Вказує навмисно невідстежувані файли для ігнорування"
 
 msgid "The Git repository browser"
-msgstr ""
+msgstr "Браузер сховища Git"
 
 msgid "Map author/committer names and/or E-Mail addresses"
-msgstr ""
+msgstr "Зробити мапу імен авторів/комітерів та/або адрес електронної пошти"
 
 msgid "Defining submodule properties"
-msgstr ""
+msgstr "Визначення властивостей підмодулів"
 
 msgid "Git namespaces"
-msgstr ""
+msgstr "Простори імен Git"
 
 msgid "Protocol v0 and v1 capabilities"
-msgstr ""
+msgstr "Здібності протоколів v0 та v1"
 
 msgid "Things common to various protocols"
-msgstr ""
+msgstr "Спільні риси різних протоколів"
 
 msgid "Git HTTP-based protocols"
-msgstr ""
+msgstr "Git протоколи на основі HTTP"
 
 msgid "How packs are transferred over-the-wire"
-msgstr ""
+msgstr "Як пакунки передаються по дроту"
 
 msgid "Git Wire Protocol, Version 2"
-msgstr ""
+msgstr "Протокол Git Wire, версія 2"
 
 msgid "Helper programs to interact with remote repositories"
-msgstr ""
+msgstr "Програми-помічники для взаємодії з віддаленими сховищами"
 
 msgid "Git Repository Layout"
-msgstr ""
+msgstr "Схема Git сховища"
 
 msgid "Specifying revisions and ranges for Git"
-msgstr ""
+msgstr "Визначення ревізій та діапазонів для Git"
 
 msgid "Mounting one repository inside another"
-msgstr ""
+msgstr "Монтування одного сховища всередині іншого"
 
 msgid "A tutorial introduction to Git"
-msgstr ""
+msgstr "Навчальний вступ до Git"
 
 msgid "A tutorial introduction to Git: part two"
-msgstr ""
+msgstr "Навчальний вступ до Git: частина друга"
 
 msgid "Git web interface (web frontend to Git repositories)"
-msgstr ""
+msgstr "Веб-інтерфейс Git (веб-фронтенд до сховищ Git)"
 
 msgid "An overview of recommended workflows with Git"
-msgstr ""
+msgstr "Огляд рекомендованих робочих процесів з Git"
 
 msgid "A tool for managing large Git repositories"
-msgstr ""
+msgstr "Інструмент для керування великими сховищами Git"
 
 msgid "commit-graph file is too small"
-msgstr ""
+msgstr "файл коміт-графа занадто малий"
 
 #, c-format
 msgid "commit-graph signature %X does not match signature %X"
-msgstr ""
+msgstr "підпис коміт-графа %X не збігається з підписом %X"
 
 #, c-format
 msgid "commit-graph version %X does not match version %X"
-msgstr ""
+msgstr "версія коміт-графа %X не збігається з версією %X"
 
 #, c-format
 msgid "commit-graph hash version %X does not match version %X"
-msgstr ""
+msgstr "хеш версія коміт-графа %X не збігається з версією %X"
 
 #, c-format
 msgid "commit-graph file is too small to hold %u chunks"
-msgstr ""
+msgstr "файл коміт-графа занадто малий, щоб вмістити %u шматків"
 
 msgid "commit-graph has no base graphs chunk"
-msgstr ""
+msgstr "коміт-граф не має шматка базових графів"
 
 msgid "commit-graph chain does not match"
-msgstr ""
+msgstr "ланцюжок коміт-графа не співпадає"
+
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "кількість комітів у базовому графі занадто велика: %<PRIuMAX>"
 
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
-msgstr ""
+msgstr "неприпустимий ланцюжок коміт-графа: рядок \"%s\" не є хешем"
 
 msgid "unable to find all commit-graph files"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð½Ð°Ð¹Ñ\82и Ð²Ñ\81Ñ\96 Ñ\84айли Ð³Ñ\80аÑ\84а ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\96в"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð½Ð°Ð¹Ñ\82и Ð²Ñ\81Ñ\96 Ñ\84айли ÐºÐ¾Ð¼Ñ\96Ñ\82-гÑ\80аÑ\84а"
 
 msgid "invalid commit position. commit-graph is likely corrupt"
-msgstr ""
+msgstr "неприпустима позиція коміту, ймовірно, коміт-граф пошкоджено"
 
 #, c-format
 msgid "could not find commit %s"
 msgstr "не вдалося знайти коміт %s"
 
 msgid "commit-graph requires overflow generation data but has none"
-msgstr ""
+msgstr "коміт-граф потребує даних генерації переповнення, але їх немаєданих"
 
 msgid "Loading known commits in commit graph"
-msgstr ""
+msgstr "Завантаження відомих комітів у коміт-графі"
 
 msgid "Expanding reachable commits in commit graph"
-msgstr ""
+msgstr "Розширення досяжних комітів у коміт-графі"
 
 msgid "Clearing commit marks in commit graph"
-msgstr ""
+msgstr "Очищення позначок комітів у коміт-графі"
 
 msgid "Computing commit graph topological levels"
-msgstr ""
+msgstr "Обчислення топологічних рівнів коміт-графа"
 
 msgid "Computing commit graph generation numbers"
-msgstr ""
+msgstr "Обчислення номерів генерації коміт-графа"
 
 msgid "Computing commit changed paths Bloom filters"
-msgstr ""
+msgstr "Обчислення фільтрів Блума для шляхів, змінених комітом"
 
 msgid "Collecting referenced commits"
-msgstr ""
+msgstr "Збір посилань на коміти"
 
 #, 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[2] ""
+msgstr[0] "Пошук комітів для коміт-графа у %<PRIuMAX> пакунку"
+msgstr[1] "Пошук комітів для коміт-графа у %<PRIuMAX> пакунках"
+msgstr[2] "Пошук комітів для коміт-графа у %<PRIuMAX> пакунках"
 
 #, c-format
 msgid "error adding pack %s"
@@ -13710,16 +14525,16 @@ msgstr "помилка додавання пакету %s"
 
 #, c-format
 msgid "error opening index for %s"
-msgstr ""
+msgstr "помилка відкриття індексу для %s"
 
 msgid "Finding commits for commit graph among packed objects"
-msgstr ""
+msgstr "Пошук комітів для коміт-графа серед запакованих обʼєктів"
 
 msgid "Finding extra edges in commit graph"
-msgstr ""
+msgstr "Пошук додаткових ребер у коміт-графі"
 
 msgid "failed to write correct number of base graph ids"
-msgstr ""
+msgstr "не вдалося записати правильну кількість ідентифікаторів базових графів"
 
 msgid "unable to create temporary graph layer"
 msgstr "не вдалося створити тимчасовий шар графа"
@@ -13731,90 +14546,100 @@ msgstr "не вдалося налаштувати спільні дозволи
 #, c-format
 msgid "Writing out commit graph in %d pass"
 msgid_plural "Writing out commit graph in %d passes"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Виведення коміт-графа за %d прохід"
+msgstr[1] "Виведення коміт-графа за %d проходи"
+msgstr[2] "Виведення коміт-графа за %d проходів"
 
 msgid "unable to open commit-graph chain file"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\96дкÑ\80иÑ\82и Ð»Ð°Ð½Ñ\86Ñ\8eжковий Ñ\84айл Ð³Ñ\80аÑ\84а ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\96в"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\96дкÑ\80иÑ\82и Ð»Ð°Ð½Ñ\86Ñ\8eжковий Ñ\84айл ÐºÐ¾Ð¼Ñ\96Ñ\82-гÑ\80аÑ\84а"
 
 msgid "failed to rename base commit-graph file"
-msgstr ""
+msgstr "не вдалося перейменувати базовий файл коміт-графа"
 
 msgid "failed to rename temporary commit-graph file"
-msgstr "не вдалося перейменувати тимчасовий файл графа комітів"
+msgstr "не вдалося перейменувати тимчасовий файл коміт-графа"
+
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "неможливо обʼєднати графи з %<PRIuMAX>, %<PRIuMAX> комітів"
+
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "неможливо обʼєднати граф %s, занадто багато комітів: %<PRIuMAX>"
 
 msgid "Scanning merged commits"
-msgstr ""
+msgstr "Сканування злитих комітів"
 
 msgid "Merging commit-graph"
-msgstr ""
+msgstr "Злиття коміт-графа"
 
 msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
-msgstr ""
+msgstr "спроба записати коміт-граф, але \"core.commitGraph\" відключено"
 
 msgid "too many commits to write graph"
-msgstr ""
+msgstr "занадто багато комітів, щоб записати граф"
 
 msgid "the commit-graph file has incorrect checksum and is likely corrupt"
-msgstr ""
+msgstr "файл коміт-графа має невірну контрольну суму і, ймовірно, пошкоджений"
 
 #, c-format
 msgid "commit-graph has incorrect OID order: %s then %s"
-msgstr ""
+msgstr "коміт-граф має невірну OID послідовність: %s потім %s"
 
 #, c-format
 msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
-msgstr ""
+msgstr "коміт-граф має невірне fanout значення: fanout[%d] = %u != %u"
 
 #, c-format
 msgid "failed to parse commit %s from commit-graph"
 msgstr "не вдалося розібрати коміт %s з графа комітв"
 
-msgid "Verifying commits in commit graph"
-msgstr ""
-
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
-msgstr ""
+msgstr "не вдалося розібрати коміт %s з бази даних обʼєктів для коміт-графа"
 
 #, c-format
 msgid "root tree OID for commit %s in commit-graph is %s != %s"
-msgstr ""
+msgstr "OID кореневого дерева для коміту %s у коміт-графі є %s != %s"
 
 #, c-format
 msgid "commit-graph parent list for commit %s is too long"
-msgstr ""
+msgstr "список батьків для коміту %s коміт-графа занадто довгий"
 
 #, c-format
 msgid "commit-graph parent for %s is %s != %s"
-msgstr ""
+msgstr "батько для %s коміт-графа є %s != %s"
 
 #, c-format
 msgid "commit-graph parent list for commit %s terminates early"
-msgstr ""
+msgstr "список батьків коміт-графа для коміту %s завершився передчасно"
 
 #, c-format
 msgid ""
 "commit-graph has generation number zero for commit %s, but non-zero elsewhere"
 msgstr ""
+"коміт-граф має нульовий номер генерації для коміту %s, але ненульовий деінде"
 
 #, c-format
 msgid ""
 "commit-graph has non-zero generation number for commit %s, but zero elsewhere"
 msgstr ""
+"коміт-граф має ненульовий номер генерації для коміту %s, але нульовий деінде"
 
 #, c-format
 msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>"
-msgstr ""
+msgstr "генерація коміт-графа для коміту %s є %<PRIuMAX> < %<PRIuMAX>"
 
 #, c-format
 msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
-msgstr ""
+msgstr "дата коміту для коміту %s у коміт-графі є %<PRIuMAX> != %<PRIuMAX>"
+
+msgid "Verifying commits in commit graph"
+msgstr "Перевірка комітів у коміт-графі"
 
 #, c-format
 msgid "%s %s is not a commit!"
-msgstr ""
+msgstr "%s %s не є комітом!"
 
 msgid ""
 "Support for <GIT_DIR>/info/grafts is deprecated\n"
@@ -13826,14 +14651,22 @@ msgid ""
 "Turn this message off by running\n"
 "\"git config advice.graftFileDeprecated false\""
 msgstr ""
+"Підтримка <GIT_DIR>/info/grafts застаріла\n"
+"і буде вилучена в одній з наступних версій Git.\n"
+"\n"
+"Будь ласка, скористайтесь \"git replace --convert-graft-file\"\n"
+"щоб перетворити щепи на заміни посилань.\n"
+"\n"
+"Щоб вимкнути це повідомлення, виконайте\n"
+"\"git config advice.graftFileDeprecated false\""
 
 #, c-format
 msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
-msgstr ""
+msgstr "Коміт %s має недостовірний GPG-підпис, нібито від %s."
 
 #, c-format
 msgid "Commit %s has a bad GPG signature allegedly by %s."
-msgstr ""
+msgstr "Коміт %s має невірний GPG-підпис, нібито від %s."
 
 #, c-format
 msgid "Commit %s does not have a GPG signature."
@@ -13841,19 +14674,23 @@ msgstr "Коміт %s не має GPG підпису."
 
 #, c-format
 msgid "Commit %s has a good GPG signature by %s\n"
-msgstr ""
+msgstr "Коміт %s має добрий GPG-підпис від %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"
 msgstr ""
+"Попередження: допис до коміту не відповідає кодуванню UTF-8.\n"
+"Можливо, ви захочете змінити його після виправлення допису, або встановити "
+"змінну конфігурації\n"
+"i18n.commitEncoding у кодування, яке використовується у вашому проекті.\n"
 
 msgid "no compiler information available\n"
-msgstr ""
+msgstr "немає інформації про компілятор\n"
 
 msgid "no libc information available\n"
-msgstr ""
+msgstr "немає інформації про libc\n"
 
 #, c-format
 msgid "could not determine free disk size for '%s'"
@@ -13865,11 +14702,11 @@ msgstr "не вдалося отримати інформацію для \"%s\""
 
 #, c-format
 msgid "[GLE %ld] health thread could not open '%ls'"
-msgstr ""
+msgstr "[GLE %ld] потік стану не зміг відкрити \"%ls\""
 
 #, c-format
 msgid "[GLE %ld] health thread getting BHFI for '%ls'"
-msgstr ""
+msgstr "[GLE %ld] потік стану отримує BHFI для \"%ls\""
 
 #, c-format
 msgid "could not convert to wide characters: '%s'"
@@ -13877,15 +14714,15 @@ msgstr "не вдалося перетворити в широкі символ
 
 #, c-format
 msgid "BHFI changed '%ls'"
-msgstr ""
+msgstr "BHFI змінено \"%ls\""
 
 #, c-format
 msgid "unhandled case in 'has_worktree_moved': %d"
-msgstr ""
+msgstr "необроблений випадок у \"has_worktree_moved\": %d"
 
 #, c-format
 msgid "health thread wait failed [GLE %ld]"
-msgstr ""
+msgstr "очікування потоку стану завершилося невдало [GLE %ld]"
 
 #, c-format
 msgid "Invalid path: %s"
@@ -13899,23 +14736,23 @@ msgstr "Не вдалося запустити потік FSEventStream"
 
 #, c-format
 msgid "[GLE %ld] could not convert path to UTF-8: '%.*ls'"
-msgstr ""
+msgstr "[GLE %ld] не вдалося конвертувати шлях у UTF-8: \"%.*ls\""
 
 #, c-format
 msgid "[GLE %ld] could not watch '%s'"
-msgstr ""
+msgstr "[GLE %ld] стеження завершилось невдало \"%s\""
 
 #, c-format
 msgid "[GLE %ld] could not get longname of '%s'"
-msgstr ""
+msgstr "[GLE %ld] не вдалося отримати довгу назву \"%s\""
 
 #, c-format
 msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "ReadDirectoryChangedW завершилось невдало на \"%s\" [GLE %ld]"
 
 #, c-format
 msgid "GetOverlappedResult failed on '%s' [GLE %ld]"
-msgstr ""
+msgstr "GetOverlappedResult завершилось невдало на \"%s\" [GLE %ld]"
 
 #, c-format
 msgid "could not read directory changes [GLE %ld]"
@@ -13923,19 +14760,19 @@ msgstr "не вдалося прочитати зміни директорії [
 
 #, c-format
 msgid "opendir('%s') failed"
-msgstr ""
+msgstr "opendir(\"%s\") завершився невдало"
 
 #, c-format
 msgid "lstat('%s') failed"
-msgstr ""
+msgstr "lstat(\"%s\") завершився невдало"
 
 #, c-format
 msgid "strbuf_readlink('%s') failed"
-msgstr ""
+msgstr "strbuf_readlink(\"%s\") завершився невдало"
 
 #, c-format
 msgid "closedir('%s') failed"
-msgstr ""
+msgstr "closedir(\"%s\") завершився невдало"
 
 #, c-format
 msgid "[GLE %ld] unable to open for read '%ls'"
@@ -13943,7 +14780,7 @@ msgstr "[GLE %ld] не вдалося відкрити для читання \"%
 
 #, c-format
 msgid "[GLE %ld] unable to get protocol information for '%ls'"
-msgstr ""
+msgstr "[GLE %ld] не вдалося отримати інформацію про протокол для \"%ls\""
 
 #, c-format
 msgid "failed to copy SID (%ld)"
@@ -13954,64 +14791,64 @@ msgid "failed to get owner for '%s' (%ld)"
 msgstr "не вдалося отримати власника для \"%s\" (%ld)"
 
 msgid "memory exhausted"
-msgstr ""
+msgstr "памʼять вичерпано"
 
 msgid "Success"
-msgstr ""
+msgstr "Успіх"
 
 msgid "No match"
-msgstr ""
+msgstr "Немає збігів"
 
 msgid "Invalid regular expression"
-msgstr ""
+msgstr "Неприпустимий регулярний вираз"
 
 msgid "Invalid collation character"
-msgstr ""
+msgstr "Неприпустимий символ зведення"
 
 msgid "Invalid character class name"
-msgstr ""
+msgstr "Неприпустима назва класу символів"
 
 msgid "Trailing backslash"
-msgstr ""
+msgstr "Кінцева зворотна коса риска"
 
 msgid "Invalid back reference"
 msgstr "Неприпустиме зворотнє посилання"
 
 msgid "Unmatched [ or [^"
-msgstr ""
+msgstr "Непарна [ або [^"
 
 msgid "Unmatched ( or \\("
-msgstr ""
+msgstr "Непарна ( або \\("
 
 msgid "Unmatched \\{"
-msgstr ""
+msgstr "Непарна \\{"
 
 msgid "Invalid content of \\{\\}"
-msgstr ""
+msgstr "Неприпустимий вміст для \\{\\}"
 
 msgid "Invalid range end"
-msgstr ""
+msgstr "Неприпустимий кінець діапазону"
 
 msgid "Memory exhausted"
-msgstr ""
+msgstr "Памʼять вичерпано"
 
 msgid "Invalid preceding regular expression"
-msgstr ""
+msgstr "Неприпустимий попередній регулярний вираз"
 
 msgid "Premature end of regular expression"
-msgstr ""
+msgstr "Передчасне завершення регулярного виразу"
 
 msgid "Regular expression too big"
-msgstr ""
+msgstr "Занадто великий регулярний вираз"
 
 msgid "Unmatched ) or \\)"
-msgstr ""
+msgstr "Непарна ) або \\)"
 
 msgid "No previous regular expression"
-msgstr ""
+msgstr "Немає попереднього регулярного виразу"
 
 msgid "could not send IPC command"
-msgstr ""
+msgstr "не вдалося відправити IPC команду"
 
 msgid "could not read IPC response"
 msgstr "не вдалося прочитати IPC відповідь"
@@ -14026,7 +14863,7 @@ msgstr "не вдалося запустити worker[0] для \"%s\""
 
 #, c-format
 msgid "ConnectNamedPipe failed for '%s' (%lu)"
-msgstr ""
+msgstr "ConnectNamedPipe завершився невдало для \"%s\" (%lu)"
 
 #, c-format
 msgid "could not create fd from pipe for '%s'"
@@ -14042,9 +14879,11 @@ msgstr "очікування на hEvent не вдалося для \"%s\""
 
 msgid "cannot resume in the background, please use 'fg' to resume"
 msgstr ""
+"неможливо поновити роботу у фоновому режимі; будь ласка, скористайтесь "
+"\"fg\" для поновлення"
 
 msgid "cannot restore terminal settings"
-msgstr ""
+msgstr "не вдалося відновити налаштування термінала"
 
 #, c-format
 msgid ""
@@ -14054,21 +14893,29 @@ msgid ""
 "\t%s\n"
 "This might be due to circular includes."
 msgstr ""
+"перевищено максимальну глибину (%d) під час включення\n"
+"\t%s\n"
+"від\n"
+"\t%s\n"
+"Це може бути повʼязано з циклічним включенням."
 
 #, c-format
 msgid "could not expand include path '%s'"
 msgstr "не вдалося визначити include path \"%s\""
 
 msgid "relative config includes must come from files"
-msgstr ""
+msgstr "відносні конфігураційні включення мають надходити з файлів"
 
 msgid "relative config include conditionals must come from files"
 msgstr ""
+"відносні умовні позначення конфігураційних включень мають надходити з файлів"
 
 msgid ""
 "remote URLs cannot be configured in file directly or indirectly included by "
 "includeIf.hasconfig:remote.*.url"
 msgstr ""
+"віддалені URL-адреси не можуть бути налаштовані у файлі, прямо чи "
+"опосередковано включеному за допомогою includeIf.hasconfig:remote.*.url"
 
 #, c-format
 msgid "invalid config format: %s"
@@ -14076,19 +14923,19 @@ msgstr "неприпустимий формат конфігурації: %s"
 
 #, c-format
 msgid "missing environment variable name for configuration '%.*s'"
-msgstr ""
+msgstr "відсутня назва змінної оточення для конфігурації \"%.*s\""
 
 #, c-format
 msgid "missing environment variable '%s' for configuration '%.*s'"
-msgstr ""
+msgstr "відсутня змінна оточення \"%s\" для конфігурації \"%.*s\""
 
 #, c-format
 msgid "key does not contain a section: %s"
-msgstr ""
+msgstr "ключ не містить розділу: %s"
 
 #, c-format
 msgid "key does not contain variable name: %s"
-msgstr ""
+msgstr "ключ не містить назви змінної: %s"
 
 #, c-format
 msgid "invalid key: %s"
@@ -14099,89 +14946,95 @@ msgid "invalid key (newline): %s"
 msgstr "неприпустимий ключ (новий рядок): %s"
 
 msgid "empty config key"
-msgstr ""
+msgstr "порожній ключ конфігурації"
 
 #, c-format
 msgid "bogus config parameter: %s"
-msgstr ""
+msgstr "хибний параметр конфігурації: %s"
 
 #, c-format
 msgid "bogus format in %s"
-msgstr ""
+msgstr "хибний формат у %s"
 
 #, c-format
 msgid "bogus count in %s"
-msgstr ""
+msgstr "хибна кількість у %s"
 
 #, c-format
 msgid "too many entries in %s"
-msgstr ""
+msgstr "забагато записів у %s"
 
 #, c-format
 msgid "missing config key %s"
-msgstr ""
+msgstr "відсутній ключ конфігурації %s"
 
 #, c-format
 msgid "missing config value %s"
-msgstr ""
+msgstr "відсутнє значення конфігурації %s"
 
 #, c-format
 msgid "bad config line %d in blob %s"
-msgstr ""
+msgstr "невірний конфігураційний рядок %d у blob %s"
 
 #, c-format
 msgid "bad config line %d in file %s"
-msgstr ""
+msgstr "невірний конфігураційний рядок %d у файлі %s"
 
 #, c-format
 msgid "bad config line %d in standard input"
-msgstr ""
+msgstr "невірний конфігураційний рядок %d у стандартному вводі"
 
 #, c-format
 msgid "bad config line %d in submodule-blob %s"
-msgstr ""
+msgstr "невірний конфігураційний рядок %d у підмодулі-blob %s"
 
 #, c-format
 msgid "bad config line %d in command line %s"
-msgstr ""
+msgstr "невірний конфігураційний рядок %d у командному рядку %s"
 
 #, c-format
 msgid "bad config line %d in %s"
-msgstr ""
+msgstr "невірний конфігураційний рядок %d в %s"
 
 msgid "out of range"
-msgstr ""
+msgstr "поза межами діапазону"
 
 msgid "invalid unit"
 msgstr "неприпустима одиниця виміру"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s': %s"
-msgstr ""
+msgstr "невірне числове значення конфігурації \"%s\" для \"%s\": %s"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
-msgstr ""
+msgstr "невірне числове значення конфігурації \"%s\" для \"%s\" у blob %s: %s"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in file %s: %s"
-msgstr ""
+msgstr "невірне числове значення конфігурації \"%s\" для \"%s\" у файлі %s: %s"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in standard input: %s"
 msgstr ""
+"невірне числове значення конфігурації \"%s\" для \"%s\" у стандартному "
+"вводі: %s"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
 msgstr ""
+"невірне числове значення конфігурації \"%s\" для \"%s\" у підмодулі-blob %s: "
+"%s"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
 msgstr ""
+"невірне числове значення конфігурації \"%s\" для \"%s\" у командному рядку "
+"%s: %s"
 
 #, c-format
 msgid "bad numeric config value '%s' for '%s' in %s: %s"
-msgstr ""
+msgstr "невірне числове значення конфігурації \"%s\" для \"%s\" у \"%s\": %s"
 
 #, c-format
 msgid "invalid value for variable %s"
@@ -14189,11 +15042,11 @@ msgstr "неприпустиме значення для змінної %s"
 
 #, c-format
 msgid "ignoring unknown core.fsync component '%s'"
-msgstr ""
+msgstr "ігнорування невідомого компонента core.fsync \"%s\""
 
 #, c-format
 msgid "bad boolean config value '%s' for '%s'"
-msgstr "непÑ\80авилÑ\8cне булеве значення конфігурації \"%s\" для \"%s\""
+msgstr "невÑ\96Ñ\80не булеве значення конфігурації \"%s\" для \"%s\""
 
 #, c-format
 msgid "failed to expand user dir in: '%s'"
@@ -14205,21 +15058,21 @@ msgstr "\"%s\" для \"%s\" не є припустимою міткою час
 
 #, c-format
 msgid "abbrev length out of range: %d"
-msgstr ""
+msgstr "довжина скорочення поза діапазоном: %d"
 
 #, c-format
 msgid "bad zlib compression level %d"
-msgstr ""
+msgstr "невірний рівень zlib компресії %d"
 
 msgid "core.commentChar should only be one ASCII character"
-msgstr ""
+msgstr "core.commentChar має бути лише одним символом ASCII"
 
 #, c-format
 msgid "ignoring unknown core.fsyncMethod value '%s'"
-msgstr ""
+msgstr "ігнорування невідомого значення core.fsyncMethod \"%s\""
 
 msgid "core.fsyncObjectFiles is deprecated; use core.fsync instead"
-msgstr ""
+msgstr "core.fsyncObjectFiles застаріла; натомість використовуйте core.fsync"
 
 #, c-format
 msgid "invalid mode for object creation: %s"
@@ -14227,14 +15080,14 @@ msgstr "неприпустимий режим створення обʼєкта:
 
 #, c-format
 msgid "malformed value for %s"
-msgstr "непÑ\80авилÑ\8cно сформоване значення для %s"
+msgstr "невÑ\96Ñ\80но сформоване значення для %s"
 
 #, c-format
 msgid "malformed value for %s: %s"
-msgstr "непÑ\80авилÑ\8cно сформоване значення для %s: %s"
+msgstr "невÑ\96Ñ\80но сформоване значення для %s: %s"
 
 msgid "must be one of nothing, matching, simple, upstream or current"
-msgstr ""
+msgstr "має бути одним з nothing, matching, simple, upstream або current"
 
 #, c-format
 msgid "unable to load config blob object '%s'"
@@ -14256,7 +15109,7 @@ msgid "unable to parse command-line config"
 msgstr "не вдалося розібрати конфігурацію командного рядка"
 
 msgid "unknown error occurred while reading the configuration files"
-msgstr ""
+msgstr "невідома помилка виникла під час читання конфігураційних файлів"
 
 #, c-format
 msgid "Invalid %s: '%s'"
@@ -14265,6 +15118,7 @@ msgstr "Неприпустимий %s: \"%s\""
 #, c-format
 msgid "splitIndex.maxPercentChange value '%d' should be between 0 and 100"
 msgstr ""
+"значення splitIndex.maxPercentChange \"%d\" має бути в діапазоні від 0 до 100"
 
 #, c-format
 msgid "unable to parse '%s' from command-line config"
@@ -14272,7 +15126,7 @@ msgstr "не вдалося розібрати \"%s\" з конфігураці
 
 #, c-format
 msgid "bad config variable '%s' in file '%s' at line %d"
-msgstr ""
+msgstr "невірна конфігураційна змінна \"%s\" у файлі \"%s\", рядок \"%d\""
 
 #, c-format
 msgid "invalid section name '%s'"
@@ -14280,7 +15134,7 @@ msgstr "неприпустима назва секції \"%s\""
 
 #, c-format
 msgid "%s has multiple values"
-msgstr ""
+msgstr "%s має кілька значень"
 
 #, c-format
 msgid "failed to write new configuration file %s"
@@ -14292,7 +15146,7 @@ msgstr "не вдалося зафіксувати файл конфігурац
 
 #, c-format
 msgid "opening %s"
-msgstr ""
+msgstr "відкриття %s"
 
 #, c-format
 msgid "invalid config file %s"
@@ -14300,7 +15154,7 @@ msgstr "неприпустимий конфігураційний файл %s"
 
 #, c-format
 msgid "fstat on %s failed"
-msgstr ""
+msgstr "не вдалося виконати fstat на %s"
 
 #, c-format
 msgid "unable to mmap '%s'%s"
@@ -14308,7 +15162,7 @@ msgstr "не вдалося виконати mmap \"%s\"%s"
 
 #, c-format
 msgid "chmod on %s failed"
-msgstr ""
+msgstr "не вдалося виконати chmod на %s"
 
 #, c-format
 msgid "could not write config file %s"
@@ -14325,13 +15179,14 @@ msgstr "неприпустима назва секції: %s"
 #, c-format
 msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>"
 msgstr ""
+"відмовлено в роботі з занадто довгим рядком у \"%s\", рядок  %<PRIuMAX>"
 
 #, c-format
 msgid "missing value for '%s'"
 msgstr "відсутнє значення для \"%s\""
 
 msgid "the remote end hung up upon initial contact"
-msgstr ""
+msgstr "віддалене призначеня відключилося при першому контакті"
 
 msgid ""
 "Could not read from remote repository.\n"
@@ -14339,70 +15194,74 @@ msgid ""
 "Please make sure you have the correct access rights\n"
 "and the repository exists."
 msgstr ""
+"Не вдалося прочитати з віддаленого сховища.\n"
+"\n"
+"Будь ласка, переконайтеся, що у вас є правильні права доступу\n"
+"і що сховище існує."
 
 #, c-format
 msgid "server doesn't support '%s'"
-msgstr ""
+msgstr "сервер не підтримує \"%s\""
 
 #, c-format
 msgid "server doesn't support feature '%s'"
-msgstr ""
+msgstr "сервер не підтримує особливість \"%s\""
 
 msgid "expected flush after capabilities"
-msgstr ""
+msgstr "очікувалось flush після здібностей"
 
 #, c-format
 msgid "ignoring capabilities after first line '%s'"
-msgstr ""
+msgstr "ігнорування здібностей після першого рядка \"%s\""
 
 msgid "protocol error: unexpected capabilities^{}"
-msgstr ""
+msgstr "помилка протоколу: неочікувані здібності^{}"
 
 #, c-format
 msgid "protocol error: expected shallow sha-1, got '%s'"
-msgstr ""
+msgstr "помилка протоколу: очікувалось неглибоке sha-1, отримано \"%s\""
 
 msgid "repository on the other end cannot be shallow"
-msgstr ""
+msgstr "сховище на іншому кінці не може бути неглибоким"
 
 msgid "invalid packet"
 msgstr "неприпустимий пакет"
 
 #, c-format
 msgid "protocol error: unexpected '%s'"
-msgstr ""
+msgstr "помилка протоколу: неочікуване \"%s\""
 
 #, c-format
 msgid "unknown object format '%s' specified by server"
-msgstr ""
+msgstr "невідомий формат обʼєкта \"%s\", вказаний сервером"
 
 #, c-format
 msgid "error on bundle-uri response line %d: %s"
-msgstr ""
+msgstr "помилка у рядку відповіді bundle-uri %d: %s"
 
 msgid "expected flush after bundle-uri listing"
-msgstr ""
+msgstr "очікувалось flush після виводу bundle-uri"
 
 msgid "expected response end packet after ref listing"
-msgstr ""
+msgstr "очікувалось response end пакет після виводу посилань"
 
 #, c-format
 msgid "invalid ls-refs response: %s"
 msgstr "неприпустима ls-refs відповідь: %s"
 
 msgid "expected flush after ref listing"
-msgstr ""
+msgstr "очікувалось flush після виводу посилань"
 
 #, c-format
 msgid "protocol '%s' is not supported"
 msgstr "протокол \"%s\" не підтримується"
 
 msgid "unable to set SO_KEEPALIVE on socket"
-msgstr ""
+msgstr "не вдалося встановити SO_KEEPALIVE сокету"
 
 #, c-format
 msgid "Looking up %s ... "
-msgstr ""
+msgstr "Пошук %s ... "
 
 #, c-format
 msgid "unable to look up %s (port %s) (%s)"
@@ -14415,6 +15274,8 @@ msgid ""
 "done.\n"
 "Connecting to %s (port %s) ... "
 msgstr ""
+"готово.\n"
+"Підключення до %s (порт %s) ... "
 
 #, c-format
 msgid ""
@@ -14439,34 +15300,34 @@ msgstr "невідомий порт %s"
 
 #, c-format
 msgid "strange hostname '%s' blocked"
-msgstr ""
+msgstr "дивне імʼя хоста \"%s\" заблоковано"
 
 #, c-format
 msgid "strange port '%s' blocked"
-msgstr ""
+msgstr "дивний порт \"%s\" заблоковано"
 
 #, c-format
 msgid "cannot start proxy %s"
 msgstr "неможливо запустити проксі %s"
 
 msgid "no path specified; see 'git help pull' for valid url syntax"
-msgstr ""
+msgstr "не вказано шлях; дивіться \"git help pull\" для чинного url синтаксису"
 
 msgid "newline is forbidden in git:// hosts and repo paths"
-msgstr ""
+msgstr "новий рядок у хостах git:// та шляхах репозиторіїв заборонено"
 
 msgid "ssh variant 'simple' does not support -4"
-msgstr ""
+msgstr "ssh опція \"simple\" не підтримує -4"
 
 msgid "ssh variant 'simple' does not support -6"
-msgstr ""
+msgstr "ssh опція \"simple\" не підтримує -6"
 
 msgid "ssh variant 'simple' does not support setting port"
-msgstr ""
+msgstr "ssh опція \"simple\" не підтримує встановлення порту"
 
 #, c-format
 msgid "strange pathname '%s' blocked"
-msgstr ""
+msgstr "дивне імʼя шляху \"%s\" заблоковано"
 
 msgid "unable to fork"
 msgstr "неможливо розгалужити"
@@ -14478,51 +15339,60 @@ msgid "failed write to rev-list"
 msgstr "не вдалося записати до rev-list"
 
 msgid "failed to close rev-list's stdin"
-msgstr ""
+msgstr "не вдалося закрити stdin для rev-list"
 
 #, c-format
 msgid "illegal crlf_action %d"
-msgstr ""
+msgstr "неприпустиме crlf_action %d"
 
 #, c-format
 msgid "CRLF would be replaced by LF in %s"
-msgstr ""
+msgstr "CRLF буде замінено на LF у %s"
 
 #, c-format
 msgid ""
 "in the working copy of '%s', CRLF will be replaced by LF the next time Git "
 "touches it"
 msgstr ""
+"у робочій копії \"%s\" CRLF буде замінено на LF наступного разу, коли Git "
+"доторкнеться до неї"
 
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
-msgstr ""
+msgstr "LF буде замінено на CRLF у %s"
 
 #, c-format
 msgid ""
 "in the working copy of '%s', LF will be replaced by CRLF the next time Git "
 "touches it"
 msgstr ""
+"у робочій копії \"%s\" LF буде замінено на CRLF наступного разу, коли Git "
+"доторкнеться до неї"
 
 #, c-format
 msgid "BOM is prohibited in '%s' if encoded as %s"
-msgstr ""
+msgstr "BOM заборонено в \"%s\", якщо закодовано як %s"
 
 #, c-format
 msgid ""
 "The file '%s' contains a byte order mark (BOM). Please use UTF-%.*s as "
 "working-tree-encoding."
 msgstr ""
+"Файл \"%s\" містить позначку порядку байтів (BOM). Будь ласка, "
+"використовуйте UTF-%.*s як кодування робочого дерева."
 
 #, c-format
 msgid "BOM is required in '%s' if encoded as %s"
-msgstr ""
+msgstr "BOM необхідний в \"%s\", якщо закодовано як %s"
 
 #, c-format
 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 ""
+"У файлі \"%s\" відсутня позначка послідовності байтів (BOM). Будь ласка, "
+"використовуйте UTF-%sBE або UTF-%sLE (залежно від послідовності байтів) як "
+"кодування робочого дерева."
 
 #, c-format
 msgid "failed to encode '%s' from %s to %s"
@@ -14530,7 +15400,7 @@ msgstr "не вдалося закодувати \"%s\" з %s в %s"
 
 #, c-format
 msgid "encoding '%s' from %s to %s and back is not the same"
-msgstr ""
+msgstr "кодування \"%s\" з %s в %s і назад не однакове"
 
 #, c-format
 msgid "cannot fork to run external filter '%s'"
@@ -14542,131 +15412,133 @@ msgstr "неможливо подати вхідні дані на зовніш
 
 #, c-format
 msgid "external filter '%s' failed %d"
-msgstr ""
+msgstr "помилка зовнішнього фільтра \"%s\", код: %d"
 
 #, c-format
 msgid "read from external filter '%s' failed"
-msgstr ""
+msgstr "не вдалося прочитати з зовнішнього фільтра \"%s\""
 
 #, c-format
 msgid "external filter '%s' failed"
-msgstr ""
+msgstr "помилка зовнішнього фільтра \"%s\""
 
 msgid "unexpected filter type"
-msgstr ""
+msgstr "несподіваний тип фільтра"
 
 msgid "path name too long for external filter"
-msgstr ""
+msgstr "назва шляху занадто довга для зовнішнього фільтра"
 
 #, c-format
 msgid ""
 "external filter '%s' is not available anymore although not all paths have "
 "been filtered"
 msgstr ""
+"зовнішній фільтр \"%s\" більше не доступний, хоча не всі шляхи були "
+"відфільтровані"
 
 msgid "true/false are no valid working-tree-encodings"
-msgstr ""
+msgstr "true/false не є допустимими кодуваннями робочого дерева"
 
 #, c-format
 msgid "%s: clean filter '%s' failed"
-msgstr ""
+msgstr "%s: помилка фільтра очистки \"%s\""
 
 #, c-format
 msgid "%s: smudge filter %s failed"
-msgstr ""
+msgstr "%s: помилка фільтра розмиття %s"
 
 #, c-format
 msgid "skipping credential lookup for key: credential.%s"
-msgstr ""
+msgstr "пропуск пошуку облікових даних для ключа: credential.%s"
 
 msgid "refusing to work with credential missing host field"
-msgstr ""
+msgstr "відмовлено в роботі з відсутнім полем хоста в облікових даних"
 
 msgid "refusing to work with credential missing protocol field"
-msgstr ""
+msgstr "відмовлено в роботі з відсутнім полем протоколу облікових даних"
 
 #, c-format
 msgid "url contains a newline in its %s component: %s"
-msgstr ""
+msgstr "url містить новий рядок у %s компоненті: %s"
 
 #, c-format
 msgid "url has no scheme: %s"
-msgstr ""
+msgstr "url не має схеми: %s"
 
 #, c-format
 msgid "credential url cannot be parsed: %s"
-msgstr ""
+msgstr "неможливо розібрати url облікових даних: %s"
 
 msgid "in the future"
-msgstr ""
+msgstr "у майбутньому"
 
 #, c-format
 msgid "%<PRIuMAX> second ago"
 msgid_plural "%<PRIuMAX> seconds ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> секунду тому"
+msgstr[1] "%<PRIuMAX> секунди тому"
+msgstr[2] "%<PRIuMAX> секунд тому"
 
 #, c-format
 msgid "%<PRIuMAX> minute ago"
-msgid_plural "%<PRIuMAX> minutes ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgid_plural "%<PRIuMAX> minutes ago"
+msgstr[0] "%<PRIuMAX> хвилину тому"
+msgstr[1] "%<PRIuMAX> хвилини тому"
+msgstr[2] "%<PRIuMAX> хвилин тому"
 
 #, c-format
 msgid "%<PRIuMAX> hour ago"
 msgid_plural "%<PRIuMAX> hours ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> годину тому"
+msgstr[1] "%<PRIuMAX> години тому"
+msgstr[2] "%<PRIuMAX> годин тому"
 
 #, c-format
 msgid "%<PRIuMAX> day ago"
 msgid_plural "%<PRIuMAX> days ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> день тому"
+msgstr[1] "%<PRIuMAX> дні тому"
+msgstr[2] "%<PRIuMAX> днів тому"
 
 #, c-format
 msgid "%<PRIuMAX> week ago"
 msgid_plural "%<PRIuMAX> weeks ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> тиждень тому"
+msgstr[1] "%<PRIuMAX> тижні тому"
+msgstr[2] "%<PRIuMAX> тижнів тому"
 
 #, c-format
 msgid "%<PRIuMAX> month ago"
 msgid_plural "%<PRIuMAX> months ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> місяць тому"
+msgstr[1] "%<PRIuMAX> місяці тому"
+msgstr[2] "%<PRIuMAX> місяців тому"
 
 #, c-format
 msgid "%<PRIuMAX> year"
 msgid_plural "%<PRIuMAX> years"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> рік"
+msgstr[1] "%<PRIuMAX> роки"
+msgstr[2] "%<PRIuMAX> років"
 
 #. TRANSLATORS: "%s" is "<n> years"
 
 #, c-format
 msgid "%s, %<PRIuMAX> month ago"
 msgid_plural "%s, %<PRIuMAX> months ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%s, %<PRIuMAX> місяць тому"
+msgstr[1] "%s, %<PRIuMAX> місяці тому"
+msgstr[2] "%s, %<PRIuMAX> місяців тому"
 
 #, c-format
 msgid "%<PRIuMAX> year ago"
 msgid_plural "%<PRIuMAX> years ago"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%<PRIuMAX> рік тому"
+msgstr[1] "%<PRIuMAX> роки тому"
+msgstr[2] "%<PRIuMAX> років тому"
 
 msgid "Propagating island marks"
-msgstr ""
+msgstr "Розповсюдження острівних позначок"
 
 #, c-format
 msgid "bad tree object %s"
@@ -14678,11 +15550,11 @@ msgstr "не вдалося завантажити island регвир для \"
 
 #, c-format
 msgid "island regex from config has too many capture groups (max=%d)"
-msgstr ""
+msgstr "регвир острова з конфігурації має забагато груп захоплення (max=%d)"
 
 #, c-format
 msgid "Marked %d islands, done.\n"
-msgstr ""
+msgstr "Позначено %d островів, готово.\n"
 
 #, c-format
 msgid "invalid --%s value '%s'"
@@ -14698,7 +15570,7 @@ msgstr "не вдалося відкрити директорію \"%s\""
 
 #, c-format
 msgid "skipping '%s', which is neither file nor directory"
-msgstr ""
+msgstr "пропускання \"%s\", який не є ні файлом, ні директорією"
 
 msgid "could not duplicate stdout"
 msgstr "не вдалося продублювати stdout"
@@ -14711,19 +15583,25 @@ msgid "failed to write archive"
 msgstr "не вдалося записати архів"
 
 msgid "--merge-base does not work with ranges"
-msgstr ""
+msgstr "--merge-base не працює з діапазонами"
 
 msgid "--merge-base only works with commits"
-msgstr ""
+msgstr "--merge-base працює лише з комітами"
 
 msgid "unable to get HEAD"
 msgstr "не вдалося отримати HEAD"
 
 msgid "no merge base found"
-msgstr ""
+msgstr "базу злиття не знайдено"
 
 msgid "multiple merge bases found"
-msgstr ""
+msgstr "знайдено кілька баз злиття"
+
+msgid "cannot compare stdin to a directory"
+msgstr "неможливо порівняти stdin з директорією"
+
+msgid "cannot compare a named pipe to a directory"
+msgstr "неможливо порівняти іменований канал з директорією"
 
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<опції>] <шлях> <шлях>"
@@ -14732,44 +15610,62 @@ msgid ""
 "Not a git repository. Use --no-index to compare two paths outside a working "
 "tree"
 msgstr ""
+"Це не git сховище. Скористайтесь --no-index для порівняння двох шляхів поза "
+"робочим деревом"
 
 #, c-format
 msgid "  Failed to parse dirstat cut-off percentage '%s'\n"
-msgstr ""
+msgstr " Не вдалося розібрати відсоток відсікання dirstat \"%s\"\n"
 
 #, c-format
 msgid "  Unknown dirstat parameter '%s'\n"
-msgstr ""
+msgstr " Невідомий параметр dirstat \"%s\"\n"
 
 msgid ""
 "color moved setting must be one of 'no', 'default', 'blocks', 'zebra', "
 "'dimmed-zebra', 'plain'"
 msgstr ""
+"значення параметра кольору перенесення має бути одним з \"no\", \"default\", "
+"\"blocks\", \"zebra\", \"dimmed-zebra\", \"plain\""
 
 #, c-format
 msgid ""
 "unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', "
 "'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"
 msgstr ""
+"невідомий режим color-moved-ws \"%s\", можливі значення \"ignore-space-"
+"change\", \"ignore-space-at-eol\", \"ignore-all-space\", \"allow-indentation-"
+"change\""
 
 msgid ""
 "color-moved-ws: allow-indentation-change cannot be combined with other "
 "whitespace modes"
 msgstr ""
+"color-moved-ws: allow-indentation-change не можна комбінувати з іншими "
+"режимами відображення пробілів"
 
 #, c-format
 msgid "Unknown value for 'diff.submodule' config variable: '%s'"
-msgstr ""
+msgstr "Невідоме значення конфігураційної змінної \"diff.submodule\": \"%s\""
 
 #, c-format
 msgid ""
 "Found errors in 'diff.dirstat' config variable:\n"
 "%s"
 msgstr ""
+"Знайдено помилки у конфігураційній змінній \"diff.dirstat\":\n"
+"%s"
 
 #, c-format
 msgid "external diff died, stopping at %s"
-msgstr ""
+msgstr "зовнішній diff завершився невдало, зупинившись на %s"
+
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow потрібен лишень один визначник шляху"
+
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "магічне значення визначника шляху не підтримується --follow: %s"
 
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
@@ -14788,30 +15684,29 @@ msgstr ""
 "опції \"%s\" і \"%s\" неможливо використати разом, використовуйте \"%s\" з "
 "\"%s\" та \"%s\""
 
-msgid "--follow requires exactly one pathspec"
-msgstr ""
-
 #, c-format
 msgid "invalid --stat value: %s"
 msgstr "неприпустиме --stat значення: %s"
 
 #, c-format
 msgid "%s expects a numerical value"
-msgstr ""
+msgstr "%s очікує числове значення"
 
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
 "%s"
 msgstr ""
+"Не вдалося розібрати параметр опції --dirstat/-X:\n"
+"%s"
 
 #, c-format
 msgid "unknown change class '%c' in --diff-filter=%s"
-msgstr ""
+msgstr "невідома зміна класу \"%c\" у --diff-filter=%s"
 
 #, c-format
 msgid "unknown value after ws-error-highlight=%.*s"
-msgstr ""
+msgstr "невідоме значення після ws-error-highlight=%.*s"
 
 #, c-format
 msgid "unable to resolve '%s'"
@@ -14819,7 +15714,7 @@ msgstr "не вдалося розпізнати \"%s\""
 
 #, c-format
 msgid "%s expects <n>/<m> form"
-msgstr ""
+msgstr "%s очікує <n>/<m> форму"
 
 #, c-format
 msgid "%s expects a character, got '%s'"
@@ -14827,16 +15722,18 @@ msgstr "%s очікує символ, отримано \"%s\""
 
 #, c-format
 msgid "bad --color-moved argument: %s"
-msgstr ""
+msgstr "невірний --color-moved аргумент: %s"
 
 #, c-format
 msgid "invalid mode '%s' in --color-moved-ws"
-msgstr ""
+msgstr "неприпустимий режим \"%s\" у --color-moved-ws"
 
 msgid ""
 "option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
 "\"histogram\""
 msgstr ""
+"опція diff-algorithm приймає значення \"myers\", \"minimal\", \"patience\" "
+"та \"histogram\""
 
 #, c-format
 msgid "invalid argument to %s"
@@ -14852,361 +15749,383 @@ msgstr "не вдалося розібрати параметр опції --sub
 
 #, c-format
 msgid "bad --word-diff argument: %s"
-msgstr ""
+msgstr "невірний --word-diff аргумент: %s"
 
 msgid "Diff output format options"
-msgstr ""
+msgstr "Варіанти формату виводу різниці"
 
 msgid "generate patch"
 msgstr "згенерувати латку"
 
 msgid "<n>"
-msgstr ""
+msgstr "<n>"
 
 msgid "generate diffs with <n> lines context"
-msgstr ""
+msgstr "згенерувати різниці з контекстом в <n> рядків"
 
 msgid "generate the diff in raw format"
-msgstr ""
+msgstr "згенерувати різницю у форматі raw"
 
 msgid "synonym for '-p --raw'"
-msgstr ""
+msgstr "синонім для \"-p --raw\""
 
 msgid "synonym for '-p --stat'"
-msgstr ""
+msgstr "синонім для \"-p --stat\""
 
 msgid "machine friendly --stat"
 msgstr "машинний вивід --stat"
 
 msgid "output only the last line of --stat"
-msgstr ""
+msgstr "вивести лише останній рядок --stat"
 
 msgid "<param1,param2>..."
-msgstr ""
+msgstr "<параметр1,параметр2>..."
 
 msgid ""
 "output the distribution of relative amount of changes for each sub-directory"
-msgstr ""
+msgstr "вивести розподіл відносної кількості змін для кожної піддиректорії"
 
 msgid "synonym for --dirstat=cumulative"
-msgstr ""
+msgstr "синонім для --dirstat=cumulative"
 
 msgid "synonym for --dirstat=files,param1,param2..."
-msgstr ""
+msgstr "синонім для --dirstat=files,параметр1,параметр2..."
 
 msgid "warn if changes introduce conflict markers or whitespace errors"
 msgstr ""
+"попереджати, якщо зміни призводять до появи конфліктних маркерів або помилок "
+"пробільних символів"
 
 msgid "condensed summary such as creations, renames and mode changes"
-msgstr ""
+msgstr "стислі підсумки, такі як створення, перейменування та зміни режимів"
 
 msgid "show only names of changed files"
-msgstr ""
+msgstr "показувати тільки назви змінених файлів"
 
 msgid "show only names and status of changed files"
-msgstr ""
+msgstr "показувати тільки назви та статус змінених файлів"
 
 msgid "<width>[,<name-width>[,<count>]]"
-msgstr ""
+msgstr "<ширина>[,<ширина-назви>[,<кількість>]]"
 
 msgid "generate diffstat"
-msgstr ""
+msgstr "згенерувати diffstat"
 
 msgid "<width>"
-msgstr ""
+msgstr "<ширина>"
 
 msgid "generate diffstat with a given width"
-msgstr ""
+msgstr "згенерувати diffstat із заданою шириною"
 
 msgid "generate diffstat with a given name width"
-msgstr ""
+msgstr "згенерувати diffstat із заданою шириною назви"
 
 msgid "generate diffstat with a given graph width"
-msgstr ""
+msgstr "згенерувати diffstat із заданою шириною графіка"
 
 msgid "<count>"
-msgstr ""
+msgstr "<кількість>"
 
 msgid "generate diffstat with limited lines"
-msgstr ""
+msgstr "згенерувати diffstat з обмеженою кількістю рядків"
 
 msgid "generate compact summary in diffstat"
-msgstr ""
+msgstr "згенерувати компактний підсумок у diffstat"
 
 msgid "output a binary diff that can be applied"
-msgstr ""
+msgstr "вивести бінарну різницю, яку можна застосувати"
 
 msgid "show full pre- and post-image object names on the \"index\" lines"
 msgstr ""
+"показувати повні назви обʼєктів до та після зображення в \"index\" рядках"
 
 msgid "show colored diff"
-msgstr ""
+msgstr "показати кольорову різницю"
 
 msgid "<kind>"
-msgstr ""
+msgstr "<тип>"
 
 msgid ""
 "highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
 "diff"
 msgstr ""
+"виділяти помилки пробільних символів у \"context\", \"old\" або \"new\" "
+"рядках різниці"
 
 msgid ""
 "do not munge pathnames and use NULs as output field terminators in --raw or "
 "--numstat"
 msgstr ""
+"не змінювати імена шляхів і використовувати NUL як термінатори полів виводу "
+"в --raw або --numstat"
 
 msgid "<prefix>"
-msgstr ""
+msgstr "<префікс>"
 
 msgid "show the given source prefix instead of \"a/\""
-msgstr ""
+msgstr "показувати заданий префікс джерела замість \"a/\""
 
 msgid "show the given destination prefix instead of \"b/\""
-msgstr ""
+msgstr "показувати заданий префікс призначення замість \"b/\""
 
 msgid "prepend an additional prefix to every line of output"
-msgstr ""
+msgstr "додавати префікс до кожного рядка виводу"
 
 msgid "do not show any source or destination prefix"
-msgstr ""
+msgstr "не показувати жодного префікса джерела або призначення"
 
 msgid "use default prefixes a/ and b/"
-msgstr ""
+msgstr "використовувати префікси за замовчуванням a/ та b/"
 
 msgid "show context between diff hunks up to the specified number of lines"
-msgstr ""
+msgstr "показувати контекст між шматками різниці до вказаної кількості рядків"
 
 msgid "<char>"
-msgstr ""
+msgstr "<символ>"
 
 msgid "specify the character to indicate a new line instead of '+'"
-msgstr ""
+msgstr "вкажіть символ для позначення нового рядка замість \"+\""
 
 msgid "specify the character to indicate an old line instead of '-'"
-msgstr ""
+msgstr "вкажіть символ для позначення старого рядка замість \"-\""
 
 msgid "specify the character to indicate a context instead of ' '"
-msgstr ""
+msgstr "вкажіть символ для позначення контексту замість \" \""
 
 msgid "Diff rename options"
-msgstr ""
+msgstr "Варіанти перейменування різниці"
 
 msgid "<n>[/<m>]"
-msgstr ""
+msgstr "<n>[/<m>]"
 
 msgid "break complete rewrite changes into pairs of delete and create"
-msgstr ""
+msgstr "розбити повний перезапис змін на пари delete та create"
 
 msgid "detect renames"
-msgstr ""
+msgstr "виявляти перейменування"
 
 msgid "omit the preimage for deletes"
-msgstr ""
+msgstr "пропускати попереднє зображення для видалень"
 
 msgid "detect copies"
-msgstr ""
+msgstr "виявляти копії"
 
 msgid "use unmodified files as source to find copies"
-msgstr ""
+msgstr "використовувати незмінені файли як джерело для пошуку копій"
 
 msgid "disable rename detection"
-msgstr ""
+msgstr "вимкнути виявлення перейменування"
 
 msgid "use empty blobs as rename source"
-msgstr ""
+msgstr "використовувати порожні blobs як джерело перейменування"
 
 msgid "continue listing the history of a file beyond renames"
-msgstr ""
+msgstr "продовжити виведення історії файлу після перейменування"
 
 msgid ""
 "prevent rename/copy detection if the number of rename/copy targets exceeds "
 "given limit"
 msgstr ""
+"запобігати виявленню перейменування/копіювання, якщо кількість обʼєктів "
+"перейменування/копіювання перевищує заданий ліміт"
 
 msgid "Diff algorithm options"
-msgstr ""
+msgstr "Варіанти алгоритмів різниці"
 
 msgid "produce the smallest possible diff"
-msgstr ""
+msgstr "створювати найменшу можливу різницю"
 
 msgid "ignore whitespace when comparing lines"
-msgstr ""
+msgstr "ігнорувати пробіли при порівнянні рядків"
 
 msgid "ignore changes in amount of whitespace"
-msgstr ""
+msgstr "ігнорувати зміни кількості пробілів"
 
 msgid "ignore changes in whitespace at EOL"
-msgstr ""
+msgstr "ігнорувати зміни пробілів у EOL"
 
 msgid "ignore carrier-return at the end of line"
-msgstr ""
+msgstr "ігнорувати повернення каретки в кінці рядка"
 
 msgid "ignore changes whose lines are all blank"
-msgstr ""
+msgstr "ігнорувати зміни, всі рядки яких порожні"
 
 msgid "<regex>"
-msgstr ""
+msgstr "<регвир>"
 
 msgid "ignore changes whose all lines match <regex>"
-msgstr ""
+msgstr "ігнорувати зміни, всі рядки яких збігаються з <регвир>"
 
 msgid "heuristic to shift diff hunk boundaries for easy reading"
-msgstr ""
+msgstr "евристичне визначення зміщення меж шматка різниці для зручного читання"
 
 msgid "generate diff using the \"patience diff\" algorithm"
-msgstr ""
+msgstr "згенерувати різницю за алгоритмом \"patience diff\""
 
 msgid "generate diff using the \"histogram diff\" algorithm"
-msgstr ""
+msgstr "згенерувати різницю за алгоритмом \"histogram diff\""
 
 msgid "<algorithm>"
-msgstr ""
+msgstr "<алгоритм>"
 
 msgid "choose a diff algorithm"
-msgstr ""
+msgstr "вибрати алгоритм різниці"
 
 msgid "<text>"
-msgstr ""
+msgstr "<текст>"
 
 msgid "generate diff using the \"anchored diff\" algorithm"
-msgstr ""
+msgstr "згенерувати різницю за алгоритмом \"anchored diff\""
 
 msgid "<mode>"
-msgstr ""
+msgstr "<режим>"
 
 msgid "show word diff, using <mode> to delimit changed words"
 msgstr ""
+"показати різницю по словам, використовуючи <режим> для відокремлення "
+"змінених слів"
 
 msgid "use <regex> to decide what a word is"
-msgstr ""
+msgstr "скористайтесь <регвир>, щоб визначити, що це за слово"
 
 msgid "equivalent to --word-diff=color --word-diff-regex=<regex>"
-msgstr ""
+msgstr "еквівалентно --word-diff=color --word-diff-regex=<регвир>"
 
 msgid "moved lines of code are colored differently"
-msgstr ""
+msgstr "переміщені рядки коду мають інший колір"
 
 msgid "how white spaces are ignored in --color-moved"
-msgstr ""
+msgstr "як ігноруються пробіли в --color-moved"
 
 msgid "Other diff options"
-msgstr ""
+msgstr "Інші опції різниці"
 
 msgid "when run from subdir, exclude changes outside and show relative paths"
 msgstr ""
+"при запуску з піддиректорії не враховувати зміни ззовні та показувати "
+"відносні шляхи"
 
 msgid "treat all files as text"
-msgstr ""
+msgstr "обробляти всі файли як текстові"
 
 msgid "swap two inputs, reverse the diff"
-msgstr ""
+msgstr "поміняти місцями два вводи, змінити різницю на протилежну"
 
 msgid "exit with 1 if there were differences, 0 otherwise"
 msgstr ""
+"завершити виконання з кодом 1, якщо були різниці, або з кодом 0 в іншому "
+"випадку"
 
 msgid "disable all output of the program"
-msgstr ""
+msgstr "вимкнути весь вивід програми"
 
 msgid "allow an external diff helper to be executed"
-msgstr ""
+msgstr "дозволити виконання зовнішнього помічника різниці"
 
 msgid "run external text conversion filters when comparing binary files"
 msgstr ""
+"запускати зовнішні фільтри конвертації тексту під час порівняння бінарних "
+"файлів"
 
 msgid "<when>"
-msgstr ""
+msgstr "<коли>"
 
 msgid "ignore changes to submodules in the diff generation"
-msgstr ""
+msgstr "ігнорувати зміни підмодулів у генерації різниці"
 
 msgid "<format>"
-msgstr ""
+msgstr "<формат>"
 
 msgid "specify how differences in submodules are shown"
-msgstr ""
+msgstr "вказати як відображати різниці в підмодулях"
 
 msgid "hide 'git add -N' entries from the index"
 msgstr "приховати записи \"git add -N\" з індексу"
 
 msgid "treat 'git add -N' entries as real in the index"
-msgstr ""
+msgstr "обробляти \"git add -N\" записи як дійсні в індексі"
 
 msgid "<string>"
-msgstr ""
+msgstr "<строка>"
 
 msgid ""
 "look for differences that change the number of occurrences of the specified "
 "string"
-msgstr ""
+msgstr "шукати різниці, які змінюють кількість входжень вказаного рядка"
 
 msgid ""
 "look for differences that change the number of occurrences of the specified "
 "regex"
-msgstr ""
+msgstr "шукати різниці, які змінюють кількість входжень вказаного регвиру"
 
 msgid "show all changes in the changeset with -S or -G"
-msgstr ""
+msgstr "показати всі зміни у змінному наборі з -S або -G"
 
 msgid "treat <string> in -S as extended POSIX regular expression"
-msgstr ""
+msgstr "обробляти <рядок> у -S як розширений POSIX регулярний вираз"
 
 msgid "control the order in which files appear in the output"
-msgstr ""
+msgstr "керувати порядком, у якому файли зʼявляються у виводі"
 
 msgid "<path>"
 msgstr "<шлях>"
 
 msgid "show the change in the specified path first"
-msgstr ""
+msgstr "спочатку показати зміну для зазначеного шляху"
 
 msgid "skip the output to the specified path"
-msgstr ""
+msgstr "пропустити вивід для зазначеного шляху"
 
 msgid "<object-id>"
-msgstr ""
+msgstr "<id-обʼєкта>"
 
 msgid ""
 "look for differences that change the number of occurrences of the specified "
 "object"
-msgstr ""
+msgstr "шукати різниці, які змінюють кількість входжень вказаного обʼєкта"
 
 msgid "[(A|C|D|M|R|T|U|X|B)...[*]]"
-msgstr ""
+msgstr "[(A|C|D|M|R|T|U|X|B)...[*]]"
 
 msgid "select files by diff type"
-msgstr ""
+msgstr "вибрати файли за типом різниці"
 
 msgid "<file>"
-msgstr ""
+msgstr "<файл>"
 
 msgid "output to a specific file"
-msgstr ""
+msgstr "виводити до певного файла"
 
 msgid "exhaustive rename detection was skipped due to too many files."
 msgstr ""
+"вичерпне виявлення перейменування було пропущено через занадто велику "
+"кількість файлів."
 
 msgid "only found copies from modified paths due to too many files."
 msgstr ""
+"знайдено лише копії зі змінених шляхів через занадто велику кількість файлів."
 
 #, c-format
 msgid ""
 "you may want to set your %s variable to at least %d and retry the command."
 msgstr ""
+"можливо, вам слід встановити значення змінної %s принаймні у %d і повторити "
+"команду."
 
 #, c-format
 msgid "failed to read orderfile '%s'"
 msgstr "не вдалося прочитати orderfile \"%s\""
 
 msgid "Performing inexact rename detection"
-msgstr ""
+msgstr "Виявлення неточного перейменування"
 
 #, c-format
 msgid "No such path '%s' in the diff"
-msgstr ""
+msgstr "Немає такого шляху \"%s\" у різниці"
 
 #, c-format
 msgid "pathspec '%s' did not match any file(s) known to git"
-msgstr ""
+msgstr "визначник шляху \"%s\" не збігається з жодним файлом, відомим git"
 
 #, c-format
 msgid "unrecognized pattern: '%s'"
@@ -15219,24 +16138,28 @@ msgstr "нерозпізнаний негативний шаблон: \"%s\""
 #, c-format
 msgid "your sparse-checkout file may have issues: pattern '%s' is repeated"
 msgstr ""
+"ваш файл розрідженого переходу може мати певні проблеми: шаблон \"%s\" "
+"повторюється"
 
 msgid "disabling cone pattern matching"
-msgstr ""
+msgstr "вимкнення зіставлення шаблону конуса"
 
 #, c-format
 msgid "cannot use %s as an exclude file"
 msgstr "неможливо використовувати %s як файл виключення"
 
 msgid "failed to get kernel name and information"
-msgstr ""
+msgstr "не вдалося отримати назву та інформацію про ядро"
 
 msgid "untracked cache is disabled on this system or location"
-msgstr ""
+msgstr "невідстежуваний кеш вимкнено на цій системі або в цьому місці"
 
 msgid ""
 "No directory name could be guessed.\n"
 "Please specify a directory on the command line"
 msgstr ""
+"Hе вдалося вгадати назву директорії.\n"
+"Будь ласка, вкажіть директорію в командному рядку"
 
 #, c-format
 msgid "index file corrupt in repo %s"
@@ -15252,7 +16175,7 @@ msgstr "не вдалося перенести git директорію з \"%s\
 
 #, c-format
 msgid "hint: Waiting for your editor to close the file...%c"
-msgstr ""
+msgstr "підказка: чекаємо, поки редактор закриє файл...%c"
 
 #, c-format
 msgid "could not write to '%s'"
@@ -15263,7 +16186,7 @@ msgid "could not edit '%s'"
 msgstr "не вдалося відредагувати \"%s\""
 
 msgid "Filtering content"
-msgstr ""
+msgstr "Фільтрація вмісту"
 
 #, c-format
 msgid "could not stat file '%s'"
@@ -15271,20 +16194,20 @@ msgstr "не вдалося виконати stat для %s"
 
 #, c-format
 msgid "bad git namespace path \"%s\""
-msgstr ""
+msgstr "невірний шлях до простору імен git \"%s\""
 
 #, c-format
 msgid "too many args to run %s"
 msgstr "забагато аргументів для запуску %s"
 
 msgid "git fetch-pack: expected shallow list"
-msgstr ""
+msgstr "git fetch-pack: очікувався неглибокий список"
 
 msgid "git fetch-pack: expected a flush packet after shallow list"
-msgstr ""
+msgstr "git fetch-pack: очікувалось flush пакет після неглибокого списку"
 
 msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
-msgstr ""
+msgstr "git fetch-pack: очікувалось ACK/NAK, отримано flush пакет"
 
 #, c-format
 msgid "git fetch-pack: expected ACK/NAK, got '%s'"
@@ -15294,7 +16217,7 @@ msgid "unable to write to remote"
 msgstr "не вдалося записати до віддаленого сховища"
 
 msgid "Server supports filter"
-msgstr ""
+msgstr "Сервер підтримує фільтр"
 
 #, c-format
 msgid "invalid shallow line: %s"
@@ -15306,7 +16229,7 @@ msgstr "неприпустимий unshallow рядок: %s"
 
 #, c-format
 msgid "object not found: %s"
-msgstr ""
+msgstr "обʼєкт не знайдено: %s"
 
 #, c-format
 msgid "error in object: %s"
@@ -15314,97 +16237,97 @@ msgstr "помилка в обʼєкті: %s"
 
 #, c-format
 msgid "no shallow found: %s"
-msgstr ""
+msgstr "не знайдено неглибоких: %s"
 
 #, c-format
 msgid "expected shallow/unshallow, got %s"
-msgstr ""
+msgstr "очікувалось shallow/unshallow, отримано %s"
 
 #, c-format
 msgid "got %s %d %s"
-msgstr ""
+msgstr "отримано %s %d %s"
 
 #, c-format
 msgid "invalid commit %s"
 msgstr "неприпустимий коміт %s"
 
 msgid "giving up"
-msgstr ""
+msgstr "здаюся"
 
 msgid "done"
 msgstr "готово"
 
 #, c-format
 msgid "got %s (%d) %s"
-msgstr ""
+msgstr "отримано %s (%d) %s"
 
 #, c-format
 msgid "Marking %s as complete"
-msgstr ""
+msgstr "Позначення %s як завершеного"
 
 #, c-format
 msgid "already have %s (%s)"
-msgstr ""
+msgstr "вже є %s (%s)"
 
 msgid "fetch-pack: unable to fork off sideband demultiplexer"
-msgstr ""
+msgstr "fetch-pack: не вдалося розгалужити sideband demultiplexer"
 
 msgid "protocol error: bad pack header"
-msgstr ""
+msgstr "помилка протоколу: невірний заголовок пакунка"
 
 #, c-format
 msgid "fetch-pack: unable to fork off %s"
-msgstr ""
+msgstr "fetch-pack: не вдалося розгалужити %s"
 
 msgid "fetch-pack: invalid index-pack output"
-msgstr ""
+msgstr "fetch-pack: неприпустиме виведення індексного пакунка"
 
 #, c-format
 msgid "%s failed"
-msgstr ""
+msgstr "%s завершився невдало"
 
 msgid "error in sideband demultiplexer"
-msgstr ""
+msgstr "помилка в sideband demultiplexer"
 
 #, c-format
 msgid "Server version is %.*s"
-msgstr ""
+msgstr "Версія сервера %.*s"
 
 #, c-format
 msgid "Server supports %s"
-msgstr ""
+msgstr "Сервер підтримує %s"
 
 msgid "Server does not support shallow clients"
-msgstr ""
+msgstr "Сервер не підтримує неглибоких клієнтів"
 
 msgid "Server does not support --shallow-since"
-msgstr ""
+msgstr "Сервер не підтримує параметр --shallow-since"
 
 msgid "Server does not support --shallow-exclude"
-msgstr ""
+msgstr "Сервер не підтримує параметр --shallow-exclude"
 
 msgid "Server does not support --deepen"
-msgstr ""
+msgstr "Сервер не підтримує параметр --deepen"
 
 msgid "Server does not support this repository's object format"
-msgstr ""
+msgstr "Сервер не підтримує формат об’єктів цього сховища"
 
 msgid "no common commits"
 msgstr "немає спільних комітів"
 
 msgid "git fetch-pack: fetch failed."
-msgstr ""
+msgstr "git fetch-pack: помилка отримання."
 
 #, c-format
 msgid "mismatched algorithms: client %s; server %s"
-msgstr ""
+msgstr "невідповідність алгоритмів: клієнт %s; сервер %s"
 
 #, c-format
 msgid "the server does not support algorithm '%s'"
 msgstr "сервер не підтримує алгоритм \"%s\""
 
 msgid "Server does not support shallow requests"
-msgstr ""
+msgstr "Сервер не підтримує неглибокі запити"
 
 msgid "unable to write request to remote"
 msgstr "не вдалося записати запит до віддаленого сховища"
@@ -15419,11 +16342,11 @@ msgstr "очікувалось \"%s\""
 
 #, c-format
 msgid "unexpected acknowledgment line: '%s'"
-msgstr ""
+msgstr "несподіваний рядок підтвердження: \"%s\""
 
 #, c-format
 msgid "error processing acks: %d"
-msgstr ""
+msgstr "помилка при обробці підтверджень: %d"
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
@@ -15431,7 +16354,7 @@ msgstr ""
 
 #, c-format
 msgid "expected packfile to be sent after '%s'"
-msgstr ""
+msgstr "очікувалось надсилання файла пакунка після \"%s\""
 
 #. TRANSLATORS: The parameter will be 'ready', a protocol
 #. keyword.
@@ -15439,55 +16362,55 @@ msgstr ""
 
 #, c-format
 msgid "expected no other sections to be sent after no '%s'"
-msgstr ""
+msgstr "не очікувалось надсилання жодної секції для статусу не \"%s\""
 
 #, c-format
 msgid "error processing shallow info: %d"
-msgstr ""
+msgstr "помилка при обробці неглибокої інформації: %d"
 
 #, c-format
 msgid "expected wanted-ref, got '%s'"
-msgstr "оÑ\87Ñ\96кÑ\83валоÑ\81Ñ\8f wanted-ref, отримано \"%s\""
+msgstr "оÑ\87Ñ\96кÑ\83валоÑ\81Ñ\8c wanted-ref, отримано \"%s\""
 
 #, c-format
 msgid "unexpected wanted-ref: '%s'"
-msgstr ""
+msgstr "несподіване запитуване посилання: \"%s\""
 
 #, c-format
 msgid "error processing wanted refs: %d"
-msgstr ""
+msgstr "помилка під час обробки запитуваних посилань: %d"
 
 msgid "git fetch-pack: expected response end packet"
-msgstr ""
+msgstr "git fetch-pack: очікувався response end пакет"
 
 msgid "no matching remote head"
-msgstr ""
+msgstr "немає відповідного віддаленого head"
 
 msgid "unexpected 'ready' from remote"
-msgstr ""
+msgstr "несподіване \"ready\" з віддаленого призначення"
 
 #, c-format
 msgid "no such remote ref %s"
-msgstr "немаÑ\94 Ñ\82акого Ð²Ñ\96ддаленного Ð¿Ð¾Ñ\81иланнÑ\8f %s"
+msgstr "немає такого віддаленого посилання %s"
 
 #, c-format
 msgid "Server does not allow request for unadvertised object %s"
-msgstr ""
+msgstr "Сервер забороняє запити до неоголошених обʼєктів %s"
 
 #, c-format
 msgid "fsmonitor_ipc__send_query: invalid path '%s'"
-msgstr ""
+msgstr "fsmonitor_ipc__send_query: неприпустимий шлях \"%s\""
 
 #, c-format
 msgid "fsmonitor_ipc__send_query: unspecified error on '%s'"
-msgstr ""
+msgstr "fsmonitor_ipc__send_query: невизначена помилка на \"%s\""
 
 msgid "fsmonitor--daemon is not running"
-msgstr ""
+msgstr "fsmonitor--daemon не запущено"
 
 #, c-format
 msgid "could not send '%s' command to fsmonitor--daemon"
-msgstr ""
+msgstr "не вдалося відправити команду \"%s\" до fsmonitor--daemon"
 
 #, c-format
 msgid "bare repository '%s' is incompatible with fsmonitor"
@@ -15495,7 +16418,7 @@ msgstr "порожнє сховище \"%s\" несумісне з fsmonitor"
 
 #, c-format
 msgid "repository '%s' is incompatible with fsmonitor due to errors"
-msgstr ""
+msgstr "сховище \"%s\" несумісне з fsmonitor через помилки"
 
 #, c-format
 msgid "remote repository '%s' is incompatible with fsmonitor"
@@ -15503,13 +16426,15 @@ msgstr "віддалене сховище \"%s\" несумісне з fsmonitor
 
 #, c-format
 msgid "virtual repository '%s' is incompatible with fsmonitor"
-msgstr ""
+msgstr "віртуальне сховище \"%s\" несумісне з fsmonitor"
 
 #, c-format
 msgid ""
 "socket directory '%s' is incompatible with fsmonitor due to lack of Unix "
 "sockets support"
 msgstr ""
+"директорія сокетів \"%s\" несумісна з fsmonitor через відсутність підтримки "
+"сокетів Unix"
 
 msgid ""
 "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
@@ -15519,6 +16444,12 @@ msgid ""
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
 "           [--config-env=<name>=<envvar>] <command> [<args>]"
 msgstr ""
+"git [-v | --version] [-h | --help] [-C <шлях>] [-c <назва>=<значення>]\n"
+"           [--exec-path[=<шлях>]] [--html-path] [--man-path] [--info-path]\n"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
+"bare]\n"
+"           [--git-dir=<шлях>] [--work-tree=<шлях>] [--namespace=<назва>]\n"
+"[--config-env=<назва>=<змінна-оточення>] <команда> [<аргументи>]"
 
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -15526,75 +16457,86 @@ msgid ""
 "to read about a specific subcommand or concept.\n"
 "See 'git help git' for an overview of the system."
 msgstr ""
+"\"git help -a\" і \"git help -g\" виводять доступні підкоманди та деякі\n"
+"посібники з понять. Дивіться \"git help <команда>\" або \"git help "
+"<поняття>\n"
+"щоб прочитати про конкретну підкоманду або поняття.\n"
+"Дивіться \"git help git\" для ознайомлення з системою."
 
 #, c-format
 msgid "unsupported command listing type '%s'"
-msgstr ""
+msgstr "непідтримуваний тип виводу команд \"%s\""
 
 #, c-format
 msgid "no directory given for '%s' option\n"
-msgstr ""
+msgstr "не вказано директорію для \"%s\" опціі\n"
 
 #, c-format
 msgid "no namespace given for --namespace\n"
-msgstr ""
+msgstr "не вказано простір імен для --namespace\n"
 
 #, c-format
 msgid "-c expects a configuration string\n"
-msgstr ""
+msgstr "-c очікує на рядок конфігурації\n"
 
 #, c-format
 msgid "no config key given for --config-env\n"
-msgstr ""
+msgstr "не вказано ключ конфігурації для --config-env\n"
+
+#, c-format
+msgid "no attribute source given for --attr-source\n"
+msgstr "для --attr-source не вказано джерело атрибутів\n"
 
 #, c-format
 msgid "unknown option: %s\n"
-msgstr ""
+msgstr "невідома опція: %s\n"
 
 #, c-format
 msgid "while expanding alias '%s': '%s'"
-msgstr ""
+msgstr "під час розгортання псевдоніма \"%s\": \"%s\""
 
 #, c-format
 msgid ""
 "alias '%s' changes environment variables.\n"
 "You can use '!git' in the alias to do this"
 msgstr ""
+"псевдонім \"%s\" перемінює змінні оточення.\n"
+"Ви можете використовувати \"!git\" в псевдонімі для цього"
 
 #, c-format
 msgid "empty alias for %s"
-msgstr ""
+msgstr "порожній псевдонім для %s"
 
 #, c-format
 msgid "recursive alias: %s"
-msgstr ""
+msgstr "рекурсивний псевдонім: %s"
 
 msgid "write failure on standard output"
-msgstr ""
+msgstr "помилка запису в стандартний вивід"
 
 msgid "unknown write failure on standard output"
-msgstr ""
+msgstr "невідома помилка запису в стандартний вивід"
 
 msgid "close failed on standard output"
-msgstr ""
+msgstr "не вдалося закрити стандартний вивід"
 
 #, c-format
 msgid "alias loop detected: expansion of '%s' does not terminate:%s"
-msgstr ""
+msgstr "виявлено цикл псевдонімів: розширення \"%s\" не припиняє:%s"
 
 #, c-format
 msgid "cannot handle %s as a builtin"
-msgstr ""
+msgstr "неможливо обробити %s як вбудовану команду"
 
 #, c-format
 msgid ""
 "usage: %s\n"
 "\n"
-msgstr ""
+msgstr "використання: %s\n"
 
 #, c-format
 msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
-msgstr ""
+msgstr "не вдалося розширити псевдонім \"%s\"; \"%s\" не є командою git\n"
 
 #, c-format
 msgid "failed to run command '%s': %s\n"
@@ -15611,19 +16553,23 @@ msgid ""
 "gpg.ssh.allowedSignersFile needs to be configured and exist for ssh "
 "signature verification"
 msgstr ""
+"gpg.ssh.allowedSignersFile має бути налаштований та існувати для перевірки "
+"ssh підпису"
 
 msgid ""
 "ssh-keygen -Y find-principals/verify is needed for ssh signature "
 "verification (available in openssh version 8.2p1+)"
 msgstr ""
+"ssh-keygen -Y find-principals/verify необхідно для перевірки підпису ssh "
+"(доступно у версії openssh 8.2p1+)"
 
 #, c-format
 msgid "ssh signing revocation file configured but not found: %s"
-msgstr ""
+msgstr "файл скасування підпису ssh налаштовано, але не знайдено: %s"
 
 #, c-format
 msgid "bad/incompatible signature '%s'"
-msgstr ""
+msgstr "невірний/несумісний підпис \"%s\""
 
 #, c-format
 msgid "failed to get the ssh fingerprint for key '%s'"
@@ -15632,14 +16578,17 @@ msgstr "не вдалося отримати ssh відбиток для клю
 msgid ""
 "either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured"
 msgstr ""
+"потрібно налаштувати або user.signingkey, або gpg.ssh.defaultKeyCommand"
 
 #, c-format
 msgid "gpg.ssh.defaultKeyCommand succeeded but returned no keys: %s %s"
 msgstr ""
+"gpg.ssh.defaultKeyCommand команда виконалася успішно, але не повернула "
+"жодного ключа: %s %s"
 
 #, c-format
 msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
-msgstr ""
+msgstr "gpg.ssh.defaultKeyCommand завершився невдало: %s %s"
 
 #, c-format
 msgid ""
@@ -15650,7 +16599,7 @@ msgstr ""
 "%s"
 
 msgid "user.signingKey needs to be set for ssh signing"
-msgstr ""
+msgstr "user.signingKey має бути налаштований для ssh підписання"
 
 #, c-format
 msgid "failed writing ssh signing key to '%s'"
@@ -15664,19 +16613,23 @@ msgid ""
 "ssh-keygen -Y sign is needed for ssh signing (available in openssh version "
 "8.2p1+)"
 msgstr ""
+"ssh-keygen -Y знак потрібен для ssh підписання (доступно у openssh версії "
+"8.2p1+)"
 
 #, c-format
 msgid "failed reading ssh signing data buffer from '%s'"
-msgstr ""
+msgstr "не вдалося прочитати буфер даних ssh підписання з \"%s\""
 
 #, c-format
 msgid "ignored invalid color '%.*s' in log.graphColors"
-msgstr ""
+msgstr "проігноровано неприпустимий колір \"%.*s\" у log.graphColors"
 
 msgid ""
 "given pattern contains NULL byte (via -f <file>). This is only supported "
 "with -P under PCRE v2"
 msgstr ""
+"заданий шаблон містить NULL байт (через -f <файл>). Це підтримується лише з "
+"опцією -P у PCRE v2"
 
 #, c-format
 msgid "'%s': unable to read %s"
@@ -15684,109 +16637,112 @@ msgstr "\"%s\": не вдалося прочитати %s"
 
 #, c-format
 msgid "'%s': short read"
-msgstr ""
+msgstr "\"%s\": помилка считування"
 
 msgid "start a working area (see also: git help tutorial)"
-msgstr ""
+msgstr "запустити робочу область (дивіться також: git help tutorial)"
 
 msgid "work on the current change (see also: git help everyday)"
-msgstr ""
+msgstr "працювати над поточними змінами (дивіться також: git help everyday)"
 
 msgid "examine the history and state (see also: git help revisions)"
-msgstr ""
+msgstr "переглянути історію та стан (дивіться також: git help revisions)"
 
 msgid "grow, mark and tweak your common history"
-msgstr ""
+msgstr "розвивати, позначати та підправляти вашу спільну історію"
 
 msgid "collaborate (see also: git help workflows)"
-msgstr ""
+msgstr "співпрацювати (дивіться також: git help workflows)"
 
 msgid "Main Porcelain Commands"
-msgstr ""
+msgstr "Основні високорівневі команди"
 
 msgid "Ancillary Commands / Manipulators"
-msgstr ""
+msgstr "Допоміжні команди / Маніпулятори"
 
 msgid "Ancillary Commands / Interrogators"
-msgstr ""
+msgstr "Допоміжні команди / Допитувачі"
 
 msgid "Interacting with Others"
-msgstr ""
+msgstr "Взаємодія з іншими"
 
 msgid "Low-level Commands / Manipulators"
-msgstr ""
+msgstr "Низькорівневі команди / Маніпулятори"
 
 msgid "Low-level Commands / Interrogators"
-msgstr ""
+msgstr "Низькорівневі команди / Допитувачі"
 
 msgid "Low-level Commands / Syncing Repositories"
-msgstr ""
+msgstr "Низькорівневі команди / Сховища синхронізації"
 
 msgid "Low-level Commands / Internal Helpers"
-msgstr ""
+msgstr "Низькорівневі команди / Внутрішні помічники"
 
 msgid "User-facing repository, command and file interfaces"
-msgstr ""
+msgstr "Інтерфейси користувача для сховищ, команд та файлів"
 
 msgid "Developer-facing file formats, protocols and other interfaces"
-msgstr ""
+msgstr "Формати файлів, протоколи та інші інтерфейси розробника"
 
 #, c-format
 msgid "available git commands in '%s'"
 msgstr "доступні команди git в \"%s\""
 
 msgid "git commands available from elsewhere on your $PATH"
-msgstr ""
+msgstr "команди git доступні з будь-якого місця на вашому $PATH"
 
 msgid "These are common Git commands used in various situations:"
-msgstr ""
+msgstr "Це загальні команди Git, які використовуються в різних ситуаціях:"
 
 msgid "The Git concept guides are:"
-msgstr ""
+msgstr "Посібники з понять Git:"
 
 msgid "User-facing repository, command and file interfaces:"
-msgstr ""
+msgstr "Інтерфейси користувача для сховищ, команд та файлів:"
 
 msgid "File formats, protocols and other developer interfaces:"
-msgstr ""
+msgstr "Формати файлів, протоколи та інші інтерфейси розробника:"
 
 msgid "External commands"
-msgstr ""
+msgstr "Зовнішні команди"
 
 msgid "Command aliases"
-msgstr ""
+msgstr "Псевдоніми команд"
 
 msgid "See 'git help <command>' to read about a specific subcommand"
 msgstr ""
+"Дивіться \"git help <команда>\", щоб прочитати про конкретну підкоманду"
 
 #, c-format
 msgid ""
 "'%s' appears to be a git command, but we were not\n"
 "able to execute it. Maybe git-%s is broken?"
 msgstr ""
+"Схоже, що \"%s\" є git командою, але ми не змогли\n"
+"виконати її. Можливо, git-%s не працює?"
 
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr ""
+msgstr "git: \"%s\" не є командою git. Дивітья git --help."
 
 msgid "Uh oh. Your system reports no Git commands at all."
-msgstr ""
+msgstr "Ой-ой. Ваша система повідомляє про повну відсутність Git команд."
 
 #, c-format
 msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr ""
+msgstr "ПОПЕРЕДЖЕННЯ: Ви викликали Git команду \"%s\", якої не існує."
 
 #, c-format
 msgid "Continuing under the assumption that you meant '%s'."
-msgstr ""
+msgstr "Продовжую, припускаючи, що ви мали на увазі \"%s\"."
 
 #, c-format
 msgid "Run '%s' instead [y/N]? "
-msgstr ""
+msgstr "Запустити натомість \"%s\" [y/N]? "
 
 #, c-format
 msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
-msgstr ""
+msgstr "Продовжую через %0.1f секунд, припускаючи, що ви мали на увазі \"%s\"."
 
 msgid ""
 "\n"
@@ -15795,15 +16751,21 @@ msgid_plural ""
 "\n"
 "The most similar commands are"
 msgstr[0] ""
+"\n"
+"Найбільш схожою командою є"
 msgstr[1] ""
+"\n"
+"Найбільш схожими командами є"
 msgstr[2] ""
+"\n"
+"Найбільш схожими командами є"
 
 msgid "git version [--build-options]"
-msgstr ""
+msgstr "git версія [--build-options]"
 
 #, c-format
 msgid "%s: %s - %s"
-msgstr ""
+msgstr "%s: %s - %s"
 
 msgid ""
 "\n"
@@ -15812,18 +16774,27 @@ msgid_plural ""
 "\n"
 "Did you mean one of these?"
 msgstr[0] ""
+"\n"
+"Ви це мали на увазі?"
 msgstr[1] ""
+"\n"
+"Ви мали на увазі одну з цих?"
 msgstr[2] ""
+"\n"
+"Ви мали на увазі одну з цих?"
 
 #, c-format
 msgid ""
 "The '%s' hook was ignored because it's not set as executable.\n"
 "You can disable this warning with `git config advice.ignoredHook false`."
 msgstr ""
+"Гачок \"%s\" було проігноровано, оскільки він не визначений як виконуваний.\n"
+"Ви можете вимкнути це попередження за допомогою \"git config advice."
+"ignoredHook false\"."
 
 #, c-format
 msgid "argument to --packfile must be a valid hash (got '%s')"
-msgstr ""
+msgstr "аргумент до --packfile має бути коректним хешем (отримано \"%s\")"
 
 msgid "not a git repository"
 msgstr "не є git сховищем"
@@ -15831,27 +16802,30 @@ msgstr "не є git сховищем"
 #, c-format
 msgid "negative value for http.postBuffer; defaulting to %d"
 msgstr ""
+"відʼємне значення для http.postBuffer; зміна до значеня за замовчуванням %d"
 
 msgid "Delegation control is not supported with cURL < 7.22.0"
-msgstr ""
+msgstr "Контроль делегування не підтримується з cURL < 7.22.0"
 
 msgid "Public key pinning not supported with cURL < 7.39.0"
-msgstr ""
+msgstr "Закріплення відкритих ключів не підтримується з cURL < 7.39.0"
 
 msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"
-msgstr ""
+msgstr "CURLSSLOPT_NO_REVOKE не підтримується з cURL < 7.44.0"
 
 #, c-format
 msgid "Unsupported SSL backend '%s'. Supported SSL backends:"
-msgstr ""
+msgstr "Непідтримуваний SSL обробник \"%s\". Підтримувані SSL обробники:"
 
 #, c-format
 msgid "Could not set SSL backend to '%s': cURL was built without SSL backends"
 msgstr ""
+"Не вдалося встановити SSL обробник в \"%s\": cURL було зібрано без підтримки "
+"SSL обробників"
 
 #, c-format
 msgid "Could not set SSL backend to '%s': already set"
-msgstr ""
+msgstr "Не вдалося встановити SSL обробник в \"%s\": вже встановлено"
 
 #, c-format
 msgid ""
@@ -15859,12 +16833,15 @@ msgid ""
 "  asked for: %s\n"
 "   redirect: %s"
 msgstr ""
+"не вдалося оновити базу url з перенаправлення:\n"
+"  запитували: %s\n"
+"   перенаправлення: %s"
 
 msgid "Author identity unknown\n"
-msgstr ""
+msgstr "Особистість автора невідома\n"
 
 msgid "Committer identity unknown\n"
-msgstr ""
+msgstr "Особистість комітера невідома\n"
 
 msgid ""
 "\n"
@@ -15879,16 +16856,27 @@ msgid ""
 "Omit --global to set the identity only in this repository.\n"
 "\n"
 msgstr ""
+"\n"
+"*** Будь ласка, скажіть мені, хто ви.\n"
+"\n"
+"Виконайте\n"
+"\n"
+"  git config --global user.email \"you@example.com\"\n"
+"  git config --global user.name \"Ваше Імʼя\"\n"
+"\n"
+"щоб встановити особистість акаунту за замовчуванням.\n"
+"Пропустіть --global, щоб встановити особистість лише для цього сховища.\n"
 
 msgid "no email was given and auto-detection is disabled"
-msgstr ""
+msgstr "не вказана адреса електронної пошти і автоматичне визначення вимкнено"
 
 #, c-format
 msgid "unable to auto-detect email address (got '%s')"
 msgstr ""
+"не вдалося автоматично визначити адресу електронної пошти (отримано \"%s\")"
 
 msgid "no name was given and auto-detection is disabled"
-msgstr ""
+msgstr "імʼя не вказано і автоматичне визначення вимкнено"
 
 #, c-format
 msgid "unable to auto-detect name (got '%s')"
@@ -15896,21 +16884,21 @@ msgstr "не вдалося автоматично визначити назву
 
 #, c-format
 msgid "empty ident name (for <%s>) not allowed"
-msgstr ""
+msgstr "порожнє імʼя особистості (для <%s>) заборонено"
 
 #, c-format
 msgid "name consists only of disallowed characters: %s"
-msgstr ""
+msgstr "імʼя складається лише з заборонених символів: %s"
 
 msgid "expected 'tree:<depth>'"
-msgstr ""
+msgstr "очікувалось \"tree:<глибина>\""
 
 msgid "sparse:path filters support has been dropped"
-msgstr ""
+msgstr "підтримку фільтрів sparse:path було припинено"
 
 #, c-format
 msgid "'%s' for 'object:type=<type>' is not a valid object type"
-msgstr ""
+msgstr "\"%s\" для \"object:type=<type>\" не є припустимим типом обʼєкта"
 
 #, c-format
 msgid "invalid filter-spec '%s'"
@@ -15918,38 +16906,38 @@ msgstr "неприпустимий визначник фільтра \"%s\""
 
 #, c-format
 msgid "must escape char in sub-filter-spec: '%c'"
-msgstr ""
+msgstr "необхідно екранувати символ у sub-filter-spec: \"%c\""
 
 msgid "expected something after combine:"
-msgstr ""
+msgstr "щоcь очікувалось після комбінування:"
 
 msgid "multiple filter-specs cannot be combined"
-msgstr ""
+msgstr "не можна комбінувати кілька визначників фільтра"
 
 msgid "unable to upgrade repository format to support partial clone"
-msgstr ""
+msgstr "не вдалося оновити формат сховища для підтримки часткового клонування"
 
 msgid "args"
-msgstr ""
+msgstr "аргументи"
 
 msgid "object filtering"
-msgstr ""
+msgstr "фільтрація обʼєктів"
 
 #, c-format
 msgid "unable to access sparse blob in '%s'"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð¾Ñ\82Ñ\80имаÑ\82и Ð´Ð¾Ñ\81Ñ\82Ñ\83п Ð´Ð¾ Ñ\87аÑ\81Ñ\82кового blob в \"%s\""
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð¾Ñ\82Ñ\80имаÑ\82и Ð´Ð¾Ñ\81Ñ\82Ñ\83п Ð´Ð¾ Ñ\80озÑ\80Ñ\96дженого blob в \"%s\""
 
 #, c-format
 msgid "unable to parse sparse filter data in %s"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\80озÑ\96бÑ\80аÑ\82и Ð´Ð°Ð½Ñ\96 Ñ\87аÑ\81Ñ\82кового фільтра в %s"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ñ\80озÑ\96бÑ\80аÑ\82и Ð´Ð°Ð½Ñ\96 Ñ\80озÑ\80Ñ\96дженого фільтра в %s"
 
 #, c-format
 msgid "entry '%s' in tree %s has tree mode, but is not a tree"
-msgstr ""
+msgstr "запис \"%s\" у дереві %s має режим tree, але не є деревом"
 
 #, c-format
 msgid "entry '%s' in tree %s has blob mode, but is not a blob"
-msgstr ""
+msgstr "запис \"%s\" у дереві %s має режим blob, але не є blob"
 
 #, c-format
 msgid "unable to load root tree for commit %s"
@@ -15965,6 +16953,15 @@ msgid ""
 "may have crashed in this repository earlier:\n"
 "remove the file manually to continue."
 msgstr ""
+"Не вдалося створити \"%s.lock\": %s.\n"
+"\n"
+"Схоже, у цьому сховищі запущено інший git процес, наприклад\n"
+"редактор, відкритий командою \"git commit\". Будь ласка, переконайтеся, що "
+"всі процеси\n"
+"завершено, а потім спробуйте ще раз. Якщо все одно не вдасться, можливо, "
+"раніше \n"
+"у цьому сховищі аварійно завершився git процес:\n"
+"видаліть файл вручну, щоб продовжити."
 
 #, c-format
 msgid "Unable to create '%s.lock': %s"
@@ -15972,33 +16969,33 @@ msgstr "Не вдалося створити \"%s.lock\": %s"
 
 #, c-format
 msgid "unexpected line: '%s'"
-msgstr ""
+msgstr "неочікуваний рядок: \"%s\""
 
 msgid "expected flush after ls-refs arguments"
-msgstr ""
+msgstr "очікувався flush після ls-refs аргументів"
 
 msgid "quoted CRLF detected"
-msgstr ""
+msgstr "виявлено цитований CRLF"
 
 #, c-format
 msgid "Failed to merge submodule %s (not checked out)"
-msgstr ""
+msgstr "Не вдалося обʼєднати підмодуль %s (не активне)"
 
 #, c-format
 msgid "Failed to merge submodule %s (no merge base)"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s (немає бази злиття)"
 
 #, c-format
 msgid "Failed to merge submodule %s (commits not present)"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s (відсутні коміти)"
 
 #, c-format
 msgid "Failed to merge submodule %s (commits don't follow merge-base)"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s (коміти не відповідають базі)"
 
 #, c-format
 msgid "Note: Fast-forwarding submodule %s to %s"
-msgstr ""
+msgstr "Примітка: перемотування підмодуля %s вперед до %s"
 
 #, c-format
 msgid "Failed to merge submodule %s"
@@ -16007,16 +17004,18 @@ msgstr "Не вдалося злити підмодуль %s"
 #, c-format
 msgid ""
 "Failed to merge submodule %s, but a possible merge resolution exists: %s"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s, але існує можливе вирішення злиття: %s"
 
 #, c-format
 msgid ""
 "Failed to merge submodule %s, but multiple possible merges exist:\n"
 "%s"
 msgstr ""
+"Не вдалося злити підмодуль %s, але існує кілька можливих варіантів злиття:\n"
+"%s"
 
 msgid "Failed to execute internal merge"
-msgstr ""
+msgstr "Не вдалося виконати внутрішнє злиття"
 
 #, c-format
 msgid "Unable to add %s to database"
@@ -16024,19 +17023,24 @@ msgstr "Не вдалося додати %s до бази даних"
 
 #, c-format
 msgid "Auto-merging %s"
-msgstr ""
+msgstr "Автоматичне злиття %s"
 
 #, c-format
 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 ""
+"КОНФЛІКТ (неявне перейменування каталогу): існуючий файл/директорія в %s "
+"заважає неявному перейменуванню директорії, додавши наступні шляхи до: %s."
 
 #, c-format
 msgid ""
 "CONFLICT (implicit dir rename): Cannot map more than one path to %s; "
 "implicit directory renames tried to put these paths there: %s"
 msgstr ""
+"КОНФЛІКТ (неявне перейменування директорії): Неможливо зіставити більше "
+"одного шляху з %s; неявне перейменування директорій намагалося помістити "
+"туди ці шляхи: %s"
 
 #, c-format
 msgid ""
@@ -16044,40 +17048,56 @@ msgid ""
 "renamed to multiple other directories, with no destination getting a "
 "majority of the files."
 msgstr ""
+"КОНФЛІКТ (розбіжність під час перейменування директорії): Неясно, як "
+"перейменувати директорію %s; її було перейменовано в кілька інших "
+"директорій, жодна з яких не отримала більшості файлів."
 
 #, c-format
 msgid ""
 "WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
 "renamed."
 msgstr ""
+"ПОПЕРЕДЖЕННЯ: уникнення застосування %s -> %s перейменування на %s, оскільки "
+"%s було перейменовано."
 
 #, c-format
 msgid ""
 "Path updated: %s added in %s inside a directory that was renamed in %s; "
 "moving it to %s."
 msgstr ""
+"Шлях було оновлено: %s додано до %s всередині директорії, яку було "
+"перейменовано в %s; переміщення до %s."
 
 #, c-format
 msgid ""
 "Path updated: %s renamed to %s in %s, inside a directory that was renamed in "
 "%s; moving it to %s."
 msgstr ""
+"Шлях було оновлено: %s перейменовано на %s в %s, всередині директорії, яку "
+"було перейменовано в %s; переміщення до %s."
 
 #, c-format
 msgid ""
 "CONFLICT (file location): %s added in %s inside a directory that was renamed "
 "in %s, suggesting it should perhaps be moved to %s."
 msgstr ""
+"КОНФЛІКТ (розташування файлу): %s додано до %s всередині директорії, яку "
+"було перейменовано в %s, що свідчить про те, що його слід перемістити до %s."
 
 #, c-format
 msgid ""
 "CONFLICT (file location): %s renamed to %s in %s, inside a directory that "
 "was renamed in %s, suggesting it should perhaps be moved to %s."
 msgstr ""
+"КОНФЛІКТ (розташування файлу): %s перейменовано на %s в %s всередині "
+"директорії, яку було перейменовано в %s, що свідчить про те, що його слід "
+"перемістити до %s."
 
 #, c-format
 msgid "CONFLICT (rename/rename): %s renamed to %s in %s and to %s in %s."
 msgstr ""
+"КОНФЛІКТ (перейменовано/перейменовано): %s перейменовано на %s в %s та на %s "
+"в %s."
 
 #, c-format
 msgid ""
@@ -16085,10 +17105,15 @@ msgid ""
 "conflicts AND collides with another path; this may result in nested conflict "
 "markers."
 msgstr ""
+"КОНФЛІКТ (перейменування призвело до колізії): перейменування %s -> %s має "
+"конфлікт вмісту та зіткається з іншим шляхом; це може призвести до появи "
+"вкладених маркерів конфлікту."
 
 #, c-format
 msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s."
 msgstr ""
+"КОНФЛІКТ (перейменовано/видалено): %s перейменовано на %s в %s, але видалено "
+"в %s."
 
 #, c-format
 msgid "cannot read object %s"
@@ -16103,37 +17128,45 @@ msgid ""
 "CONFLICT (file/directory): directory in the way of %s from %s; moving it to "
 "%s instead."
 msgstr ""
+"КОНФЛІКТ (файл/директорія): директорія на шляху %s від %s; переміщення її до "
+"%s замість цього."
 
 #, c-format
 msgid ""
 "CONFLICT (distinct types): %s had different types on each side; renamed both "
 "of them so each can be recorded somewhere."
 msgstr ""
+"КОНФЛІКТ (різні типи): %s мали різні типи з обох боків; перейменовано "
+"обидва, щоб кожен можна було десь записати."
 
 #, c-format
 msgid ""
 "CONFLICT (distinct types): %s had different types on each side; renamed one "
 "of them so each can be recorded somewhere."
 msgstr ""
+"КОНФЛІКТ (різні типи): %s мали різні типи з обох боків; перейменовано один з "
+"них, щоб кожен можна було десь записати."
 
 msgid "content"
-msgstr ""
+msgstr "вміст"
 
 msgid "add/add"
-msgstr ""
+msgstr "додано/додано"
 
 msgid "submodule"
-msgstr ""
+msgstr "підмодуль"
 
 #, c-format
 msgid "CONFLICT (%s): Merge conflict in %s"
-msgstr ""
+msgstr "КОНФЛІКТ (%s): конфлікт злиття в %s"
 
 #, c-format
 msgid ""
 "CONFLICT (modify/delete): %s deleted in %s and modified in %s.  Version %s "
 "of %s left in tree."
 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
@@ -16147,6 +17180,8 @@ 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"
 
 #, c-format
 msgid ""
@@ -16161,6 +17196,16 @@ msgid ""
 " - 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.
@@ -16168,10 +17213,10 @@ msgstr ""
 
 #, c-format
 msgid "collecting merge info failed for trees %s, %s, %s"
-msgstr ""
+msgstr "збирання інформації про злиття не вдалося для дерев %s, %s, %s"
 
 msgid "(bad commit)\n"
-msgstr ""
+msgstr "(невірний коміт)\n"
 
 #, c-format
 msgid "add_cacheinfo failed for path '%s'; merge aborting."
@@ -16180,6 +17225,8 @@ msgstr "невдала спроба add_cacheinfo для шляху \"%s\"; пе
 #, c-format
 msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
 msgstr ""
+"процесу add_cacheinfo не вдалося зробити оновлення для шляху \"%s\"; "
+"переривання злиття."
 
 #, c-format
 msgid "failed to create path '%s'%s"
@@ -16187,14 +17234,14 @@ msgstr "не вдалося створити шлях \"%s\"%s"
 
 #, c-format
 msgid "Removing %s to make room for subdirectory\n"
-msgstr ""
+msgstr "Видалення %s, щоб звільнити місце для піддиректорії\n"
 
 msgid ": perhaps a D/F conflict?"
-msgstr ""
+msgstr ": можливо, D/F конфлікт?"
 
 #, c-format
 msgid "refusing to lose untracked file at '%s'"
-msgstr "вÑ\96дмова Ð²Ñ\96д Ð²Ñ\82Ñ\80аÑ\82и невідстежуваного файла \"%s\""
+msgstr "вÑ\96дмовлено Ñ\83 Ð²Ñ\82Ñ\80аÑ\82Ñ\96 невідстежуваного файла \"%s\""
 
 #, c-format
 msgid "blob expected for %s '%s'"
@@ -16210,26 +17257,26 @@ msgstr "не вдалося зробити символьне посилання
 
 #, c-format
 msgid "do not know what to do with %06o %s '%s'"
-msgstr ""
+msgstr "не знаю, що робити з %06o %s \"%s\""
 
 #, c-format
 msgid "Fast-forwarding submodule %s to the following commit:"
-msgstr ""
+msgstr "Перемотування підмодуля %s вперед до наступного коміту:"
 
 #, c-format
 msgid "Fast-forwarding submodule %s"
-msgstr ""
+msgstr "Перемотування підмодуля %s вперед"
 
 #, c-format
 msgid "Failed to merge submodule %s (merge following commits not found)"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s (злиття наступних комітів не знайдено)"
 
 #, c-format
 msgid "Failed to merge submodule %s (not fast-forward)"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s (не вдалося перемотати вперед)"
 
 msgid "Found a possible merge resolution for the submodule:\n"
-msgstr ""
+msgstr "Знайдено можливе вирішення злиття для підмодуля:\n"
 
 #, c-format
 msgid ""
@@ -16240,38 +17287,54 @@ msgid ""
 "\n"
 "which will accept this suggestion.\n"
 msgstr ""
+"Якщо все вірно, просто додайте це до індексу, наприклад,\n"
+"використавши:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"який прийме цю пропозицію.\n"
 
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
-msgstr ""
+msgstr "Не вдалося злити підмодуль %s (знайдено більше одного злиття)"
 
 #, c-format
 msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
 msgstr ""
+"Помилка: відмовлено у втраті невідстежуваного файла %s; натомість записуємо "
+"до %s."
 
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
 "in tree."
 msgstr ""
+"КОНФЛІКТ (%s/видалено): %s видалено в %s та %s в %s. Версію %s з %s залишено "
+"в дереві."
 
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s to %s in %s. Version %s of %s "
 "left in tree."
 msgstr ""
+"КОНФЛІКТ (%s/видалено): %s видалено в %s і %s в %s в %s. Версію %s з %s "
+"залишено у дереві."
 
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
 "in tree at %s."
 msgstr ""
+"КОНФЛІКТ (%s/видалено): %s видалено в %s і %s в %s. Версію %s з %s залишено "
+"у дереві в %s."
 
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s to %s in %s. Version %s of %s "
 "left in tree at %s."
 msgstr ""
+"КОНФЛІКТ (%s/видалено): %s видалено в %s і %s в %s в %s. Версію %s з %s "
+"залишено в дереві в %s."
 
 msgid "rename"
 msgstr "перейменувати"
@@ -16281,36 +17344,43 @@ msgstr "перейменовано"
 
 #, c-format
 msgid "Refusing to lose dirty file at %s"
-msgstr "Ð\92Ñ\96дмова Ð²Ñ\96д Ð²Ñ\82Ñ\80аÑ\82и брудного файла %s"
+msgstr "Ð\92Ñ\96дмовлено Ñ\83 Ð²Ñ\82Ñ\80аÑ\82Ñ\96 брудного файла %s"
 
 #, c-format
 msgid "Refusing to lose untracked file at %s, even though it's in the way."
 msgstr ""
+"Відмовлено у втраті невідстежуваного файла %s, не дивлячись на те, що він "
+"знаходиться на шляху."
 
 #, c-format
 msgid "CONFLICT (rename/add): Rename %s->%s in %s.  Added %s in %s"
 msgstr ""
+"КОНФЛІКТ (перейменовано/додано): перейменовано %s->%s в %s.  Додано %s в %s"
 
 #, c-format
 msgid "%s is a directory in %s adding as %s instead"
-msgstr ""
+msgstr "%s є директорією в %s, натомість додаємо як %s"
 
 #, c-format
 msgid "Refusing to lose untracked file at %s; adding as %s instead"
-msgstr ""
+msgstr "Відмовлено у втраті невідстежуваного файла %s; натомість додаємо як %s"
 
 #, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename "
 "\"%s\"->\"%s\" in \"%s\"%s"
 msgstr ""
+"КОНФЛІКТ (перейменовано/перейменовано): перейменовано \"%s\"->\"%s\" у гілці "
+"\"%s\" перейменовано \"%s\"->\"%s\" у \"%s\"%s"
 
 msgid " (left unresolved)"
-msgstr ""
+msgstr " (залишилося нерозвʼязаним)"
 
 #, c-format
 msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
 msgstr ""
+"КОНФЛІКТ (перейменовано/перейменовано): перейменовано %s->%s в %s. "
+"Перейменовано %s->%s в %s"
 
 #, c-format
 msgid ""
@@ -16318,12 +17388,17 @@ msgid ""
 "directory %s was renamed to multiple other directories, with no destination "
 "getting a majority of the files."
 msgstr ""
+"КОНФЛІКТ (розбіжність під час перейменування директорії): Неясно, куди "
+"помістити %s, оскільки директорію %s було перейменовано в кілька інших "
+"директорій,  жодна з яких не отримала більшості файлів."
 
 #, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename directory %s->%s in %s. Rename directory %s-"
 ">%s in %s"
 msgstr ""
+"КОНФЛІКТ (перейменовано/перейменовано): перейменовано директорію %s->%s в "
+"%s. Перейменовано директорію %s->%s в %s"
 
 msgid "modify"
 msgstr "змінити"
@@ -16333,11 +17408,11 @@ msgstr "змінено"
 
 #, c-format
 msgid "Skipped %s (merged same as existing)"
-msgstr ""
+msgstr "Пропущено %s (злите - те саме, що й існуюче)"
 
 #, c-format
 msgid "Adding as %s instead"
-msgstr ""
+msgstr "Додавання як %s замість цього"
 
 #, c-format
 msgid "Removing %s"
@@ -16347,36 +17422,36 @@ msgid "file/directory"
 msgstr "файл/директорія"
 
 msgid "directory/file"
-msgstr ""
+msgstr "директорія/файл"
 
 #, c-format
 msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
-msgstr ""
+msgstr "КОНФЛІКТ (%s): в %s існує директорія з іменем %s. Додавання %s як %s"
 
 #, c-format
 msgid "Adding %s"
-msgstr ""
+msgstr "Додавання %s"
 
 #, c-format
 msgid "CONFLICT (add/add): Merge conflict in %s"
-msgstr ""
+msgstr "КОНФЛІКТ (додано/додано): Конфлікт злиття у %s"
 
 #, c-format
 msgid "merging of trees %s and %s failed"
-msgstr ""
+msgstr "не вдалося злити дерева %s та %s"
 
 msgid "Merging:"
-msgstr ""
+msgstr "Злиття:"
 
 #, c-format
 msgid "found %u common ancestor:"
 msgid_plural "found %u common ancestors:"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "знайшли %u спільного предка:"
+msgstr[1] "знайшли %u спільних предків:"
+msgstr[2] "знайшли %u спільних предків:"
 
 msgid "merge returned no commit"
-msgstr ""
+msgstr "злиття не повернуло коміт"
 
 #, c-format
 msgid "Could not parse object '%s'"
@@ -16386,46 +17461,49 @@ msgid "failed to read the cache"
 msgstr "не вдалося прочитати кеш"
 
 msgid "multi-pack-index OID fanout is of the wrong size"
-msgstr ""
+msgstr "multi-pack-index OID fanout має невірний розмір"
 
 #, c-format
 msgid "multi-pack-index file %s is too small"
-msgstr ""
+msgstr "multi-pack-index файл %s занадто малий"
 
 #, c-format
 msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
-msgstr ""
+msgstr "multi-pack-index підпис 0x%08x не збігається з підписом 0x%08x"
 
 #, c-format
 msgid "multi-pack-index version %d not recognized"
-msgstr ""
+msgstr "multi-pack-index версія %d не розпізнана"
 
 #, c-format
 msgid "multi-pack-index hash version %u does not match version %u"
-msgstr ""
+msgstr "версія хешу multi-pack-index %u не збігається з версією %u"
 
 msgid "multi-pack-index missing required pack-name chunk"
-msgstr ""
+msgstr "multi-pack-index недостає необхідного фрагмента імені пакунка"
 
 msgid "multi-pack-index missing required OID fanout chunk"
-msgstr ""
+msgstr "multi-pack-index недостає необхідного OID fanout фрагмента"
 
 msgid "multi-pack-index missing required OID lookup chunk"
-msgstr ""
+msgstr "multi-pack-index недостає необхідного OID lookup фрагмента"
 
 msgid "multi-pack-index missing required object offsets chunk"
-msgstr ""
+msgstr "multi-pack-index недостає необхідного фрагмента зміщення обʼєктів"
 
 #, c-format
 msgid "multi-pack-index pack names out of order: '%s' before '%s'"
 msgstr ""
+"multi-pack-index назви пакунків знаходяться у невірній послідовності: \"%s\" "
+"перед \"%s\""
 
 #, c-format
 msgid "bad pack-int-id: %u (%u total packs)"
-msgstr ""
+msgstr "невірний pack-int-id: %u (%u всього пакунків)"
 
 msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
 msgstr ""
+"multi-pack-index зберігає 64-бітне зміщення, але значення off_t занадто мале"
 
 #, c-format
 msgid "failed to add packfile '%s'"
@@ -16437,7 +17515,7 @@ msgstr "не вдалося відкрити pack-index \"%s\""
 
 #, c-format
 msgid "failed to locate object %d in packfile"
-msgstr ""
+msgstr "не вдалося знайти обʼєкт %d у файлі пакунка"
 
 msgid "cannot store reverse index file"
 msgstr "неможливо зберегти файл зворотнього індексу"
@@ -16448,10 +17526,11 @@ msgstr "не вдалося розібрати рядок: %s"
 
 #, c-format
 msgid "malformed line: %s"
-msgstr ""
+msgstr "невірно сформований рядок: %s"
 
 msgid "ignoring existing multi-pack-index; checksum mismatch"
 msgstr ""
+"ігнорування існуючого multi-pack-index; невідповідність контрольних сум"
 
 msgid "could not load pack"
 msgstr "не вдалося завантажити пакет"
@@ -16461,32 +17540,32 @@ msgid "could not open index for %s"
 msgstr "не вдалося відкрити індекс для %s"
 
 msgid "Adding packfiles to multi-pack-index"
-msgstr ""
+msgstr "Додавання пакунків до multi-pack-index"
 
 #, c-format
 msgid "unknown preferred pack: '%s'"
-msgstr ""
+msgstr "невідомий бажаний пакунок: \"%s\""
 
 #, c-format
 msgid "cannot select preferred pack %s with no objects"
-msgstr ""
+msgstr "неможливо вибрати бажаний пакунок %s за відсутності об’єктів"
 
 #, c-format
 msgid "did not see pack-file %s to drop"
-msgstr ""
+msgstr "не побачив файл пакунка %s, який потрібно скинути"
 
 #, c-format
 msgid "preferred pack '%s' is expired"
-msgstr ""
+msgstr "у бажаного пакета \"%s\" закінчився термін дії"
 
 msgid "no pack files to index."
-msgstr ""
+msgstr "немає файлів пакунків для індексації."
 
 msgid "refusing to write multi-pack .bitmap without any objects"
-msgstr ""
+msgstr "відмовлено в записі мультіпакункового .bitmap без обʼєктів"
 
 msgid "could not write multi-pack bitmap"
-msgstr ""
+msgstr "не вдалося записати мультіпакунковий bitmap"
 
 msgid "could not write multi-pack-index"
 msgstr "не вдалося записати multi-pack-index"
@@ -16496,10 +17575,10 @@ msgid "failed to clear multi-pack-index at %s"
 msgstr "не вдалося очистити multi-pack-index при %s"
 
 msgid "multi-pack-index file exists, but failed to parse"
-msgstr ""
+msgstr "multi-pack-index файл існує, але його не вдалося розібрати"
 
 msgid "incorrect checksum"
-msgstr ""
+msgstr "невірна контрольна сума"
 
 msgid "Looking for referenced packfiles"
 msgstr "Пошук файлів пакунків, на які є посилання"
@@ -16508,40 +17587,42 @@ msgstr "Пошук файлів пакунків, на які є посилан
 msgid ""
 "oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
 msgstr ""
+"невірна послідовность oid fanout: fanout[%d] = %<PRIx32> > %<PRIx32> = "
+"fanout[%d]"
 
 msgid "the midx contains no oid"
-msgstr ""
+msgstr "midx не містить oid"
 
 msgid "Verifying OID order in multi-pack-index"
-msgstr ""
+msgstr "Перевірка OID послідовності в multi-pack-index"
 
 #, c-format
 msgid "oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"
-msgstr ""
+msgstr "невірна послідовність oid lookup: oid[%d] = %s >= %s = oid[%d]"
 
 msgid "Sorting objects by packfile"
-msgstr ""
+msgstr "Сортування обʼєктів за файлом пакунка"
 
 msgid "Verifying object offsets"
 msgstr "Перевірка зміщень обʼєкта"
 
 #, c-format
 msgid "failed to load pack entry for oid[%d] = %s"
-msgstr ""
+msgstr "не вдалося завантажити запис пакунка для oid[%d] = %s"
 
 #, c-format
 msgid "failed to load pack-index for packfile %s"
-msgstr ""
+msgstr "не вдалося завантажити індекс файла пакунка %s"
 
 #, c-format
 msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-msgstr ""
+msgstr "невірне зміщення обʼєкта для oid[%d] = %s: %<PRIx64> != %<PRIx64>"
 
 msgid "Counting referenced objects"
 msgstr "Підрахунок обʼєктів, на які є посилання"
 
 msgid "Finding and deleting unreferenced packfiles"
-msgstr ""
+msgstr "Пошук і видалення файлів пакунків без посилань"
 
 msgid "could not start pack-objects"
 msgstr "не вдалося розпочати pack-objects"
@@ -16567,21 +17648,25 @@ 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 ""
+"Ви не завершили попереднє злиття нотаток (існує %s).\n"
+"Будь ласка, скористайтесь командами \"git notes merge --commit\" або \"git "
+"notes merge --abort\", щоб зробити коміт/скасувати попереднє злиття, перш "
+"ніж розпочати нове злиття нотаток."
 
 #, c-format
 msgid "You have not concluded your notes merge (%s exists)."
-msgstr ""
+msgstr "Ви не завершили злиття ваших нотаток (%s існує)."
 
 msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr ""
+msgstr "Неможливо зробити коміт неініціалізованого/непосиланого дерева нотаток"
 
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
-msgstr ""
+msgstr "Невірнe notes.rewriteMode значення: \"%s\""
 
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
-msgstr ""
+msgstr "Відмовлено в перезаписі нотаток у %s (за межами refs/notes/)"
 
 #. TRANSLATORS: The first %s is the name of
 #. the environment variable, the second %s is
@@ -16594,24 +17679,26 @@ msgstr "Невірне %s значення: \"%s\""
 
 #, c-format
 msgid "object directory %s does not exist; check .git/objects/info/alternates"
-msgstr ""
+msgstr "директорія об’єкта %s не існує; перевірте .git/objects/info/alternates"
 
 #, c-format
 msgid "unable to normalize alternate object path: %s"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð½Ð¾Ñ\80малÑ\96зÑ\83ваÑ\82и Ñ\88лÑ\8fÑ\85 Ð°Ð»Ñ\8cÑ\82еÑ\80наÑ\82ивного обʼєкта: %s"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð½Ð¾Ñ\80малÑ\96зÑ\83ваÑ\82и Ñ\88лÑ\8fÑ\85 Ð·Ð°Ð¿Ð¾Ð·Ð¸Ñ\87еного обʼєкта: %s"
 
 #, c-format
 msgid "%s: ignoring alternate object stores, nesting too deep"
 msgstr ""
+"%s: ігнорування місць збереження запозичених об’єктів, надто глибока "
+"вкладеність"
 
 msgid "unable to fdopen alternates lockfile"
-msgstr "не вдалося виконати fdopen для файла блокування спільних обʼєктів"
+msgstr "не вдалося виконати fdopen для файла блокування запозичених обʼєктів"
 
 msgid "unable to read alternates file"
-msgstr "не вдалося прочитати файл спільних обʼєктів"
+msgstr "не вдалося прочитати файл запозичених обʼєктів"
 
 msgid "unable to move new alternates file into place"
-msgstr "не вдалося перемістити файл нових спільних обʼєктів на місце"
+msgstr "не вдалося перемістити файл нових запозичених обʼєктів на місце"
 
 #, c-format
 msgid "path '%s' does not exist"
@@ -16619,7 +17706,7 @@ msgstr "шлях \"%s\" не існує"
 
 #, c-format
 msgid "reference repository '%s' as a linked checkout is not supported yet."
-msgstr ""
+msgstr "посилання на сховище \"%s\" як повʼязане поки що не підтримується."
 
 #, c-format
 msgid "reference repository '%s' is not a local repository."
@@ -16627,7 +17714,7 @@ msgstr "сховище посилання \"%s\" не є локальним сх
 
 #, c-format
 msgid "reference repository '%s' is shallow"
-msgstr "Ñ\81Ñ\85овиÑ\89е Ð¿Ð¾Ñ\81иланнÑ\8f \"%s\" Ñ\94 Ð¿Ð¾Ð²ÐµÑ\80Ñ\85невим"
+msgstr "Ñ\81Ñ\85овиÑ\89е Ð¿Ð¾Ñ\81иланнÑ\8f \"%s\" Ñ\94 Ð½ÐµÐ³Ð»Ð¸Ð±Ð¾Ðºим"
 
 #, c-format
 msgid "reference repository '%s' is grafted"
@@ -16639,15 +17726,15 @@ msgstr "не вдалося знайти директорію обʼєктів,
 
 #, c-format
 msgid "invalid line while parsing alternate refs: %s"
-msgstr ""
+msgstr "неприпустимий рядок при розбиранні посилань запозичених обʼєктів: %s"
 
 #, c-format
 msgid "attempting to mmap %<PRIuMAX> over limit %<PRIuMAX>"
-msgstr ""
+msgstr "спроба виконати mmap %<PRIuMAX> за межею %<PRIuMAX>"
 
 #, c-format
 msgid "mmap failed%s"
-msgstr ""
+msgstr "операція mmap не вдалася%s"
 
 #, c-format
 msgid "object file %s is empty"
@@ -16659,7 +17746,7 @@ msgstr "пошкоджено вільний обʼєкт \"%s\""
 
 #, c-format
 msgid "garbage at end of loose object '%s'"
-msgstr ""
+msgstr "непотріб в кінці вільного обʼєкта \"%s\""
 
 #, c-format
 msgid "unable to open loose object %s"
@@ -16678,7 +17765,7 @@ msgstr "не вдалося розпакувати %s заголовок"
 
 #, c-format
 msgid "header for %s too long, exceeds %d bytes"
-msgstr ""
+msgstr "заголовок для %s занадто довгий, перевищує %d байт"
 
 #, c-format
 msgid "loose object %s (stored in %s) is corrupt"
@@ -16698,14 +17785,14 @@ msgstr "не вдалося записати файл %s"
 
 #, c-format
 msgid "unable to set permission to '%s'"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\81Ñ\82ановиÑ\82и Ð¿Ñ\80ава Ð´Ð¾Ñ\81Ñ\82Ñ\83пÑ\83 Ð´Ð¾ \"%s\""
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\81Ñ\82ановиÑ\82и Ð´Ð¾Ð·Ð²Ð¾Ð»Ð¸ Ð´Ð»Ñ\8f \"%s\""
 
 msgid "error when closing loose object file"
 msgstr "помилка при закритті файла вільного об’єкта"
 
 #, c-format
 msgid "insufficient permission for adding an object to repository database %s"
-msgstr ""
+msgstr "недостатньо дозволу для додавання обʼєкта до бази даних сховища %s"
 
 msgid "unable to create temporary file"
 msgstr "не вдалося створити тимчасовий файл"
@@ -16719,15 +17806,15 @@ msgstr "не вдалося запакувати новий обʼєкт %s (%d)
 
 #, c-format
 msgid "deflateEnd on object %s failed (%d)"
-msgstr ""
+msgstr "операція deflateEnd на обʼєкті %s завершилася невдало (%d)"
 
 #, c-format
 msgid "confused by unstable object source data for %s"
-msgstr ""
+msgstr "збентежений нестабільними початковими даними обʼєкта для %s"
 
 #, c-format
 msgid "write stream object %ld != %<PRIuMAX>"
-msgstr ""
+msgstr "запис обʼєкта потока %ld != %<PRIuMAX>"
 
 #, c-format
 msgid "unable to stream deflate new object (%d)"
@@ -16735,7 +17822,7 @@ msgstr "не вдалося запакувати новий обʼєкт (%d) п
 
 #, c-format
 msgid "deflateEnd on stream object failed (%d)"
-msgstr ""
+msgstr "операція deflateEnd на обʼєкті потоку завершилася невдало (%d)"
 
 #, c-format
 msgid "unable to create directory %s"
@@ -16747,26 +17834,26 @@ msgstr "неможливо прочитати обʼєкт для %s"
 
 #, c-format
 msgid "object fails fsck: %s"
-msgstr ""
+msgstr "об’єкт не пройшов перевірку fsck: %s"
 
 msgid "refusing to create malformed object"
-msgstr ""
+msgstr "відмовлено в створенні невірно сформованого обʼєкта"
 
 #, c-format
 msgid "read error while indexing %s"
-msgstr ""
+msgstr "помилка считування при індексаціі %s"
 
 #, c-format
 msgid "short read while indexing %s"
-msgstr ""
+msgstr "помилка считування замалого вмісту при індексаціі %s"
 
 #, c-format
 msgid "%s: failed to insert into database"
-msgstr ""
+msgstr "%s: не вдалося внести до бази даних"
 
 #, c-format
 msgid "%s: unsupported file type"
-msgstr ""
+msgstr "%s: непідтримуваний тип файлу"
 
 #, c-format
 msgid "%s is not a valid '%s' object"
@@ -16778,7 +17865,7 @@ msgstr "не вдалося відкрити %s"
 
 #, c-format
 msgid "hash mismatch for %s (expected %s)"
-msgstr ""
+msgstr "невідповідність хешу для %s (очікувалось %s)"
 
 #, c-format
 msgid "unable to mmap %s"
@@ -16803,7 +17890,7 @@ msgstr "не вдалося розпакувати вміст %s"
 
 #, c-format
 msgid "%s [bad object]"
-msgstr ""
+msgstr "%s [невірний обʼект]"
 
 #. TRANSLATORS: This is a line of ambiguous commit
 #. object output. E.g.:
@@ -16840,7 +17927,7 @@ msgstr "%s тег %s - %s"
 
 #, c-format
 msgid "%s [bad tag, could not parse it]"
-msgstr ""
+msgstr "%s [невірний тег, не вдалося розібрати]"
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef tree".
@@ -16848,7 +17935,7 @@ msgstr ""
 
 #, c-format
 msgid "%s tree"
-msgstr ""
+msgstr "%s дерево"
 
 #. TRANSLATORS: This is a line of ambiguous <type>
 #. object output. E.g. "deadbeef blob".
@@ -16856,11 +17943,11 @@ msgstr ""
 
 #, c-format
 msgid "%s blob"
-msgstr ""
+msgstr "%s blob"
 
 #, c-format
 msgid "short object ID %s is ambiguous"
-msgstr ""
+msgstr "короткий ідентифікатор обʼєкта %s неоднозначний"
 
 #. TRANSLATORS: The argument is the list of ambiguous
 #. objects composed in show_ambiguous_object(). See
@@ -16872,6 +17959,8 @@ msgid ""
 "The candidates are:\n"
 "%s"
 msgstr ""
+"Кандидати такі:\n"
+"%s"
 
 msgid ""
 "Git normally never creates a ref that ends with 40 hex characters\n"
@@ -16884,6 +17973,18 @@ msgid ""
 "examine these refs and maybe delete them. Turn this message off by\n"
 "running \"git config advice.objectNameWarning false\""
 msgstr ""
+"Зазвичай Git ніколи не створює посилання, яке закінчується 40-hex "
+"символами,\n"
+"тому що воно буде проігноровано, якщо ви просто вкажете 40-hex. Такі "
+"посилання\n"
+"можуть бути створені помилково. Наприклад\n"
+"\n"
+"  git switch -c $br $(git rev-parse ...)\n"
+"\n"
+"де \"$br\" якимось чином порожнє, створює 40-hex посилання. Будь ласка\n"
+"перевірте ці посилання і, можливо, видаліть їх. Щоб вимкнути це "
+"повідомлення, виконайте\n"
+"\"git config advice.objectNameWarning false\""
 
 #, c-format
 msgid "log for '%.*s' only goes back to %s"
@@ -17061,7 +18162,7 @@ msgid "failed to load bitmap indexes"
 msgstr "не вдалося завантажити bitmap індекси"
 
 msgid "you must specify exactly one commit to test"
-msgstr "ви маєте вказати тільки один коміт для тестування"
+msgstr "ви маєте вказати лишень один коміт для тестування"
 
 #, c-format
 msgid "commit '%s' doesn't have an indexed bitmap"
@@ -17093,7 +18194,7 @@ msgstr "mtimes файл %s має невідомий підпис"
 
 #, c-format
 msgid "mtimes file %s has unsupported version %<PRIu32>"
-msgstr "mtimes файл %s має непідтримувану версію %<PRIu32>."
+msgstr "mtimes файл %s має непідтримувану версію %<PRIu32>"
 
 #, c-format
 msgid "mtimes file %s has unsupported hash id %<PRIu32>"
@@ -17125,7 +18226,7 @@ msgstr ""
 "файл зворотного індексу %s має непідтримуваний хеш-ідентифікатор %<PRIu32>"
 
 msgid "invalid checksum"
-msgstr "невÑ\96Ñ\80на контрольна сума"
+msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82има контрольна сума"
 
 #, c-format
 msgid "invalid rev-index position at %<PRIu64>: %<PRIu32> != %<PRIu32>"
@@ -17164,7 +18265,7 @@ msgstr "зміщення за межою кінця індекса пакунк
 
 #, c-format
 msgid "malformed expiration date '%s'"
-msgstr "непÑ\80авилÑ\8cно сформована дата закінчення терміну дії \"%s\""
+msgstr "невÑ\96Ñ\80но сформована дата закінчення терміну дії \"%s\""
 
 #, c-format
 msgid "option `%s' expects \"always\", \"auto\", or \"never\""
@@ -17172,7 +18273,7 @@ msgstr "опція \"%s\" очікує \"always\", \"auto\" або \"never\""
 
 #, c-format
 msgid "malformed object name '%s'"
-msgstr "непÑ\80авилÑ\8cно сформована назва обʼєкта \"%s\""
+msgstr "невÑ\96Ñ\80но сформована назва обʼєкта \"%s\""
 
 #, c-format
 msgid "option `%s' expects \"%s\" or \"%s\""
@@ -17212,7 +18313,7 @@ msgstr "ви мали на увазі \"--%s\" (з двома рисками)?"
 
 #, c-format
 msgid "alias of --%s"
-msgstr "псевдонім --%s"
+msgstr "псевдонім для --%s"
 
 msgid "need a subcommand"
 msgstr "потрібна підкоманда"
@@ -17480,7 +18581,14 @@ msgstr "не вдалося згенерувати різницю"
 
 #, c-format
 msgid "could not parse log for '%s'"
-msgstr "не вдалося розібрати лог для \"%s\""
+msgstr "не вдалося розібрати журнал для \"%s\""
+
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "неприпустима додаткова марна верхівка: \"%s\""
+
+msgid "unable to enumerate additional recent objects"
+msgstr "не вдалося перерахувати додаткові нещодавні обʼєкти"
 
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
@@ -17585,7 +18693,7 @@ msgstr "%s: не вдалося виконати stat відкритого ін
 
 #, c-format
 msgid "%s: index file smaller than expected"
-msgstr "%s: Ñ\96ндекÑ\81ний Ñ\84айл Ð¼ÐµÐ½Ñ\88ий, Ð½Ñ\96ж Ð¾Ñ\87Ñ\96кÑ\83валося"
+msgstr "%s: Ñ\96ндекÑ\81ний Ñ\84айл Ð¼ÐµÐ½Ñ\88ий, Ð½Ñ\96ж Ð¾Ñ\87Ñ\96кÑ\83вався"
 
 #, c-format
 msgid "%s: unable to map index file%s"
@@ -17608,7 +18716,7 @@ msgid "broken index, expect %s in %s, got %s"
 msgstr "пошкоджений індекс, очікувався %s у %s, отримано %s"
 
 msgid "cannot write split index for a sparse index"
-msgstr "неможливо записати розділений індекс для часткового індексу"
+msgstr "неможливо записати розщеплений індекс для розрідженого індексу"
 
 msgid "failed to convert to a sparse-index"
 msgstr "не вдалося перетворити в sparse-index"
@@ -17623,7 +18731,7 @@ msgstr "не вдалося відкрити git-директорію: %s"
 
 #, c-format
 msgid "unable to unlink: %s"
-msgstr "не вдалося відʼєднати: %s"
+msgstr "не вдалося видалити: %s"
 
 #, c-format
 msgid "cannot fix permission bits on '%s'"
@@ -17633,6 +18741,14 @@ msgstr "неможливо виправити біти дозволу на \"%s\
 msgid "%s: cannot drop to stage #0"
 msgstr "%s: неможливо скинути індекс до стану #0"
 
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "неочікуваний статус diff %c"
+
+#, c-format
+msgid "remove '%s'\n"
+msgstr "видалити \"%s\"\n"
+
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
 "continue'.\n"
@@ -17830,6 +18946,22 @@ msgstr "невідомий %%(trailers) аргумент: %s"
 msgid "positive value expected contents:lines=%s"
 msgstr "очікувалось додатне значення contents:lines=%s"
 
+#, c-format
+msgid "argument expected for %s"
+msgstr "очікувався аргумент для %s"
+
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "очікувалось додатне значення %s=%s"
+
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "неможливо повністю розібрати %s=%s"
+
+#, c-format
+msgid "value expected %s="
+msgstr "очікувалось значення %s="
+
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
 msgstr "очікувалось додатне значення \"%s\" у %%(%s)"
@@ -17860,7 +18992,7 @@ msgstr "очікуваний формат: %%(ahead-behind:<комітоподі
 
 #, c-format
 msgid "malformed field name: %.*s"
-msgstr "непÑ\80авилÑ\8cно сформована назва поля: %.*s"
+msgstr "невÑ\96Ñ\80но сформована назва поля: %.*s"
 
 #, c-format
 msgid "unknown field name: %.*s"
@@ -17893,7 +19025,7 @@ msgstr "формат: %%(end) частка використана без від
 
 #, c-format
 msgid "malformed format string %s"
-msgstr "непÑ\80авилÑ\8cно сформований рядок форматування %s"
+msgstr "невÑ\96Ñ\80но сформований рядок форматування %s"
 
 #, c-format
 msgid "this command reject atom %%(%.*s)"
@@ -17903,6 +19035,9 @@ msgstr "ця команда відхиляє частку %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s не може бути використаний з --python, --shell, --tcl"
 
+msgid "failed to run 'describe'"
+msgstr "не вдалося запустити команду \"describe\""
+
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(немає гілки, перебазування %s)"
@@ -17936,7 +19071,7 @@ msgstr "parse_object_buffer завершився невдало на %s для %
 
 #, c-format
 msgid "malformed object at '%s'"
-msgstr "непÑ\80авилÑ\8cно сформований обʼєкт за адресою \"%s\""
+msgstr "невÑ\96Ñ\80но сформований обʼєкт за адресою \"%s\""
 
 #, c-format
 msgid "ignoring ref with broken name %s"
@@ -17952,7 +19087,7 @@ msgstr "формат: %%(end) частка відсутня"
 
 #, c-format
 msgid "malformed object name %s"
-msgstr "непÑ\80авилÑ\8cно сформована назва обʼєкта %s"
+msgstr "невÑ\96Ñ\80но сформована назва обʼєкта %s"
 
 #, c-format
 msgid "option `%s' must point to a commit"
@@ -17964,13 +19099,16 @@ msgstr "ключ"
 msgid "field name to sort on"
 msgstr "назва поля для сортування"
 
+msgid "exclude refs which match pattern"
+msgstr "виключити посилання, які збігаються з шаблоном"
+
 #, c-format
 msgid "not a reflog: %s"
-msgstr "не reflog: %s"
+msgstr "не є журналом посилань: %s"
 
 #, c-format
 msgid "no reflog for '%s'"
-msgstr "немає reflog для \"%s\""
+msgstr "немає журналу посилань для \"%s\""
 
 #, c-format
 msgid "%s does not point to a valid object!"
@@ -17992,7 +19130,7 @@ msgstr ""
 "Використання \"%s\" як назви початкової гілки. Назву гілки за замовчуванням\n"
 "може бути змінено. Щоб налаштувати назву початкової гілки для використання у "
 "всіх\n"
-"ваших нових сховищах, що приховуватиме це попередження, викличте\n"
+"ваших нових сховищах, що приховає це попередження, викличте\n"
 "\n"
 "\tgit config --global init.defaultBranch <назва>.\n"
 "\n"
@@ -18029,7 +19167,7 @@ msgstr "лог для %s порожній"
 
 #, c-format
 msgid "refusing to update ref with bad name '%s'"
-msgstr "вÑ\96дмова Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ\8f посилання з невірною назвою \"%s\""
+msgstr "вÑ\96дмовлено Ð² Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ\96 посилання з невірною назвою \"%s\""
 
 #, c-format
 msgid "update_ref failed for ref '%s': %s"
@@ -18079,7 +19217,7 @@ msgstr "%sinfo/refs не дійсні: це git сховище?"
 
 msgid "invalid server response; expected service, got flush packet"
 msgstr ""
-"непÑ\80ипÑ\83Ñ\81Ñ\82има Ð²Ñ\96дповÑ\96дÑ\8c Ñ\81еÑ\80веÑ\80а; Ð¾Ñ\87Ñ\96кÑ\83вавÑ\81Ñ\8f service, отримано flush пакет"
+"непÑ\80ипÑ\83Ñ\81Ñ\82има Ð²Ñ\96дповÑ\96дÑ\8c Ñ\81еÑ\80веÑ\80а; Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c service, отримано flush пакет"
 
 #, c-format
 msgid "invalid server response; got '%s'"
@@ -18114,7 +19252,8 @@ msgstr "віддалений сервер надіслав неочікуван
 
 msgid "unable to rewind rpc post data - try increasing http.postBuffer"
 msgstr ""
-"не вдалося перемотати rpc post дані - спробуйте збільшити http.postBuffer"
+"не вдалося перемотати  вперед rpc post дані - спробуйте збільшити http."
+"postBuffer"
 
 #, c-format
 msgid "remote-curl: bad line length character: %.4s"
@@ -18157,14 +19296,14 @@ msgstr "неможливо отримати дані за допомогою sha
 
 #, c-format
 msgid "protocol error: expected sha/ref, got '%s'"
-msgstr "помилка Ð¿Ñ\80оÑ\82околÑ\83: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8f sha/ref, отримано \"%s\""
+msgstr "помилка Ð¿Ñ\80оÑ\82околÑ\83: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c sha/ref, отримано \"%s\""
 
 #, c-format
 msgid "http transport does not support %s"
 msgstr "http засіб передачі не підтримує %s"
 
 msgid "protocol error: expected '<url> <path>', missing space"
-msgstr "помилка Ð¿Ñ\80оÑ\82околÑ\83: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8f \"<url> <шлях>\", пропущено пробіл"
+msgstr "помилка Ð¿Ñ\80оÑ\82околÑ\83: Ð¾Ñ\87Ñ\96кÑ\83валоÑ\81Ñ\8c \"<url> <шлях>\", пропущено пробіл"
 
 #, c-format
 msgid "failed to download file at URL '%s'"
@@ -18189,7 +19328,7 @@ msgstr "remote-curl: невідома команда \"%s\" з git"
 
 #, c-format
 msgid "config remote shorthand cannot begin with '/': %s"
-msgstr "Ñ\81коÑ\80оÑ\87еннÑ\8f Ð²Ñ\96ддаленноÑ\97 ÐºÐ¾Ð½Ñ\84Ñ\96гÑ\83Ñ\80аÑ\86Ñ\96Ñ\96 Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð¿Ð¾Ñ\87инаÑ\82иÑ\81Ñ\8f Ð· '/': %s"
+msgstr "скорочення віддаленої конфігураціі не може починатися з '/': %s"
 
 msgid "more than one receivepack given, using the first"
 msgstr "надано більше одного пакунка для отримання, використано перший"
@@ -18203,7 +19342,7 @@ msgstr "нерозпізнане значення transfer.credentialsInUrl: '%s
 
 #, c-format
 msgid "URL '%s' uses plaintext credentials"
-msgstr "URL-адреса '%s' використовує облікові дані у відкритому тексті"
+msgstr "URL-адреса \"%s\" використовує облікові дані у відкритому тексті"
 
 #, c-format
 msgid "Cannot fetch both %s and %s to %s"
@@ -18254,8 +19393,8 @@ msgstr ""
 "що починається з \"refs/\"). Ми спробували вгадати, що ви мали на увазі "
 "через:\n"
 "\n"
-"- Пошук посилання, яке відповідає '%s' на віддаленій стороні.\n"
-"- Перевірку, чи є <джерело> надсилання, ('%s')\n"
+"- Пошук посилання, яке відповідає \"%s\" на віддаленій стороні.\n"
+"- Перевірку, чи є <джерело> надсилання, (\"%s\")\n"
 "  посиланням у \"refs/{heads,tags}/\". Якщо так, то ми додаємо відповідний\n"
 "  refs/{heads,tags}/ префікс на віддаленій стороні.\n"
 "\n"
@@ -18270,7 +19409,7 @@ msgid ""
 msgstr ""
 "Частина <джерело> визаначника посилання є об’єктом коміту.\n"
 "Ви хотіли створити нову гілку, надіславши зміни до\n"
-"'%s:refs/heads/%s'?"
+"\"%s:refs/heads/%s\"?"
 
 #, c-format
 msgid ""
@@ -18280,7 +19419,7 @@ msgid ""
 msgstr ""
 "Частина <джерело> визаначника посилання є об’єктом тегу.\n"
 "Ви хотіли створити новий тег, надіславши зміни до\n"
-"'%s:refs/tags/%s'?"
+"\"%s:refs/tags/%s\"?"
 
 #, c-format
 msgid ""
@@ -18290,7 +19429,7 @@ msgid ""
 msgstr ""
 "Частина <джерело> визаначника посилання є об’єктом дерева.\n"
 "Ви хотіли позначити нове дерево, надіславши зміни до\n"
-"'%s:refs/tags/%s'?"
+"\"%s:refs/tags/%s\"?"
 
 #, c-format
 msgid ""
@@ -18300,7 +19439,7 @@ msgid ""
 msgstr ""
 "Частина <джерело> визаначника посилання є об’єктом blob.\n"
 "Ви хотіли позначити новий blob, надіславши зміни до\n"
-"'%s:refs/tags/%s'?"
+"\"%s:refs/tags/%s\"?"
 
 #, c-format
 msgid "%s cannot be resolved to branch"
@@ -18308,7 +19447,7 @@ msgstr "%s неможливо розвʼязати в гілку"
 
 #, c-format
 msgid "unable to delete '%s': remote ref does not exist"
-msgstr "не вдалося видалити '%s': віддалене посилання не існує"
+msgstr "не вдалося видалити \"%s\": віддалене посилання не існує"
 
 #, c-format
 msgid "dst refspec %s matches more than one"
@@ -18331,19 +19470,17 @@ msgstr "першоджерельне сховище не налаштовано
 
 #, c-format
 msgid "upstream branch '%s' not stored as a remote-tracking branch"
-msgstr ""
-"гілка '%s' першоджерельного сховища не збережена як віддалено відстежувана "
-"гілка"
+msgstr "висхідна гілка \"%s\" не збережена як віддалено відстежувана гілка"
 
 #, c-format
 msgid "push destination '%s' on remote '%s' has no local tracking branch"
 msgstr ""
-"шлях призначення надсилання '%s' на віддаленому '%s' не має гілки локального "
-"відстежування"
+"шлях призначення надсилання \"%s\" на віддаленому \"%s\" не має гілки "
+"локалÑ\8cного Ð²Ñ\96дÑ\81Ñ\82ежÑ\83ваннÑ\8f"
 
 #, c-format
 msgid "branch '%s' has no remote for pushing"
-msgstr "гілка '%s' не має віддаленого призначення для надсилання"
+msgstr "гілка \"%s\" не має віддаленого призначення для надсилання"
 
 #, c-format
 msgid "push refspecs for '%s' do not include '%s'"
@@ -18354,7 +19491,7 @@ msgstr "надсилання не має призначення (push.default д
 
 msgid "cannot resolve 'simple' push to a single destination"
 msgstr ""
-"неможливо розвʼязати \"simple\" надсилання до одного пункту призначення"
+"неможливо розвʼязати \"simple\" надсилання до єдиного пункту призначення"
 
 #, c-format
 msgid "couldn't find remote ref %s"
@@ -18362,11 +19499,11 @@ msgstr "не вдалося знайти віддалене посилання %
 
 #, c-format
 msgid "* Ignoring funny ref '%s' locally"
-msgstr "* Ігнорування кумедних рефів '%s' локально"
+msgstr "* Ігнорування кумедних посилань \"%s\" локально"
 
 #, c-format
 msgid "Your branch is based on '%s', but the upstream is gone.\n"
-msgstr "Ваша гілка базується на '%s', але першоджерельне сховище зникло.\n"
+msgstr "Ваша гілка базується на \"%s\", але першоджерельне сховище зникло.\n"
 
 msgid "  (use \"git branch --unset-upstream\" to fixup)\n"
 msgstr ""
@@ -18374,11 +19511,11 @@ msgstr ""
 
 #, c-format
 msgid "Your branch is up to date with '%s'.\n"
-msgstr "Ваша гілка не відрізняється від '%s'.\n"
+msgstr "Ваша гілка не відрізняється від \"%s\".\n"
 
 #, c-format
 msgid "Your branch and '%s' refer to different commits.\n"
-msgstr "Ваша гілка та гілка '%s' посилаються до різних комітів.\n"
+msgstr "Ваша гілка та гілка \"%s\" посилаються до різних комітів.\n"
 
 #, c-format
 msgid "  (use \"%s\" for details)\n"
@@ -18387,12 +19524,12 @@ msgstr "  (використовуйте \"%s\" для отримання дет
 #, c-format
 msgid "Your branch is ahead of '%s' by %d commit.\n"
 msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
-msgstr[0] "Ваша гілка випереджає '%s' на %d коміт.\n"
-msgstr[1] "Ваша гілка випереджає '%s' на %d коміти.\n"
-msgstr[2] "Ваша гілка випереджає '%s' на %d комітів.\n"
+msgstr[0] "Ваша гілка випереджає \"%s\" на %d коміт.\n"
+msgstr[1] "Ваша гілка випереджає \"%s\" на %d коміти.\n"
+msgstr[2] "Ваша гілка випереджає \"%s\" на %d комітів.\n"
 
 msgid "  (use \"git push\" to publish your local commits)\n"
-msgstr "  (використовуйте \"git push\" для публікації локальних комітів)\n"
+msgstr "  (скористайтесь \"git push\", щоб надіслати локальні коміти)\n"
 
 #, c-format
 msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
@@ -18420,14 +19557,17 @@ msgstr[0] ""
 "Ваша гілка і гілка '%s' розійшлися,\n"
 "і мають %d і %d різний коміт відповідно.\n"
 msgstr[1] ""
-"Ваша гілка і гілка '%s' розійшлися,\n"
-"Ñ\96 Ð¼Ð°Ñ\8eÑ\82Ñ\8c %d Ñ\96 %d Ñ\80Ñ\96зниÑ\85 ÐºÐ¾Ð¼Ñ\96Ñ\82а відповідно.\n"
+"Ваша гілка і гілка \"%s\" розійшлися,\n"
+"Ñ\96 Ð¼Ð°Ñ\8eÑ\82Ñ\8c %d Ñ\96 %d Ñ\80Ñ\96зниÑ\85 ÐºÐ¾Ð¼Ñ\96Ñ\82и відповідно.\n"
 msgstr[2] ""
-"Ваша гілка і гілка '%s' розійшлися,\n"
+"Ваша гілка і гілка \"%s\" розійшлися,\n"
 "і мають %d і %d різних комітів відповідно.\n"
 
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (використовуйте \"git pull\", щоб злити віддалену гілку з вашою)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr ""
+"  (скористайтесь \"git pull\", якщо ви хочете інтегрувати віддалену гілку зі "
+"своєю)\n"
 
 #, c-format
 msgid "cannot parse expected object name '%s'"
@@ -18439,7 +19579,7 @@ msgstr "неможливо вилучити один компонент з url '
 
 #, c-format
 msgid "bad replace ref name: %s"
-msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82има Ð½Ð°Ð·Ð²Ð° Ð·Ð¼Ñ\96нного посилання: %s"
+msgstr "непÑ\80ипÑ\83Ñ\81Ñ\82има Ð½Ð°Ð·Ð²Ð° Ð·Ð°Ð¼Ñ\96ни посилання: %s"
 
 #, c-format
 msgid "duplicate replace ref: %s"
@@ -18473,19 +19613,19 @@ msgstr "запис \"%s\" завершився невдало"
 
 #, c-format
 msgid "Staged '%s' using previous resolution."
-msgstr "Індексовано \"%s\" з використанням попереднього розвʼязання."
+msgstr "Індексовано \"%s\" з використанням попереднього вирішення."
 
 #, c-format
 msgid "Recorded resolution for '%s'."
-msgstr "Записано розвʼязання для \"%s\"."
+msgstr "Записано вирішення для \"%s\"."
 
 #, c-format
 msgid "Resolved '%s' using previous resolution."
-msgstr "РозвʼÑ\8fзано \"%s\" Ð· Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82аннÑ\8fм Ð¿Ð¾Ð¿ÐµÑ\80еднÑ\8cого Ñ\80озвʼÑ\8fзання."
+msgstr "Ð\92иÑ\80Ñ\96Ñ\88ено \"%s\" Ð· Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82аннÑ\8fм Ð¿Ð¾Ð¿ÐµÑ\80еднÑ\8cого Ð²Ð¸Ñ\80Ñ\96Ñ\88ення."
 
 #, c-format
 msgid "cannot unlink stray '%s'"
-msgstr "неможливо відʼєднати блукаючий \"%s\""
+msgstr "неможливо видалити блукаючий \"%s\""
 
 #, c-format
 msgid "Recorded preimage for '%s'"
@@ -18505,14 +19645,14 @@ msgstr "Оновлено попереднє зображення для \"%s\""
 
 #, c-format
 msgid "Forgot resolution for '%s'\n"
-msgstr "Забуто розвʼязання для \"%s\"\n"
+msgstr "Забуто вирішення для \"%s\"\n"
 
 msgid "unable to open rr-cache directory"
 msgstr "неможливо відкрити rr-cache директорію"
 
 msgid "update the index with reused conflict resolution if possible"
 msgstr ""
-"оновити індекс з повторним використанням розвʼязання конфліктів, якщо це "
+"оновити індекс з повторним використанням вирішення конфліктів, якщо це "
 "можливо"
 
 msgid "could not determine HEAD revision"
@@ -18531,17 +19671,21 @@ msgstr "--exclude-hidden= передано більше одного разу"
 
 #, c-format
 msgid "resolve-undo records `%s` which is missing"
-msgstr ""
+msgstr "resolve-undo записує \"%s\", який відсутній"
 
 #, c-format
 msgid "could not get commit for ancestry-path argument %s"
-msgstr ""
+msgstr "не вдалося отримати коміт для ancestry-path аргументу %s"
 
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<файл пакунка> більше не підтримується"
 
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "неприпустима опція \"%s\" у режимі --stdin"
+
 msgid "your current branch appears to be broken"
-msgstr "ваÑ\88а Ð¿Ð¾Ñ\82оÑ\87на Ð³Ñ\96лка Ð²Ð¸Ð³Ð»Ñ\8fдаÑ\94 Ð·Ð»Ð°Ð¼Ð°ною"
+msgstr "ваÑ\88а Ð¿Ð¾Ñ\82оÑ\87на Ð³Ñ\96лка Ð²Ð¸Ð³Ð»Ñ\8fдаÑ\94 Ð¿Ð¾Ñ\88кодженою"
 
 #, c-format
 msgid "your current branch '%s' does not have any commits yet"
@@ -18569,7 +19713,7 @@ msgid "need a working directory"
 msgstr "потрібна робоча директорія"
 
 msgid "Scalar enlistments require a worktree"
-msgstr ""
+msgstr "Коренева директорія проекту потребує робоче дерево"
 
 #, c-format
 msgid "could not configure %s=%s"
@@ -18615,7 +19759,7 @@ msgid "failed to stop the FSMonitor daemon"
 msgstr "не вдалося зупинити FSMonitor демон"
 
 msgid "failed to delete enlistment directory"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ\82и Ð´Ð¸Ñ\80екÑ\82оÑ\80Ñ\96Ñ\8e Ð²ÐµÑ\80Ñ\85нÑ\8cого Ñ\80Ñ\96внÑ\8f"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ\82и ÐºÐ¾Ñ\80еневÑ\83 Ð´Ð¸Ñ\80екÑ\82оÑ\80Ñ\96Ñ\8e Ð¿Ñ\80оекÑ\82Ñ\83"
 
 msgid "branch to checkout after clone"
 msgstr "гілка, на яку перейти після клонування"
@@ -18651,7 +19795,7 @@ msgid "could not configure '%s'"
 msgstr "не вдалося налаштувати \"%s\""
 
 msgid "partial clone failed; attempting full clone"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ñ\80обиÑ\82и Ñ\87аÑ\81Ñ\82ковий клон; спроба зробити повний клон"
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ñ\80обиÑ\82и Ñ\80озÑ\80Ñ\96джений клон; спроба зробити повний клон"
 
 msgid "could not configure for full clone"
 msgstr "не вдалося налаштувати для повного клона"
@@ -18704,7 +19848,7 @@ msgid "scalar delete <enlistment>"
 msgstr "scalar delete <коренева-директорія-проекту>"
 
 msgid "refusing to delete current working directory"
-msgstr "вÑ\96дмова Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ\8f поточної робочої директорії"
+msgstr "вÑ\96дмовлено Ñ\83 Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ\96 поточної робочої директорії"
 
 msgid "include Git version"
 msgstr "включити версію Git"
@@ -18713,7 +19857,7 @@ msgid "include Git's build options"
 msgstr "включити опції збірки Git"
 
 msgid "scalar verbose [-v | --verbose] [--build-options]"
-msgstr ""
+msgstr "scalar verbose [-v | --verbose] [--build-options]"
 
 msgid "-C requires a <directory>"
 msgstr "-C потребує наявності <директорії>"
@@ -18753,7 +19897,7 @@ msgid "send-pack: unable to fork off fetch subprocess"
 msgstr "send-pack: не вдалося розгалужити підпроцес отримання"
 
 msgid "push negotiation failed; proceeding anyway with push"
-msgstr "пеÑ\80еговоÑ\80и з надсилання не вдалися; все одно продовжуємо надсилання"
+msgstr "пеÑ\80емовини з надсилання не вдалися; все одно продовжуємо надсилання"
 
 msgid "the receiving end does not support this repository's hash algorithm"
 msgstr "отримуюча сторона не підтримує хеш-алгоритм цього сховища"
@@ -18799,7 +19943,7 @@ msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
-"після розвʼязання конфліктів позначте виправлені шляхи\n"
+"після вирішення конфліктів позначте виправлені шляхи\n"
 "за допомогою \"git add <шляхи>\" або \"git rm <шляхи>\""
 
 msgid ""
@@ -18810,10 +19954,10 @@ msgid ""
 "To abort and get back to the state before \"git cherry-pick\",\n"
 "run \"git cherry-pick --abort\"."
 msgstr ""
-"Після розвʼязання конфліктів позначте їх за допомогою\n"
+"Після вирішення конфліктів позначте їх за допомогою\n"
 "\"git add/rm <визначник шляху>\", а потім виконайте\n"
 "\"git cherry-pick --continue\".\n"
-"Замість цього ви можете пропустити цей комміт за допомогою \"git cherry-pick "
+"Замість цього ви можете пропустити цей коміт за допомогою \"git cherry-pick "
 "--skip\".\n"
 "Щоб перервати процес і повернутися до стану перед \"git cherry-pick\",\n"
 "виконайте \"git cherry-pick --abort\"."
@@ -18826,7 +19970,7 @@ msgid ""
 "To abort and get back to the state before \"git revert\",\n"
 "run \"git revert --abort\"."
 msgstr ""
-"Після розвʼязання конфліктів позначте їх за допомогою\n"
+"Після вирішення конфліктів позначте їх за допомогою\n"
 "\"git add/rm <визначник шляху>\", а потім виконайте\n"
 "\"git revert --continue\".\n"
 "Замість цього ви можете пропустити цей коміт за допомогою \"git revert --"
@@ -18975,7 +20119,7 @@ msgstr ""
 "правильність.\n"
 "Ви можете приховати це повідомлення, вказавши їх явно:\n"
 "\n"
-"    git config --global user.name \"Ваше імʼя\"\n"
+"    git config --global user.name \"Ваше Імʼя\"\n"
 "    git config --global user.email you@example.com\n"
 "\n"
 "Після цього ви можете виправити особистість автора, використану для цього "
@@ -18996,7 +20140,7 @@ msgid "detached HEAD"
 msgstr "відʼєднаний HEAD"
 
 msgid " (root-commit)"
-msgstr " (кореневий комміт)"
+msgstr " (кореневий коміт)"
 
 msgid "could not parse HEAD"
 msgstr "неможливо розібрати HEAD"
@@ -19010,11 +20154,11 @@ msgstr "не вдалося розібрати автора коміту"
 
 #, c-format
 msgid "unable to read commit message from '%s'"
-msgstr "не вдалося прочитати допис до коміта від \"%s\""
+msgstr "не вдалося прочитати допис до коміту від \"%s\""
 
 #, c-format
 msgid "invalid author identity '%s'"
-msgstr "неприпустима ідентичність автора \"%s\""
+msgstr "неприпустима особистість автора \"%s\""
 
 msgid "corrupt author: missing date information"
 msgstr "пошкоджені дані про автора: відсутня інформація про дату"
@@ -19036,18 +20180,18 @@ msgid "unknown command: %d"
 msgstr "невідома команда: %d"
 
 msgid "This is the 1st commit message:"
-msgstr "Це перший допис до коміта:"
+msgstr "Це перший допис до коміту:"
 
 #, c-format
 msgid "This is the commit message #%d:"
-msgstr "Це допис до коміта #%d:"
+msgstr "Це допис до коміту #%d:"
 
 msgid "The 1st commit message will be skipped:"
-msgstr "Перший допис до коміта буде пропущено:"
+msgstr "Перший допис до коміту буде пропущено:"
 
 #, c-format
 msgid "The commit message #%d will be skipped:"
-msgstr "Допис до коміта #%d буде пропущено:"
+msgstr "Допис до коміту #%d буде пропущено:"
 
 #, c-format
 msgid "This is a combination of %d commits."
@@ -19064,11 +20208,11 @@ msgid "could not read HEAD"
 msgstr "не вдалося прочитати HEAD"
 
 msgid "could not read HEAD's commit message"
-msgstr "не вдалося прочитати допис до коміта HEAD"
+msgstr "не вдалося прочитати допис до коміту HEAD"
 
 #, c-format
 msgid "could not read commit message of %s"
-msgstr "не вдалося прочитати допис до коміта %s"
+msgstr "не вдалося прочитати допис до коміту %s"
 
 msgid "your index file is unmerged."
 msgstr "ваш індексний файл не злитий."
@@ -19086,7 +20230,7 @@ msgstr "коміт %s не має джерела %d"
 
 #, c-format
 msgid "cannot get commit message for %s"
-msgstr "неможливо отримати допис до коміта для %s"
+msgstr "неможливо отримати допис до коміту для %s"
 
 #. TRANSLATORS: The first %s will be a "todo" command like
 #. "revert" or "pick", the second %s a SHA1.
@@ -19157,7 +20301,7 @@ msgid "cannot '%s' without a previous commit"
 msgstr "неможливо зробити \"%s\" без попереднього коміту"
 
 msgid "cancelling a cherry picking in progress"
-msgstr "скасування поточного висмикування"
+msgstr "наразі йде скасування висмикування"
 
 msgid "cancelling a revert in progress"
 msgstr "наразі йде скасування вивертання"
@@ -19189,7 +20333,7 @@ msgid "empty commit set passed"
 msgstr "передано порожній набір комітів"
 
 msgid "revert is already in progress"
-msgstr "наÑ\80азÑ\96 Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ð¾Ð¿ÐµÑ\80аÑ\86Ñ\96Ñ\8f вивертання"
+msgstr "наÑ\80азÑ\96 Ð²Ð¶Ðµ Ñ\82Ñ\80иваÑ\94 вивертання"
 
 #, c-format
 msgid "try \"git revert (--continue | %s--abort | --quit)\""
@@ -19228,14 +20372,14 @@ msgstr "збережений pre-cherry-pick HEAD файл \"%s\" пошкодж
 
 msgid "You seem to have moved HEAD. Not rewinding, check your HEAD!"
 msgstr ""
-"Здається, ви пересунули HEAD. Перемотування не виконується, перевірте свій "
-"HEAD!"
+"Здається, ви перемістили HEAD. Перемотування назад не виконується, перевірте "
+"свій HEAD!"
 
 msgid "no revert in progress"
-msgstr "наÑ\80азÑ\96 Ð¾Ð¿ÐµÑ\80аÑ\86Ñ\96Ñ\8f Ð²Ð¸Ð²ÐµÑ\80Ñ\82аннÑ\8f Ð½Ðµ Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81я"
+msgstr "наÑ\80азÑ\96 Ð½Ðµ Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ð²Ð¸Ð²ÐµÑ\80Ñ\82ання"
 
 msgid "no cherry-pick in progress"
-msgstr "наÑ\80азÑ\96 Ð²Ð¸Ñ\81микÑ\83ваннÑ\8f Ð½Ðµ Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81я"
+msgstr "наÑ\80азÑ\96 Ð½Ðµ Ð²Ð¸ÐºÐ¾Ð½Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ð²Ð¸Ñ\81микÑ\83вання"
 
 msgid "failed to skip the commit"
 msgstr "не вдалося пропустити коміт"
@@ -19314,11 +20458,10 @@ msgid ""
 "\n"
 msgstr ""
 "виконання пройшло успішно: %s\n"
-"але залишило зміни в індексі та/або робочому дереві.\n"
+"але залишило зміни в індексі та/або робочому дереві\n"
 "Зробіть коміт або додайте зміни до схову, а потім запустіть\n"
 "\n"
 "  git rebase --continue\n"
-"\n"
 
 #, c-format
 msgid "illegal label name: '%.*s'"
@@ -19350,7 +20493,7 @@ msgstr "octopus злиття неможливо виконати поверх [n
 
 #, c-format
 msgid "could not get commit message of '%s'"
-msgstr "не вдалося отримати допис до коміта \"%s\""
+msgstr "не вдалося отримати допис до коміту \"%s\""
 
 #, c-format
 msgid "could not even attempt to merge '%.*s'"
@@ -19699,7 +20842,7 @@ msgid ""
 "The owner of files must always have read and write permissions."
 msgstr ""
 "проблема зі значенням файлового режиму core.sharedRepository (0%.3o).\n"
-"Ð\92лаÑ\81ник Ñ\84айлÑ\96в Ð·Ð°Ð²Ð¶Ð´Ð¸ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ Ð¼Ð°Ñ\82и Ð¿Ñ\80ава на читання та запис."
+"Ð\92лаÑ\81ник Ñ\84айлÑ\96в Ð·Ð°Ð²Ð¶Ð´Ð¸ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ Ð¼Ð°Ñ\82и Ð´Ð¾Ð·Ð²Ñ\96л на читання та запис."
 
 msgid "fork failed"
 msgstr "fork завершився невдало"
@@ -19707,12 +20850,83 @@ msgstr "fork завершився невдало"
 msgid "setsid failed"
 msgstr "setsid завершився невдало"
 
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "неможливо виконати stat шаблона \"%s\""
+
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "неможливо виконати opendir \"%s\""
+
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "неможливо виконати readlink \"%s\""
+
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "неможливо виконати symlink \"%s\" \"%s\""
+
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "неможливо скопіювати \"%s\" до \"%s\""
+
+#, c-format
+msgid "ignoring template %s"
+msgstr "ігнорування шаблону %s"
+
+#, c-format
+msgid "templates not found in %s"
+msgstr "шаблонів не знайдено в %s"
+
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "не копіюються шаблони з \"%s\": %s"
+
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "неприпустиме початкове ім’я гілки: \"%s\""
+
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "не вдалося обробити тип файлу %d"
+
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "не вдалося перемістити %s на %s"
+
+msgid "attempt to reinitialize repository with different hash"
+msgstr "спроба переініціалізувати репозиторій з іншим хеш-алгоритмом"
+
+#, c-format
+msgid "%s already exists"
+msgstr "%s вже існує"
+
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: ігноровано --initial-branch=%s"
+
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "Переініціалізовано існуюче спільне Git сховище в %s%s\n"
+
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "Переініціалізовано існуюче Git сховище в %s%s\n"
+
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "Ініціалізовано порожнє спільне Git сховище в %s%s\n"
+
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "Ініціалізовано порожнє Git сховище в %s%s\n"
+
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
-msgstr "Ñ\96ндекÑ\81ний Ð·Ð°Ð¿Ð¸Ñ\81 Ñ\94 Ð´Ð¸Ñ\80екÑ\82оÑ\80Ñ\96Ñ\94Ñ\8e, Ð°Ð»Ðµ Ð½Ðµ Ñ\94 Ñ\87аÑ\81Ñ\82ковим (%08x)"
+msgstr "Ñ\96ндекÑ\81ний Ð·Ð°Ð¿Ð¸Ñ\81 Ñ\94 Ð´Ð¸Ñ\80екÑ\82оÑ\80Ñ\96Ñ\94Ñ\8e, Ð°Ð»Ðµ Ð½Ðµ Ñ\94 Ñ\80озÑ\80Ñ\96дженим (%08x)"
 
 msgid "cannot use split index with a sparse index"
-msgstr "не можна використовувати розділений індекс з частковим індексом"
+msgstr "не можна використовувати розщеплений індекс з розрідженим індексом"
 
 #, c-format
 msgid "%u.%2.2u GiB"
@@ -19771,7 +20985,7 @@ msgstr "Не вдалося оновити запис %s у .gitmodules"
 
 msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
 msgstr ""
-"Неможливо змінити незлиті .gitmodules, спочатку розвʼяжіть конфлікти злиття"
+"Неможливо змінити не злиті .gitmodules, спочатку розвʼяжіть конфлікти злиття"
 
 #, c-format
 msgid "Could not find section in .gitmodules where path=%s"
@@ -19838,11 +21052,11 @@ msgstr "Не вдалося отримати доступ до підмодул
 
 #, c-format
 msgid "Could not access submodule '%s' at commit %s\n"
-msgstr "Не вдалося отримати доступ до підмодуля \"%s\" для коміта %s\n"
+msgstr "Не вдалося отримати доступ до підмодуля \"%s\" для коміту %s\n"
 
 #, c-format
 msgid "Fetching submodule %s%s at commit %s\n"
-msgstr "Отримання підмодуля %s%s для коміта %s\n"
+msgstr "Отримання підмодуля %s%s для коміту %s\n"
 
 #, c-format
 msgid ""
@@ -19909,7 +21123,7 @@ msgstr "не вдалося знайти назву для підмодуля \"
 
 #, c-format
 msgid "refusing to move '%s' into an existing git dir"
-msgstr "вÑ\96дмова Ð¿ÐµÑ\80емÑ\96Ñ\89еннÑ\8f \"%s\" до існуючої git директорії"
+msgstr "вÑ\96дмовлено Ð² Ð¿ÐµÑ\80емÑ\96Ñ\89еннÑ\96 \"%s\" до існуючої git директорії"
 
 #, c-format
 msgid ""
@@ -20006,7 +21220,7 @@ msgid "name or pathname of unix domain socket"
 msgstr "назва або назва шляху сокета домену unix"
 
 msgid "named-pipe name"
-msgstr ""
+msgstr "назва іменованого канала"
 
 msgid "number of threads in server thread pool"
 msgstr "кількість потоків у пулі потоків сервера"
@@ -20131,7 +21345,7 @@ msgstr "\"option\" без відповідної директиви \"ok/error\"
 
 #, c-format
 msgid "expected ok/error, helper said '%s'"
-msgstr "оÑ\87Ñ\96кÑ\83валоÑ\81Ñ\8f ok/error, помічник сказав \"%s\""
+msgstr "оÑ\87Ñ\96кÑ\83валоÑ\81Ñ\8c ok/error, помічник сказав \"%s\""
 
 #, c-format
 msgid "helper reported unexpected status of %s"
@@ -20188,7 +21402,7 @@ msgstr "непідтримуваний обʼєкт формата \"%s\""
 
 #, c-format
 msgid "malformed response in ref list: %s"
-msgstr "непÑ\80авилÑ\8cно сформована відповідь у списку посилань: %s"
+msgstr "невÑ\96Ñ\80но сформована відповідь у списку посилань: %s"
 
 #, c-format
 msgid "read(%s) failed"
@@ -20227,7 +21441,7 @@ msgstr "Встановить першоджерельне сховище для
 
 #, c-format
 msgid "could not read bundle '%s'"
-msgstr "не вдалося прочитати пакет \"%s\""
+msgstr "не вдалося прочитати пакунок \"%s\""
 
 #, c-format
 msgid "transport: invalid depth option '%s'"
@@ -20383,7 +21597,7 @@ msgid ""
 "Refusing to remove the current working directory:\n"
 "%s"
 msgstr ""
-"Ð\92Ñ\96дмова Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ\8f поточної робочої директорії:\n"
+"Ð\92Ñ\96дмовлено Ñ\83 Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ\96 поточної робочої директорії:\n"
 "%s"
 
 #, c-format
@@ -20512,7 +21726,7 @@ msgid ""
 "patterns:\n"
 "%s"
 msgstr ""
-"Ð\9dаÑ\81Ñ\82Ñ\83пнÑ\96 Ñ\88лÑ\8fÑ\85и Ð½Ðµ Ñ\94 Ð°ÐºÑ\82Ñ\83алÑ\8cними Ñ\96 Ð±Ñ\83ли Ð·Ð°Ð»Ð¸Ñ\88енÑ\96, Ð½ÐµÐ·Ð²Ð°Ð¶Ð°Ñ\8eÑ\87и Ð½Ð° Ñ\87аÑ\81Ñ\82кові "
+"Ð\9dаÑ\81Ñ\82Ñ\83пнÑ\96 Ñ\88лÑ\8fÑ\85и Ð½Ðµ Ñ\94 Ð°ÐºÑ\82Ñ\83алÑ\8cними Ñ\96 Ð±Ñ\83ли Ð·Ð°Ð»Ð¸Ñ\88енÑ\96, Ð½ÐµÐ·Ð²Ð°Ð¶Ð°Ñ\8eÑ\87и Ð½Ð° Ñ\80озÑ\80Ñ\96джені "
 "шаблони:\n"
 "%s"
 
@@ -20521,7 +21735,7 @@ msgid ""
 "The following paths are unmerged and were left despite sparse patterns:\n"
 "%s"
 msgstr ""
-"Ð\9dаÑ\81Ñ\82Ñ\83пнÑ\96 Ñ\88лÑ\8fÑ\85и Ð½Ðµ Ð·Ð»Ð¸Ñ\82Ñ\96 Ñ\96 Ð±Ñ\83ли Ð·Ð°Ð»Ð¸Ñ\88енÑ\96, Ð½ÐµÐ·Ð²Ð°Ð¶Ð°Ñ\8eÑ\87и Ð½Ð° Ñ\87аÑ\81Ñ\82кові шаблони:\n"
+"Ð\9dаÑ\81Ñ\82Ñ\83пнÑ\96 Ñ\88лÑ\8fÑ\85и Ð½Ðµ Ð·Ð»Ð¸Ñ\82Ñ\96 Ñ\96 Ð±Ñ\83ли Ð·Ð°Ð»Ð¸Ñ\88енÑ\96, Ð½ÐµÐ·Ð²Ð°Ð¶Ð°Ñ\8eÑ\87и Ð½Ð° Ñ\80озÑ\80Ñ\96джені шаблони:\n"
 "%s"
 
 #, c-format
@@ -20530,8 +21744,8 @@ msgid ""
 "patterns:\n"
 "%s"
 msgstr ""
-"Наступні шляхи вже існували і тому не були оновлені, незважаючи на часткові "
-"шаблони:\n"
+"Наступні шляхи вже існували і тому не були оновлені, незважаючи на "
+"Ñ\80озÑ\80Ñ\96дженÑ\96 Ñ\88аблони:\n"
 "%s"
 
 #, c-format
@@ -20616,7 +21830,7 @@ msgstr ""
 
 #, c-format
 msgid "'%s' is not a .git file, error code %d"
-msgstr "\"%s\" не є .git-файлом, код помилки %d"
+msgstr "\"%s\" не є .git файлом, код помилки %d"
 
 #, c-format
 msgid "'%s' does not point back to '%s'"
@@ -20632,7 +21846,7 @@ msgid ".git file broken"
 msgstr ".git файл пошкоджено"
 
 msgid ".git file incorrect"
-msgstr "Неправильний файл .git"
+msgstr ".git файл не є коректним"
 
 msgid "not a valid path"
 msgstr "неприпустимий шлях"
@@ -20647,10 +21861,10 @@ msgid "unable to locate repository; .git file broken"
 msgstr "не вдалося знайти сховище; файл .git пошкоджено"
 
 msgid "gitdir unreadable"
-msgstr "git-директорія нечитабельна"
+msgstr "нечитабельна git директорія"
 
 msgid "gitdir incorrect"
-msgstr "git-директорія неправильна"
+msgstr "невірна git директорія"
 
 msgid "not a valid directory"
 msgstr "неприпустима директорія"
@@ -20668,14 +21882,14 @@ msgstr ""
 "помилка при зчитуванні (очікувалось %<PRIuMAX> байтів, прочитано %<PRIuMAX>)"
 
 msgid "invalid gitdir file"
-msgstr "неприпустимий файл git-директорії"
+msgstr "неприпустимий файл git директорії"
 
 msgid "gitdir file points to non-existent location"
-msgstr "файл git-директорії вказує на неіснуюче розташування"
+msgstr "файл git директорії вказує на неіснуюче розташування"
 
 #, c-format
 msgid "unable to set %s in '%s'"
-msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð·Ð°Ð´Ð°ти %s в \"%s\""
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\81Ñ\82ановити %s в \"%s\""
 
 #, c-format
 msgid "unable to unset %s in '%s'"
@@ -20686,7 +21900,7 @@ msgstr "не вдалося встановити extensions.worktreeConfig па
 
 #, c-format
 msgid "could not setenv '%s'"
-msgstr "не вдалося встановити оточення \"%s\""
+msgstr "не Ð²Ð´Ð°Ð»Ð¾Ñ\81Ñ\8f Ð²Ñ\81Ñ\82ановиÑ\82и Ð·Ð¼Ñ\96ннÑ\83 Ð¾Ñ\82оÑ\87еннÑ\8f \"%s\""
 
 #, c-format
 msgid "unable to create '%s'"
@@ -20704,65 +21918,61 @@ msgid "unable to get current working directory"
 msgstr "не вдалося завантажити поточну робочу директорію"
 
 msgid "Unmerged paths:"
-msgstr "Ð\9dе злиті шляхи:"
+msgstr "не злиті шляхи:"
 
 msgid "  (use \"git restore --staged <file>...\" to unstage)"
 msgstr ""
-"  (викоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е \"git restore --staged <Ñ\84айл>...\", Ñ\89об Ð²Ð¸Ð»Ñ\83Ñ\87ити з індексу)"
+"  (викоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е \"git restore --staged <Ñ\84айл>...\", Ñ\89об Ð²Ð¸Ð´Ð°Ð»ити з індексу)"
 
 #, c-format
 msgid "  (use \"git restore --source=%s --staged <file>...\" to unstage)"
 msgstr ""
 "  (використовуйте \"git restore --source=%s --staged <file>...\", щоб "
-"видалити з індексу)"
+"пÑ\80ибÑ\80ати з індексу)"
 
 msgid "  (use \"git rm --cached <file>...\" to unstage)"
 msgstr ""
-"  (викоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е \"git rm --cached <file>...\", Ñ\89об Ð²Ð¸Ð»Ñ\83Ñ\87ити з індексу)"
+"  (викоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е \"git rm --cached <file>...\", Ñ\89об Ð²Ð¸Ð´Ð°Ð»ити з індексу)"
 
 msgid "  (use \"git add <file>...\" to mark resolution)"
-msgstr "  (використовуйте \"git add <файл>...\", щоб позначити як вирішене)"
+msgstr "  (використовуйте \"git add <файл>...\", щоб позначити як розвʼязане)"
 
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr ""
-"  (використовуйте \"git add/rm <файл>...\" за потребою, щоб позначити як "
-"виÑ\80Ñ\96Ñ\88ене)"
+"  (використовуйте \"git add/rm <файл>...\" за потребою, щоб позначити "
+"виÑ\80Ñ\96Ñ\88еннÑ\8f)"
 
 msgid "  (use \"git rm <file>...\" to mark resolution)"
-msgstr "  (використовуйте \"git rm <файл>...\", щоб позначити як вирішене)"
+msgstr "  (використовуйте \"git rm <файл>...\", щоб позначити вирішення)"
 
 msgid "Changes to be committed:"
-msgstr "Зміни, що будуть додані до коміту:"
+msgstr "Зміни, додані до майбутнього коміту:"
 
 msgid "Changes not staged for commit:"
-msgstr "Зміни, що не будуть додані до коміту:"
+msgstr "Зміни, не додані до майбутнього коміту:"
 
 msgid "  (use \"git add <file>...\" to update what will be committed)"
-msgstr ""
-"  (використовуйте \"git add <файл>...\", для оновлення того, що буде "
-"закомічено)"
+msgstr "  (скористайтесь \"git add <файл>...\", щоб оновити майбутній коміт)"
 
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr ""
-"  (використовуйте \"git add/rm <файл>...\" для оновлення того, що буде "
-"закомічено)"
+"  (скористайтесь \"git add/rm <файл>...\", щоб оновити майбутній коміт)"
 
 msgid ""
 "  (use \"git restore <file>...\" to discard changes in working directory)"
 msgstr ""
-"  (використовуйте \"git restore <файл>...\", щоб скасувати зміни в робочій "
+"  (скористайтесь \"git restore <файл>...\", щоб скасувати зміни в робочій "
 "директорії)"
 
 msgid "  (commit or discard the untracked or modified content in submodules)"
 msgstr ""
-"  (зробіть коміт або скасуйте невідстежуваний або змінений контент у "
+"  (зробіть коміт або відкиньте невідстежуваний або змінений вміст у "
 "підмодулях)"
 
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr ""
-"  (використовуйте \"git %s <файл>...\" для включення до того, що буде "
-"закомічено)"
+"  (скористайтесь \"git %s <файл>...\", щоб додати до майбутнього коміту)"
 
 msgid "both deleted:"
 msgstr "видалено обома:"
@@ -20856,13 +22066,13 @@ msgstr "  (виправте конфлікти та виконайте \"git com
 
 msgid "  (use \"git merge --abort\" to abort the merge)"
 msgstr ""
-"  (використовуйте команду \"git merge --abort\", щоб перервати злиття)."
+"  (скористайтесь командою \"git merge --abort\", щоб перервати злиття)."
 
 msgid "All conflicts fixed but you are still merging."
 msgstr "Усі конфлікти виправлено, але ви все ще продовжуєте злиття."
 
 msgid "  (use \"git commit\" to conclude merge)"
-msgstr "  (використовуйте \"git commit\" для завершення злиття)"
+msgstr "  (скористайтесь \"git commit\", щоб завершити злиття)"
 
 msgid "You are in the middle of an am session."
 msgstr "Ви всередині am сеансу."
@@ -20874,16 +22084,16 @@ msgid "  (fix conflicts and then run \"git am --continue\")"
 msgstr "  (виправте конфлікти, а потім виконайте \"git am --continue\")"
 
 msgid "  (use \"git am --skip\" to skip this patch)"
-msgstr "  (використовуйте команду \"git am --skip\", щоб пропустити цю латку)"
+msgstr "  (скористайтесь командою \"git am --skip\", щоб пропустити цю латку)"
 
 msgid ""
 "  (use \"git am --allow-empty\" to record this patch as an empty commit)"
 msgstr ""
-"  (використовуйте \"git am --allow-empty\", щоб записати цю латку як "
-"поÑ\80ожнÑ\96й ÐºÐ¾Ð¼Ñ\96Ñ\82)"
+"  (скористайтесь \"git am --allow-empty\", щоб записати цю латку як порожній "
+"коміт)"
 
 msgid "  (use \"git am --abort\" to restore the original branch)"
-msgstr "  (використовуйте \"git am --abort\", щоб відновити початкову гілку)"
+msgstr "  (скористайтесь \"git am --abort\", щоб відновити початкову гілку)"
 
 msgid "git-rebase-todo is missing."
 msgstr "git-rebase-todo відсутній."
@@ -20914,11 +22124,12 @@ msgstr[2] "Наступні команди для виконання (залиш
 
 msgid "  (use \"git rebase --edit-todo\" to view and edit)"
 msgstr ""
-"  (використовуйте \"git rebase --edit-todo\" для перегляду та редагування)"
+"  (скористайтесь \"git rebase --edit-todo\", щоб переглянути та "
+"відредагувати)"
 
 #, c-format
 msgid "You are currently rebasing branch '%s' on '%s'."
-msgstr "Наразі ви перебазовуєте гілку '%s' на '%s'."
+msgstr "Наразі ви перебазовуєте гілку \"%s\" на \"%s\"."
 
 msgid "You are currently rebasing."
 msgstr "Наразі йде перебазування."
@@ -20927,11 +22138,11 @@ msgid "  (fix conflicts and then run \"git rebase --continue\")"
 msgstr "  (виправте конфлікти, а потім виконайте \"git rebase --continue\")"
 
 msgid "  (use \"git rebase --skip\" to skip this patch)"
-msgstr "  (використовуйте \"git rebase --skip\", щоб пропустити цю латку)"
+msgstr "  (скористайтесь \"git rebase --skip\", щоб пропустити цю латку)"
 
 msgid "  (use \"git rebase --abort\" to check out the original branch)"
 msgstr ""
-"  (використовуйте \"git rebase --abort\", щоб перейти до початкової гілки)"
+"  (скористайтесь \"git rebase --abort\", щоб перейти до початкової гілки)"
 
 msgid "  (all conflicts fixed: run \"git rebase --continue\")"
 msgstr "  (усі конфлікти виправлено: виконайте \"git rebase --continue\")"
@@ -20940,11 +22151,11 @@ msgstr "  (усі конфлікти виправлено: виконайте \"
 msgid ""
 "You are currently splitting a commit while rebasing branch '%s' on '%s'."
 msgstr ""
-"Наразі виконується розділення коміту під час перебазування гілки \"%s\" на "
+"Наразі виконується розщеплення коміту під час перебазування гілки \"%s\" на "
 "\"%s\"."
 
 msgid "You are currently splitting a commit during a rebase."
-msgstr "Ви розбиваєте коміт під час перебазування."
+msgstr "Ви розщеплюєте коміт під час перебазування."
 
 msgid "  (Once your working directory is clean, run \"git rebase --continue\")"
 msgstr ""
@@ -20952,14 +22163,14 @@ msgstr ""
 
 #, c-format
 msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
-msgstr "Ð\92и Ñ\80едагÑ\83Ñ\94Ñ\82е ÐºÐ¾Ð¼Ð¼Ñ\96Ñ\82 Ð¿Ñ\96д Ñ\87аÑ\81 Ð¿ÐµÑ\80ебазÑ\83ваннÑ\8f Ð³Ñ\96лки '%s' Ð½Ð° '%s'."
+msgstr "Ð\9dаÑ\80азÑ\96 Ð²Ð¸ Ñ\80едагÑ\83Ñ\94Ñ\82е ÐºÐ¾Ð¼Ñ\96Ñ\82 Ð¿Ñ\80и Ð¿ÐµÑ\80ебазÑ\83ваннÑ\96 Ð³Ñ\96лки \"%s\" Ð½Ð° \"%s\"."
 
 msgid "You are currently editing a commit during a rebase."
-msgstr "Ð\92и Ñ\80едагÑ\83Ñ\94Ñ\82е ÐºÐ¾Ð¼Ñ\96Ñ\82 Ð¿Ñ\96д Ñ\87аÑ\81 Ð¿ÐµÑ\80ебазÑ\83ваннÑ\8f."
+msgstr "Ð\9dаÑ\80азÑ\96 Ð²Ð¸ Ñ\80едагÑ\83Ñ\94Ñ\82е ÐºÐ¾Ð¼Ñ\96Ñ\82 Ð¿Ñ\80и Ð¿ÐµÑ\80ебазÑ\83ваннÑ\96."
 
 msgid "  (use \"git commit --amend\" to amend the current commit)"
 msgstr ""
-"  (використовуйте \"git commit --amend\" для внесення змін до поточного "
+"  (скористайтесь \"git commit --amend\", щоб внести зміни до поточного "
 "коміту)"
 
 msgid ""
@@ -20995,7 +22206,7 @@ msgstr ""
 "висмикування)"
 
 msgid "Revert currently in progress."
-msgstr "Наразі виконується операція вивертання."
+msgstr "Наразі триває вивертання."
 
 #, c-format
 msgid "You are currently reverting commit %s."
@@ -21011,11 +22222,11 @@ msgid "  (all conflicts fixed: run \"git revert --continue\")"
 msgstr "  (усі конфлікти виправлено: виконайте \"git revert --continue\")"
 
 msgid "  (use \"git revert --skip\" to skip this patch)"
-msgstr "  (використовуйте \"git revert --skip\", щоб пропустити цю латку)"
+msgstr "  (скористайтесь \"git revert --skip\", щоб пропустити цю латку)"
 
 msgid "  (use \"git revert --abort\" to cancel the revert operation)"
 msgstr ""
-"  (використовуйте \"git revert --abort\", щоб скасувати операцію повернення)"
+"  (скористайтесь \"git revert --abort\", щоб скасувати операцію повернення)"
 
 #, c-format
 msgid "You are currently bisecting, started from branch '%s'."
@@ -21026,24 +22237,25 @@ msgstr "Наразі ви робите бісекцію."
 
 msgid "  (use \"git bisect reset\" to get back to the original branch)"
 msgstr ""
-"  (використовуйте \"git bisect reset\", щоб повернутись до початкової гілки)"
+"  (скористайтесь \"git bisect reset\", щоб повернутись на початкову гілку)"
 
 msgid "You are in a sparse checkout."
-msgstr "Ð\92и Ð¿ÐµÑ\80ебÑ\83ваÑ\94Ñ\82е Ð² Ñ\87аÑ\81Ñ\82ковомÑ\83 Ð¿ÐµÑ\80еÑ\85одÑ\96 Ð´Ð¾ Ð³Ñ\96лки."
+msgstr "Ð\92и Ð¿ÐµÑ\80ебÑ\83ваÑ\94Ñ\82е Ð² Ñ\80озÑ\80Ñ\96дженомÑ\83 Ð¿ÐµÑ\80еÑ\85одÑ\96 Ð½Ð° Ð³Ñ\96лкÑ\83."
 
 #, c-format
 msgid "You are in a sparse checkout with %d%% of tracked files present."
 msgstr ""
-"Ви перебуваєте в частковому переході до гілки з %d%% відстежуваних файлів."
+"Ви перебуваєте в розрідженому переході на гілку з %d%% наявних відстежуваних "
+"файлів."
 
 msgid "On branch "
 msgstr "На гілці "
 
 msgid "interactive rebase in progress; onto "
-msgstr "Ñ\96нÑ\82еÑ\80акÑ\82ивне Ð¿ÐµÑ\80ебазовÑ\83ваннÑ\8f Ð² Ð¿Ñ\80оÑ\86еÑ\81Ñ\96; на "
+msgstr "Ñ\82Ñ\80иваÑ\94 Ñ\96нÑ\82еÑ\80акÑ\82ивне Ð¿ÐµÑ\80ебазÑ\83ваннÑ\8f на "
 
 msgid "rebase in progress; onto "
-msgstr "перебазовування в процесі; на "
+msgstr "триває перебазування на "
 
 msgid "HEAD detached at "
 msgstr "HEAD відʼєднано на "
@@ -21052,7 +22264,7 @@ msgid "HEAD detached from "
 msgstr "HEAD відʼєднано від "
 
 msgid "Not currently on any branch."
-msgstr "Ð\9dаÑ\80азÑ\96 Ð½Ðµ Ð·Ð½Ð°Ñ\85одиÑ\82еÑ\81Ñ\8c Ð² Ð¶Ð¾Ð´Ð½Ñ\96й гілці."
+msgstr "Ð\9dе Ð½Ð° гілці."
 
 msgid "Initial commit"
 msgstr "Початковий коміт"
@@ -21079,14 +22291,14 @@ msgid "It took %.2f seconds to enumerate untracked files."
 msgstr "На перерахування невідстежуваних файлів пішло %.2f секунд."
 
 msgid "See 'git help status' for information on how to improve this."
-msgstr "Дивіться 'git help status' для інформаціі з того, як це покращити."
+msgstr "Дивіться \"git help status\" для інформації про те, як це покращити."
 
 #, c-format
 msgid "Untracked files not listed%s"
-msgstr "Ð\9dевÑ\96дÑ\81Ñ\82ежÑ\83ванÑ\96 Ñ\84айли Ð½Ðµ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾%s"
+msgstr "Ð\9dевÑ\96дÑ\81Ñ\82ежÑ\83ванÑ\96 Ñ\84айли Ð½Ðµ Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ñ\96%s"
 
 msgid " (use -u option to show untracked files)"
-msgstr " (використовуйте опцію -u для відображення невідстежуваних файлів)"
+msgstr " (використовуйте опцію -u, щоб показати невідстежувані файли)"
 
 msgid "No changes"
 msgstr "Немає змін"
@@ -21094,7 +22306,7 @@ msgstr "Немає змін"
 #, c-format
 msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
 msgstr ""
-"не додано жодних змін до коміту (використовуйте \"git add\" та/або \"git "
+"не додано жодних змін до коміту (скористайтесь \"git add\" та/або \"git "
 "commit -a\")\n"
 
 #, c-format
@@ -21106,8 +22318,8 @@ msgid ""
 "nothing added to commit but untracked files present (use \"git add\" to "
 "track)\n"
 msgstr ""
-"нічого не додано до коміту, але присутні невідстежувані файли (скористайтесь "
-"\"git add\" щоб почати відстежувати)\n"
+"нічого не додано до коміту, але є невідстежувані файли (скористайтесь \"git "
+"add\" для відстежування)\n"
 
 #, c-format
 msgid "nothing added to commit but untracked files present\n"
@@ -21125,21 +22337,20 @@ msgstr "нічого комітити\n"
 
 #, c-format
 msgid "nothing to commit (use -u to show untracked files)\n"
-msgstr ""
-"нічого комітити (скористайтесь -u щоб подивитись невідстежувані файли)\n"
+msgstr "нічого комітити (скористайтесь -u щоб показати невідстежувані файли)\n"
 
 #, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "нічого комітити, робоче дерево чисте\n"
 
 msgid "No commits yet on "
-msgstr "Ð\9dаÑ\80азÑ\96 Ð½ÐµÐ¼Ð°Ñ\94 ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\96в Ð½Ð° "
+msgstr "Ð\9fоки Ñ\89о Ð½ÐµÐ¼Ð°Ñ\94 ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\96в Ñ\83 "
 
 msgid "HEAD (no branch)"
 msgstr "HEAD (немає гілки)"
 
 msgid "different"
-msgstr "різниться"
+msgstr "відрізняється"
 
 msgid "behind "
 msgstr "позаду "
@@ -21151,27 +22362,27 @@ msgstr "попереду "
 
 #, c-format
 msgid "cannot %s: You have unstaged changes."
-msgstr "не можливо %s: У вас є не індексовані зміни."
+msgstr "неможливо %s: У вас є неіндексовані зміни."
 
 msgid "additionally, your index contains uncommitted changes."
-msgstr "крім того, ваш індекс містить не закомічені зміни."
+msgstr "крім того, ваш індекс містить незакомічені зміни."
 
 #, c-format
 msgid "cannot %s: Your index contains uncommitted changes."
-msgstr "не можливо %s: Ваш індекс містить не закомічені зміни."
+msgstr "неможливо виконати %s: Ваш індекс містить незакомічені зміни."
 
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
 msgstr ""
-"Ð\9fомилка: Ð\92аÑ\88Ñ\96 Ð»Ð¾ÐºÐ°Ð»Ñ\8cнÑ\96 Ð·Ð¼Ñ\96ни Ð² Ð½Ð°Ñ\81Ñ\82Ñ\83пниÑ\85 Ñ\84айлаÑ\85 Ð±Ñ\83де Ð¿ÐµÑ\80езапиÑ\81ано під час "
+"Ð\9fомилка: Ð\92аÑ\88Ñ\96 Ð»Ð¾ÐºÐ°Ð»Ñ\8cнÑ\96 Ð·Ð¼Ñ\96ни Ð² Ð½Ð°Ñ\81Ñ\82Ñ\83пниÑ\85 Ñ\84айлаÑ\85 Ð±Ñ\83ли Ð± Ð¿ÐµÑ\80езапиÑ\81анÑ\96 під час "
 "злиття"
 
 msgid "Automated merge did not work."
 msgstr "Автоматичне злиття не спрацювало."
 
 msgid "Should not be doing an octopus."
-msgstr "Не варто робити octopus злиття."
+msgstr "Не слід робити octopus злиття."
 
 #, sh-format
 msgid "Unable to find common commit with $pretty_name"
@@ -21198,7 +22409,7 @@ msgstr "використання: $dashless $USAGE"
 
 #, sh-format
 msgid "Cannot chdir to $cdup, the toplevel of the working tree"
-msgstr "Неможливо chdir до $cdup, верхнього рівня робочого дерева"
+msgstr "Неможливо виконати chdir до $cdup, верхнього рівня робочого дерева"
 
 #, sh-format
 msgid "fatal: $program_name cannot be used without a working tree."
@@ -21261,7 +22472,7 @@ msgstr ""
 "перевірку.\n"
 
 msgid "Cannot run git format-patch from outside a repository\n"
-msgstr "Ð\9dеможливо Ð·Ð°Ð¿Ñ\83Ñ\81Ñ\82иÑ\82и git format-patch Ð·Ð° Ð¼ÐµÐ¶Ð°Ð¼Ð¸ Ñ\81Ñ\85овиÑ\89а\n"
+msgstr "Ð\9dеможливо Ð·Ð°Ð¿Ñ\83Ñ\81Ñ\82иÑ\82и git format-patch Ð¿Ð¾Ð·Ð° Ñ\81Ñ\85овиÑ\89ем\n"
 
 msgid ""
 "`batch-size` and `relogin` must be specified together (via command-line or "
@@ -21280,7 +22491,7 @@ msgstr "Невідомий --confirm параметр: \"%s\"\n"
 
 #, perl-format
 msgid "warning: sendmail alias with quotes is not supported: %s\n"
-msgstr "попеÑ\80едженнÑ\8f: sendmail Ð°Ð»Ñ\96аÑ\81 у лапках не підтримується: %s\n"
+msgstr "попеÑ\80едженнÑ\8f: sendmail Ð¿Ñ\81евдонÑ\96м у лапках не підтримується: %s\n"
 
 #, perl-format
 msgid "warning: `:include:` not supported: %s\n"
@@ -21304,14 +22515,14 @@ msgid ""
 "    * Giving --format-patch option if you mean a range.\n"
 msgstr ""
 "Файл \"%s\" існує, але це також може бути діапазон комітів\n"
-"для яких випускаються латки.  Будь ласка, розтлумачте...\n"
+"для яких створюються латки.  Будь ласка, розтлумачте...\n"
 "\n"
-"    * Вказавши \"./%s\", якщо на увазі мається файл або\n"
+"    * Вказавши \"./%s\", якщо на увазі мається файл\n"
 "    * Додавши --format-patch, якщо на увазі мається діапазон.\n"
 
 #, perl-format
 msgid "Failed to opendir %s: %s"
-msgstr "Не вдалося відкрити директорію %s: %s"
+msgstr "Не вдалося виконати opendir %s: %s"
 
 msgid ""
 "\n"
@@ -21338,7 +22549,7 @@ msgid ""
 "Clear the body content if you don't wish to send a summary.\n"
 msgstr ""
 "Рядки, що починаються з \"GIT:\", будуть вилучені.\n"
-"Ð\9fодÑ\83майÑ\82е Ð¿Ñ\80о Ñ\82е, Ñ\89об Ð´Ð¾Ð´Ð°Ñ\82и Ð·Ð°Ð³Ð°Ð»Ñ\8cний diffstat Ð°Ð±Ð¾ Ð·Ð¼Ñ\96Ñ\81Ñ\82\n"
+"РозглÑ\8fнÑ\8cÑ\82е Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ñ\96Ñ\81Ñ\82Ñ\8c Ð²ÐºÐ»Ñ\8eÑ\87еннÑ\8f Ð·Ð°Ð³Ð°Ð»Ñ\8cного diffstat Ð°Ð±Ð¾ Ð·Ð¼Ñ\96Ñ\81Ñ\82Ñ\83\n"
 "для латки, яку ви пишете.\n"
 "\n"
 "Очистіть вміст тіла, якщо ви не бажаєте надсилати підсумок.\n"
@@ -21352,7 +22563,7 @@ msgid "Failed to open %s.final: %s"
 msgstr "Не вдалося відкрити %s.final: %s"
 
 msgid "Summary email is empty, skipping it\n"
-msgstr "Підсумковий лист порожній, перескочено\n"
+msgstr "Підсумковий лист порожній, пропущено\n"
 
 #. TRANSLATORS: please keep [y/N] as is.
 
@@ -21364,6 +22575,7 @@ msgid ""
 "The following files are 8bit, but do not declare a Content-Transfer-"
 "Encoding.\n"
 msgstr ""
+"Наступні файли є 8-бітними, але не містять Content-Transfer-Encoding.\n"
 
 msgid "Which 8bit encoding should I declare [UTF-8]? "
 msgstr "Яке 8-бітне кодування слід оголосити [UTF-8]? "
@@ -21375,7 +22587,7 @@ msgid ""
 "has the template subject '*** SUBJECT HERE ***'. Pass --force if you really "
 "want to send.\n"
 msgstr ""
-"Ð\92Ñ\96дмова Ñ\83 надсиланні, тому що латка\n"
+"Ð\92Ñ\96дмовлено Ð² надсиланні, тому що латка\n"
 "\t%s\n"
 "має шаблонну тему \"*** SUBJECT HERE ***\". Додайте --force, якщо ви дійсно "
 "хочете відправити.\n"
@@ -21385,10 +22597,12 @@ msgstr "Кому слід надсилати електронні листи (я
 
 #, perl-format
 msgid "fatal: alias '%s' expands to itself\n"
-msgstr "збÑ\96й: Ð°Ð»Ñ\96аÑ\81 \"%s\" розгортається на самого себе\n"
+msgstr "збÑ\96й: Ð¿Ñ\81евдонÑ\96м \"%s\" розгортається на самого себе\n"
 
 msgid "Message-ID to be used as In-Reply-To for the first email (if any)? "
 msgstr ""
+"Message-ID, який буде використовуватися як In-Reply-To для першого листа "
+"(якщо такий є)? "
 
 #, perl-format
 msgid "error: unable to extract a valid address from: %s\n"
@@ -21418,7 +22632,7 @@ msgid ""
 "\n"
 msgstr ""
 "    Наведений вище список копій було розширено додатковими\n"
-"    Ð°Ð´Ñ\80еÑ\81ами, Ð·Ð½Ð°Ð¹Ð´ÐµÐ½Ð¸Ð¼Ð¸ Ñ\83 Ð¿Ð¾Ð²Ñ\96домленнÑ\96 ÐºÐ¾Ð¼Ñ\96Ñ\82а латки. Зазвичай\n"
+"    Ð°Ð´Ñ\80еÑ\81ами, Ð·Ð½Ð°Ð¹Ð´ÐµÐ½Ð¸Ð¼Ð¸ Ñ\83 Ð´Ð¾Ð¿Ð¸Ñ\81Ñ\96 Ð´Ð¾ ÐºÐ¾Ð¼Ñ\96Ñ\82Ñ\83 латки. Зазвичай\n"
 "    send-email запитує перед надсиланням, коли це трапляється.\n"
 "    Цю поведінку можна контролювати за допомогою параметра sendemail."
 "confirm\n"
@@ -21437,7 +22651,7 @@ msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
 msgstr "Надіслати цей лист? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
 
 msgid "Send this email reply required"
-msgstr ""
+msgstr "Відповідь на запитання \"Надіслати цей лист?\" є обовʼязковою"
 
 msgid "The required SMTP server is not properly defined."
 msgstr "Потрібний SMTP-сервер не визначено належним чином."
@@ -21448,12 +22662,12 @@ msgstr "Сервер не підтримує STARTTLS! %s"
 
 #, perl-format
 msgid "STARTTLS failed! %s"
-msgstr ""
+msgstr "STARTTLS завершився невдало! %s"
 
 msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
 msgstr ""
 "Не вдалося правильно ініціалізувати SMTP. Перевірте конфігурацію і "
-"Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8f --smtp-debug."
+"Ñ\81коÑ\80иÑ\81Ñ\82айÑ\82еÑ\81Ñ\8c --smtp-debug."
 
 #, perl-format
 msgid "Failed to send %s\n"
@@ -21468,10 +22682,10 @@ msgid "Sent %s\n"
 msgstr "Відправлено %s\n"
 
 msgid "Dry-OK. Log says:\n"
-msgstr ""
+msgstr "Пробно OK. Журнал каже:\n"
 
 msgid "OK. Log says:\n"
-msgstr "Ð\9eÐ\9a. Ð\9bог каже:\n"
+msgstr "Ð\9eÐ\9a. Ð\96Ñ\83Ñ\80нал каже:\n"
 
 msgid "Result: "
 msgstr "Результат: "
@@ -21505,7 +22719,7 @@ msgstr "(%s) Не вдалося виконати \"%s\""
 
 #, perl-format
 msgid "(%s) Malformed output from '%s'"
-msgstr "(%s) Невірно сформований рядок виводу з \"%s\"."
+msgstr "(%s) Невірно сформований вивід з \"%s\""
 
 #, perl-format
 msgid "(%s) failed to close pipe to '%s'"
@@ -21545,7 +22759,7 @@ msgstr ""
 
 #, perl-format
 msgid "Skipping %s with backup suffix '%s'.\n"
-msgstr "Ð\9fÑ\80опÑ\83Ñ\81к %s Ð· Ñ\80езеÑ\80вним Ñ\81Ñ\83Ñ\84Ñ\96кÑ\81ом \"%s\".\n"
+msgstr "Ð\9fÑ\80опÑ\83Ñ\81к %s Ð· Ñ\81Ñ\83Ñ\84Ñ\96кÑ\81ом Ñ\80езеÑ\80вноÑ\97 ÐºÐ¾Ð¿Ñ\96Ñ\97 \"%s\".\n"
 
 #. TRANSLATORS: please keep "[y|N]" as is.
 
index aa25e9a1593ac21a1bb84174184312b283226d89..b70ae3866b26691c11992d4ffa606ac3aea7b35e 100644 (file)
@@ -14,6 +14,7 @@
 #   - 依云 <lilydjwg AT gmail.com>
 #   - Yichao Yu <yyc1992 AT gmail.com>
 #   - Zhuang Ya <zhuangya AT me.com>
+#   - Teng Long <dyroneteng AT gmail.com>
 #
 #  Git glossary for Chinese translators
 #
@@ -76,6 +77,7 @@
 #   index entry                      |  索引条目
 #   loose object                     |  松散对象
 #   loose refs                       |  松散引用
+#   magic                            |  神奇前缀(路径规格支持的一种前缀表达式)
 #   master                           |  master(默认分支名)
 #   merge                            |  合并
 #   object                           |  对象
@@ -85,6 +87,7 @@
 #   object type                      |  对象类型
 #   octopus                          |  章鱼式合并(两分支以上的合并)
 #   origin                           |  origin(默认的远程名称)
+#   orphan                           |  孤立(一般指孤立分支,即没有任何提交的分支)
 #   pack                             |  包
 #   pack index                       |  包索引
 #   packfile                         |  包文件
@@ -148,8 +151,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-20 12:27+0800\n"
-"PO-Revision-Date: 2023-05-20 12:38+0800\n"
+"POT-Creation-Date: 2023-08-18 10:21+0800\n"
+"PO-Revision-Date: 2023-08-18 19:29+0800\n"
 "Last-Translator: Teng Long <dyroneteng@gmail.com>\n"
 "Language-Team: GitHub <https://github.com/dyrone/git/>\n"
 "Language: zh_CN\n"
@@ -891,9 +894,8 @@ msgid "Reverting is not possible because you have unmerged files."
 msgstr "无法回退,因为您有未合并的文件。"
 
 #: advice.c
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "无法 %s,因为您有未合并的文件。"
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "无法变基,因为您有未合并的文件。"
 
 #: advice.c
 msgid ""
@@ -1060,6 +1062,14 @@ msgstr "选项 '%s' 和 '%s' 不能同时使用"
 msgid "'%s' outside a repository"
 msgstr "'%s' 在仓库之外"
 
+#: apply.c
+msgid "failed to read patch"
+msgstr "无法读取补丁"
+
+#: apply.c
+msgid "patch too large"
+msgstr "补丁过大"
+
 #: apply.c
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
@@ -2157,8 +2167,8 @@ msgstr "一个名为 '%s' 的分支已经存在"
 
 #: branch.c
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "无法强制更新检出于 '%2$s' 的分支 '%1$s'"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr "无法强制更新被工作区 '%2$s' 所使用的分支 '%1$s'"
 
 #: branch.c
 #, c-format
@@ -2236,20 +2246,6 @@ msgstr "git add [<选项>] [--] <路径规格>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "不能 chmod %cx '%s'"
 
-#: builtin/add.c
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "意外的差异状态 %c"
-
-#: builtin/add.c builtin/commit.c
-msgid "updating files failed"
-msgstr "更新文件失败"
-
-#: builtin/add.c
-#, c-format
-msgid "remove '%s'\n"
-msgstr "删除 '%s'\n"
-
 #: builtin/add.c
 msgid "Unstaged changes after refreshing the index:"
 msgstr "刷新索引之后尚未被暂存的变更:"
@@ -2776,10 +2772,6 @@ msgstr "向 git-mailinfo 传递 -m 参数"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "针对 mbox 格式,向 git-mailsplit 传递 --keep-cr 参数"
 
-#: builtin/am.c
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr "不向 git-mailsplit 传递 --keep-cr 参数,覆盖 am.keepcr 的设置"
-
 #: builtin/am.c
 msgid "strip everything before a scissors line"
 msgstr "丢弃裁切线前的所有内容"
@@ -4080,12 +4072,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 #: builtin/cat-file.c
 msgid ""
@@ -4143,6 +4135,10 @@ msgstr "类似于 --batch,但不输出 <内容>"
 msgid "stdin is NUL-terminated"
 msgstr "标准输入以 NUL 字符分隔"
 
+#: builtin/cat-file.c
+msgid "stdin and stdout is NUL-terminated"
+msgstr "标准输入和标准输出以 NUL 字符分隔"
+
 #: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "从标准输入读取命令"
@@ -5039,7 +5035,8 @@ msgid "remove whole directories"
 msgstr "删除整个目录"
 
 #: builtin/clean.c builtin/describe.c builtin/grep.c builtin/log.c
-#: builtin/ls-files.c builtin/name-rev.c builtin/show-ref.c
+#: builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c builtin/show-ref.c
+#: ref-filter.h
 msgid "pattern"
 msgstr "模式"
 
@@ -5209,14 +5206,6 @@ msgstr "server-specific"
 msgid "option to transmit"
 msgstr "传输选项"
 
-#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/push.c
-msgid "use IPv4 addresses only"
-msgstr "只使用 IPv4 地址"
-
-#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/push.c
-msgid "use IPv6 addresses only"
-msgstr "只使用 IPv6 地址"
-
 #: builtin/clone.c
 msgid "apply partial clone filters to submodules"
 msgstr "对子模组使用部分克隆过滤器"
@@ -5751,6 +5740,10 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+#: builtin/commit.c read-cache.c
+msgid "updating files failed"
+msgstr "更新文件失败"
+
 #: builtin/commit.c
 msgid "failed to unpack HEAD tree object"
 msgstr "无法解包 HEAD 树对象"
@@ -5826,8 +5819,8 @@ msgstr "无法选择一个未被当前提交说明使用的注释字符"
 
 #: builtin/commit.c builtin/merge-tree.c
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "不能查询提交 %s"
+msgid "could not lookup commit '%s'"
+msgstr "不能查询提交 '%s'"
 
 #: builtin/commit.c builtin/shortlog.c
 #, c-format
@@ -8050,7 +8043,7 @@ msgstr "对 %s 调用 fstat 失败:%s"
 msgid "failed to parse '%s' value '%s'"
 msgstr "无法解析 '%s' 值 '%s'"
 
-#: builtin/gc.c builtin/init-db.c
+#: builtin/gc.c setup.c
 #, c-format
 msgid "cannot stat '%s'"
 msgstr "不能对 '%s' 调用 stat"
@@ -9061,7 +9054,7 @@ msgstr "无法返回当前工作目录"
 msgid "bad %s"
 msgstr "错误选项 %s"
 
-#: builtin/index-pack.c builtin/init-db.c
+#: builtin/index-pack.c builtin/init-db.c setup.c
 #, c-format
 msgid "unknown hash algorithm '%s'"
 msgstr "未知的哈希算法 '%s'"
@@ -9078,95 +9071,6 @@ msgstr "--verify 没有提供包文件名参数"
 msgid "fsck error in pack objects"
 msgstr "在打包对象中 fsck 检查出错"
 
-#: builtin/init-db.c
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "不能对模版 '%s' 调用 stat"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "不能打开目录 '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "不能读取链接 '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "不能自 '%s' 到 '%s' 创建符号链接"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "不能拷贝 '%s' 至 '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "ignoring template %s"
-msgstr "忽略模版 %s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "templates not found in %s"
-msgstr "没有在 %s 中找到模版"
-
-#: builtin/init-db.c
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "没有从 '%s' 复制模版:%s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "无效的初始分支名:'%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "不能处理 %d 类型的文件"
-
-#: builtin/init-db.c
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "不能移动 %s 至 %s"
-
-#: builtin/init-db.c
-msgid "attempt to reinitialize repository with different hash"
-msgstr "尝试用不同的哈希算法重新初始化仓库"
-
-#: builtin/init-db.c
-#, c-format
-msgid "%s already exists"
-msgstr "%s 已经存在"
-
-#: builtin/init-db.c
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init:已忽略 --initial-branch=%s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "重新初始化已存在的共享 Git 仓库于 %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "已重新初始化已存在的 Git 仓库于 %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "已初始化空的共享 Git 仓库于 %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "已初始化空的 Git 仓库于 %s%s\n"
-
 #: builtin/init-db.c
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
@@ -9714,6 +9618,11 @@ msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "不能找到跟踪的远程分支,请手工指定 <上游>。\n"
 
+#: builtin/ls-files.c builtin/ls-tree.c
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "无法获得关于 '%s' 的对象信息"
+
 #: builtin/ls-files.c
 #, c-format
 msgid "bad ls-files format: element '%s' does not start with '('"
@@ -9899,11 +9808,6 @@ msgstr "除了显示指向的对象外,显示指向的引用名"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<选项>] <树对象> [<路径>...]"
 
-#: builtin/ls-tree.c
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "无法获得关于 '%s' 的对象信息"
-
 #: builtin/ls-tree.c
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
@@ -10829,11 +10733,13 @@ msgstr "git notes [--ref <注解引用>] [list [<对象>]]"
 
 #: builtin/notes.c
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <注解引用>] add [-f] [--allow-empty] [-m <说明> | -F <文件> "
-"| (-c | -C) <对象>] [<对象>]"
+"git notes [--ref <注解引用>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<分段符>] [--[no-]stripspace] [-m <说明> | -F <文件> | (-c | -C) <"
+"对象>] [<对象>]"
 
 #: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
@@ -10841,11 +10747,13 @@ msgstr "git notes [--ref <注解引用>] copy [-f] <源对象> <目标对象>"
 
 #: builtin/notes.c
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <注解引用>] append [--allow-empty] [-m <说明> | -F <文件> | "
-"(-c | -C) <对象>] [<对象>]"
+"git notes [--ref <注解引用>] append [--allow-empty] [--[no-]separator|--"
+"separator=<分段符>] [--[no-]stripspace] [-m <说明> | -F <文件> | (-c | -C) <"
+"对象>] [<对象>]"
 
 #: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
@@ -11013,6 +10921,18 @@ msgstr "允许保存空白注释"
 msgid "replace existing notes"
 msgstr "替换已存在的注解"
 
+#: builtin/notes.c
+msgid "<paragraph-break>"
+msgstr "<分段符>"
+
+#: builtin/notes.c
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "在段落之间插入<分段符>"
+
+#: builtin/notes.c
+msgid "remove unnecessary whitespace"
+msgstr "删除不必要的空白字符"
+
 #: builtin/notes.c
 #, c-format
 msgid ""
@@ -11691,8 +11611,11 @@ msgid "refusing to run without --i-still-use-this"
 msgstr "拒绝在未指定 --i-still-use-this 选项时运行"
 
 #: builtin/pack-refs.c
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <模式>] [--exclude <模式>]"
 
 #: builtin/pack-refs.c
 msgid "pack everything"
@@ -11702,6 +11625,14 @@ msgstr "打包一切"
 msgid "prune loose refs (default)"
 msgstr "清除松散的引用(默认)"
 
+#: builtin/pack-refs.c
+msgid "references to include"
+msgstr "需包含的引用"
+
+#: builtin/pack-refs.c
+msgid "references to exclude"
+msgstr "需排除的引用"
+
 #: builtin/patch-id.c
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
@@ -11778,6 +11709,14 @@ msgstr "强制覆盖本地分支"
 msgid "number of submodules pulled in parallel"
 msgstr "并发拉取的子模组的数量"
 
+#: builtin/pull.c parse-options.h
+msgid "use IPv4 addresses only"
+msgstr "只使用 IPv4 地址"
+
+#: builtin/pull.c parse-options.h
+msgid "use IPv6 addresses only"
+msgstr "只使用 IPv6 地址"
+
 #: builtin/pull.c
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
@@ -12059,36 +11998,36 @@ msgstr ""
 #: builtin/push.c
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "更新被拒绝,因为您当前分支的最新提交落后于其对应的远程分支。\n"
-"å\86\8d次æ\8e¨é\80\81å\89\8dï¼\8cå\85\88ä¸\8eè¿\9cç¨\8bå\8f\98æ\9b´å\90\88并ï¼\88å¦\82 'git pull ...'ï¼\89ã\80\82详è§\81\n"
-"'git push --help' 中的 'Note about fast-forwards' 小节。"
+"å¦\82æ\9e\9cæ\82¨å¸\8cæ\9c\9bå\85\88ä¸\8eè¿\9cç¨\8bå\8f\98æ\9b´å\90\88并ï¼\8c请å\9c¨æ\8e¨é\80\81å\89\8dæ\89§è¡\8c 'git pull'ã\80\82\n"
+"详见 'git push --help' 中的 'Note about fast-forwards' 小节。"
 
 #: builtin/push.c
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "更新被拒绝,因为推送的一个分支的最新提交落后于其对应的远程分支。\n"
-"检出该分支并整合远程变更(如 'git pull ...'),然后再推送。详见\n"
-"'git push --help' 中的 'Note about fast-forwards' 小节。"
+"如果您希望先与远程变更合并,请在推送前执行 'git pull'。\n"
+"详见 'git push --help' 中的 'Note about fast-forwards' 小节。"
 
 #: builtin/push.c
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "更新被拒绝,因为远程仓库包含您本地尚不存在的提交。这通常是因为另外\n"
-"ä¸\80个ä»\93åº\93å·²å\90\91该å¼\95ç\94¨è¿\9bè¡\8cäº\86æ\8e¨é\80\81ã\80\82å\86\8d次æ\8e¨é\80\81å\89\8dï¼\8cæ\82¨å\8f¯è\83½é\9c\80è¦\81å\85\88æ\95´å\90\88è¿\9cç¨\8bå\8f\98æ\9b´\n"
-"(如 'git pull ...')。\n"
+"ä¸\80个ä»\93åº\93å·²å\90\91该å¼\95ç\94¨è¿\9bè¡\8cäº\86æ\8e¨é\80\81ã\80\82å¦\82æ\9e\9cæ\82¨å¸\8cæ\9c\9bå\85\88ä¸\8eè¿\9cç¨\8bå\8f\98æ\9b´å\90\88并ï¼\8c请å\9c¨æ\8e¨é\80\81\n"
+"前执行 'git pull'。\n"
 "详见 'git push --help' 中的 'Note about fast-forwards' 小节。"
 
 #: builtin/push.c
@@ -12106,13 +12045,14 @@ msgstr ""
 
 #: builtin/push.c
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "更新被拒绝,因为远程跟踪分支的最新提交自从上次检出之后已被更新。\n"
-"在强制更新前,您可能想将这些变更整合到本地(如 'git pull ...')。\n"
+"如果您希望先与远程变更合并,请在推送前执行 'git pull'。\n"
+"详见 'git push --help' 中的 'Note about fast-forwards' 小节。"
 
 #: builtin/push.c
 #, c-format
@@ -13141,12 +13081,10 @@ msgid "fetch the remote branches"
 msgstr "抓取远程的分支"
 
 #: builtin/remote.c
-msgid "import all tags and associated objects when fetching"
-msgstr "抓取时导入所有的标签和关联对象"
-
-#: builtin/remote.c
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "或不抓取任何标签(--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr "抓取时导入所有的标签和关联对象,或不抓取任何标签(--no-tags)"
 
 #: builtin/remote.c
 msgid "branch(es) to track"
@@ -15530,6 +15468,11 @@ msgstr "略过未合并的子模组 %s"
 msgid "Skipping submodule '%s'"
 msgstr "略过子模组 '%s'"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "无法在不提供 URL 时克隆子模组 '%s'"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
@@ -16442,10 +16385,10 @@ msgstr "打印标签内容"
 #: builtin/worktree.c
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <字符串>]]\n"
-"                 [-b <新分支>] <路径> [<提交号>]"
+"                 [--orphan] [(-b | -B) <新分支>] <路径> [<提交号>]"
 
 #: builtin/worktree.c
 msgid "git worktree list [-v | --porcelain [-z]]"
@@ -16475,6 +16418,40 @@ msgstr "git worktree repair [<路径>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <工作区>"
 
+#: builtin/worktree.c
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "没有可用的源分支,将基于 '--orphan' 选项进行推断"
+
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"如果你打算为此仓库创建一个包含新的孤立分支\n"
+"(没有提交的分支)的工作区,你可以使用选项\n"
+"--orphan 来执行此操作:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"如果你打算为此仓库创建一个包含新的孤立分支\n"
+"(没有提交的分支)的工作区,你可以使用选项\n"
+"--orphan 来执行此操作:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #: builtin/worktree.c
 #, c-format
 msgid "Removing %s/%s: %s"
@@ -16555,11 +16532,40 @@ msgstr "准备工作区(重置分支 '%s',之前为 %s)"
 msgid "Preparing worktree (checking out '%s')"
 msgstr "准备工作区(检出 '%s')"
 
+#: builtin/worktree.c
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "不可达:无效引用:%s"
+
 #: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "准备工作区(分离头指针 %s)"
 
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD 指向了一个无用的(或孤立的)引用。\n"
+"HEAD 路径: '%s'\n"
+"HEAD 内容: '%s'"
+
+#: builtin/worktree.c
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"尽管已配置远程仓库,但不存在任何本地的或远程的引用,操作终止;\n"
+"请使用 'add -f' 来覆盖或拉取一个远程仓库"
+
+#: builtin/worktree.c
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "'%s' 和 '%s' 不能同时使用"
+
 #: builtin/worktree.c
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr "检出 <分支>,即使已经被检出到其它工作区"
@@ -16572,6 +16578,10 @@ msgstr "创建一个新分支"
 msgid "create or reset a branch"
 msgstr "创建或重置一个分支"
 
+#: builtin/worktree.c
+msgid "create unborn/orphaned branch"
+msgstr "创建一个尚未诞生的/孤立的分支"
+
 #: builtin/worktree.c
 msgid "populate the new working tree"
 msgstr "生成新的工作区"
@@ -16597,6 +16607,15 @@ msgstr "尝试为新分支名匹配一个远程跟踪分支"
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "选项 '%s'、'%s' 和 '%s' 不能同时使用"
 
+#: builtin/worktree.c
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "选项 '%s',与 '%s' 不能同时使用"
+
+#: builtin/worktree.c
+msgid "<commit-ish>"
+msgstr "<提交号>"
+
 #: builtin/worktree.c
 msgid "added with --lock"
 msgstr "由 --lock 添加"
@@ -16877,6 +16896,16 @@ msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "这个归档包需要这个引用:"
 msgstr[1] "这个归档包需要 %<PRIuMAX> 个引用:"
 
+#: bundle.c
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "该归档包使用的哈希算法:%s"
+
+#: bundle.c
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "归档包使用了过滤器:%s"
+
 #: bundle.c
 msgid "unable to dup bundle descriptor"
 msgstr "无法复制归档包描述符"
@@ -17174,8 +17203,8 @@ msgid "A portable graphical interface to Git"
 msgstr "一个便携的 Git 图形客户端"
 
 #: command-list.h
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "从一个文件计算对象 ID,并可以创建 blob 数据对象"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "从一个文件计算对象 ID,并支持可选地创建一个对象"
 
 #: command-list.h
 msgid "Display help information about Git"
@@ -17715,6 +17744,11 @@ msgstr "提交图形没有基础图形块"
 msgid "commit-graph chain does not match"
 msgstr "提交图形链不匹配"
 
+#: commit-graph.c
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "基础图形中的提交数量过高:%<PRIuMAX>"
+
 #: commit-graph.c
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
@@ -17822,6 +17856,17 @@ msgstr "无法重命名基础提交图形文件"
 msgid "failed to rename temporary commit-graph file"
 msgstr "无法重命名临时提交图形文件"
 
+#: commit-graph.c
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr ""
+"无法合并提交图形,总共已累加提交数:%<PRIuMAX>,当前待累加提交数:%<PRIuMAX>"
+
+#: commit-graph.c
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "无法合并提交图形 %s, 提交过多:%<PRIuMAX>"
+
 #: commit-graph.c
 msgid "Scanning merged commits"
 msgstr "正在扫描合并提交"
@@ -17857,10 +17902,6 @@ msgstr "提交图形有不正确的扇出值:fanout[%d] = %u != %u"
 msgid "failed to parse commit %s from commit-graph"
 msgstr "无法从提交图形中解析提交 %s"
 
-#: commit-graph.c
-msgid "Verifying commits in commit graph"
-msgstr "正在校验提交图中的提交"
-
 #: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
@@ -17908,6 +17949,10 @@ msgstr "提交图形中的提交 %s 的世代号是 %<PRIuMAX> < %<PRIuMAX>"
 msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
 msgstr "提交图形中提交 %s 的提交日期是 %<PRIuMAX> != %<PRIuMAX>"
 
+#: commit-graph.c
+msgid "Verifying commits in commit graph"
+msgstr "正在校验提交图中的提交"
+
 #: commit.c
 #, c-format
 msgid "%s %s is not a commit!"
@@ -19064,6 +19109,14 @@ msgstr "未找到合并基线"
 msgid "multiple merge bases found"
 msgstr "找到了多条合并基线"
 
+#: diff-no-index.c
+msgid "cannot compare stdin to a directory"
+msgstr "无法将标准输入和目录进行比较"
+
+#: diff-no-index.c
+msgid "cannot compare a named pipe to a directory"
+msgstr "无法将命名管道和目录进行比较"
+
 #: diff-no-index.c
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<选项>] <路径> <路径>"
@@ -19128,6 +19181,15 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "外部 diff 退出,停止在 %s"
 
+#: diff.c
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow 明确要求只跟一个路径规格"
+
+#: diff.c
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "指定 --follow: %s 的同时,不支持在路径规格中使用神奇前缀"
+
 #: diff.c parse-options.c
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
@@ -19144,10 +19206,6 @@ msgid ""
 "options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
 msgstr "选项 '%1$s'、'%2$s' 不能同时使用,与 '%4$s' 和 '%5$s' 一起使用 '%3$s'"
 
-#: diff.c
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow 明确要求只跟一个路径规格"
-
 #: diff.c
 #, c-format
 msgid "invalid --stat value: %s"
@@ -22607,6 +22665,15 @@ msgstr "无法生成 diff"
 msgid "could not parse log for '%s'"
 msgstr "不能解析 '%s' 的日志"
 
+#: reachable.c
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "无效的额外废弃提交版本:'%s'"
+
+#: reachable.c
+msgid "unable to enumerate additional recent objects"
+msgstr "无法枚举额外的近期对象"
+
 #: read-cache.c
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
@@ -22794,6 +22861,16 @@ msgstr "不能修复 '%s' 的权限位"
 msgid "%s: cannot drop to stage #0"
 msgstr "%s:不能落到暂存区 #0"
 
+#: read-cache.c
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "意外的差异状态 %c"
+
+#: read-cache.c
+#, c-format
+msgid "remove '%s'\n"
+msgstr "删除 '%s'\n"
+
 #: rebase-interactive.c
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
@@ -23007,6 +23084,26 @@ msgstr "未知的 %%(trailers) 参数:%s"
 msgid "positive value expected contents:lines=%s"
 msgstr "期望一个正数 contents:lines=%s"
 
+#: ref-filter.c
+#, c-format
+msgid "argument expected for %s"
+msgstr "预期参数 %s"
+
+#: ref-filter.c
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "预期正数参数值 %s=%s"
+
+#: ref-filter.c
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "不能完整解析 %s=%s"
+
+#: ref-filter.c
+#, c-format
+msgid "value expected %s="
+msgstr "预期值 %s="
+
 #: ref-filter.c
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
@@ -23098,6 +23195,10 @@ msgstr "这个命令拒绝元素 %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s 不能和 --python、--shell、--tcl 同时使用"
 
+#: ref-filter.c
+msgid "failed to run 'describe'"
+msgstr "无法运行 'describe'"
+
 #: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing %s)"
@@ -23175,6 +23276,10 @@ msgstr "key"
 msgid "field name to sort on"
 msgstr "排序的字段名"
 
+#: ref-filter.h
+msgid "exclude refs which match pattern"
+msgstr "排除与 <模式> 相匹配的引用"
+
 #: reflog.c
 #, c-format
 msgid "not a reflog: %s"
@@ -23704,8 +23809,9 @@ msgstr[1] ""
 
 #  译者:注意保持前导空格
 #: remote.c
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (使用 \"git pull\" 来合并远程分支)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr "  (如果您想将远程分支与您的更改合并,请使用 \"git pull\")\n"
 
 #: remote.c
 #, c-format
@@ -23845,6 +23951,11 @@ msgstr "无法获得 ancestry-path 参数 %s 的提交"
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "不再支持 --unpacked=<packfile>"
 
+#: revision.c
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "在 --stdin 模式下的无效选项:'%s'"
+
 #: revision.c
 msgid "your current branch appears to be broken"
 msgstr "您的当前分支好像被损坏"
@@ -25233,6 +25344,95 @@ msgstr "fork 失败"
 msgid "setsid failed"
 msgstr "setsid 失败"
 
+#: setup.c
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "不能对模版 '%s' 调用 stat"
+
+#: setup.c
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "不能打开目录 '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "不能读取链接 '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "不能自 '%s' 到 '%s' 创建符号链接"
+
+#: setup.c
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "不能拷贝 '%s' 至 '%s'"
+
+#: setup.c
+#, c-format
+msgid "ignoring template %s"
+msgstr "忽略模版 %s"
+
+#: setup.c
+#, c-format
+msgid "templates not found in %s"
+msgstr "没有在 %s 中找到模版"
+
+#: setup.c
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "没有从 '%s' 复制模版:%s"
+
+#: setup.c
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "无效的初始分支名:'%s'"
+
+#: setup.c
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "不能处理 %d 类型的文件"
+
+#: setup.c
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "不能移动 %s 至 %s"
+
+#: setup.c
+msgid "attempt to reinitialize repository with different hash"
+msgstr "尝试用不同的哈希算法重新初始化仓库"
+
+#: setup.c
+#, c-format
+msgid "%s already exists"
+msgstr "%s 已经存在"
+
+#: setup.c
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init:已忽略 --initial-branch=%s"
+
+#: setup.c
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "重新初始化已存在的共享 Git 仓库于 %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "已重新初始化已存在的 Git 仓库于 %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "已初始化空的共享 Git 仓库于 %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "已初始化空的 Git 仓库于 %s%s\n"
+
 #: sparse-index.c
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
index 1c549b868fa3c4c54073e8400457e3a06433ceb0..6ae75e7e19f7db0fd7e2bec03619f616efb2734b 100644 (file)
 #
 # Yi-Jyun Pan <pan93412@gmail.com>, 2021, 2022, 2023.
 # Kaiyang Wu <self@origincode.me>, 2022.
+# lumynou5 <lumynou5.tw@gmail.com>, 2023.
 msgid ""
 msgstr ""
 "Project-Id-Version: Git\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2023-05-19 19:57+0000\n"
-"PO-Revision-Date: 2023-05-31 23:41+0800\n"
+"POT-Creation-Date: 2023-08-20 21:51+0800\n"
+"PO-Revision-Date: 2023-08-20 21:58+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"
@@ -35,7 +36,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.3.1\n"
+"X-Generator: Poedit 3.3.2\n"
 "X-ZhConverter: 繁化姬 dict-f4bc617e-r910 @ 2019/11/16 20:23:12 | https://"
 "zhconvert.org\n"
 
@@ -126,7 +127,7 @@ msgstr "忽略未合併項目:%s"
 #: add-interactive.c add-patch.c
 #, c-format
 msgid "Only binary files changed.\n"
-msgstr "只變更二進位檔案。\n"
+msgstr "只有二進位檔案更動了。\n"
 
 #: add-interactive.c add-patch.c
 #, c-format
@@ -770,9 +771,8 @@ msgid "Reverting is not possible because you have unmerged files."
 msgstr "無法還原提交,有未合併的檔案。"
 
 #: advice.c
-#, c-format
-msgid "It is not possible to %s because you have unmerged files."
-msgstr "無法 %s,有未合併的檔案。"
+msgid "Rebasing is not possible because you have unmerged files."
+msgstr "無法重定基底,有未合併的檔案。"
 
 #: advice.c
 msgid ""
@@ -941,6 +941,14 @@ msgstr "無法同時使用 “%s” 和 “%s” 選項"
 msgid "'%s' outside a repository"
 msgstr "“%s” 在版本庫之外"
 
+#: apply.c
+msgid "failed to read patch"
+msgstr "無法讀取修補檔"
+
+#: apply.c
+msgid "patch too large"
+msgstr "修補檔過大"
+
 #: apply.c
 #, c-format
 msgid "Cannot prepare timestamp regexp %s"
@@ -1585,7 +1593,7 @@ msgstr "無法讀取 “%s”"
 #: archive.c
 #, c-format
 msgid "pathspec '%s' matches files outside the current directory"
-msgstr "符合路徑規格「%s」的檔案在目前目錄之外"
+msgstr "符合路徑規格 “%s” 的檔案在目前目錄之外"
 
 #: archive.c builtin/add.c builtin/rm.c
 #, c-format
@@ -2030,8 +2038,8 @@ msgstr "已有同名 “%s” 分支"
 
 #: branch.c
 #, c-format
-msgid "cannot force update the branch '%s' checked out at '%s'"
-msgstr "無法強制更新在 “%2$s” 簽出的 “%1$s” 分支"
+msgid "cannot force update the branch '%s' used by worktree at '%s'"
+msgstr "無法強制更新被位於 “%2$s” 的工作區使用的 “%1$s” 分支"
 
 #: branch.c
 #, c-format
@@ -2110,20 +2118,6 @@ msgstr "git add [<options>] [--] <pathspec>..."
 msgid "cannot chmod %cx '%s'"
 msgstr "無法 chmod %cx '%s'"
 
-#: builtin/add.c
-#, c-format
-msgid "unexpected diff status %c"
-msgstr "非預期的 diff 狀態 %c"
-
-#: builtin/add.c builtin/commit.c
-msgid "updating files failed"
-msgstr "更新檔案失敗"
-
-#: builtin/add.c
-#, c-format
-msgid "remove '%s'\n"
-msgstr "移除 “%s”\n"
-
 #: builtin/add.c
 msgid "Unstaged changes after refreshing the index:"
 msgstr "重新整理索引之後,尚未被暫存的更動:"
@@ -2656,10 +2650,6 @@ msgstr "向 git-mailinfo 傳入 -m 參數"
 msgid "pass --keep-cr flag to git-mailsplit for mbox format"
 msgstr "若為 mbox 格式,向 git-mailsplit 傳入 --keep-cr 標記"
 
-#: builtin/am.c
-msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
-msgstr "不向 git-mailsplit 傳入 --keep-cr 標記,無視 am.keepcr 的設定"
-
 #: builtin/am.c
 msgid "strip everything before a scissors line"
 msgstr "截掉裁切線前的所有內容"
@@ -3085,7 +3075,7 @@ msgstr "好的修訂版回傳偽造的錯誤碼 %d"
 #: builtin/bisect.c
 #, c-format
 msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
-msgstr "二分搜尋執行失敗:%2$s 回傳的離開碼 %1$d 小於 0 或大於 128"
+msgstr "二分搜尋執行失敗:%2$s 回傳的結束代碼 %1$d 小於 0 或大於 128"
 
 #: builtin/bisect.c
 #, c-format
@@ -3964,12 +3954,12 @@ msgid ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 msgstr ""
 "git cat-file (--batch | --batch-check | --batch-command) [--batch-all-"
 "objects]\n"
 "             [--buffer] [--follow-symlinks] [--unordered]\n"
-"             [--textconv | --filters] [-z]"
+"             [--textconv | --filters] [-Z]"
 
 #: builtin/cat-file.c
 msgid ""
@@ -4027,6 +4017,10 @@ msgstr "類似 --batch 但不輸出 <contents>"
 msgid "stdin is NUL-terminated"
 msgstr "stdin 以 NUL 字元終止"
 
+#: builtin/cat-file.c
+msgid "stdin and stdout is NUL-terminated"
+msgstr "stdin 和 stdout 以 NUL 字元終止"
+
 #: builtin/cat-file.c
 msgid "read commands from stdin"
 msgstr "從 stdin 讀取命令"
@@ -4914,7 +4908,8 @@ msgid "remove whole directories"
 msgstr "移除整個目錄"
 
 #: builtin/clean.c builtin/describe.c builtin/grep.c builtin/log.c
-#: builtin/ls-files.c builtin/name-rev.c builtin/show-ref.c
+#: builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c builtin/show-ref.c
+#: ref-filter.h
 msgid "pattern"
 msgstr "pattern"
 
@@ -5084,14 +5079,6 @@ msgstr "server-specific"
 msgid "option to transmit"
 msgstr "傳輸選項"
 
-#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/push.c
-msgid "use IPv4 addresses only"
-msgstr "只使用 IPv4 位址"
-
-#: builtin/clone.c builtin/fetch.c builtin/pull.c builtin/push.c
-msgid "use IPv6 addresses only"
-msgstr "只使用 IPv6 位址"
-
 #: builtin/clone.c
 msgid "apply partial clone filters to submodules"
 msgstr "將部分複製過濾器套用至子模組"
@@ -5626,6 +5613,10 @@ msgstr ""
 "    git cherry-pick --skip\n"
 "\n"
 
+#: builtin/commit.c read-cache.c
+msgid "updating files failed"
+msgstr "更新檔案失敗"
+
 #: builtin/commit.c
 msgid "failed to unpack HEAD tree object"
 msgstr "解包 HEAD 樹狀物件失敗"
@@ -5701,8 +5692,8 @@ msgstr "無法選擇一個未被目前提交說明使用的備註字元"
 
 #: builtin/commit.c builtin/merge-tree.c
 #, c-format
-msgid "could not lookup commit %s"
-msgstr "不能查詢提交 %s"
+msgid "could not lookup commit '%s'"
+msgstr "無法查詢提交 “%s”"
 
 #: builtin/commit.c builtin/shortlog.c
 #, c-format
@@ -7936,7 +7927,7 @@ msgstr "對 %s 呼叫 fstat 失敗:%s"
 msgid "failed to parse '%s' value '%s'"
 msgstr "無法解析 '%s' 值 '%s'"
 
-#: builtin/gc.c builtin/init-db.c
+#: builtin/gc.c setup.c
 #, c-format
 msgid "cannot stat '%s'"
 msgstr "不能對 '%s' 呼叫 stat"
@@ -8940,7 +8931,7 @@ msgstr "無法返回目前工作目錄"
 msgid "bad %s"
 msgstr "錯誤選項 %s"
 
-#: builtin/index-pack.c builtin/init-db.c
+#: builtin/index-pack.c builtin/init-db.c setup.c
 #, c-format
 msgid "unknown hash algorithm '%s'"
 msgstr "未知的「%s」雜湊算法"
@@ -8957,95 +8948,6 @@ msgstr "--verify 沒有提供 packfile 名稱參數"
 msgid "fsck error in pack objects"
 msgstr "在打包物件中 fsck 檢查發生錯誤"
 
-#: builtin/init-db.c
-#, c-format
-msgid "cannot stat template '%s'"
-msgstr "不能對範本 '%s' 呼叫 stat"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot opendir '%s'"
-msgstr "不能開啟目錄 '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot readlink '%s'"
-msgstr "不能讀取連結 '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot symlink '%s' '%s'"
-msgstr "不能自 '%s' 到 '%s' 建立符號連結"
-
-#: builtin/init-db.c
-#, c-format
-msgid "cannot copy '%s' to '%s'"
-msgstr "不能複製 '%s' 至 '%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "ignoring template %s"
-msgstr "忽略範本 %s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "templates not found in %s"
-msgstr "沒有在 %s 中找到範本"
-
-#: builtin/init-db.c
-#, c-format
-msgid "not copying templates from '%s': %s"
-msgstr "沒有從 '%s' 複製範本:%s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "invalid initial branch name: '%s'"
-msgstr "無效的初始分支名稱:'%s'"
-
-#: builtin/init-db.c
-#, c-format
-msgid "unable to handle file type %d"
-msgstr "不能處理 %d 類型的檔案"
-
-#: builtin/init-db.c
-#, c-format
-msgid "unable to move %s to %s"
-msgstr "不能移動 %s 至 %s"
-
-#: builtin/init-db.c
-msgid "attempt to reinitialize repository with different hash"
-msgstr "嘗試以不同的雜湊值重新初始化版本庫"
-
-#: builtin/init-db.c
-#, c-format
-msgid "%s already exists"
-msgstr "%s 已經存在"
-
-#: builtin/init-db.c
-#, c-format
-msgid "re-init: ignored --initial-branch=%s"
-msgstr "re-init: 忽略 --initial-branch=%s"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "重新初始化已存在的共享 Git 版本庫於 %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "重新初始化已存在的 Git 版本庫於 %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "已初始化空的共享 Git 版本庫於 %s%s\n"
-
-#: builtin/init-db.c
-#, c-format
-msgid "Initialized empty Git repository in %s%s\n"
-msgstr "已初始化空的 Git 版本庫於 %s%s\n"
-
 #: builtin/init-db.c
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
@@ -9593,6 +9495,11 @@ msgid ""
 "Could not find a tracked remote branch, please specify <upstream> manually.\n"
 msgstr "不能找到追蹤的遠端分支,請手動指定 <上游>。\n"
 
+#: builtin/ls-files.c builtin/ls-tree.c
+#, c-format
+msgid "could not get object info about '%s'"
+msgstr "無法取得「%s」相關的物件資訊"
+
 #: builtin/ls-files.c
 #, c-format
 msgid "bad ls-files format: element '%s' does not start with '('"
@@ -9777,11 +9684,6 @@ msgstr "除了顯示指向的物件外,顯示指向的引用名"
 msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
 msgstr "git ls-tree [<選項>] <樹或提交> [<路徑>...]"
 
-#: builtin/ls-tree.c
-#, c-format
-msgid "could not get object info about '%s'"
-msgstr "無法取得「%s」相關的物件資訊"
-
 #: builtin/ls-tree.c
 #, c-format
 msgid "bad ls-tree format: element '%s' does not start with '('"
@@ -10707,11 +10609,13 @@ msgstr "git notes [--ref <註解引用>] [list [<物件>]]"
 
 #: builtin/notes.c
 msgid ""
-"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> "
-"| (-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <註解引用>] add [-f] [--allow-empty] [-m <說明> | -F <檔案> "
-"| (-c | -C) <物件>] [<物件>]"
+"git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 
 #: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"
@@ -10719,11 +10623,13 @@ msgstr "git notes [--ref <註解引用>] copy [-f] <來源物件> <目標物件>
 
 #: builtin/notes.c
 msgid ""
-"git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | "
-"(-c | -C) <object>] [<object>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 msgstr ""
-"git notes [--ref <註解引用>] append [--allow-empty] [-m <說明> | -F <檔案> | "
-"(-c | -C) <物件>] [<物件>]"
+"git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--"
+"separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c "
+"| -C) <object>] [<object>]"
 
 #: builtin/notes.c
 msgid "git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"
@@ -10891,6 +10797,18 @@ msgstr "允許儲存空白備註"
 msgid "replace existing notes"
 msgstr "取代已存在的註解"
 
+#: builtin/notes.c
+msgid "<paragraph-break>"
+msgstr "<paragraph-break>"
+
+#: builtin/notes.c
+msgid "insert <paragraph-break> between paragraphs"
+msgstr "在段落間插入 <paragraph-break>"
+
+#: builtin/notes.c
+msgid "remove unnecessary whitespace"
+msgstr "移除不必要的空白字元"
+
 #: builtin/notes.c
 #, c-format
 msgid ""
@@ -11570,8 +11488,12 @@ msgid "refusing to run without --i-still-use-this"
 msgstr "傳入 --i-still-use-this 前拒絕執行"
 
 #: builtin/pack-refs.c
-msgid "git pack-refs [--all] [--no-prune]"
-msgstr "git pack-refs [--all] [--no-prune]"
+msgid ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
+msgstr ""
+"git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude "
+"<pattern>]"
 
 #: builtin/pack-refs.c
 msgid "pack everything"
@@ -11581,6 +11503,14 @@ msgstr "打包一切"
 msgid "prune loose refs (default)"
 msgstr "剪除鬆散引用(預設值)"
 
+#: builtin/pack-refs.c
+msgid "references to include"
+msgstr "要包含的引用"
+
+#: builtin/pack-refs.c
+msgid "references to exclude"
+msgstr "要排除的引用"
+
 #: builtin/patch-id.c
 msgid "git patch-id [--stable | --unstable | --verbatim]"
 msgstr "git patch-id [--stable | --unstable | --verbatim]"
@@ -11657,6 +11587,14 @@ msgstr "強制覆蓋本機分支"
 msgid "number of submodules pulled in parallel"
 msgstr "並行拉取的子模組數量"
 
+#: builtin/pull.c parse-options.h
+msgid "use IPv4 addresses only"
+msgstr "只使用 IPv4 位址"
+
+#: builtin/pull.c parse-options.h
+msgid "use IPv6 addresses only"
+msgstr "只使用 IPv6 位址"
+
 #: builtin/pull.c
 msgid ""
 "There is no candidate for rebasing against among the refs that you just "
@@ -11941,37 +11879,37 @@ msgstr ""
 #: builtin/push.c
 msgid ""
 "Updates were rejected because the tip of your current branch is behind\n"
-"its remote counterpart. Integrate the remote changes (e.g.\n"
-"'git pull ...') before pushing again.\n"
+"its remote counterpart. If you want to integrate the remote changes,\n"
+"use 'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "更新被拒絕,因為您目前分支的最新提交落後於其對應的遠端分支。\n"
-"å\86\8d次æ\8e¨é\80\81å\89\8dï¼\8cå\85\88è\88\87é\81 ç«¯è®\8aæ\9b´å\90\88ä½µï¼\88å¦\82 'git pull ...'ï¼\89。詳見\n"
-"'git push --help' 中的 'Note about fast-forwards' 小節。"
+"å¦\82æ\9e\9cæ\82¨æ\83³è¦\81æ\95´å\90\88é\81 ç«¯æ\9b´å\8b\95ï¼\8cè«\8bå\9c¨å\86\8d次æ\8e¨é\80\81å\89\8d使ç\94¨ â\80\9cgit pullâ\80\9d。詳見\n"
+"“git push --help” 中的〈Note about fast-forwards〉小節。"
 
 #: builtin/push.c
 msgid ""
 "Updates were rejected because a pushed branch tip is behind its remote\n"
-"counterpart. Check out this branch and integrate the remote changes\n"
-"(e.g. 'git pull ...') before pushing again.\n"
+"counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+"before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"更新被拒絕,因為推送的一個分支的最新提交落後於其對應的遠端分支。\n"
-"簽出該分支並整合遠端變更(如 'git pull ...'),然後再推送。詳見\n"
-"'git push --help' 中的 'Note about fast-forwards' 小節。"
+"更新被拒絕,因為推送的分支的最新提交落後於其對應的遠端分支。\n"
+"如果您想要整合遠端更動,請在再次推送前使用 “git pull”。詳見\n"
+"“git push --help” 中的〈Note about fast-forwards〉小節。"
 
 #: builtin/push.c
 msgid ""
-"Updates were rejected because the remote contains work that you do\n"
-"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first integrate the remote changes\n"
-"(e.g., 'git pull ...') before pushing again.\n"
+"Updates were rejected because the remote contains work that you do not\n"
+"have locally. This is usually caused by another repository pushing to\n"
+"the same ref. If you want to integrate the remote changes, use\n"
+"'git pull' before pushing again.\n"
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"因為遠端版本庫包含您本機尚不存在的提交,而導致更新被拒絕。這通常是因為另外\n"
-"一個版本庫已向該引用進行了推送。再次推送前,您可能需要先整合遠端變更\n"
-"(如 'git pull ...')。\n"
-"詳見 'git push --help' 中的 'Note about fast-forwards' 小節。"
+"更新被拒絕,因為遠端包含您本機沒有的提交。這通常是因為\n"
+"另一個版本庫有推送更動到同個引用。如果您想要整合遠端更動,\n"
+"請在再次推送前使用 “git pull”。詳見 “git push --help” 中的\n"
+"〈Note about fast-forwards〉小節。"
 
 #: builtin/push.c
 msgid "Updates were rejected because the tag already exists in the remote."
@@ -11988,14 +11926,14 @@ msgstr ""
 
 #: builtin/push.c
 msgid ""
-"Updates were rejected because the tip of the remote-tracking\n"
-"branch has been updated since the last checkout. You may want\n"
-"to integrate those changes locally (e.g., 'git pull ...')\n"
-"before forcing an update.\n"
+"Updates were rejected because the tip of the remote-tracking branch has\n"
+"been updated since the last checkout. If you want to integrate the\n"
+"remote changes, use 'git pull' before pushing again.\n"
+"See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
-"更新被拒,因為遠端追蹤分支的最新指針繼上次簽出後有更新。\n"
-"您可能會希望先將這些變更整合至本地(例如:‘git pull …’)\n"
-"最後才強制更新。\n"
+"更新被拒絕,因為遠端追蹤分支的最新提交自上次簽出後有改變。\n"
+"如果您想要整合遠端更動,請在再次推送前使用 “git pull”。\n"
+"詳見 “git push --help” 中的〈Note about fast-forwards〉小節。"
 
 #: builtin/push.c
 #, c-format
@@ -13024,12 +12962,12 @@ msgid "fetch the remote branches"
 msgstr "抓取遠端的分支"
 
 #: builtin/remote.c
-msgid "import all tags and associated objects when fetching"
-msgstr "抓取時匯入所有的標籤和關聯物件"
-
-#: builtin/remote.c
-msgid "or do not fetch any tag at all (--no-tags)"
-msgstr "或不抓取任何標籤(--no-tags)"
+msgid ""
+"import all tags and associated objects when fetching\n"
+"or do not fetch any tag at all (--no-tags)"
+msgstr ""
+"抓取時匯入所有的標籤和關聯物件\n"
+"或者是完全不抓取所有標籤 (--no-tags)"
 
 #: builtin/remote.c
 msgid "branch(es) to track"
@@ -15410,6 +15348,11 @@ msgstr "略過未合併的子模組 %s"
 msgid "Skipping submodule '%s'"
 msgstr "略過子模組 '%s'"
 
+#: builtin/submodule--helper.c
+#, c-format
+msgid "cannot clone submodule '%s' without a URL"
+msgstr "無法在沒有網址的情況下複製 “%s” 子模組"
+
 #: builtin/submodule--helper.c
 #, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
@@ -16320,10 +16263,10 @@ msgstr "列印標籤內容"
 #: builtin/worktree.c
 msgid ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 msgstr ""
 "git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n"
-"                 [-b <new-branch>] <path> [<commit-ish>]"
+"                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]"
 
 #: builtin/worktree.c
 msgid "git worktree list [-v | --porcelain [-z]]"
@@ -16353,6 +16296,40 @@ msgstr "git worktree repair [<路徑>...]"
 msgid "git worktree unlock <worktree>"
 msgstr "git worktree unlock <worktree>"
 
+#: builtin/worktree.c
+msgid "No possible source branch, inferring '--orphan'"
+msgstr "沒有可能的來源分支,推測為 “--orphan”"
+
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+msgstr ""
+"如果您是想要在這個版本庫建立一個工作區,裡面包含一個\n"
+"孤立分支(即沒有提交的分支),可以使用 --orphan 達到\n"
+"這個效果:\n"
+"\n"
+"    git worktree add --orphan -b %s %s\n"
+
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"If you meant to create a worktree containing a new orphan branch\n"
+"(branch with no commits) for this repository, you can do so\n"
+"using the --orphan flag:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+msgstr ""
+"如果您是想要在這個版本庫建立一個工作區,裡面包含一個\n"
+"孤立分支(即沒有提交的分支),可以使用 --orphan 達到\n"
+"這個效果:\n"
+"\n"
+"    git worktree add --orphan %s\n"
+
 #: builtin/worktree.c
 #, c-format
 msgid "Removing %s/%s: %s"
@@ -16433,11 +16410,40 @@ msgstr "準備工作區(重設分支 '%s',之前為 %s)"
 msgid "Preparing worktree (checking out '%s')"
 msgstr "準備工作區(簽出 '%s')"
 
+#: builtin/worktree.c
+#, c-format
+msgid "unreachable: invalid reference: %s"
+msgstr "不可達:無效引用:%s"
+
 #: builtin/worktree.c
 #, c-format
 msgid "Preparing worktree (detached HEAD %s)"
 msgstr "準備工作區(分離開頭指標 %s)"
 
+#: builtin/worktree.c
+#, c-format
+msgid ""
+"HEAD points to an invalid (or orphaned) reference.\n"
+"HEAD path: '%s'\n"
+"HEAD contents: '%s'"
+msgstr ""
+"HEAD 指向無效(或孤立)引用。\n"
+"HEAD 路徑:“%s”\n"
+"HEAD 內容:“%s”"
+
+#: builtin/worktree.c
+msgid ""
+"No local or remote refs exist despite at least one remote\n"
+"present, stopping; use 'add -f' to overide or fetch a remote first"
+msgstr ""
+"即使有提供一個遠端,卻不存在本機或遠端引用,\n"
+"故停止。使用 “add -f” 先覆蓋或抓取遠端"
+
+#: builtin/worktree.c
+#, c-format
+msgid "'%s' and '%s' cannot be used together"
+msgstr "無法同時使用 “%s” 和 “%s”"
+
 #: builtin/worktree.c
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr "簽出 <分支>,即使已經被簽出到其它工作區"
@@ -16450,6 +16456,10 @@ msgstr "建立一個新分支"
 msgid "create or reset a branch"
 msgstr "建立或重設一個分支"
 
+#: builtin/worktree.c
+msgid "create unborn/orphaned branch"
+msgstr "建立尚無內容(孤立)的分支"
+
 #: builtin/worktree.c
 msgid "populate the new working tree"
 msgstr "生成新的工作區"
@@ -16475,6 +16485,15 @@ msgstr "嘗試為新分支名符合一個遠端追蹤分支"
 msgid "options '%s', '%s', and '%s' cannot be used together"
 msgstr "「%s」、「%s」和「%s」選項不得同時使用"
 
+#: builtin/worktree.c
+#, c-format
+msgid "options '%s', and '%s' cannot be used together"
+msgstr "無法同時使用 “%s” 和 “%s” 選項"
+
+#: builtin/worktree.c
+msgid "<commit-ish>"
+msgstr "<提交指示元>"
+
 #: builtin/worktree.c
 msgid "added with --lock"
 msgstr "已使用 --lock 加入"
@@ -16753,6 +16772,16 @@ msgid "The bundle requires this ref:"
 msgid_plural "The bundle requires these %<PRIuMAX> refs:"
 msgstr[0] "這個套件包需要這 %<PRIuMAX> 個引用:"
 
+#: bundle.c
+#, c-format
+msgid "The bundle uses this hash algorithm: %s"
+msgstr "本套件包採用此雜湊演算法:%s"
+
+#: bundle.c
+#, c-format
+msgid "The bundle uses this filter: %s"
+msgstr "本套件包使用此過濾器:%s"
+
 #: bundle.c
 msgid "unable to dup bundle descriptor"
 msgstr "無法複製套件包描述元"
@@ -17050,8 +17079,8 @@ msgid "A portable graphical interface to Git"
 msgstr "一個便攜的 Git 圖形用戶端"
 
 #: command-list.h
-msgid "Compute object ID and optionally creates a blob from a file"
-msgstr "å¾\9eä¸\80å\80\8bæª\94æ¡\88è¨\88ç®\97ç\89©ä»¶ IDï¼\8c並å\8f¯ä»¥å»ºç«\8b blob è³\87æ\96\99物件"
+msgid "Compute object ID and optionally create an object from a file"
+msgstr "å¾\9eä¸\80å\80\8bæª\94æ¡\88è¨\88ç®\97ç\89©ä»¶ IDï¼\8cä¹\9fè\83½é \86帶建ç«\8bä¸\80å\80\8b物件"
 
 #: command-list.h
 msgid "Display help information about Git"
@@ -17591,6 +17620,11 @@ msgstr "提交圖形沒有基礎圖形區塊"
 msgid "commit-graph chain does not match"
 msgstr "提交圖形鏈不符合"
 
+#: commit-graph.c
+#, c-format
+msgid "commit count in base graph too high: %<PRIuMAX>"
+msgstr "基礎圖 (base graph) 中的提交數過多:%<PRIuMAX>"
+
 #: commit-graph.c
 #, c-format
 msgid "invalid commit-graph chain: line '%s' not a hash"
@@ -17696,6 +17730,16 @@ msgstr "無法重新命名基礎提交圖形檔案"
 msgid "failed to rename temporary commit-graph file"
 msgstr "無法重新命名暫時提交圖形檔案"
 
+#: commit-graph.c
+#, c-format
+msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits"
+msgstr "無法將圖與 %<PRIuMAX>, %<PRIuMAX> 個提交進行合併"
+
+#: commit-graph.c
+#, c-format
+msgid "cannot merge graph %s, too many commits: %<PRIuMAX>"
+msgstr "無法合併 %s 圖,太多提交:%<PRIuMAX>"
+
 #: commit-graph.c
 msgid "Scanning merged commits"
 msgstr "正在掃描合併提交"
@@ -17731,10 +17775,6 @@ msgstr "提交圖形有不正確的扇出值:fanout[%d] = %u != %u"
 msgid "failed to parse commit %s from commit-graph"
 msgstr "無法從提交圖形中解析提交 %s"
 
-#: commit-graph.c
-msgid "Verifying commits in commit graph"
-msgstr "正在驗證提交圖中的提交"
-
 #: commit-graph.c
 #, c-format
 msgid "failed to parse commit %s from object database for commit-graph"
@@ -17782,6 +17822,10 @@ msgstr "提交 %s 的提交圖形處於 %<PRIuMAX> < %<PRIuMAX> 世代"
 msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
 msgstr "提交圖形中提交 %s 的提交日期是 %<PRIuMAX> != %<PRIuMAX>"
 
+#: commit-graph.c
+msgid "Verifying commits in commit graph"
+msgstr "正在驗證提交圖中的提交"
+
 #: commit.c
 #, c-format
 msgid "%s %s is not a commit!"
@@ -18928,6 +18972,14 @@ msgstr "找不到合併基底"
 msgid "multiple merge bases found"
 msgstr "找到多個合併基底"
 
+#: diff-no-index.c
+msgid "cannot compare stdin to a directory"
+msgstr "無法比對 stdin 和目錄"
+
+#: diff-no-index.c
+msgid "cannot compare a named pipe to a directory"
+msgstr "無法比對命名管線 (pipe) 和目錄"
+
 #: diff-no-index.c
 msgid "git diff --no-index [<options>] <path> <path>"
 msgstr "git diff --no-index [<選項>] <路徑> <路徑>"
@@ -18992,6 +19044,15 @@ msgstr ""
 msgid "external diff died, stopping at %s"
 msgstr "外部 diff 離開,停止在 %s"
 
+#: diff.c
+msgid "--follow requires exactly one pathspec"
+msgstr "--follow 明確要求只跟一個路徑規格"
+
+#: diff.c
+#, c-format
+msgid "pathspec magic not supported by --follow: %s"
+msgstr "--follow 不支援路徑規格魔法:%s"
+
 #: diff.c parse-options.c
 #, c-format
 msgid "options '%s', '%s', '%s', and '%s' cannot be used together"
@@ -19008,10 +19069,6 @@ msgid ""
 "options '%s' and '%s' cannot be used together, use '%s' with '%s' and '%s'"
 msgstr "「%s」和「%s」選項不得同時使用,請使用「%s」搭配「%s」、「%s」"
 
-#: diff.c
-msgid "--follow requires exactly one pathspec"
-msgstr "--follow 明確要求只跟一個路徑規格"
-
 #: diff.c
 #, c-format
 msgid "invalid --stat value: %s"
@@ -22470,6 +22527,15 @@ msgstr "生成 diff 失敗"
 msgid "could not parse log for '%s'"
 msgstr "不能解析 '%s' 的日誌"
 
+#: reachable.c
+#, c-format
+msgid "invalid extra cruft tip: '%s'"
+msgstr "無效的額外廢棄提交修訂版:“%s”"
+
+#: reachable.c
+msgid "unable to enumerate additional recent objects"
+msgstr "無法列舉多出來的近期物件"
+
 #: read-cache.c
 #, c-format
 msgid "will not add file alias '%s' ('%s' already exists in index)"
@@ -22658,6 +22724,16 @@ msgstr "不能修復 '%s' 的權限位"
 msgid "%s: cannot drop to stage #0"
 msgstr "%s:不能落到暫存區 #0"
 
+#: read-cache.c
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "非預期的 diff 狀態 %c"
+
+#: read-cache.c
+#, c-format
+msgid "remove '%s'\n"
+msgstr "移除 “%s”\n"
+
 #: rebase-interactive.c
 msgid ""
 "You can fix this with 'git rebase --edit-todo' and then run 'git rebase --"
@@ -22869,6 +22945,26 @@ msgstr "未知的 %%(trailers) 參數:%s"
 msgid "positive value expected contents:lines=%s"
 msgstr "期望一個正數 contents:lines=%s"
 
+#: ref-filter.c
+#, c-format
+msgid "argument expected for %s"
+msgstr "引數預期 %s"
+
+#: ref-filter.c
+#, c-format
+msgid "positive value expected %s=%s"
+msgstr "期望一個正數 %s=%s"
+
+#: ref-filter.c
+#, c-format
+msgid "cannot fully parse %s=%s"
+msgstr "無法完全解析 %s=%s"
+
+#: ref-filter.c
+#, c-format
+msgid "value expected %s="
+msgstr "數值預期 %s="
+
 #: ref-filter.c
 #, c-format
 msgid "positive value expected '%s' in %%(%s)"
@@ -22960,6 +23056,10 @@ msgstr "本命令拒絕 atom %%(%.*s)"
 msgid "--format=%.*s cannot be used with --python, --shell, --tcl"
 msgstr "--format=%.*s 不能和 --python、--shell、--tcl 一起使用"
 
+#: ref-filter.c
+msgid "failed to run 'describe'"
+msgstr "無法執行 “describe”"
+
 #: ref-filter.c
 #, c-format
 msgid "(no branch, rebasing %s)"
@@ -23037,6 +23137,10 @@ msgstr "key"
 msgid "field name to sort on"
 msgstr "排序的欄位名"
 
+#: ref-filter.h
+msgid "exclude refs which match pattern"
+msgstr "排除符合模式的引用"
+
 #: reflog.c
 #, c-format
 msgid "not a reflog: %s"
@@ -23566,8 +23670,9 @@ msgstr[0] ""
 
 #  譯者:請維持前導空格
 #: remote.c
-msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr "  (使用 \"git pull\" 來合併遠端分支)\n"
+msgid ""
+"  (use \"git pull\" if you want to integrate the remote branch with yours)\n"
+msgstr "  (使用 “git pull” 來將遠端分支整合進您的分支)\n"
 
 #: remote.c
 #, c-format
@@ -23707,6 +23812,11 @@ msgstr "無法取得 ancestry-path 引數 %s 的提交"
 msgid "--unpacked=<packfile> no longer supported"
 msgstr "--unpacked=<packfile> 已不受支援"
 
+#: revision.c
+#, c-format
+msgid "invalid option '%s' in --stdin mode"
+msgstr "在 --stdin 模式下,“%s” 選項無效"
+
 #: revision.c
 msgid "your current branch appears to be broken"
 msgstr "您的目前分支好像被損壞"
@@ -25098,6 +25208,95 @@ msgstr "fork 失敗"
 msgid "setsid failed"
 msgstr "setsid 失敗"
 
+#: setup.c
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "不能對範本 '%s' 呼叫 stat"
+
+#: setup.c
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "不能開啟目錄 '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "不能讀取連結 '%s'"
+
+#: setup.c
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "不能自 '%s' 到 '%s' 建立符號連結"
+
+#: setup.c
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "不能複製 '%s' 至 '%s'"
+
+#: setup.c
+#, c-format
+msgid "ignoring template %s"
+msgstr "忽略範本 %s"
+
+#: setup.c
+#, c-format
+msgid "templates not found in %s"
+msgstr "沒有在 %s 中找到範本"
+
+#: setup.c
+#, c-format
+msgid "not copying templates from '%s': %s"
+msgstr "沒有從 '%s' 複製範本:%s"
+
+#: setup.c
+#, c-format
+msgid "invalid initial branch name: '%s'"
+msgstr "無效的初始分支名稱:'%s'"
+
+#: setup.c
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "不能處理 %d 類型的檔案"
+
+#: setup.c
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "不能移動 %s 至 %s"
+
+#: setup.c
+msgid "attempt to reinitialize repository with different hash"
+msgstr "嘗試以不同的雜湊值重新初始化版本庫"
+
+#: setup.c
+#, c-format
+msgid "%s already exists"
+msgstr "%s 已經存在"
+
+#: setup.c
+#, c-format
+msgid "re-init: ignored --initial-branch=%s"
+msgstr "re-init: 忽略 --initial-branch=%s"
+
+#: setup.c
+#, c-format
+msgid "Reinitialized existing shared Git repository in %s%s\n"
+msgstr "重新初始化已存在的共享 Git 版本庫於 %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Reinitialized existing Git repository in %s%s\n"
+msgstr "重新初始化已存在的 Git 版本庫於 %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Initialized empty shared Git repository in %s%s\n"
+msgstr "已初始化空的共享 Git 版本庫於 %s%s\n"
+
+#: setup.c
+#, c-format
+msgid "Initialized empty Git repository in %s%s\n"
+msgstr "已初始化空的 Git 版本庫於 %s%s\n"
+
 #: sparse-index.c
 #, c-format
 msgid "index entry is a directory, but not sparse (%08x)"
@@ -27305,6 +27504,26 @@ msgstr "略過 %s 含備份後綴 '%s'。\n"
 msgid "Do you really want to send %s? [y|N]: "
 msgstr "您真的要傳送 %s?[y|N]: "
 
+#, c-format
+#~ msgid "It is not possible to %s because you have unmerged files."
+#~ msgstr "無法 %s,有未合併的檔案。"
+
+#~ msgid "do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"
+#~ msgstr "不向 git-mailsplit 傳入 --keep-cr 標記,無視 am.keepcr 的設定"
+
+#~ msgid ""
+#~ "Updates were rejected because the tip of the remote-tracking\n"
+#~ "branch has been updated since the last checkout. You may want\n"
+#~ "to integrate those changes locally (e.g., 'git pull ...')\n"
+#~ "before forcing an update.\n"
+#~ msgstr ""
+#~ "更新被拒,因為遠端追蹤分支的最新指針繼上次簽出後有更新。\n"
+#~ "您可能會希望先將這些變更整合至本地(例如:‘git pull …’)\n"
+#~ "最後才強制更新。\n"
+
+#~ msgid "or do not fetch any tag at all (--no-tags)"
+#~ msgstr "或不抓取任何標籤(--no-tags)"
+
 #~ msgid "current working directory is untracked"
 #~ msgstr "尚未追蹤目前的工作目錄"
 
index 7a26b08c2133d428c59ff46485c0211afe52a06d..63fd35d64b141f6f1488c40c4fb34b1fe1e53ae0 100644 (file)
@@ -1,14 +1,16 @@
 /*
  * Copyright (C) 2008 Linus Torvalds
  */
-#include "cache.h"
+#include "git-compat-util.h"
 #include "pathspec.h"
 #include "dir.h"
 #include "environment.h"
 #include "fsmonitor.h"
 #include "gettext.h"
-#include "config.h"
+#include "parse.h"
+#include "preload-index.h"
 #include "progress.h"
+#include "read-cache.h"
 #include "thread-utils.h"
 #include "repository.h"
 #include "symlinks.h"
diff --git a/preload-index.h b/preload-index.h
new file mode 100644 (file)
index 0000000..251b1ed
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef PRELOAD_INDEX_H
+#define PRELOAD_INDEX_H
+
+struct index_state;
+struct pathspec;
+struct repository;
+
+void preload_index(struct index_state *index,
+                  const struct pathspec *pathspec,
+                  unsigned int refresh_flags);
+int repo_read_index_preload(struct repository *,
+                           const struct pathspec *pathspec,
+                           unsigned refresh_flags);
+
+#endif /* PRELOAD_INDEX_H */
index 0bb938021ba593df826b91d39a2ec7a059e84b61..cf964b060cd128e2bc271c07ed8bb8b4c28bfe29 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1,9 +1,9 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "commit.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "utf8.h"
 #include "diff.h"
@@ -18,6 +18,7 @@
 #include "gpg-interface.h"
 #include "trailer.h"
 #include "run-command.h"
+#include "object-name.h"
 
 /*
  * The limit for formatting directives, which enable the caller to append
@@ -56,6 +57,7 @@ static void save_user_format(struct rev_info *rev, const char *cp, int is_tforma
 }
 
 static int git_pretty_formats_config(const char *var, const char *value,
+                                    const struct config_context *ctx UNUSED,
                                     void *cb UNUSED)
 {
        struct cmt_fmt_map *commit_format = NULL;
@@ -1250,6 +1252,27 @@ static int format_trailer_match_cb(const struct strbuf *key, void *ud)
        return 0;
 }
 
+static struct strbuf *expand_string_arg(struct strbuf *sb,
+                                       const char *argval, size_t arglen)
+{
+       char *fmt = xstrndup(argval, arglen);
+       const char *format = fmt;
+
+       strbuf_reset(sb);
+       while (strbuf_expand_step(sb, &format)) {
+               size_t len;
+
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(sb, '%');
+               else if ((len = strbuf_expand_literal(sb, format)))
+                       format += len;
+               else
+                       strbuf_addch(sb, '%');
+       }
+       free(fmt);
+       return sb;
+}
+
 int format_set_trailers_options(struct process_trailer_options *opts,
                                struct string_list *filter_list,
                                struct strbuf *sepbuf,
@@ -1278,21 +1301,9 @@ int format_set_trailers_options(struct process_trailer_options *opts,
                        opts->filter_data = filter_list;
                        opts->only_trailers = 1;
                } else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) {
-                       char *fmt;
-
-                       strbuf_reset(sepbuf);
-                       fmt = xstrndup(argval, arglen);
-                       strbuf_expand(sepbuf, fmt, strbuf_expand_literal_cb, NULL);
-                       free(fmt);
-                       opts->separator = sepbuf;
+                       opts->separator = expand_string_arg(sepbuf, argval, arglen);
                } else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
-                       char *fmt;
-
-                       strbuf_reset(kvsepbuf);
-                       fmt = xstrndup(argval, arglen);
-                       strbuf_expand(kvsepbuf, fmt, strbuf_expand_literal_cb, NULL);
-                       free(fmt);
-                       opts->key_value_separator = kvsepbuf;
+                       opts->key_value_separator = expand_string_arg(kvsepbuf, argval, arglen);
                } else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) &&
                           !match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) &&
                           !match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) &&
@@ -1373,6 +1384,44 @@ static size_t parse_describe_args(const char *start, struct strvec *args)
        return arg - start;
 }
 
+
+static int parse_decoration_option(const char **arg,
+                                  const char *name,
+                                  char **opt)
+{
+       const char *argval;
+       size_t arglen;
+
+       if (match_placeholder_arg_value(*arg, name, arg, &argval, &arglen)) {
+               struct strbuf sb = STRBUF_INIT;
+
+               expand_string_arg(&sb, argval, arglen);
+               *opt = strbuf_detach(&sb, NULL);
+               return 1;
+       }
+       return 0;
+}
+
+static void parse_decoration_options(const char **arg,
+                                    struct decoration_options *opts)
+{
+       while (parse_decoration_option(arg, "prefix", &opts->prefix) ||
+              parse_decoration_option(arg, "suffix", &opts->suffix) ||
+              parse_decoration_option(arg, "separator", &opts->separator) ||
+              parse_decoration_option(arg, "pointer", &opts->pointer) ||
+              parse_decoration_option(arg, "tag", &opts->tag))
+               ;
+}
+
+static void free_decoration_options(const struct decoration_options *opts)
+{
+       free(opts->prefix);
+       free(opts->suffix);
+       free(opts->separator);
+       free(opts->pointer);
+       free(opts->tag);
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                const char *placeholder,
                                void *context)
@@ -1386,7 +1435,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
        char **slot;
 
        /* these are independent of the commit */
-       res = strbuf_expand_literal_cb(sb, placeholder, NULL);
+       res = strbuf_expand_literal(sb, placeholder);
        if (res)
                return res;
 
@@ -1526,11 +1575,18 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                strbuf_addstr(sb, get_revision_mark(NULL, commit));
                return 1;
        case 'd':
-               format_decorations(sb, commit, c->auto_color);
+               format_decorations(sb, commit, c->auto_color, NULL);
                return 1;
        case 'D':
-               format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
-               return 1;
+               {
+                       const struct decoration_options opts = {
+                               .prefix = "",
+                               .suffix = ""
+                       };
+
+                       format_decorations(sb, commit, c->auto_color, &opts);
+                       return 1;
+               }
        case 'S':               /* tag/branch like --source */
                if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
                        return 0;
@@ -1627,6 +1683,23 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                return 2;
        }
 
+       if (skip_prefix(placeholder, "(decorate", &arg)) {
+               struct decoration_options opts = { NULL };
+               size_t ret = 0;
+
+               if (*arg == ':') {
+                       arg++;
+                       parse_decoration_options(&arg, &opts);
+               }
+               if (*arg == ')') {
+                       format_decorations(sb, commit, c->auto_color, &opts);
+                       ret = arg - placeholder + 1;
+               }
+
+               free_decoration_options(&opts);
+               return ret;
+       }
+
        /* For the rest we have to parse the commit header. */
        if (!c->commit_header_parsed) {
                msg = c->message =
@@ -1804,7 +1877,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
                                 const char *placeholder,
-                                void *context)
+                                struct format_commit_context *context)
 {
        size_t consumed, orig_len;
        enum {
@@ -1843,10 +1916,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
        }
 
        orig_len = sb->len;
-       if (((struct format_commit_context *)context)->flush_type != no_flush)
-               consumed = format_and_pad_commit(sb, placeholder, context);
-       else
+       if (context->flush_type == no_flush)
                consumed = format_commit_one(sb, placeholder, context);
+       else
+               consumed = format_and_pad_commit(sb, placeholder, context);
        if (magic == NO_MAGIC)
                return consumed;
 
@@ -1862,41 +1935,38 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
        return consumed + 1;
 }
 
-static size_t userformat_want_item(struct strbuf *sb UNUSED,
-                                  const char *placeholder,
-                                  void *context)
-{
-       struct userformat_want *w = context;
-
-       if (*placeholder == '+' || *placeholder == '-' || *placeholder == ' ')
-               placeholder++;
-
-       switch (*placeholder) {
-       case 'N':
-               w->notes = 1;
-               break;
-       case 'S':
-               w->source = 1;
-               break;
-       case 'd':
-       case 'D':
-               w->decorate = 1;
-               break;
-       }
-       return 0;
-}
-
 void userformat_find_requirements(const char *fmt, struct userformat_want *w)
 {
-       struct strbuf dummy = STRBUF_INIT;
-
        if (!fmt) {
                if (!user_format)
                        return;
                fmt = user_format;
        }
-       strbuf_expand(&dummy, fmt, userformat_want_item, w);
-       strbuf_release(&dummy);
+       while ((fmt = strchr(fmt, '%'))) {
+               fmt++;
+               if (skip_prefix(fmt, "%", &fmt))
+                       continue;
+
+               if (*fmt == '+' || *fmt == '-' || *fmt == ' ')
+                       fmt++;
+
+               switch (*fmt) {
+               case 'N':
+                       w->notes = 1;
+                       break;
+               case 'S':
+                       w->source = 1;
+                       break;
+               case 'd':
+               case 'D':
+                       w->decorate = 1;
+                       break;
+               case '(':
+                       if (starts_with(fmt + 1, "decorate"))
+                               w->decorate = 1;
+                       break;
+               }
+       }
 }
 
 void repo_format_commit_message(struct repository *r,
@@ -1913,7 +1983,16 @@ void repo_format_commit_message(struct repository *r,
        const char *output_enc = pretty_ctx->output_encoding;
        const char *utf8 = "UTF-8";
 
-       strbuf_expand(sb, format, format_commit_item, &context);
+       while (strbuf_expand_step(sb, &format)) {
+               size_t len;
+
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(sb, '%');
+               else if ((len = format_commit_item(sb, format, &context)))
+                       format += len;
+               else
+                       strbuf_addch(sb, '%');
+       }
        rewrap_message_tail(sb, &context, 0, 0, 0);
 
        /*
index dc2476be53a30a6e9c682d934f620422dd855ada..450775a37492082130211431229ce5645ae17613 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "prio-queue.h"
 
 static inline int compare(struct prio_queue *queue, int i, int j)
index f695798acac72bd703dfacc59f83054fd761b619..c83cb60bf17eb490ccc3abc97a1b6f6679196e07 100644 (file)
@@ -17,7 +17,7 @@
 #include "trace.h"
 #include "trace2.h"
 #include "utf8.h"
-#include "config.h"
+#include "parse.h"
 
 #define TP_IDX_MAX      8
 
index 1adcd6fb0a51a0abc5c93a1fe3fc26dc51d60ab8..ac3aa1e365760596990188548410a16900e005d7 100644 (file)
@@ -1,7 +1,7 @@
 #include "git-compat-util.h"
 #include "gettext.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "promisor-remote.h"
 #include "config.h"
 #include "trace2.h"
@@ -100,7 +100,9 @@ static void promisor_remote_move_to_tail(struct promisor_remote_config *config,
        config->promisors_tail = &r->next;
 }
 
-static int promisor_remote_config(const char *var, const char *value, void *data)
+static int promisor_remote_config(const char *var, const char *value,
+                                 const struct config_context *ctx UNUSED,
+                                 void *data)
 {
        struct promisor_remote_config *config = data;
        const char *name;
index 3baa33f63d87a675947bafcdfe3a798b02410de2..8935fe4dfb9414f101bf603aaf866ac6a1f6e027 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -1,5 +1,5 @@
 #include "git-compat-util.h"
-#include "config.h"
+#include "parse.h"
 #include "environment.h"
 #include "run-command.h"
 #include "strbuf.h"
index a90c48852e58f8c0898d1ab7e337356fb39731f7..808a68c974ab7715513657c62d238aae8d3af07f 100644 (file)
@@ -7,7 +7,7 @@
 #include "hash-ll.h"
 #include "hex.h"
 #include "object.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "string-list.h"
 #include "strbuf.h"
 
index 58412b4fb9157f6ef5d3bf6dde7b890e500b741f..e54daf740a26345a182eb67d7ab2716916e41c37 100644 (file)
@@ -1,7 +1,7 @@
 #include "git-compat-util.h"
 #include "environment.h"
 #include "gettext.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
 #include "progress.h"
 #include "prune-packed.h"
diff --git a/quote.c b/quote.c
index 43c739671ed0cb33cd246a98737136b2154c2a57..3c05194496f65f879f437abd29823986ef118f47 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "path.h"
 #include "quote.h"
 #include "strbuf.h"
index 6a704e6f4719d85f5c3bc49c4999a4dac0bd65cc..c45b6d849cbf4f97ec3d6eb893259837d25d9052 100644 (file)
@@ -13,6 +13,7 @@
 #include "commit.h"
 #include "pager.h"
 #include "pretty.h"
+#include "repository.h"
 #include "userdiff.h"
 #include "apply.h"
 #include "revision.h"
@@ -59,7 +60,7 @@ static int read_patches(const char *range, struct string_list *list,
                     "--output-indicator-context=#",
                     "--no-abbrev-commit",
                     "--pretty=medium",
-                    "--notes",
+                    "--show-notes-by-default",
                     NULL);
        strvec_push(&cp.args, range);
        if (other_arg)
@@ -229,16 +230,19 @@ cleanup:
 }
 
 static int patch_util_cmp(const void *cmp_data UNUSED,
-                         const struct patch_util *a,
-                         const struct patch_util *b,
-                         const char *keydata)
+                         const struct hashmap_entry *ha,
+                         const struct hashmap_entry *hb,
+                         const void *keydata)
 {
+       const struct patch_util
+               *a = container_of(ha, const struct patch_util, e),
+               *b = container_of(hb, const struct patch_util, e);
        return strcmp(a->diff, keydata ? keydata : b->diff);
 }
 
 static void find_exact_matches(struct string_list *a, struct string_list *b)
 {
-       struct hashmap map = HASHMAP_INIT((hashmap_cmp_fn)patch_util_cmp, NULL);
+       struct hashmap map = HASHMAP_INIT(patch_util_cmp, NULL);
        int i;
 
        /* First, add the patches of a to a hash map */
index 55bb1143530fceb53f4f68450ecb455861cbbe2d..0ce8f83e56a9b42400b8ec792b19deb3a69ddb6e 100644 (file)
 #include "list-objects.h"
 #include "packfile.h"
 #include "worktree.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pack-bitmap.h"
 #include "pack-mtimes.h"
+#include "config.h"
+#include "run-command.h"
 
 struct connectivity_progress {
        struct progress *progress;
@@ -67,8 +69,77 @@ struct recent_data {
        timestamp_t timestamp;
        report_recent_object_fn *cb;
        int ignore_in_core_kept_packs;
+
+       struct oidset extra_recent_oids;
+       int extra_recent_oids_loaded;
 };
 
+static int run_one_gc_recent_objects_hook(struct oidset *set,
+                                           const char *args)
+{
+       struct child_process cmd = CHILD_PROCESS_INIT;
+       struct strbuf buf = STRBUF_INIT;
+       FILE *out;
+       int ret = 0;
+
+       cmd.use_shell = 1;
+       cmd.out = -1;
+
+       strvec_push(&cmd.args, args);
+
+       if (start_command(&cmd))
+               return -1;
+
+       out = xfdopen(cmd.out, "r");
+       while (strbuf_getline(&buf, out) != EOF) {
+               struct object_id oid;
+               const char *rest;
+
+               if (parse_oid_hex(buf.buf, &oid, &rest) || *rest) {
+                       ret = error(_("invalid extra cruft tip: '%s'"), buf.buf);
+                       break;
+               }
+
+               oidset_insert(set, &oid);
+       }
+
+       fclose(out);
+       ret |= finish_command(&cmd);
+
+       strbuf_release(&buf);
+       return ret;
+}
+
+static void load_gc_recent_objects(struct recent_data *data)
+{
+       const struct string_list *programs;
+       int ret = 0;
+       size_t i;
+
+       data->extra_recent_oids_loaded = 1;
+
+       if (git_config_get_string_multi("gc.recentobjectshook", &programs))
+               return;
+
+       for (i = 0; i < programs->nr; i++) {
+               ret = run_one_gc_recent_objects_hook(&data->extra_recent_oids,
+                                                      programs->items[i].string);
+               if (ret)
+                       die(_("unable to enumerate additional recent objects"));
+       }
+}
+
+static int obj_is_recent(const struct object_id *oid, timestamp_t mtime,
+                        struct recent_data *data)
+{
+       if (mtime > data->timestamp)
+               return 1;
+
+       if (!data->extra_recent_oids_loaded)
+               load_gc_recent_objects(data);
+       return oidset_contains(&data->extra_recent_oids, oid);
+}
+
 static void add_recent_object(const struct object_id *oid,
                              struct packed_git *pack,
                              off_t offset,
@@ -78,7 +149,7 @@ static void add_recent_object(const struct object_id *oid,
        struct object *obj;
        enum object_type type;
 
-       if (mtime <= data->timestamp)
+       if (!obj_is_recent(oid, mtime, data))
                return;
 
        /*
@@ -193,16 +264,24 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
        data.cb = cb;
        data.ignore_in_core_kept_packs = ignore_in_core_kept_packs;
 
+       oidset_init(&data.extra_recent_oids, 0);
+       data.extra_recent_oids_loaded = 0;
+
        r = for_each_loose_object(add_recent_loose, &data,
                                  FOR_EACH_OBJECT_LOCAL_ONLY);
        if (r)
-               return r;
+               goto done;
 
        flags = FOR_EACH_OBJECT_LOCAL_ONLY | FOR_EACH_OBJECT_PACK_ORDER;
        if (ignore_in_core_kept_packs)
                flags |= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS;
 
-       return for_each_packed_object(add_recent_packed, &data, flags);
+       r = for_each_packed_object(add_recent_packed, &data, flags);
+
+done:
+       oidset_clear(&data.extra_recent_oids);
+
+       return r;
 }
 
 static int mark_object_seen(const struct object_id *oid,
similarity index 79%
rename from cache.h
rename to read-cache-ll.h
index bdedb87e83b8bc8b5fd596b00552072191f96bb2..9a1a7edc5a22cf0b0d91f7edd03225ea19607156 100644 (file)
--- a/cache.h
@@ -1,11 +1,8 @@
-#ifndef CACHE_H
-#define CACHE_H
+#ifndef READ_CACHE_LL_H
+#define READ_CACHE_LL_H
 
-#include "git-compat-util.h"
-#include "strbuf.h"
+#include "hash-ll.h"
 #include "hashmap.h"
-#include "pathspec.h"
-#include "object.h"
 #include "statinfo.h"
 
 /*
@@ -126,42 +123,6 @@ static inline unsigned create_ce_flags(unsigned stage)
 #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
 #define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
 
-static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
-                                            unsigned int mode)
-{
-       extern int trust_executable_bit, has_symlinks;
-       if (!has_symlinks && S_ISREG(mode) &&
-           ce && S_ISLNK(ce->ce_mode))
-               return ce->ce_mode;
-       if (!trust_executable_bit && S_ISREG(mode)) {
-               if (ce && S_ISREG(ce->ce_mode))
-                       return ce->ce_mode;
-               return create_ce_mode(0666);
-       }
-       return create_ce_mode(mode);
-}
-static inline int ce_to_dtype(const struct cache_entry *ce)
-{
-       unsigned ce_mode = ntohl(ce->ce_mode);
-       if (S_ISREG(ce_mode))
-               return DT_REG;
-       else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
-               return DT_DIR;
-       else if (S_ISLNK(ce_mode))
-               return DT_LNK;
-       else
-               return DT_UNKNOWN;
-}
-
-static inline int ce_path_match(struct index_state *istate,
-                               const struct cache_entry *ce,
-                               const struct pathspec *pathspec,
-                               char *seen)
-{
-       return match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,
-                             S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
-}
-
 #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
 
 #define SOMETHING_CHANGED      (1 << 0) /* unclassified changes go here */
@@ -245,12 +206,6 @@ struct index_state {
 void index_state_init(struct index_state *istate, struct repository *r);
 void release_index(struct index_state *istate);
 
-/* Name hashing */
-int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
-void add_name_hash(struct index_state *istate, struct cache_entry *ce);
-void remove_name_hash(struct index_state *istate, struct cache_entry *ce);
-void free_name_hash(struct index_state *istate);
-
 /* Cache entry creation and cleanup */
 
 /*
@@ -318,31 +273,14 @@ typedef int (*must_prefetch_predicate)(const struct cache_entry *);
 void prefetch_cache_entries(const struct index_state *istate,
                            must_prefetch_predicate must_prefetch);
 
-#ifdef USE_THE_INDEX_VARIABLE
-extern struct index_state the_index;
-#endif
-
-#define INIT_DB_QUIET 0x0001
-#define INIT_DB_EXIST_OK 0x0002
-
-int init_db(const char *git_dir, const char *real_git_dir,
-           const char *template_dir, int hash_algo,
-           const char *initial_branch, unsigned int flags);
-void initialize_repository_version(int hash_algo, int reinit);
-
 /* Initialize and use the cache information */
 struct lock_file;
-void preload_index(struct index_state *index,
-                  const struct pathspec *pathspec,
-                  unsigned int refresh_flags);
 int do_read_index(struct index_state *istate, const char *path,
                  int must_exist); /* for testting only! */
 int read_index_from(struct index_state *, const char *path,
                    const char *gitdir);
 int is_index_unborn(struct index_state *);
 
-void ensure_full_index(struct index_state *istate);
-
 /* For use with `write_locked_index()`. */
 #define COMMIT_LOCK            (1 << 0)
 #define SKIP_IF_UNCHANGED      (1 << 1)
@@ -385,9 +323,6 @@ int repo_index_has_changes(struct repository *repo,
 
 int verify_path(const char *path, unsigned mode);
 int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
-int index_dir_exists(struct index_state *istate, const char *name, int namelen);
-void adjust_dirname_case(struct index_state *istate, char *name);
-struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
 
 /*
  * Searches for an entry defined by name and namelen in the given index.
@@ -496,19 +431,6 @@ int has_racy_timestamp(struct index_state *istate);
 int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 
-/*
- * Record to sd the data from st that we use to check whether a file
- * might have changed.
- */
-void fill_stat_data(struct stat_data *sd, struct stat *st);
-
-/*
- * Return 0 if st is consistent with a file not having been changed
- * since sd was filled.  If there are differences, return a
- * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
- * INODE_CHANGED, and DATA_CHANGED.
- */
-int match_stat_data(const struct stat_data *sd, struct stat *st);
 int match_stat_data_racy(const struct index_state *istate,
                         const struct stat_data *sd, struct stat *st);
 
@@ -547,69 +469,13 @@ void set_alternate_index_output(const char *);
 extern int verify_index_checksum;
 extern int verify_ce_order;
 
-#define MTIME_CHANGED  0x0001
-#define CTIME_CHANGED  0x0002
-#define OWNER_CHANGED  0x0004
-#define MODE_CHANGED    0x0008
-#define INODE_CHANGED   0x0010
-#define DATA_CHANGED    0x0020
-#define TYPE_CHANGED    0x0040
-
 int cmp_cache_name_compare(const void *a_, const void *b_);
 
-/* add */
-/*
- * return 0 if success, 1 - if addition of a file failed and
- * ADD_FILES_IGNORE_ERRORS was specified in flags
- */
-int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
+int add_files_to_cache(struct repository *repo, const char *prefix,
+                      const struct pathspec *pathspec, int include_sparse,
+                      int flags);
 
-/* diff.c */
-extern int diff_auto_refresh_index;
-
-/* ls-files */
 void overlay_tree_on_index(struct index_state *istate,
                           const char *tree_name, const char *prefix);
 
-/* merge.c */
-struct commit_list;
-int try_merge_command(struct repository *r,
-               const char *strategy, size_t xopts_nr,
-               const char **xopts, struct commit_list *common,
-               const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(struct repository *r,
-                         const struct object_id *from,
-                         const struct object_id *to,
-                         int overwrite_ignore);
-
-
-int sane_execvp(const char *file, char *const argv[]);
-
-/*
- * A struct to encapsulate the concept of whether a file has changed
- * since we last checked it. This uses criteria similar to those used
- * for the index.
- */
-struct stat_validity {
-       struct stat_data *sd;
-};
-
-void stat_validity_clear(struct stat_validity *sv);
-
-/*
- * Returns 1 if the path is a regular file (or a symlink to a regular
- * file) and matches the saved stat_validity, 0 otherwise.  A missing
- * or inaccessible file is considered a match if the struct was just
- * initialized, or if the previous update found an inaccessible file.
- */
-int stat_validity_check(struct stat_validity *sv, const char *path);
-
-/*
- * Update the stat_validity from a file opened at descriptor fd. If
- * the file is missing, inaccessible, or not a regular file, then
- * future calls to stat_validity_check will match iff one of those
- * conditions continues to be true.
- */
-void stat_validity_update(struct stat_validity *sv, int fd);
-
-#endif /* CACHE_H */
+#endif /* READ_CACHE_LL_H */
index f4c31a68c85a62705c370b0a34bf021e91538de6..080bd39713bc1782434b7212954e6bc590fa4d6d 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
+#include "bulk-checkin.h"
 #include "config.h"
 #include "date.h"
 #include "diff.h"
@@ -16,7 +16,7 @@
 #include "refs.h"
 #include "dir.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oid-array.h"
 #include "tree.h"
 #include "commit.h"
 #include "environment.h"
 #include "gettext.h"
 #include "mem-pool.h"
+#include "name-hash.h"
 #include "object-name.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
 #include "resolve-undo.h"
+#include "revision.h"
 #include "run-command.h"
 #include "strbuf.h"
 #include "trace2.h"
@@ -40,7 +45,6 @@
 #include "csum-file.h"
 #include "promisor-remote.h"
 #include "hook.h"
-#include "wrapper.h"
 
 /* Mask for the name length in ce_flags in the on-disk index */
 
@@ -175,61 +179,6 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
                add_index_entry(istate, new_entry, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 }
 
-void fill_stat_data(struct stat_data *sd, struct stat *st)
-{
-       sd->sd_ctime.sec = (unsigned int)st->st_ctime;
-       sd->sd_mtime.sec = (unsigned int)st->st_mtime;
-       sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
-       sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
-       sd->sd_dev = st->st_dev;
-       sd->sd_ino = st->st_ino;
-       sd->sd_uid = st->st_uid;
-       sd->sd_gid = st->st_gid;
-       sd->sd_size = st->st_size;
-}
-
-int match_stat_data(const struct stat_data *sd, struct stat *st)
-{
-       int changed = 0;
-
-       if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
-               changed |= MTIME_CHANGED;
-       if (trust_ctime && check_stat &&
-           sd->sd_ctime.sec != (unsigned int)st->st_ctime)
-               changed |= CTIME_CHANGED;
-
-#ifdef USE_NSEC
-       if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
-               changed |= MTIME_CHANGED;
-       if (trust_ctime && check_stat &&
-           sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
-               changed |= CTIME_CHANGED;
-#endif
-
-       if (check_stat) {
-               if (sd->sd_uid != (unsigned int) st->st_uid ||
-                       sd->sd_gid != (unsigned int) st->st_gid)
-                       changed |= OWNER_CHANGED;
-               if (sd->sd_ino != (unsigned int) st->st_ino)
-                       changed |= INODE_CHANGED;
-       }
-
-#ifdef USE_STDEV
-       /*
-        * st_dev breaks on network filesystems where different
-        * clients will have different views of what "device"
-        * the filesystem is on
-        */
-       if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
-                       changed |= INODE_CHANGED;
-#endif
-
-       if (sd->sd_size != (unsigned int) st->st_size)
-               changed |= DATA_CHANGED;
-
-       return changed;
-}
-
 /*
  * This only updates the "non-critical" parts of the directory
  * cache, ie the parts that aren't tracked by GIT, and only used
@@ -2285,6 +2234,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        if (fd < 0) {
                if (!must_exist && errno == ENOENT) {
                        set_new_index_sparsity(istate);
+                       istate->initialized = 1;
                        return 0;
                }
                die_errno(_("%s: index file open failed"), path);
@@ -2454,12 +2404,14 @@ int read_index_from(struct index_state *istate, const char *path,
 
        base_oid_hex = oid_to_hex(&split_index->base_oid);
        base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
-       trace2_region_enter_printf("index", "shared/do_read_index",
-                                  the_repository, "%s", base_path);
-       ret = do_read_index(split_index->base, base_path, 0);
-       trace2_region_leave_printf("index", "shared/do_read_index",
-                                  the_repository, "%s", base_path);
-       if (!ret) {
+       if (file_exists(base_path)) {
+               trace2_region_enter_printf("index", "shared/do_read_index",
+                                       the_repository, "%s", base_path);
+
+               ret = do_read_index(split_index->base, base_path, 0);
+               trace2_region_leave_printf("index", "shared/do_read_index",
+                                       the_repository, "%s", base_path);
+       } else {
                char *path_copy = xstrdup(path);
                char *base_path2 = xstrfmt("%s/sharedindex.%s",
                                           dirname(path_copy), base_oid_hex);
@@ -3534,35 +3486,6 @@ void *read_blob_data_from_index(struct index_state *istate,
        return data;
 }
 
-void stat_validity_clear(struct stat_validity *sv)
-{
-       FREE_AND_NULL(sv->sd);
-}
-
-int stat_validity_check(struct stat_validity *sv, const char *path)
-{
-       struct stat st;
-
-       if (stat(path, &st) < 0)
-               return sv->sd == NULL;
-       if (!sv->sd)
-               return 0;
-       return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
-}
-
-void stat_validity_update(struct stat_validity *sv, int fd)
-{
-       struct stat st;
-
-       if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
-               stat_validity_clear(sv);
-       else {
-               if (!sv->sd)
-                       CALLOC_ARRAY(sv->sd, 1);
-               fill_stat_data(sv->sd, &st);
-       }
-}
-
 void move_index_extensions(struct index_state *dst, struct index_state *src)
 {
        dst->untracked = src->untracked;
@@ -3806,3 +3729,240 @@ void prefetch_cache_entries(const struct index_state *istate,
                                   to_fetch.oid, to_fetch.nr);
        oid_array_clear(&to_fetch);
 }
+
+static int read_one_entry_opt(struct index_state *istate,
+                             const struct object_id *oid,
+                             struct strbuf *base,
+                             const char *pathname,
+                             unsigned mode, int opt)
+{
+       int len;
+       struct cache_entry *ce;
+
+       if (S_ISDIR(mode))
+               return READ_TREE_RECURSIVE;
+
+       len = strlen(pathname);
+       ce = make_empty_cache_entry(istate, base->len + len);
+
+       ce->ce_mode = create_ce_mode(mode);
+       ce->ce_flags = create_ce_flags(1);
+       ce->ce_namelen = base->len + len;
+       memcpy(ce->name, base->buf, base->len);
+       memcpy(ce->name + base->len, pathname, len+1);
+       oidcpy(&ce->oid, oid);
+       return add_index_entry(istate, ce, opt);
+}
+
+static int read_one_entry(const struct object_id *oid, struct strbuf *base,
+                         const char *pathname, unsigned mode,
+                         void *context)
+{
+       struct index_state *istate = context;
+       return read_one_entry_opt(istate, oid, base, pathname,
+                                 mode,
+                                 ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
+}
+
+/*
+ * This is used when the caller knows there is no existing entries at
+ * the stage that will conflict with the entry being added.
+ */
+static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
+                               const char *pathname, unsigned mode,
+                               void *context)
+{
+       struct index_state *istate = context;
+       return read_one_entry_opt(istate, oid, base, pathname,
+                                 mode, ADD_CACHE_JUST_APPEND);
+}
+
+/*
+ * Read the tree specified with --with-tree option
+ * (typically, HEAD) into stage #1 and then
+ * squash them down to stage #0.  This is used for
+ * --error-unmatch to list and check the path patterns
+ * that were given from the command line.  We are not
+ * going to write this index out.
+ */
+void overlay_tree_on_index(struct index_state *istate,
+                          const char *tree_name, const char *prefix)
+{
+       struct tree *tree;
+       struct object_id oid;
+       struct pathspec pathspec;
+       struct cache_entry *last_stage0 = NULL;
+       int i;
+       read_tree_fn_t fn = NULL;
+       int err;
+
+       if (repo_get_oid(the_repository, tree_name, &oid))
+               die("tree-ish %s not found.", tree_name);
+       tree = parse_tree_indirect(&oid);
+       if (!tree)
+               die("bad tree-ish %s", tree_name);
+
+       /* Hoist the unmerged entries up to stage #3 to make room */
+       /* TODO: audit for interaction with sparse-index. */
+       ensure_full_index(istate);
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
+               if (!ce_stage(ce))
+                       continue;
+               ce->ce_flags |= CE_STAGEMASK;
+       }
+
+       if (prefix) {
+               static const char *(matchbuf[1]);
+               matchbuf[0] = NULL;
+               parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
+                              PATHSPEC_PREFER_CWD, prefix, matchbuf);
+       } else
+               memset(&pathspec, 0, sizeof(pathspec));
+
+       /*
+        * See if we have cache entry at the stage.  If so,
+        * do it the original slow way, otherwise, append and then
+        * sort at the end.
+        */
+       for (i = 0; !fn && i < istate->cache_nr; i++) {
+               const struct cache_entry *ce = istate->cache[i];
+               if (ce_stage(ce) == 1)
+                       fn = read_one_entry;
+       }
+
+       if (!fn)
+               fn = read_one_entry_quick;
+       err = read_tree(the_repository, tree, &pathspec, fn, istate);
+       clear_pathspec(&pathspec);
+       if (err)
+               die("unable to read tree entries %s", tree_name);
+
+       /*
+        * Sort the cache entry -- we need to nuke the cache tree, though.
+        */
+       if (fn == read_one_entry_quick) {
+               cache_tree_free(&istate->cache_tree);
+               QSORT(istate->cache, istate->cache_nr, cmp_cache_name_compare);
+       }
+
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
+               switch (ce_stage(ce)) {
+               case 0:
+                       last_stage0 = ce;
+                       /* fallthru */
+               default:
+                       continue;
+               case 1:
+                       /*
+                        * If there is stage #0 entry for this, we do not
+                        * need to show it.  We use CE_UPDATE bit to mark
+                        * such an entry.
+                        */
+                       if (last_stage0 &&
+                           !strcmp(last_stage0->name, ce->name))
+                               ce->ce_flags |= CE_UPDATE;
+               }
+       }
+}
+
+struct update_callback_data {
+       struct index_state *index;
+       int include_sparse;
+       int flags;
+       int add_errors;
+};
+
+static int fix_unmerged_status(struct diff_filepair *p,
+                              struct update_callback_data *data)
+{
+       if (p->status != DIFF_STATUS_UNMERGED)
+               return p->status;
+       if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
+               /*
+                * This is not an explicit add request, and the
+                * path is missing from the working tree (deleted)
+                */
+               return DIFF_STATUS_DELETED;
+       else
+               /*
+                * Either an explicit add request, or path exists
+                * in the working tree.  An attempt to explicitly
+                * add a path that does not exist in the working tree
+                * will be caught as an error by the caller immediately.
+                */
+               return DIFF_STATUS_MODIFIED;
+}
+
+static void update_callback(struct diff_queue_struct *q,
+                           struct diff_options *opt UNUSED, void *cbdata)
+{
+       int i;
+       struct update_callback_data *data = cbdata;
+
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p = q->queue[i];
+               const char *path = p->one->path;
+
+               if (!data->include_sparse &&
+                   !path_in_sparse_checkout(path, data->index))
+                       continue;
+
+               switch (fix_unmerged_status(p, data)) {
+               default:
+                       die(_("unexpected diff status %c"), p->status);
+               case DIFF_STATUS_MODIFIED:
+               case DIFF_STATUS_TYPE_CHANGED:
+                       if (add_file_to_index(data->index, path, data->flags)) {
+                               if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
+                                       die(_("updating files failed"));
+                               data->add_errors++;
+                       }
+                       break;
+               case DIFF_STATUS_DELETED:
+                       if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
+                               break;
+                       if (!(data->flags & ADD_CACHE_PRETEND))
+                               remove_file_from_index(data->index, path);
+                       if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
+                               printf(_("remove '%s'\n"), path);
+                       break;
+               }
+       }
+}
+
+int add_files_to_cache(struct repository *repo, const char *prefix,
+                      const struct pathspec *pathspec, int include_sparse,
+                      int flags)
+{
+       struct update_callback_data data;
+       struct rev_info rev;
+
+       memset(&data, 0, sizeof(data));
+       data.index = repo->index;
+       data.include_sparse = include_sparse;
+       data.flags = flags;
+
+       repo_init_revisions(repo, &rev, prefix);
+       setup_revisions(0, NULL, &rev, NULL);
+       if (pathspec)
+               copy_pathspec(&rev.prune_data, pathspec);
+       rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+       rev.diffopt.format_callback = update_callback;
+       rev.diffopt.format_callback_data = &data;
+       rev.diffopt.flags.override_submodule_config = 1;
+       rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
+
+       /*
+        * Use an ODB transaction to optimize adding multiple objects.
+        * This function is invoked from commands other than 'add', which
+        * may not have their own transaction active.
+        */
+       begin_odb_transaction();
+       run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
+       end_odb_transaction();
+
+       release_revisions(&rev);
+       return !!data.add_errors;
+}
diff --git a/read-cache.h b/read-cache.h
new file mode 100644 (file)
index 0000000..043da1f
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef READ_CACHE_H
+#define READ_CACHE_H
+
+#include "read-cache-ll.h"
+#include "object.h"
+#include "pathspec.h"
+
+static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce,
+                                            unsigned int mode)
+{
+       extern int trust_executable_bit, has_symlinks;
+       if (!has_symlinks && S_ISREG(mode) &&
+           ce && S_ISLNK(ce->ce_mode))
+               return ce->ce_mode;
+       if (!trust_executable_bit && S_ISREG(mode)) {
+               if (ce && S_ISREG(ce->ce_mode))
+                       return ce->ce_mode;
+               return create_ce_mode(0666);
+       }
+       return create_ce_mode(mode);
+}
+
+static inline int ce_to_dtype(const struct cache_entry *ce)
+{
+       unsigned ce_mode = ntohl(ce->ce_mode);
+       if (S_ISREG(ce_mode))
+               return DT_REG;
+       else if (S_ISDIR(ce_mode) || S_ISGITLINK(ce_mode))
+               return DT_DIR;
+       else if (S_ISLNK(ce_mode))
+               return DT_LNK;
+       else
+               return DT_UNKNOWN;
+}
+
+static inline int ce_path_match(struct index_state *istate,
+                               const struct cache_entry *ce,
+                               const struct pathspec *pathspec,
+                               char *seen)
+{
+       return match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,
+                             S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
+}
+
+#endif /* READ_CACHE_H */
index 852a33131827150e54cf9b7143dfeb73cc6ece5c..d9718409b3d7862fee0eaa7e2255e83f50379656 100644 (file)
@@ -11,7 +11,6 @@
 #include "config.h"
 #include "dir.h"
 #include "object-name.h"
-#include "wrapper.h"
 
 static const char edit_todo_list_advice[] =
 N_("You can fix this with 'git rebase --edit-todo' "
@@ -72,13 +71,14 @@ void append_todo_help(int command_count,
 
        if (!edit_todo) {
                strbuf_addch(buf, '\n');
-               strbuf_commented_addf(buf, Q_("Rebase %s onto %s (%d command)",
-                                             "Rebase %s onto %s (%d commands)",
-                                             command_count),
+               strbuf_commented_addf(buf, comment_line_char,
+                                     Q_("Rebase %s onto %s (%d command)",
+                                        "Rebase %s onto %s (%d commands)",
+                                        command_count),
                                      shortrevisions, shortonto, command_count);
        }
 
-       strbuf_add_commented_lines(buf, msg, strlen(msg));
+       strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
 
        if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)
                msg = _("\nDo not remove any line. Use 'drop' "
@@ -87,7 +87,7 @@ void append_todo_help(int command_count,
                msg = _("\nIf you remove a line here "
                         "THAT COMMIT WILL BE LOST.\n");
 
-       strbuf_add_commented_lines(buf, msg, strlen(msg));
+       strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
 
        if (edit_todo)
                msg = _("\nYou are editing the todo file "
@@ -98,7 +98,7 @@ void append_todo_help(int command_count,
                msg = _("\nHowever, if you remove everything, "
                        "the rebase will be aborted.\n\n");
 
-       strbuf_add_commented_lines(buf, msg, strlen(msg));
+       strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
 }
 
 int edit_todo_list(struct repository *r, struct todo_list *todo_list,
@@ -130,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
        if (launch_sequence_editor(todo_file, &new_todo->buf, NULL))
                return -2;
 
-       strbuf_stripspace(&new_todo->buf, 1);
+       strbuf_stripspace(&new_todo->buf, comment_line_char);
        if (initial && new_todo->buf.len == 0)
                return -3;
 
index 17a570f1ff97fab8e789d2960ae54894b1c42a80..69a1822da34ce7b5877c7aace0a770ef51c655fd 100644 (file)
--- a/rebase.c
+++ b/rebase.c
@@ -1,6 +1,6 @@
 #include "git-compat-util.h"
 #include "rebase.h"
-#include "config.h"
+#include "parse.h"
 #include "gettext.h"
 
 /*
index 4991cd4f7a860be1cf508e88668d1fd8af2ff9ae..e4d3510e28e15a7ff967737f08a8c1acadb588e1 100644 (file)
@@ -1,17 +1,20 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
+#include "config.h"
 #include "gpg-interface.h"
 #include "hex.h"
 #include "parse-options.h"
+#include "run-command.h"
 #include "refs.h"
 #include "wildmatch.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oid-array.h"
 #include "repository.h"
 #include "commit.h"
+#include "mailmap.h"
+#include "ident.h"
 #include "remote.h"
 #include "color.h"
 #include "tag.h"
@@ -146,10 +149,12 @@ enum atom_type {
        ATOM_TAGGERDATE,
        ATOM_CREATOR,
        ATOM_CREATORDATE,
+       ATOM_DESCRIBE,
        ATOM_SUBJECT,
        ATOM_BODY,
        ATOM_TRAILERS,
        ATOM_CONTENTS,
+       ATOM_SIGNATURE,
        ATOM_RAW,
        ATOM_UPSTREAM,
        ATOM_PUSH,
@@ -212,9 +217,22 @@ static struct used_atom {
                struct {
                        enum { O_SIZE, O_SIZE_DISK } option;
                } objectsize;
-               struct email_option {
-                       enum { EO_RAW, EO_TRIM, EO_LOCALPART } option;
+               struct {
+                       enum { N_RAW, N_MAILMAP } option;
+               } name_option;
+               struct {
+                       enum {
+                               EO_RAW = 0,
+                               EO_TRIM = 1<<0,
+                               EO_LOCALPART = 1<<1,
+                               EO_MAILMAP = 1<<2,
+                       } option;
                } email_option;
+               struct {
+                       enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
+                              S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
+               } signature;
+               const char **describe_args;
                struct refname_atom refname;
                char *head;
        } u;
@@ -251,6 +269,110 @@ static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
        return -1;
 }
 
+/*
+ * Parse option of name "candidate" in the option string "to_parse" of
+ * the form
+ *
+ *     "candidate1[=val1],candidate2[=val2],candidate3[=val3],..."
+ *
+ * The remaining part of "to_parse" is stored in "end" (if we are
+ * parsing the last candidate, then this is NULL) and the value of
+ * the candidate is stored in "valuestart" and its length in "valuelen",
+ * that is the portion after "=". Since it is possible for a "candidate"
+ * to not have a value, in such cases, "valuestart" is set to point to
+ * NULL and "valuelen" to 0.
+ *
+ * The function returns 1 on success. It returns 0 if we don't find
+ * "candidate" in "to_parse" or we find "candidate" but it is followed
+ * by more chars (for example, "candidatefoo"), that is, we don't find
+ * an exact match.
+ *
+ * This function only does the above for one "candidate" at a time. So
+ * it has to be called each time trying to parse a "candidate" in the
+ * option string "to_parse".
+ */
+static int match_atom_arg_value(const char *to_parse, const char *candidate,
+                               const char **end, const char **valuestart,
+                               size_t *valuelen)
+{
+       const char *atom;
+
+       if (!skip_prefix(to_parse, candidate, &atom))
+               return 0; /* definitely not "candidate" */
+
+       if (*atom == '=') {
+               /* we just saw "candidate=" */
+               *valuestart = atom + 1;
+               atom = strchrnul(*valuestart, ',');
+               *valuelen = atom - *valuestart;
+       } else if (*atom != ',' && *atom != '\0') {
+               /* key begins with "candidate" but has more chars */
+               return 0;
+       } else {
+               /* just "candidate" without "=val" */
+               *valuestart = NULL;
+               *valuelen = 0;
+       }
+
+       /* atom points at either the ',' or NUL after this key[=val] */
+       if (*atom == ',')
+               atom++;
+       else if (*atom)
+               BUG("Why is *atom not NULL yet?");
+
+       *end = atom;
+       return 1;
+}
+
+/*
+ * Parse boolean option of name "candidate" in the option list "to_parse"
+ * of the form
+ *
+ *     "candidate1[=bool1],candidate2[=bool2],candidate3[=bool3],..."
+ *
+ * The remaining part of "to_parse" is stored in "end" (if we are parsing
+ * the last candidate, then this is NULL) and the value (if given) is
+ * parsed and stored in "val", so "val" always points to either 0 or 1.
+ * If the value is not given, then "val" is set to point to 1.
+ *
+ * The boolean value is parsed using "git_parse_maybe_bool()", so the
+ * accepted values are
+ *
+ *     to set true  - "1", "yes", "true"
+ *     to set false - "0", "no", "false"
+ *
+ * This function returns 1 on success. It returns 0 when we don't find
+ * an exact match for "candidate" or when the boolean value given is
+ * not valid.
+ */
+static int match_atom_bool_arg(const char *to_parse, const char *candidate,
+                               const char **end, int *val)
+{
+       const char *argval;
+       char *strval;
+       size_t arglen;
+       int v;
+
+       if (!match_atom_arg_value(to_parse, candidate, end, &argval, &arglen))
+               return 0;
+
+       if (!argval) {
+               *val = 1;
+               return 1;
+       }
+
+       strval = xstrndup(argval, arglen);
+       v = git_parse_maybe_bool(strval);
+       free(strval);
+
+       if (v == -1)
+               return 0;
+
+       *val = v;
+
+       return 1;
+}
+
 static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
                             const char *color_value, struct strbuf *err)
 {
@@ -407,6 +529,36 @@ static int subject_atom_parser(struct ref_format *format UNUSED,
        return 0;
 }
 
+static int parse_signature_option(const char *arg)
+{
+       if (!arg)
+               return S_BARE;
+       else if (!strcmp(arg, "signer"))
+               return S_SIGNER;
+       else if (!strcmp(arg, "grade"))
+               return S_GRADE;
+       else if (!strcmp(arg, "key"))
+               return S_KEY;
+       else if (!strcmp(arg, "fingerprint"))
+               return S_FINGERPRINT;
+       else if (!strcmp(arg, "primarykeyfingerprint"))
+               return S_PRI_KEY_FP;
+       else if (!strcmp(arg, "trustlevel"))
+               return S_TRUST_LEVEL;
+       return -1;
+}
+
+static int signature_atom_parser(struct ref_format *format UNUSED,
+                                struct used_atom *atom,
+                                const char *arg, struct strbuf *err)
+{
+       int opt = parse_signature_option(arg);
+       if (opt < 0)
+               return err_bad_arg(err, "signature", arg);
+       atom->u.signature.option = opt;
+       return 0;
+}
+
 static int trailers_atom_parser(struct ref_format *format UNUSED,
                                struct used_atom *atom,
                                const char *arg, struct strbuf *err)
@@ -441,9 +593,10 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
                atom->u.contents.option = C_BARE;
        else if (!strcmp(arg, "body"))
                atom->u.contents.option = C_BODY;
-       else if (!strcmp(arg, "size"))
+       else if (!strcmp(arg, "size")) {
+               atom->type = FIELD_ULONG;
                atom->u.contents.option = C_LENGTH;
-       else if (!strcmp(arg, "signature"))
+       else if (!strcmp(arg, "signature"))
                atom->u.contents.option = C_SIG;
        else if (!strcmp(arg, "subject"))
                atom->u.contents.option = C_SUB;
@@ -462,15 +615,97 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
        return 0;
 }
 
+static int describe_atom_option_parser(struct strvec *args, const char **arg,
+                                      struct strbuf *err)
+{
+       const char *argval;
+       size_t arglen = 0;
+       int optval = 0;
+
+       if (match_atom_bool_arg(*arg, "tags", arg, &optval)) {
+               if (!optval)
+                       strvec_push(args, "--no-tags");
+               else
+                       strvec_push(args, "--tags");
+               return 1;
+       }
+
+       if (match_atom_arg_value(*arg, "abbrev", arg, &argval, &arglen)) {
+               char *endptr;
+
+               if (!arglen)
+                       return strbuf_addf_ret(err, -1,
+                                              _("argument expected for %s"),
+                                              "describe:abbrev");
+               if (strtol(argval, &endptr, 10) < 0)
+                       return strbuf_addf_ret(err, -1,
+                                              _("positive value expected %s=%s"),
+                                              "describe:abbrev", argval);
+               if (endptr - argval != arglen)
+                       return strbuf_addf_ret(err, -1,
+                                              _("cannot fully parse %s=%s"),
+                                              "describe:abbrev", argval);
+
+               strvec_pushf(args, "--abbrev=%.*s", (int)arglen, argval);
+               return 1;
+       }
+
+       if (match_atom_arg_value(*arg, "match", arg, &argval, &arglen)) {
+               if (!arglen)
+                       return strbuf_addf_ret(err, -1,
+                                              _("value expected %s="),
+                                              "describe:match");
+
+               strvec_pushf(args, "--match=%.*s", (int)arglen, argval);
+               return 1;
+       }
+
+       if (match_atom_arg_value(*arg, "exclude", arg, &argval, &arglen)) {
+               if (!arglen)
+                       return strbuf_addf_ret(err, -1,
+                                              _("value expected %s="),
+                                              "describe:exclude");
+
+               strvec_pushf(args, "--exclude=%.*s", (int)arglen, argval);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int describe_atom_parser(struct ref_format *format UNUSED,
+                               struct used_atom *atom,
+                               const char *arg, struct strbuf *err)
+{
+       struct strvec args = STRVEC_INIT;
+
+       for (;;) {
+               int found = 0;
+               const char *bad_arg = arg;
+
+               if (!arg || !*arg)
+                       break;
+
+               found = describe_atom_option_parser(&args, &arg, err);
+               if (found < 0)
+                       return found;
+               if (!found)
+                       return err_bad_arg(err, "describe", bad_arg);
+       }
+       atom->u.describe_args = strvec_detach(&args);
+       return 0;
+}
+
 static int raw_atom_parser(struct ref_format *format UNUSED,
                           struct used_atom *atom,
                           const char *arg, struct strbuf *err)
 {
        if (!arg)
                atom->u.raw_data.option = RAW_BARE;
-       else if (!strcmp(arg, "size"))
+       else if (!strcmp(arg, "size")) {
+               atom->type = FIELD_ULONG;
                atom->u.raw_data.option = RAW_LENGTH;
-       else
+       else
                return err_bad_arg(err, "raw", arg);
        return 0;
 }
@@ -495,21 +730,55 @@ static int oid_atom_parser(struct ref_format *format UNUSED,
        return 0;
 }
 
-static int person_email_atom_parser(struct ref_format *format UNUSED,
-                                   struct used_atom *atom,
-                                   const char *arg, struct strbuf *err)
+static int person_name_atom_parser(struct ref_format *format UNUSED,
+                                  struct used_atom *atom,
+                                  const char *arg, struct strbuf *err)
 {
        if (!arg)
-               atom->u.email_option.option = EO_RAW;
-       else if (!strcmp(arg, "trim"))
-               atom->u.email_option.option = EO_TRIM;
-       else if (!strcmp(arg, "localpart"))
-               atom->u.email_option.option = EO_LOCALPART;
+               atom->u.name_option.option = N_RAW;
+       else if (!strcmp(arg, "mailmap"))
+               atom->u.name_option.option = N_MAILMAP;
        else
                return err_bad_arg(err, atom->name, arg);
        return 0;
 }
 
+static int email_atom_option_parser(struct used_atom *atom,
+                                   const char **arg, struct strbuf *err)
+{
+       if (!*arg)
+               return EO_RAW;
+       if (skip_prefix(*arg, "trim", arg))
+               return EO_TRIM;
+       if (skip_prefix(*arg, "localpart", arg))
+               return EO_LOCALPART;
+       if (skip_prefix(*arg, "mailmap", arg))
+               return EO_MAILMAP;
+       return -1;
+}
+
+static int person_email_atom_parser(struct ref_format *format UNUSED,
+                                   struct used_atom *atom,
+                                   const char *arg, struct strbuf *err)
+{
+       for (;;) {
+               int opt = email_atom_option_parser(atom, &arg, err);
+               const char *bad_arg = arg;
+
+               if (opt < 0)
+                       return err_bad_arg(err, atom->name, bad_arg);
+               atom->u.email_option.option |= opt;
+
+               if (!arg || !*arg)
+                       break;
+               if (*arg == ',')
+                       arg++;
+               else
+                       return err_bad_arg(err, atom->name, bad_arg);
+       }
+       return 0;
+}
+
 static int refname_atom_parser(struct ref_format *format UNUSED,
                               struct used_atom *atom,
                               const char *arg, struct strbuf *err)
@@ -597,7 +866,7 @@ static int if_atom_parser(struct ref_format *format UNUSED,
        return 0;
 }
 
-static int rest_atom_parser(struct ref_format *format,
+static int rest_atom_parser(struct ref_format *format UNUSED,
                            struct used_atom *atom UNUSED,
                            const char *arg, struct strbuf *err)
 {
@@ -606,7 +875,8 @@ static int rest_atom_parser(struct ref_format *format,
        return 0;
 }
 
-static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int ahead_behind_atom_parser(struct ref_format *format,
+                                   struct used_atom *atom UNUSED,
                                    const char *arg, struct strbuf *err)
 {
        struct string_list_item *item;
@@ -651,23 +921,25 @@ static struct {
        [ATOM_TYPE] = { "type", SOURCE_OBJ },
        [ATOM_TAG] = { "tag", SOURCE_OBJ },
        [ATOM_AUTHOR] = { "author", SOURCE_OBJ },
-       [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ },
+       [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ, FIELD_STR, person_name_atom_parser },
        [ATOM_AUTHOREMAIL] = { "authoremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
        [ATOM_AUTHORDATE] = { "authordate", SOURCE_OBJ, FIELD_TIME },
        [ATOM_COMMITTER] = { "committer", SOURCE_OBJ },
-       [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ },
+       [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ, FIELD_STR, person_name_atom_parser },
        [ATOM_COMMITTEREMAIL] = { "committeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
        [ATOM_COMMITTERDATE] = { "committerdate", SOURCE_OBJ, FIELD_TIME },
        [ATOM_TAGGER] = { "tagger", SOURCE_OBJ },
-       [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ },
+       [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ, FIELD_STR, person_name_atom_parser },
        [ATOM_TAGGEREMAIL] = { "taggeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
        [ATOM_TAGGERDATE] = { "taggerdate", SOURCE_OBJ, FIELD_TIME },
        [ATOM_CREATOR] = { "creator", SOURCE_OBJ },
        [ATOM_CREATORDATE] = { "creatordate", SOURCE_OBJ, FIELD_TIME },
+       [ATOM_DESCRIBE] = { "describe", SOURCE_OBJ, FIELD_STR, describe_atom_parser },
        [ATOM_SUBJECT] = { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
        [ATOM_BODY] = { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
        [ATOM_TRAILERS] = { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
        [ATOM_CONTENTS] = { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
+       [ATOM_SIGNATURE] = { "signature", SOURCE_OBJ, FIELD_STR, signature_atom_parser },
        [ATOM_RAW] = { "raw", SOURCE_OBJ, FIELD_STR, raw_atom_parser },
        [ATOM_UPSTREAM] = { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
        [ATOM_PUSH] = { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
@@ -1258,32 +1530,49 @@ static const char *copy_name(const char *buf)
        return xstrdup("");
 }
 
+static const char *find_end_of_email(const char *email, int opt)
+{
+       const char *eoemail;
+
+       if (opt & EO_LOCALPART) {
+               eoemail = strchr(email, '@');
+               if (eoemail)
+                       return eoemail;
+               return strchr(email, '>');
+       }
+
+       if (opt & EO_TRIM)
+               return strchr(email, '>');
+
+       /*
+        * The option here is either the raw email option or the raw
+        * mailmap option (that is EO_RAW or EO_MAILMAP). In such cases,
+        * we directly grab the whole email including the closing
+        * angle brackets.
+        *
+        * If EO_MAILMAP was set with any other option (that is either
+        * EO_TRIM or EO_LOCALPART), we already grab the end of email
+        * above.
+        */
+       eoemail = strchr(email, '>');
+       if (eoemail)
+               eoemail++;
+       return eoemail;
+}
+
 static const char *copy_email(const char *buf, struct used_atom *atom)
 {
        const char *email = strchr(buf, '<');
        const char *eoemail;
+       int opt = atom->u.email_option.option;
+
        if (!email)
                return xstrdup("");
-       switch (atom->u.email_option.option) {
-       case EO_RAW:
-               eoemail = strchr(email, '>');
-               if (eoemail)
-                       eoemail++;
-               break;
-       case EO_TRIM:
-               email++;
-               eoemail = strchr(email, '>');
-               break;
-       case EO_LOCALPART:
+
+       if (opt & (EO_LOCALPART | EO_TRIM))
                email++;
-               eoemail = strchr(email, '@');
-               if (!eoemail)
-                       eoemail = strchr(email, '>');
-               break;
-       default:
-               BUG("unknown email option");
-       }
 
+       eoemail = find_end_of_email(email, opt);
        if (!eoemail)
                return xstrdup("");
        return xmemdupz(email, eoemail - email);
@@ -1344,16 +1633,23 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
        v->value = 0;
 }
 
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
+
 /* See grab_values */
 static void grab_person(const char *who, struct atom_value *val, int deref, void *buf)
 {
        int i;
        int wholen = strlen(who);
        const char *wholine = NULL;
+       const char *headers[] = { "author ", "committer ",
+                                 "tagger ", NULL };
 
        for (i = 0; i < used_atom_cnt; i++) {
-               const char *name = used_atom[i].name;
+               struct used_atom *atom = &used_atom[i];
+               const char *name = atom->name;
                struct atom_value *v = &val[i];
+               struct strbuf mailmap_buf = STRBUF_INIT;
+
                if (!!deref != (*name == '*'))
                        continue;
                if (deref)
@@ -1361,22 +1657,36 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
                if (strncmp(who, name, wholen))
                        continue;
                if (name[wholen] != 0 &&
-                   strcmp(name + wholen, "name") &&
+                   !starts_with(name + wholen, "name") &&
                    !starts_with(name + wholen, "email") &&
                    !starts_with(name + wholen, "date"))
                        continue;
-               if (!wholine)
+
+               if ((starts_with(name + wholen, "name") &&
+                   (atom->u.name_option.option == N_MAILMAP)) ||
+                   (starts_with(name + wholen, "email") &&
+                   (atom->u.email_option.option & EO_MAILMAP))) {
+                       if (!mailmap.items)
+                               read_mailmap(&mailmap);
+                       strbuf_addstr(&mailmap_buf, buf);
+                       apply_mailmap_to_header(&mailmap_buf, headers, &mailmap);
+                       wholine = find_wholine(who, wholen, mailmap_buf.buf);
+               } else {
                        wholine = find_wholine(who, wholen, buf);
+               }
+
                if (!wholine)
                        return; /* no point looking for it */
                if (name[wholen] == 0)
                        v->s = copy_line(wholine);
-               else if (!strcmp(name + wholen, "name"))
+               else if (starts_with(name + wholen, "name"))
                        v->s = copy_name(wholine);
                else if (starts_with(name + wholen, "email"))
                        v->s = copy_email(wholine, &used_atom[i]);
                else if (starts_with(name + wholen, "date"))
                        grab_date(wholine, v, name);
+
+               strbuf_release(&mailmap_buf);
        }
 
        /*
@@ -1405,6 +1715,92 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
        }
 }
 
+static void grab_signature(struct atom_value *val, int deref, struct object *obj)
+{
+       int i;
+       struct commit *commit = (struct commit *) obj;
+       struct signature_check sigc = { 0 };
+       int signature_checked = 0;
+
+       for (i = 0; i < used_atom_cnt; i++) {
+               struct used_atom *atom = &used_atom[i];
+               const char *name = atom->name;
+               struct atom_value *v = &val[i];
+               int opt;
+
+               if (!!deref != (*name == '*'))
+                       continue;
+               if (deref)
+                       name++;
+
+               if (!skip_prefix(name, "signature", &name) ||
+                   (*name && *name != ':'))
+                       continue;
+               if (!*name)
+                       name = NULL;
+               else
+                       name++;
+
+               opt = parse_signature_option(name);
+               if (opt < 0)
+                       continue;
+
+               if (!signature_checked) {
+                       check_commit_signature(commit, &sigc);
+                       signature_checked = 1;
+               }
+
+               switch (opt) {
+               case S_BARE:
+                       v->s = xstrdup(sigc.output ? sigc.output: "");
+                       break;
+               case S_SIGNER:
+                       v->s = xstrdup(sigc.signer ? sigc.signer : "");
+                       break;
+               case S_GRADE:
+                       switch (sigc.result) {
+                       case 'G':
+                               switch (sigc.trust_level) {
+                               case TRUST_UNDEFINED:
+                               case TRUST_NEVER:
+                                       v->s = xstrfmt("%c", (char)'U');
+                                       break;
+                               default:
+                                       v->s = xstrfmt("%c", (char)'G');
+                                       break;
+                               }
+                               break;
+                       case 'B':
+                       case 'E':
+                       case 'N':
+                       case 'X':
+                       case 'Y':
+                       case 'R':
+                               v->s = xstrfmt("%c", (char)sigc.result);
+                               break;
+                       }
+                       break;
+               case S_KEY:
+                       v->s = xstrdup(sigc.key ? sigc.key : "");
+                       break;
+               case S_FINGERPRINT:
+                       v->s = xstrdup(sigc.fingerprint ?
+                                      sigc.fingerprint : "");
+                       break;
+               case S_PRI_KEY_FP:
+                       v->s = xstrdup(sigc.primary_key_fingerprint ?
+                                      sigc.primary_key_fingerprint : "");
+                       break;
+               case S_TRUST_LEVEL:
+                       v->s = xstrdup(gpg_trust_level_to_str(sigc.trust_level));
+                       break;
+               }
+       }
+
+       if (signature_checked)
+               signature_check_clear(&sigc);
+}
+
 static void find_subpos(const char *buf,
                        const char **sub, size_t *sublen,
                        const char **body, size_t *bodylen,
@@ -1483,6 +1879,44 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
        }
 }
 
+static void grab_describe_values(struct atom_value *val, int deref,
+                                struct object *obj)
+{
+       struct commit *commit = (struct commit *)obj;
+       int i;
+
+       for (i = 0; i < used_atom_cnt; i++) {
+               struct used_atom *atom = &used_atom[i];
+               enum atom_type type = atom->atom_type;
+               const char *name = atom->name;
+               struct atom_value *v = &val[i];
+
+               struct child_process cmd = CHILD_PROCESS_INIT;
+               struct strbuf out = STRBUF_INIT;
+               struct strbuf err = STRBUF_INIT;
+
+               if (type != ATOM_DESCRIBE)
+                       continue;
+
+               if (!!deref != (*name == '*'))
+                       continue;
+
+               cmd.git_cmd = 1;
+               strvec_push(&cmd.args, "describe");
+               strvec_pushv(&cmd.args, atom->u.describe_args);
+               strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
+               if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
+                       error(_("failed to run 'describe'"));
+                       v->s = xstrdup("");
+                       continue;
+               }
+               strbuf_rtrim(&out);
+               v->s = strbuf_detach(&out, NULL);
+
+               strbuf_release(&err);
+       }
+}
+
 /* See grab_values */
 static void grab_sub_body_contents(struct atom_value *val, int deref, struct expand_data *data)
 {
@@ -1509,7 +1943,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
                                v->s = xmemdupz(buf, buf_size);
                                v->s_size = buf_size;
                        } else if (atom->u.raw_data.option == RAW_LENGTH) {
-                               v->s = xstrfmt("%"PRIuMAX, (uintmax_t)buf_size);
+                               v->value = buf_size;
+                               v->s = xstrfmt("%"PRIuMAX, v->value);
                        }
                        continue;
                }
@@ -1535,9 +1970,10 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
                        v->s = strbuf_detach(&sb, NULL);
                } else if (atom->u.contents.option == C_BODY_DEP)
                        v->s = xmemdupz(bodypos, bodylen);
-               else if (atom->u.contents.option == C_LENGTH)
-                       v->s = xstrfmt("%"PRIuMAX, (uintmax_t)strlen(subpos));
-               else if (atom->u.contents.option == C_BODY)
+               else if (atom->u.contents.option == C_LENGTH) {
+                       v->value = strlen(subpos);
+                       v->s = xstrfmt("%"PRIuMAX, v->value);
+               } else if (atom->u.contents.option == C_BODY)
                        v->s = xmemdupz(bodypos, nonsiglen);
                else if (atom->u.contents.option == C_SIG)
                        v->s = xmemdupz(sigpos, siglen);
@@ -1592,12 +2028,15 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
                grab_tag_values(val, deref, obj);
                grab_sub_body_contents(val, deref, data);
                grab_person("tagger", val, deref, buf);
+               grab_describe_values(val, deref, obj);
                break;
        case OBJ_COMMIT:
                grab_commit_values(val, deref, obj);
                grab_sub_body_contents(val, deref, data);
                grab_person("author", val, deref, buf);
                grab_person("committer", val, deref, buf);
+               grab_signature(val, deref, obj);
+               grab_describe_values(val, deref, obj);
                break;
        case OBJ_TREE:
                /* grab_tree_values(val, deref, obj, buf, sz); */
@@ -1914,6 +2353,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
                v->s_size = ATOM_SIZE_UNSPECIFIED;
                v->handler = append_atom;
+               v->value = 0;
                v->atom = atom;
 
                if (*name == '*') {
@@ -2104,12 +2544,12 @@ static int get_ref_atom_value(struct ref_array_item *ref, int atom,
  * matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
  * matches "refs/heads/mas*", too).
  */
-static int match_pattern(const struct ref_filter *filter, const char *refname)
+static int match_pattern(const char **patterns, const char *refname,
+                        int ignore_case)
 {
-       const char **patterns = filter->name_patterns;
        unsigned flags = 0;
 
-       if (filter->ignore_case)
+       if (ignore_case)
                flags |= WM_CASEFOLD;
 
        /*
@@ -2134,13 +2574,13 @@ static int match_pattern(const struct ref_filter *filter, const char *refname)
  * matches a pattern "refs/heads/" but not "refs/heads/m") or a
  * wildcard (e.g. the same ref matches "refs/heads/m*", too).
  */
-static int match_name_as_path(const struct ref_filter *filter, const char *refname)
+static int match_name_as_path(const char **pattern, const char *refname,
+                             int ignore_case)
 {
-       const char **pattern = filter->name_patterns;
        int namelen = strlen(refname);
        unsigned flags = WM_PATHNAME;
 
-       if (filter->ignore_case)
+       if (ignore_case)
                flags |= WM_CASEFOLD;
 
        for (; *pattern; pattern++) {
@@ -2165,8 +2605,20 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
        if (!*filter->name_patterns)
                return 1; /* No pattern always matches */
        if (filter->match_as_path)
-               return match_name_as_path(filter, refname);
-       return match_pattern(filter, refname);
+               return match_name_as_path(filter->name_patterns, refname,
+                                         filter->ignore_case);
+       return match_pattern(filter->name_patterns, refname,
+                            filter->ignore_case);
+}
+
+static int filter_exclude_match(struct ref_filter *filter, const char *refname)
+{
+       if (!filter->exclude.nr)
+               return 0;
+       if (filter->match_as_path)
+               return match_name_as_path(filter->exclude.v, refname,
+                                         filter->ignore_case);
+       return match_pattern(filter->exclude.v, refname, filter->ignore_case);
 }
 
 /*
@@ -2198,43 +2650,53 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
 
        if (!filter->name_patterns[0]) {
                /* no patterns; we have to look at everything */
-               return for_each_fullref_in("", cb, cb_data);
+               return refs_for_each_fullref_in(get_main_ref_store(the_repository),
+                                                "", filter->exclude.v, cb, cb_data);
        }
 
        return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
                                                 NULL, filter->name_patterns,
+                                                filter->exclude.v,
                                                 cb, cb_data);
 }
 
 /*
  * Given a ref (oid, refname), check if the ref belongs to the array
  * of oids. If the given ref is a tag, check if the given tag points
- * at one of the oids in the given oid array.
+ * at one of the oids in the given oid array. Returns non-zero if a
+ * match is found.
+ *
  * NEEDSWORK:
- * 1. Only a single level of indirection is obtained, we might want to
- * change this to account for multiple levels (e.g. annotated tags
- * pointing to annotated tags pointing to a commit.)
- * 2. As the refs are cached we might know what refname peels to without
+ * As the refs are cached we might know what refname peels to without
  * the need to parse the object via parse_object(). peel_ref() might be a
  * more efficient alternative to obtain the pointee.
  */
-static const struct object_id *match_points_at(struct oid_array *points_at,
-                                              const struct object_id *oid,
-                                              const char *refname)
+static int match_points_at(struct oid_array *points_at,
+                          const struct object_id *oid,
+                          const char *refname)
 {
-       const struct object_id *tagged_oid = NULL;
        struct object *obj;
 
        if (oid_array_lookup(points_at, oid) >= 0)
-               return oid;
-       obj = parse_object(the_repository, oid);
+               return 1;
+       obj = parse_object_with_flags(the_repository, oid,
+                                     PARSE_OBJECT_SKIP_HASH_CHECK);
+       while (obj && obj->type == OBJ_TAG) {
+               struct tag *tag = (struct tag *)obj;
+
+               if (parse_tag(tag) < 0) {
+                       obj = NULL;
+                       break;
+               }
+
+               if (oid_array_lookup(points_at, get_tagged_oid(tag)) >= 0)
+                       return 1;
+
+               obj = tag->tagged;
+       }
        if (!obj)
                die(_("malformed object at '%s'"), refname);
-       if (obj->type == OBJ_TAG)
-               tagged_oid = get_tagged_oid((struct tag *)obj);
-       if (tagged_oid && oid_array_lookup(points_at, tagged_oid) >= 0)
-               return tagged_oid;
-       return NULL;
+       return 0;
 }
 
 /*
@@ -2336,6 +2798,9 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
        if (!filter_pattern_match(filter, refname))
                return 0;
 
+       if (filter_exclude_match(filter, refname))
+               return 0;
+
        if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname))
                return 0;
 
@@ -2418,13 +2883,13 @@ void ref_array_clear(struct ref_array *array)
 #define EXCLUDE_REACHED 0
 #define INCLUDE_REACHED 1
 static void reach_filter(struct ref_array *array,
-                        struct commit_list *check_reachable,
+                        struct commit_list **check_reachable,
                         int include_reached)
 {
        int i, old_nr;
        struct commit **to_clear;
 
-       if (!check_reachable)
+       if (!*check_reachable)
                return;
 
        CALLOC_ARRAY(to_clear, array->nr);
@@ -2434,7 +2899,7 @@ static void reach_filter(struct ref_array *array,
        }
 
        tips_reachable_from_bases(the_repository,
-                                 check_reachable,
+                                 *check_reachable,
                                  to_clear, array->nr,
                                  UNINTERESTING);
 
@@ -2455,8 +2920,8 @@ static void reach_filter(struct ref_array *array,
 
        clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS);
 
-       while (check_reachable) {
-               struct commit *merge_commit = pop_commit(&check_reachable);
+       while (*check_reachable) {
+               struct commit *merge_commit = pop_commit(check_reachable);
                clear_commit_marks(merge_commit, ALL_REV_FLAGS);
        }
 
@@ -2553,8 +3018,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
        clear_contains_cache(&ref_cbdata.no_contains_cache);
 
        /*  Filters that need revision walking */
-       reach_filter(array, filter->reachable_from, INCLUDE_REACHED);
-       reach_filter(array, filter->unreachable_from, EXCLUDE_REACHED);
+       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;
@@ -2866,3 +3331,20 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
 
        return 0;
 }
+
+void ref_filter_init(struct ref_filter *filter)
+{
+       struct ref_filter blank = REF_FILTER_INIT;
+       memcpy(filter, &blank, sizeof(blank));
+}
+
+void ref_filter_clear(struct ref_filter *filter)
+{
+       strvec_clear(&filter->exclude);
+       oid_array_clear(&filter->points_at);
+       free_commit_list(filter->with_commit);
+       free_commit_list(filter->no_commit);
+       free_commit_list(filter->reachable_from);
+       free_commit_list(filter->unreachable_from);
+       ref_filter_init(filter);
+}
index 430701cfb765b557d62c6004e6ef7fb27ad5e5f0..1524bc463a5701d475cb68e50caa884a6daf890a 100644 (file)
@@ -6,6 +6,7 @@
 #include "refs.h"
 #include "commit.h"
 #include "string-list.h"
+#include "strvec.h"
 
 /* Quoting styles */
 #define QUOTE_NONE 0
@@ -59,6 +60,7 @@ struct ref_array {
 
 struct ref_filter {
        const char **name_patterns;
+       struct strvec exclude;
        struct oid_array points_at;
        struct commit_list *with_commit;
        struct commit_list *no_commit;
@@ -92,6 +94,10 @@ struct ref_format {
        struct string_list bases;
 };
 
+#define REF_FILTER_INIT { \
+       .points_at = OID_ARRAY_INIT, \
+       .exclude = STRVEC_INIT, \
+}
 #define REF_FORMAT_INIT {             \
        .use_color = -1,              \
        .bases = STRING_LIST_INIT_DUP, \
@@ -109,6 +115,9 @@ struct ref_format {
 #define OPT_REF_SORT(var) \
        OPT_STRING_LIST(0, "sort", (var), \
                        N_("key"), N_("field name to sort on"))
+#define OPT_REF_FILTER_EXCLUDE(var) \
+       OPT_STRVEC(0, "exclude", &(var)->exclude, \
+                  N_("pattern"), N_("exclude refs which match pattern"))
 
 /*
  * API for filtering a set of refs. Based on the type of refs the user
@@ -167,4 +176,7 @@ void filter_ahead_behind(struct repository *r,
                         struct ref_format *format,
                         struct ref_array *array);
 
+void ref_filter_init(struct ref_filter *filter);
+void ref_filter_clear(struct ref_filter *filter);
+
 #endif /*  REF_FILTER_H  */
index 4ba1a10c82cdd3920a1c2818de29a18e1ea153ca..d216f6f966da91459ea946790be56ba011760170 100644 (file)
@@ -1,8 +1,8 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "commit.h"
 #include "refs.h"
 #include "diff.h"
+#include "repository.h"
 #include "revision.h"
 #include "string-list.h"
 #include "reflog-walk.h"
index ee1bf5d032c823292a9a57853caf0a9be5ea9bab..9ad50e7d93e40c7a5f9c7ad0cecb0b7d1766105b 100644 (file)
--- a/reflog.c
+++ b/reflog.c
@@ -1,6 +1,6 @@
 #include "git-compat-util.h"
 #include "gettext.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "reflog.h"
 #include "refs.h"
 #include "revision.h"
diff --git a/refs.c b/refs.c
index d2a98e1c21f4e9e0be61070aeec48446b0335efc..fcae5dddc6050627668048e966384b7f9fa70171 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -4,7 +4,6 @@
 
 #include "git-compat-util.h"
 #include "advice.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "hashmap.h"
@@ -17,8 +16,9 @@
 #include "run-command.h"
 #include "hook.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "object.h"
+#include "path.h"
 #include "tag.h"
 #include "submodule.h"
 #include "worktree.h"
@@ -28,7 +28,7 @@
 #include "sigchain.h"
 #include "date.h"
 #include "commit.h"
-#include "wrapper.h"
+#include "wildmatch.h"
 
 /*
  * List of all available backends
@@ -375,8 +375,8 @@ char *resolve_refdup(const char *refname, int resolve_flags,
                                   oid, flags);
 }
 
-/* The argument to filter_refs */
-struct ref_filter {
+/* The argument to for_each_filter_refs */
+struct for_each_ref_filter {
        const char *pattern;
        const char *prefix;
        each_ref_fn *fn;
@@ -409,10 +409,11 @@ int ref_exists(const char *refname)
        return refs_ref_exists(get_main_ref_store(the_repository), refname);
 }
 
-static int filter_refs(const char *refname, const struct object_id *oid,
-                          int flags, void *data)
+static int for_each_filter_refs(const char *refname,
+                               const struct object_id *oid,
+                               int flags, void *data)
 {
-       struct ref_filter *filter = (struct ref_filter *)data;
+       struct for_each_ref_filter *filter = data;
 
        if (wildmatch(filter->pattern, refname, 0))
                return 0;
@@ -569,7 +570,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
        const char *prefix, void *cb_data)
 {
        struct strbuf real_pattern = STRBUF_INIT;
-       struct ref_filter filter;
+       struct for_each_ref_filter filter;
        int ret;
 
        if (!prefix && !starts_with(pattern, "refs/"))
@@ -589,7 +590,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
        filter.prefix = prefix;
        filter.fn = fn;
        filter.cb_data = cb_data;
-       ret = for_each_ref(filter_refs, &filter);
+       ret = for_each_ref(for_each_filter_refs, &filter);
 
        strbuf_release(&real_pattern);
        return ret;
@@ -1426,7 +1427,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
 }
 
 int parse_hide_refs_config(const char *var, const char *value, const char *section,
-                          struct string_list *hide_refs)
+                          struct strvec *hide_refs)
 {
        const char *key;
        if (!strcmp("transfer.hiderefs", var) ||
@@ -1437,22 +1438,23 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti
 
                if (!value)
                        return config_error_nonbool(var);
-               ref = xstrdup(value);
+
+               /* drop const to remove trailing '/' characters */
+               ref = (char *)strvec_push(hide_refs, value);
                len = strlen(ref);
                while (len && ref[len - 1] == '/')
                        ref[--len] = '\0';
-               string_list_append_nodup(hide_refs, ref);
        }
        return 0;
 }
 
 int ref_is_hidden(const char *refname, const char *refname_full,
-                 const struct string_list *hide_refs)
+                 const struct strvec *hide_refs)
 {
        int i;
 
        for (i = hide_refs->nr - 1; i >= 0; i--) {
-               const char *match = hide_refs->items[i].string;
+               const char *match = hide_refs->v[i];
                const char *subject;
                int neg = 0;
                const char *p;
@@ -1478,6 +1480,30 @@ int ref_is_hidden(const char *refname, const char *refname_full,
        return 0;
 }
 
+const char **hidden_refs_to_excludes(const struct strvec *hide_refs)
+{
+       const char **pattern;
+       for (pattern = hide_refs->v; *pattern; pattern++) {
+               /*
+                * We can't feed any excludes from hidden refs config
+                * sections, since later rules may override previous
+                * ones. For example, with rules "refs/foo" and
+                * "!refs/foo/bar", we should show "refs/foo/bar" (and
+                * everything underneath it), but the earlier exclusion
+                * would cause us to skip all of "refs/foo".  We
+                * likewise don't implement the namespace stripping
+                * required for '^' rules.
+                *
+                * Both are possible to do, but complicated, so avoid
+                * populating the jump list at all if we see either of
+                * these patterns.
+                */
+               if (**pattern == '!' || **pattern == '^')
+                       return NULL;
+       }
+       return hide_refs->v;
+}
+
 const char *find_descendant_ref(const char *dirname,
                                const struct string_list *extras,
                                const struct string_list *skip)
@@ -1525,7 +1551,9 @@ int head_ref(each_ref_fn fn, void *cb_data)
 
 struct ref_iterator *refs_ref_iterator_begin(
                struct ref_store *refs,
-               const char *prefix, int trim,
+               const char *prefix,
+               const char **exclude_patterns,
+               int trim,
                enum do_for_each_ref_flags flags)
 {
        struct ref_iterator *iter;
@@ -1541,8 +1569,7 @@ struct ref_iterator *refs_ref_iterator_begin(
                }
        }
 
-       iter = refs->be->iterator_begin(refs, prefix, flags);
-
+       iter = refs->be->iterator_begin(refs, prefix, exclude_patterns, flags);
        /*
         * `iterator_begin()` already takes care of prefix, but we
         * might need to do some trimming:
@@ -1576,7 +1603,7 @@ static int do_for_each_repo_ref(struct repository *r, const char *prefix,
        if (!refs)
                return 0;
 
-       iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+       iter = refs_ref_iterator_begin(refs, prefix, NULL, trim, flags);
 
        return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
 }
@@ -1586,7 +1613,7 @@ struct do_for_each_ref_help {
        void *cb_data;
 };
 
-static int do_for_each_ref_helper(struct repository *r,
+static int do_for_each_ref_helper(struct repository *r UNUSED,
                                  const char *refname,
                                  const struct object_id *oid,
                                  int flags,
@@ -1598,6 +1625,7 @@ static int do_for_each_ref_helper(struct repository *r,
 }
 
 static int do_for_each_ref(struct ref_store *refs, const char *prefix,
+                          const char **exclude_patterns,
                           each_ref_fn fn, int trim,
                           enum do_for_each_ref_flags flags, void *cb_data)
 {
@@ -1607,7 +1635,8 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
        if (!refs)
                return 0;
 
-       iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+       iter = refs_ref_iterator_begin(refs, prefix, exclude_patterns, trim,
+                                      flags);
 
        return do_for_each_repo_ref_iterator(the_repository, iter,
                                        do_for_each_ref_helper, &hp);
@@ -1615,7 +1644,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix,
 
 int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(refs, "", fn, 0, 0, cb_data);
+       return do_for_each_ref(refs, "", NULL, fn, 0, 0, cb_data);
 }
 
 int for_each_ref(each_ref_fn fn, void *cb_data)
@@ -1626,7 +1655,7 @@ int for_each_ref(each_ref_fn fn, void *cb_data)
 int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
                         each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(refs, prefix, fn, strlen(prefix), 0, cb_data);
+       return do_for_each_ref(refs, prefix, NULL, fn, strlen(prefix), 0, cb_data);
 }
 
 int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
@@ -1637,13 +1666,14 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
 int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data)
 {
        return do_for_each_ref(get_main_ref_store(the_repository),
-                              prefix, fn, 0, 0, cb_data);
+                              prefix, NULL, fn, 0, 0, cb_data);
 }
 
 int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
+                            const char **exclude_patterns,
                             each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(refs, prefix, fn, 0, 0, cb_data);
+       return do_for_each_ref(refs, prefix, exclude_patterns, fn, 0, 0, cb_data);
 }
 
 int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
@@ -1654,20 +1684,21 @@ int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_dat
                                    DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
 }
 
-int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
+int for_each_namespaced_ref(const char **exclude_patterns,
+                           each_ref_fn fn, void *cb_data)
 {
        struct strbuf buf = STRBUF_INIT;
        int ret;
        strbuf_addf(&buf, "%srefs/", get_git_namespace());
        ret = do_for_each_ref(get_main_ref_store(the_repository),
-                             buf.buf, fn, 0, 0, cb_data);
+                             buf.buf, exclude_patterns, fn, 0, 0, cb_data);
        strbuf_release(&buf);
        return ret;
 }
 
 int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(refs, "", fn, 0,
+       return do_for_each_ref(refs, "", NULL, fn, 0,
                               DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
 }
 
@@ -1737,6 +1768,7 @@ static void find_longest_prefixes(struct string_list *out,
 int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
                                      const char *namespace,
                                      const char **patterns,
+                                     const char **exclude_patterns,
                                      each_ref_fn fn, void *cb_data)
 {
        struct string_list prefixes = STRING_LIST_INIT_DUP;
@@ -1752,7 +1784,8 @@ int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
 
        for_each_string_list_item(prefix, &prefixes) {
                strbuf_addstr(&buf, prefix->string);
-               ret = refs_for_each_fullref_in(ref_store, buf.buf, fn, cb_data);
+               ret = refs_for_each_fullref_in(ref_store, buf.buf,
+                                              exclude_patterns, fn, cb_data);
                if (ret)
                        break;
                strbuf_setlen(&buf, namespace_len);
@@ -2132,9 +2165,9 @@ void base_ref_store_init(struct ref_store *refs, struct repository *repo,
 }
 
 /* backend functions */
-int refs_pack_refs(struct ref_store *refs, unsigned int flags)
+int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts)
 {
-       return refs->be->pack_refs(refs, flags);
+       return refs->be->pack_refs(refs, opts);
 }
 
 int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)
@@ -2407,7 +2440,7 @@ int refs_verify_refname_available(struct ref_store *refs,
        strbuf_addstr(&dirname, refname + dirname.len);
        strbuf_addch(&dirname, '/');
 
-       iter = refs_ref_iterator_begin(refs, dirname.buf, 0,
+       iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0,
                                       DO_FOR_EACH_INCLUDE_BROKEN);
        while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
                if (skip &&
diff --git a/refs.h b/refs.h
index 123cfa4424453fbda6503dbbb66d28f092815154..23211a5ea1cabbb0a35d091bf2b5dbbd87e28252 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -63,6 +63,12 @@ struct worktree;
 #define RESOLVE_REF_NO_RECURSE 0x02
 #define RESOLVE_REF_ALLOW_BAD_NAME 0x04
 
+struct pack_refs_opts {
+       unsigned int flags;
+       struct ref_exclusions *exclusions;
+       struct string_list *includes;
+};
+
 const char *refs_resolve_ref_unsafe(struct ref_store *refs,
                                    const char *refname,
                                    int resolve_flags,
@@ -337,7 +343,12 @@ int for_each_ref(each_ref_fn fn, void *cb_data);
  */
 int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
 
+/*
+ * references matching any pattern in "exclude_patterns" are omitted from the
+ * result set on a best-effort basis.
+ */
 int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
+                            const char **exclude_patterns,
                             each_ref_fn fn, void *cb_data);
 int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
 
@@ -345,10 +356,15 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
  * iterate all refs in "patterns" by partitioning patterns into disjoint sets
  * and iterating the longest-common prefix of each set.
  *
+ * references matching any pattern in "exclude_patterns" are omitted from the
+ * result set on a best-effort basis.
+ *
  * callers should be prepared to ignore references that they did not ask for.
  */
 int refs_for_each_fullref_in_prefixes(struct ref_store *refs,
-                                     const char *namespace, const char **patterns,
+                                     const char *namespace,
+                                     const char **patterns,
+                                     const char **exclude_patterns,
                                      each_ref_fn fn, void *cb_data);
 
 /**
@@ -366,7 +382,12 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
                         const char *prefix, void *cb_data);
 
 int head_ref_namespaced(each_ref_fn fn, void *cb_data);
-int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
+/*
+ * references matching any pattern in "exclude_patterns" are omitted from the
+ * result set on a best-effort basis.
+ */
+int for_each_namespaced_ref(const char **exclude_patterns,
+                           each_ref_fn fn, void *cb_data);
 
 /* can be used to learn about broken ref and symref */
 int refs_for_each_rawref(struct ref_store *refs, each_ref_fn fn, void *cb_data);
@@ -405,7 +426,7 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
  * Write a packed-refs file for the current repository.
  * flags: Combination of the above PACK_REFS_* flags.
  */
-int refs_pack_refs(struct ref_store *refs, unsigned int flags);
+int refs_pack_refs(struct ref_store *refs, struct pack_refs_opts *opts);
 
 /*
  * Setup reflog before using. Fill in err and return -1 on failure.
@@ -804,7 +825,7 @@ int update_ref(const char *msg, const char *refname,
               unsigned int flags, enum action_on_err onerr);
 
 int parse_hide_refs_config(const char *var, const char *value, const char *,
-                          struct string_list *);
+                          struct strvec *);
 
 /*
  * Check whether a ref is hidden. If no namespace is set, both the first and
@@ -814,7 +835,13 @@ int parse_hide_refs_config(const char *var, const char *value, const char *,
  * the ref is outside that namespace, the first parameter is NULL. The second
  * parameter always points to the full ref name.
  */
-int ref_is_hidden(const char *, const char *, const struct string_list *);
+int ref_is_hidden(const char *, const char *, const struct strvec *);
+
+/*
+ * Returns an array of patterns to use as excluded_patterns, if none of the
+ * hidden references use the token '!' or '^'.
+ */
+const char **hidden_refs_to_excludes(const struct strvec *hide_refs);
 
 /* Is this a per-worktree ref living in the refs/ namespace? */
 int is_per_worktree_ref(const char *refname);
index 6f11e6de46c8f2ed76d17a8bb8ac3bb2c5ba3acb..b7ffc4ce67e333321036592b7e53efa30f8871d8 100644 (file)
@@ -123,10 +123,10 @@ static int debug_initial_transaction_commit(struct ref_store *refs,
        return res;
 }
 
-static int debug_pack_refs(struct ref_store *ref_store, unsigned int flags)
+static int debug_pack_refs(struct ref_store *ref_store, struct pack_refs_opts *opts)
 {
        struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
-       int res = drefs->refs->be->pack_refs(drefs->refs, flags);
+       int res = drefs->refs->be->pack_refs(drefs->refs, opts);
        trace_printf_key(&trace_refs, "pack_refs: %d\n", res);
        return res;
 }
@@ -229,11 +229,12 @@ static struct ref_iterator_vtable debug_ref_iterator_vtable = {
 
 static struct ref_iterator *
 debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix,
-                        unsigned int flags)
+                        const char **exclude_patterns, unsigned int flags)
 {
        struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
        struct ref_iterator *res =
-               drefs->refs->be->iterator_begin(drefs->refs, prefix, flags);
+               drefs->refs->be->iterator_begin(drefs->refs, prefix,
+                                               exclude_patterns, flags);
        struct debug_ref_iterator *diter = xcalloc(1, sizeof(*diter));
        base_ref_iterator_init(&diter->base, &debug_ref_iterator_vtable, 1);
        diter->iter = res;
index bca7b851c5a7a12f936469928cbf608686573644..db5c0c7a724d57ad67250cb0be996ae5cfbc0372 100644 (file)
@@ -1,4 +1,4 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
 #include "../config.h"
 #include "../copy.h"
 #include "../environment.h"
 #include "../lockfile.h"
 #include "../object.h"
 #include "../object-file.h"
+#include "../path.h"
 #include "../dir.h"
 #include "../chdir-notify.h"
 #include "../setup.h"
 #include "../worktree.h"
 #include "../wrapper.h"
 #include "../write-or-die.h"
+#include "../revision.h"
+#include <wildmatch.h>
 
 /*
  * This backend uses the following flags in `ref_update::flags` for
@@ -243,10 +246,8 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
        int dirnamelen = strlen(dirname);
        struct strbuf refname;
        struct strbuf path = STRBUF_INIT;
-       size_t path_baselen;
 
        files_ref_path(refs, &path, dirname);
-       path_baselen = path.len;
 
        d = opendir(path.buf);
        if (!d) {
@@ -259,23 +260,22 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
 
        while ((de = readdir(d)) != NULL) {
                struct object_id oid;
-               struct stat st;
                int flag;
+               unsigned char dtype;
 
                if (de->d_name[0] == '.')
                        continue;
                if (ends_with(de->d_name, ".lock"))
                        continue;
                strbuf_addstr(&refname, de->d_name);
-               strbuf_addstr(&path, de->d_name);
-               if (stat(path.buf, &st) < 0) {
-                       ; /* silently ignore */
-               } else if (S_ISDIR(st.st_mode)) {
+
+               dtype = get_dtype(de, &path, 1);
+               if (dtype == DT_DIR) {
                        strbuf_addch(&refname, '/');
                        add_entry_to_dir(dir,
                                         create_dir_entry(dir->cache, refname.buf,
                                                          refname.len));
-               } else {
+               } else if (dtype == DT_REG) {
                        if (!refs_resolve_ref_unsafe(&refs->base,
                                                     refname.buf,
                                                     RESOLVE_REF_READING,
@@ -305,7 +305,6 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
                                         create_ref_entry(refname.buf, &oid, flag));
                }
                strbuf_setlen(&refname, dirnamelen);
-               strbuf_setlen(&path, path_baselen);
        }
        strbuf_release(&refname);
        strbuf_release(&path);
@@ -829,7 +828,8 @@ static struct ref_iterator_vtable files_ref_iterator_vtable = {
 
 static struct ref_iterator *files_ref_iterator_begin(
                struct ref_store *ref_store,
-               const char *prefix, unsigned int flags)
+               const char *prefix, const char **exclude_patterns,
+               unsigned int flags)
 {
        struct files_ref_store *refs;
        struct ref_iterator *loose_iter, *packed_iter, *overlay_iter;
@@ -874,7 +874,7 @@ static struct ref_iterator *files_ref_iterator_begin(
         * the packed and loose references.
         */
        packed_iter = refs_ref_iterator_begin(
-                       refs->packed_ref_store, prefix, 0,
+                       refs->packed_ref_store, prefix, exclude_patterns, 0,
                        DO_FOR_EACH_INCLUDE_BROKEN);
 
        overlay_iter = overlay_ref_iterator_begin(loose_iter, packed_iter);
@@ -1175,17 +1175,15 @@ static void prune_refs(struct files_ref_store *refs, struct ref_to_prune **refs_
  */
 static int should_pack_ref(const char *refname,
                           const struct object_id *oid, unsigned int ref_flags,
-                          unsigned int pack_flags)
+                          struct pack_refs_opts *opts)
 {
+       struct string_list_item *item;
+
        /* Do not pack per-worktree refs: */
        if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
            REF_WORKTREE_SHARED)
                return 0;
 
-       /* Do not pack non-tags unless PACK_REFS_ALL is set: */
-       if (!(pack_flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/"))
-               return 0;
-
        /* Do not pack symbolic refs: */
        if (ref_flags & REF_ISSYMREF)
                return 0;
@@ -1194,10 +1192,18 @@ static int should_pack_ref(const char *refname,
        if (!ref_resolves_to_object(refname, the_repository, oid, ref_flags))
                return 0;
 
-       return 1;
+       if (ref_excluded(opts->exclusions, refname))
+               return 0;
+
+       for_each_string_list_item(item, opts->includes)
+               if (!wildmatch(item->string, refname, 0))
+                       return 1;
+
+       return 0;
 }
 
-static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
+static int files_pack_refs(struct ref_store *ref_store,
+                          struct pack_refs_opts *opts)
 {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB,
@@ -1222,8 +1228,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
                 * in the packed ref cache. If the reference should be
                 * pruned, also add it to refs_to_prune.
                 */
-               if (!should_pack_ref(iter->refname, iter->oid, iter->flags,
-                                    flags))
+               if (!should_pack_ref(iter->refname, iter->oid, iter->flags, opts))
                        continue;
 
                /*
@@ -1237,7 +1242,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
                            iter->refname, err.buf);
 
                /* Schedule the loose reference for pruning if requested. */
-               if ((flags & PACK_REFS_PRUNE)) {
+               if ((opts->flags & PACK_REFS_PRUNE)) {
                        struct ref_to_prune *n;
                        FLEX_ALLOC_STR(n, name, iter->refname);
                        oidcpy(&n->oid, iter->oid);
index 5b412a133be1b0214ded460cbc496b45282bd789..59c78d7941f8d5e05fec6c895aafeb41803b919d 100644 (file)
@@ -1,4 +1,4 @@
-#include "../cache.h"
+#include "../git-compat-util.h"
 #include "../alloc.h"
 #include "../config.h"
 #include "../gettext.h"
 #include "../iterator.h"
 #include "../lockfile.h"
 #include "../chdir-notify.h"
+#include "../statinfo.h"
 #include "../wrapper.h"
 #include "../write-or-die.h"
+#include "../trace2.h"
 
 enum mmap_strategy {
        /*
@@ -303,7 +305,8 @@ static int cmp_packed_ref_records(const void *v1, const void *v2)
  * Compare a snapshot record at `rec` to the specified NUL-terminated
  * refname.
  */
-static int cmp_record_to_refname(const char *rec, const char *refname)
+static int cmp_record_to_refname(const char *rec, const char *refname,
+                                int start)
 {
        const char *r1 = rec + the_hash_algo->hexsz + 1;
        const char *r2 = refname;
@@ -312,7 +315,7 @@ static int cmp_record_to_refname(const char *rec, const char *refname)
                if (*r1 == '\n')
                        return *r2 ? -1 : 0;
                if (!*r2)
-                       return 1;
+                       return start ? 1 : -1;
                if (*r1 != *r2)
                        return (unsigned char)*r1 < (unsigned char)*r2 ? -1 : +1;
                r1++;
@@ -527,22 +530,9 @@ static int load_contents(struct snapshot *snapshot)
        return 1;
 }
 
-/*
- * Find the place in `snapshot->buf` where the start of the record for
- * `refname` starts. If `mustexist` is true and the reference doesn't
- * exist, then return NULL. If `mustexist` is false and the reference
- * doesn't exist, then return the point where that reference would be
- * inserted, or `snapshot->eof` (which might be NULL) if it would be
- * inserted at the end of the file. In the latter mode, `refname`
- * doesn't have to be a proper reference name; for example, one could
- * search for "refs/replace/" to find the start of any replace
- * references.
- *
- * The record is sought using a binary search, so `snapshot->buf` must
- * be sorted.
- */
-static const char *find_reference_location(struct snapshot *snapshot,
-                                          const char *refname, int mustexist)
+static const char *find_reference_location_1(struct snapshot *snapshot,
+                                            const char *refname, int mustexist,
+                                            int start)
 {
        /*
         * This is not *quite* a garden-variety binary search, because
@@ -572,7 +562,7 @@ static const char *find_reference_location(struct snapshot *snapshot,
 
                mid = lo + (hi - lo) / 2;
                rec = find_start_of_record(lo, mid);
-               cmp = cmp_record_to_refname(rec, refname);
+               cmp = cmp_record_to_refname(rec, refname, start);
                if (cmp < 0) {
                        lo = find_end_of_record(mid, hi);
                } else if (cmp > 0) {
@@ -588,6 +578,41 @@ static const char *find_reference_location(struct snapshot *snapshot,
                return lo;
 }
 
+/*
+ * Find the place in `snapshot->buf` where the start of the record for
+ * `refname` starts. If `mustexist` is true and the reference doesn't
+ * exist, then return NULL. If `mustexist` is false and the reference
+ * doesn't exist, then return the point where that reference would be
+ * inserted, or `snapshot->eof` (which might be NULL) if it would be
+ * inserted at the end of the file. In the latter mode, `refname`
+ * doesn't have to be a proper reference name; for example, one could
+ * search for "refs/replace/" to find the start of any replace
+ * references.
+ *
+ * The record is sought using a binary search, so `snapshot->buf` must
+ * be sorted.
+ */
+static const char *find_reference_location(struct snapshot *snapshot,
+                                          const char *refname, int mustexist)
+{
+       return find_reference_location_1(snapshot, refname, mustexist, 1);
+}
+
+/*
+ * Find the place in `snapshot->buf` after the end of the record for
+ * `refname`. In other words, find the location of first thing *after*
+ * `refname`.
+ *
+ * Other semantics are identical to the ones in
+ * `find_reference_location()`.
+ */
+static const char *find_reference_location_end(struct snapshot *snapshot,
+                                              const char *refname,
+                                              int mustexist)
+{
+       return find_reference_location_1(snapshot, refname, mustexist, 0);
+}
+
 /*
  * Create a newly-allocated `snapshot` of the `packed-refs` file in
  * its current state and return it. The return value will already have
@@ -779,6 +804,13 @@ struct packed_ref_iterator {
        /* The end of the part of the buffer that will be iterated over: */
        const char *eof;
 
+       struct jump_list_entry {
+               const char *start;
+               const char *end;
+       } *jump;
+       size_t jump_nr, jump_alloc;
+       size_t jump_cur;
+
        /* Scratch space for current values: */
        struct object_id oid, peeled;
        struct strbuf refname_buf;
@@ -796,14 +828,36 @@ struct packed_ref_iterator {
  */
 static int next_record(struct packed_ref_iterator *iter)
 {
-       const char *p = iter->pos, *eol;
+       const char *p, *eol;
 
        strbuf_reset(&iter->refname_buf);
 
+       /*
+        * If iter->pos is contained within a skipped region, jump past
+        * it.
+        *
+        * Note that each skipped region is considered at most once,
+        * since they are ordered based on their starting position.
+        */
+       while (iter->jump_cur < iter->jump_nr) {
+               struct jump_list_entry *curr = &iter->jump[iter->jump_cur];
+               if (iter->pos < curr->start)
+                       break; /* not to the next jump yet */
+
+               iter->jump_cur++;
+               if (iter->pos < curr->end) {
+                       iter->pos = curr->end;
+                       trace2_counter_add(TRACE2_COUNTER_ID_PACKED_REFS_JUMPS, 1);
+                       /* jumps are coalesced, so only one jump is necessary */
+                       break;
+               }
+       }
+
        if (iter->pos == iter->eof)
                return ITER_DONE;
 
        iter->base.flags = REF_ISPACKED;
+       p = iter->pos;
 
        if (iter->eof - p < the_hash_algo->hexsz + 2 ||
            parse_oid_hex(p, &iter->oid, &p) ||
@@ -911,6 +965,7 @@ static int packed_ref_iterator_abort(struct ref_iterator *ref_iterator)
        int ok = ITER_DONE;
 
        strbuf_release(&iter->refname_buf);
+       free(iter->jump);
        release_snapshot(iter->snapshot);
        base_ref_iterator_free(ref_iterator);
        return ok;
@@ -922,9 +977,112 @@ static struct ref_iterator_vtable packed_ref_iterator_vtable = {
        .abort = packed_ref_iterator_abort
 };
 
+static int jump_list_entry_cmp(const void *va, const void *vb)
+{
+       const struct jump_list_entry *a = va;
+       const struct jump_list_entry *b = vb;
+
+       if (a->start < b->start)
+               return -1;
+       if (a->start > b->start)
+               return 1;
+       return 0;
+}
+
+static int has_glob_special(const char *str)
+{
+       const char *p;
+       for (p = str; *p; p++) {
+               if (is_glob_special(*p))
+                       return 1;
+       }
+       return 0;
+}
+
+static void populate_excluded_jump_list(struct packed_ref_iterator *iter,
+                                       struct snapshot *snapshot,
+                                       const char **excluded_patterns)
+{
+       size_t i, j;
+       const char **pattern;
+       struct jump_list_entry *last_disjoint;
+
+       if (!excluded_patterns)
+               return;
+
+       for (pattern = excluded_patterns; *pattern; pattern++) {
+               struct jump_list_entry *e;
+               const char *start, *end;
+
+               /*
+                * We can't feed any excludes with globs in them to the
+                * refs machinery.  It only understands prefix matching.
+                * We likewise can't even feed the string leading up to
+                * the first meta-character, as something like "foo[a]"
+                * should not exclude "foobar" (but the prefix "foo"
+                * would match that and mark it for exclusion).
+                */
+               if (has_glob_special(*pattern))
+                       continue;
+
+               start = find_reference_location(snapshot, *pattern, 0);
+               end = find_reference_location_end(snapshot, *pattern, 0);
+
+               if (start == end)
+                       continue; /* nothing to jump over */
+
+               ALLOC_GROW(iter->jump, iter->jump_nr + 1, iter->jump_alloc);
+
+               e = &iter->jump[iter->jump_nr++];
+               e->start = start;
+               e->end = end;
+       }
+
+       if (!iter->jump_nr) {
+               /*
+                * Every entry in exclude_patterns has a meta-character,
+                * nothing to do here.
+                */
+               return;
+       }
+
+       QSORT(iter->jump, iter->jump_nr, jump_list_entry_cmp);
+
+       /*
+        * As an optimization, merge adjacent entries in the jump list
+        * to jump forwards as far as possible when entering a skipped
+        * region.
+        *
+        * For example, if we have two skipped regions:
+        *
+        *      [[A, B], [B, C]]
+        *
+        * we want to combine that into a single entry jumping from A to
+        * C.
+        */
+       last_disjoint = iter->jump;
+
+       for (i = 1, j = 1; i < iter->jump_nr; i++) {
+               struct jump_list_entry *ours = &iter->jump[i];
+               if (ours->start <= last_disjoint->end) {
+                       /* overlapping regions extend the previous one */
+                       last_disjoint->end = last_disjoint->end > ours->end
+                               ? last_disjoint->end : ours->end;
+               } else {
+                       /* otherwise, insert a new region */
+                       iter->jump[j++] = *ours;
+                       last_disjoint = ours;
+               }
+       }
+
+       iter->jump_nr = j;
+       iter->jump_cur = 0;
+}
+
 static struct ref_iterator *packed_ref_iterator_begin(
                struct ref_store *ref_store,
-               const char *prefix, unsigned int flags)
+               const char *prefix, const char **exclude_patterns,
+               unsigned int flags)
 {
        struct packed_ref_store *refs;
        struct snapshot *snapshot;
@@ -956,6 +1114,9 @@ static struct ref_iterator *packed_ref_iterator_begin(
        ref_iterator = &iter->base;
        base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable, 1);
 
+       if (exclude_patterns)
+               populate_excluded_jump_list(iter, snapshot, exclude_patterns);
+
        iter->snapshot = snapshot;
        acquire_snapshot(snapshot);
 
@@ -1149,7 +1310,7 @@ static int write_with_updates(struct packed_ref_store *refs,
         * list of refs is exhausted, set iter to NULL. When the list
         * of updates is exhausted, leave i set to updates->nr.
         */
-       iter = packed_ref_iterator_begin(&refs->base, "",
+       iter = packed_ref_iterator_begin(&refs->base, "", NULL,
                                         DO_FOR_EACH_INCLUDE_BROKEN);
        if ((ok = ref_iterator_advance(iter)) != ITER_OK)
                iter = NULL;
@@ -1577,7 +1738,7 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
 }
 
 static int packed_pack_refs(struct ref_store *ref_store UNUSED,
-                           unsigned int flags UNUSED)
+                           struct pack_refs_opts *pack_opts UNUSED)
 {
        /*
         * Packed refs are already packed. It might be that loose refs
index 2294c4564fba3e171334314a5623928c5f27c14a..6e3b725245c3e8df1ec666cc23ab51b718be1d1f 100644 (file)
@@ -412,7 +412,8 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
 
                if (level->prefix_state == PREFIX_WITHIN_DIR) {
                        entry_prefix_state = overlaps_prefix(entry->name, iter->prefix);
-                       if (entry_prefix_state == PREFIX_EXCLUDES_DIR)
+                       if (entry_prefix_state == PREFIX_EXCLUDES_DIR ||
+                           (entry_prefix_state == PREFIX_WITHIN_DIR && !(entry->flag & REF_DIR)))
                                continue;
                } else {
                        entry_prefix_state = level->prefix_state;
index a85d113123c99b55e1e7047d334c7608843eb2d6..9db8aec4da8eef6fb9542a9db5d1cbae01c129e6 100644 (file)
@@ -367,8 +367,8 @@ int is_empty_ref_iterator(struct ref_iterator *ref_iterator);
  */
 struct ref_iterator *refs_ref_iterator_begin(
                struct ref_store *refs,
-               const char *prefix, int trim,
-               enum do_for_each_ref_flags flags);
+               const char *prefix, const char **exclude_patterns,
+               int trim, enum do_for_each_ref_flags flags);
 
 /*
  * A callback function used to instruct merge_ref_iterator how to
@@ -547,7 +547,8 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,
                                      struct ref_transaction *transaction,
                                      struct strbuf *err);
 
-typedef int pack_refs_fn(struct ref_store *ref_store, unsigned int flags);
+typedef int pack_refs_fn(struct ref_store *ref_store,
+                        struct pack_refs_opts *opts);
 typedef int create_symref_fn(struct ref_store *ref_store,
                             const char *ref_target,
                             const char *refs_heads_master,
@@ -570,7 +571,8 @@ typedef int copy_ref_fn(struct ref_store *ref_store,
  */
 typedef struct ref_iterator *ref_iterator_begin_fn(
                struct ref_store *ref_store,
-               const char *prefix, unsigned int flags);
+               const char *prefix, const char **exclude_patterns,
+               unsigned int flags);
 
 /* reflog functions */
 
index 57f6c2aaf9bf2ad4d66bcbbc87c7d778383f172c..d60932f4ded876476b7dec21456b9088260d0d1f 100644 (file)
--- a/refspec.c
+++ b/refspec.c
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "gettext.h"
 #include "hash.h"
 #include "hex.h"
index acf7b2bb40ac4edc07e98934a51c4d69711bc6cb..ef05752ca5738ea16d16d38c8ea9c65e2a9ea167 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -763,7 +762,8 @@ static void check_pktline(struct check_pktline_state *state, const char *ptr, si
                        size -= digits_remaining;
 
                        if (state->len_filled == 4) {
-                               state->remaining = packet_length(state->len_buf);
+                               state->remaining = packet_length(state->len_buf,
+                                                                sizeof(state->len_buf));
                                if (state->remaining < 0) {
                                        die(_("remote-curl: bad line length character: %.4s"), state->len_buf);
                                } else if (state->remaining == 2) {
index 0764fca0db9978336ae5ae13f79853d44a1e0944..abb24822beb2a17187d4afa9474dd1c537f078ba 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -10,7 +9,8 @@
 #include "refs.h"
 #include "refspec.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
@@ -349,7 +349,8 @@ static void read_branches_file(struct remote_state *remote_state,
        remote->fetch_tags = 1; /* always auto-follow */
 }
 
-static int handle_config(const char *key, const char *value, void *cb)
+static int handle_config(const char *key, const char *value,
+                        const struct config_context *ctx, void *cb)
 {
        const char *name;
        size_t namelen;
@@ -357,6 +358,7 @@ static int handle_config(const char *key, const char *value, void *cb)
        struct remote *remote;
        struct branch *branch;
        struct remote_state *remote_state = cb;
+       const struct key_value_info *kvi = ctx->kvi;
 
        if (parse_config_key(key, "branch", &name, &namelen, &subkey) >= 0) {
                /* There is no subsection. */
@@ -414,8 +416,8 @@ static int handle_config(const char *key, const char *value, void *cb)
        }
        remote = make_remote(remote_state, name, namelen);
        remote->origin = REMOTE_CONFIG;
-       if (current_config_scope() == CONFIG_SCOPE_LOCAL ||
-           current_config_scope() == CONFIG_SCOPE_WORKTREE)
+       if (kvi->scope == CONFIG_SCOPE_LOCAL ||
+           kvi->scope == CONFIG_SCOPE_WORKTREE)
                remote->configured_in_repo = 1;
        if (!strcmp(subkey, "mirror"))
                remote->mirror = git_config_bool(key, value);
@@ -890,7 +892,7 @@ static int query_matches_negative_refspec(struct refspec *rs, struct refspec_ite
 {
        int i, matched_negative = 0;
        int find_src = !query->src;
-       struct string_list reversed = STRING_LIST_INIT_NODUP;
+       struct string_list reversed = STRING_LIST_INIT_DUP;
        const char *needle = find_src ? query->dst : query->src;
 
        /*
@@ -2257,7 +2259,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
  * Return true when there is anything to report, otherwise false.
  */
 int format_tracking_info(struct branch *branch, struct strbuf *sb,
-                        enum ahead_behind_flags abf)
+                        enum ahead_behind_flags abf,
+                        int show_divergence_advice)
 {
        int ours, theirs, sti;
        const char *full_base;
@@ -2320,9 +2323,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
                               "respectively.\n",
                           ours + theirs),
                        base, ours, theirs);
-               if (advice_enabled(ADVICE_STATUS_HINTS))
+               if (show_divergence_advice &&
+                   advice_enabled(ADVICE_STATUS_HINTS))
                        strbuf_addstr(sb,
-                               _("  (use \"git pull\" to merge the remote branch into yours)\n"));
+                               _("  (use \"git pull\" if you want to integrate the remote branch with yours)\n"));
        }
        free(base);
        return 1;
index 73638cefeb102d6dd9a6777645156a2034594240..cdc8b1db42c4a836804009a036628aaa94d94b5a 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -1,6 +1,7 @@
 #ifndef REMOTE_H
 #define REMOTE_H
 
+#include "hash-ll.h"
 #include "hashmap.h"
 #include "refspec.h"
 
@@ -379,7 +380,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
                       const char **upstream_name, int for_push,
                       enum ahead_behind_flags abf);
 int format_tracking_info(struct branch *branch, struct strbuf *sb,
-                        enum ahead_behind_flags abf);
+                        enum ahead_behind_flags abf,
+                        int show_divergence_advice);
 
 struct ref *get_local_heads(void);
 /*
index e98825d5852d80f6799904e4b0280f438375b75a..523215589de9221b0823aab9edbb06389ca52825 100644 (file)
@@ -2,7 +2,7 @@
 #include "gettext.h"
 #include "hex.h"
 #include "oidmap.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "replace-object.h"
 #include "refs.h"
 #include "repository.h"
@@ -64,7 +64,7 @@ void prepare_replace_object(struct repository *r)
  * replacement object's name (replaced recursively, if necessary).
  * The return value is either oid or a pointer to a
  * permanently-allocated value.  This function always respects replace
- * references, regardless of the value of read_replace_refs.
+ * references, regardless of the value of r->settings.read_replace_refs.
  */
 const struct object_id *do_lookup_replace_object(struct repository *r,
                                                 const struct object_id *oid)
@@ -84,3 +84,29 @@ const struct object_id *do_lookup_replace_object(struct repository *r,
        }
        die(_("replace depth too high for object %s"), oid_to_hex(oid));
 }
+
+/*
+ * This indicator determines whether replace references should be
+ * respected process-wide, regardless of which repository is being
+ * using at the time.
+ */
+static int read_replace_refs = 1;
+
+void disable_replace_refs(void)
+{
+       read_replace_refs = 0;
+}
+
+int replace_refs_enabled(struct repository *r)
+{
+       if (!read_replace_refs)
+               return 0;
+
+       if (r->gitdir) {
+               prepare_repo_settings(r);
+               return r->settings.read_replace_refs;
+       }
+
+       /* repository has no objects or refs. */
+       return 0;
+}
index 500482b02b38ce30ee51a005d00ca00e76033f19..66c41b938b44f4ba0a94521c4344aca0ca19087e 100644 (file)
@@ -3,15 +3,7 @@
 
 #include "oidmap.h"
 #include "repository.h"
-#include "object-store.h"
-
-/*
- * Do replace refs need to be checked this run?  This variable is
- * initialized to true unless --no-replace-object is used or
- * $GIT_NO_REPLACE_OBJECTS is set, but is set to false by some
- * commands that do not want replace references to be active.
- */
-extern int read_replace_refs;
+#include "object-store-ll.h"
 
 struct replace_object {
        struct oidmap_entry original;
@@ -27,6 +19,18 @@ void prepare_replace_object(struct repository *r);
 const struct object_id *do_lookup_replace_object(struct repository *r,
                                                 const struct object_id *oid);
 
+/*
+ * Some commands disable replace-refs unconditionally, and otherwise each
+ * repository could alter the core.useReplaceRefs config value.
+ *
+ * Return 1 if and only if all of the following are true:
+ *
+ *  a. disable_replace_refs() has not been called.
+ *  b. GIT_NO_REPLACE_OBJECTS is unset or zero.
+ *  c. the given repository does not have core.useReplaceRefs=false.
+ */
+int replace_refs_enabled(struct repository *r);
+
 /*
  * If object sha1 should be replaced, return the replacement object's
  * name (replaced recursively, if necessary).  The return value is
@@ -41,11 +45,19 @@ const struct object_id *do_lookup_replace_object(struct repository *r,
 static inline const struct object_id *lookup_replace_object(struct repository *r,
                                                            const struct object_id *oid)
 {
-       if (!read_replace_refs ||
+       if (!replace_refs_enabled(r) ||
            (r->objects->replace_map_initialized &&
             r->objects->replace_map->map.tablesize == 0))
                return oid;
        return do_lookup_replace_object(r, oid);
 }
 
+/*
+ * Some commands override config and environment settings for using
+ * replace references. Use this method to disable the setting and ensure
+ * those other settings will not override this choice. This applies
+ * globally to all in-process repositories.
+ */
+void disable_replace_refs(void);
+
 #endif /* REPLACE_OBJECT_H */
index d220c5dd9fefa5e9ec3481c24bc302ddfb00bc5e..525f69c0c7785845cdf8991e56c8d231c2e6d239 100644 (file)
@@ -41,8 +41,10 @@ void prepare_repo_settings(struct repository *r)
        repo_cfg_bool(r, "feature.experimental", &experimental, 0);
 
        /* Defaults modified by feature.* */
-       if (experimental)
+       if (experimental) {
                r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
+               r->settings.pack_use_bitmap_boundary_traversal = 1;
+       }
        if (manyfiles) {
                r->settings.index_version = 4;
                r->settings.index_skip_hash = 1;
@@ -62,6 +64,10 @@ void prepare_repo_settings(struct repository *r)
        repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
        repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
        repo_cfg_bool(r, "pack.readreverseindex", &r->settings.pack_read_reverse_index, 1);
+       repo_cfg_bool(r, "pack.usebitmapboundarytraversal",
+                     &r->settings.pack_use_bitmap_boundary_traversal,
+                     r->settings.pack_use_bitmap_boundary_traversal);
+       repo_cfg_bool(r, "core.usereplacerefs", &r->settings.read_replace_refs, 1);
 
        /*
         * The GIT_TEST_MULTI_PACK_INDEX variable is special in that
index c53e480e32601e0ba4ba63ea9ba31accde57a46b..a7679ceeaa45ce7a20094f9a29a82987290ad354 100644 (file)
@@ -3,13 +3,15 @@
  * declaration matches the definition in this file.
  */
 #define USE_THE_INDEX_VARIABLE
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "config.h"
 #include "object.h"
 #include "lockfile.h"
+#include "path.h"
+#include "read-cache-ll.h"
 #include "remote.h"
 #include "setup.h"
 #include "submodule-config.h"
@@ -182,6 +184,7 @@ int repo_init(struct repository *repo,
                goto error;
 
        repo_set_hash_algo(repo, format.hash_algo);
+       repo->repository_format_worktree_config = format.worktree_config;
 
        /* take ownership of format.partial_clone */
        repo->repository_format_partial_clone = format.partial_clone;
index 1a13ff28677ec0db952971c48ef725347c34bda0..5f18486f6465c44b44abb2ded74bcdda14ba7bd9 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef REPOSITORY_H
 #define REPOSITORY_H
 
-#include "path.h"
-
 struct config_set;
 struct fsmonitor_settings;
 struct git_hash_algo;
@@ -37,6 +35,16 @@ struct repo_settings {
        int command_requires_full_index;
        int sparse_index;
        int pack_read_reverse_index;
+       int pack_use_bitmap_boundary_traversal;
+
+       /*
+        * Does this repository have core.useReplaceRefs=true (on by
+        * default)? This provides a repository-scoped version of this
+        * config, though it could be disabled process-wide via some Git
+        * builtins or the --no-replace-objects option. See
+        * replace_refs_enabled() for more details.
+        */
+       int read_replace_refs;
 
        struct fsmonitor_settings *fsmonitor; /* lazily loaded */
 
@@ -163,12 +171,16 @@ struct repository {
        struct promisor_remote_config *promisor_remote_config;
 
        /* Configurations */
+       int repository_format_worktree_config;
 
        /* Indicate if a repository has a different 'commondir' from 'gitdir' */
        unsigned different_commondir:1;
 };
 
 extern struct repository *the_repository;
+#ifdef USE_THE_INDEX_VARIABLE
+extern struct index_state the_index;
+#endif
 
 /*
  * Define a custom repository layout. Any field can be NULL, which
@@ -220,9 +232,6 @@ int repo_hold_locked_index(struct repository *repo,
                           struct lock_file *lf,
                           int flags);
 
-int repo_read_index_preload(struct repository *,
-                           const struct pathspec *pathspec,
-                           unsigned refresh_flags);
 int repo_read_index_unmerged(struct repository *);
 /*
  * Opportunistically update the index but do not complain if we can't.
index e968d413d65bd63ef8cc03285d51049505104482..09e19412859b3edb7be4142947d3967fc76520cc 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -1,24 +1,24 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "config.h"
 #include "copy.h"
 #include "gettext.h"
 #include "hex.h"
 #include "lockfile.h"
 #include "string-list.h"
+#include "read-cache-ll.h"
 #include "rerere.h"
 #include "xdiff-interface.h"
 #include "dir.h"
 #include "resolve-undo.h"
-#include "ll-merge.h"
+#include "merge-ll.h"
 #include "attr.h"
+#include "path.h"
 #include "pathspec.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "hash-lookup.h"
 #include "strmap.h"
-#include "wrapper.h"
 
 #define RESOLVED 0
 #define PUNTED 1
@@ -204,7 +204,7 @@ static void read_rr(struct repository *r, struct string_list *rr)
                const unsigned hexsz = the_hash_algo->hexsz;
 
                /* There has to be the hash, tab, path and then NUL */
-               if (buf.len < hexsz + 2 || get_sha1_hex(buf.buf, hash))
+               if (buf.len < hexsz + 2 || get_hash_hex(buf.buf, hash))
                        die(_("corrupt MERGE_RR"));
 
                if (buf.buf[hexsz] != '.') {
@@ -1112,7 +1112,7 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
         * recover the original conflicted state and then
         * find the conflicted paths.
         */
-       unmerge_index(r->index, pathspec);
+       unmerge_index(r->index, pathspec, 0);
        find_conflict(r, &conflict);
        for (i = 0; i < conflict.nr; i++) {
                struct string_list_item *it = &conflict.items[i];
index 70a6db526d240da717aa7b926e10bbcddbe845a3..cd02dc99289997e5bf3ac57da3a0c5d482a8301d 100644 (file)
@@ -1,7 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "dir.h"
 #include "hash.h"
+#include "read-cache.h"
 #include "resolve-undo.h"
+#include "sparse-index.h"
 #include "string-list.h"
 
 /* The only error case is to run out of memory in string-list */
@@ -115,86 +117,59 @@ void resolve_undo_clear_index(struct index_state *istate)
        istate->cache_changed |= RESOLVE_UNDO_CHANGED;
 }
 
-int unmerge_index_entry_at(struct index_state *istate, int pos)
+int unmerge_index_entry(struct index_state *istate, const char *path,
+                       struct resolve_undo_info *ru, unsigned ce_flags)
 {
-       const struct cache_entry *ce;
-       struct string_list_item *item;
-       struct resolve_undo_info *ru;
-       int i, err = 0, matched;
-       char *name;
-
-       if (!istate->resolve_undo)
-               return pos;
-
-       ce = istate->cache[pos];
-       if (ce_stage(ce)) {
-               /* already unmerged */
-               while ((pos < istate->cache_nr) &&
-                      ! strcmp(istate->cache[pos]->name, ce->name))
-                       pos++;
-               return pos - 1; /* return the last entry processed */
+       int i = index_name_pos(istate, path, strlen(path));
+
+       if (i < 0) {
+               /* unmerged? */
+               i = -i - 1;
+               if (i < istate->cache_nr &&
+                   !strcmp(istate->cache[i]->name, path))
+                       /* yes, it is already unmerged */
+                       return 0;
+               /* fallthru: resolved to removal */
+       } else {
+               /* merged - remove it to replace it with unmerged entries */
+               remove_index_entry_at(istate, i);
        }
-       item = string_list_lookup(istate->resolve_undo, ce->name);
-       if (!item)
-               return pos;
-       ru = item->util;
-       if (!ru)
-               return pos;
-       matched = ce->ce_flags & CE_MATCHED;
-       name = xstrdup(ce->name);
-       remove_index_entry_at(istate, pos);
+
        for (i = 0; i < 3; i++) {
-               struct cache_entry *nce;
+               struct cache_entry *ce;
                if (!ru->mode[i])
                        continue;
-               nce = make_cache_entry(istate,
-                                      ru->mode[i],
-                                      &ru->oid[i],
-                                      name, i + 1, 0);
-               if (matched)
-                       nce->ce_flags |= CE_MATCHED;
-               if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
-                       err = 1;
-                       error("cannot unmerge '%s'", name);
-               }
+               ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
+                                     path, i + 1, 0);
+               ce->ce_flags |= ce_flags;
+               if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
+                       return error("cannot unmerge '%s'", path);
        }
-       free(name);
-       if (err)
-               return pos;
-       free(ru);
-       item->util = NULL;
-       return unmerge_index_entry_at(istate, pos);
+       return 0;
 }
 
-void unmerge_marked_index(struct index_state *istate)
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,
+                  unsigned ce_flags)
 {
-       int i;
+       struct string_list_item *item;
 
        if (!istate->resolve_undo)
                return;
 
        /* TODO: audit for interaction with sparse-index. */
        ensure_full_index(istate);
-       for (i = 0; i < istate->cache_nr; i++) {
-               const struct cache_entry *ce = istate->cache[i];
-               if (ce->ce_flags & CE_MATCHED)
-                       i = unmerge_index_entry_at(istate, i);
-       }
-}
 
-void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
-{
-       int i;
-
-       if (!istate->resolve_undo)
-               return;
-
-       /* TODO: audit for interaction with sparse-index. */
-       ensure_full_index(istate);
-       for (i = 0; i < istate->cache_nr; i++) {
-               const struct cache_entry *ce = istate->cache[i];
-               if (!ce_path_match(istate, ce, pathspec, NULL))
+       for_each_string_list_item(item, istate->resolve_undo) {
+               const char *path = item->string;
+               struct resolve_undo_info *ru = item->util;
+               if (!item->util)
+                       continue;
+               if (!match_pathspec(istate, pathspec,
+                                   item->string, strlen(item->string),
+                                   0, NULL, 0))
                        continue;
-               i = unmerge_index_entry_at(istate, i);
+               unmerge_index_entry(istate, path, ru, ce_flags);
+               free(ru);
+               item->util = NULL;
        }
 }
index c5deafc92fe7751532162ec308cf2bd62d97cf1b..f3f8462751bfd2e7fb2ab38b2632f059b8f07013 100644 (file)
@@ -17,8 +17,7 @@ void record_resolve_undo(struct index_state *, struct cache_entry *);
 void resolve_undo_write(struct strbuf *, struct string_list *);
 struct string_list *resolve_undo_read(const char *, unsigned long);
 void resolve_undo_clear_index(struct index_state *);
-int unmerge_index_entry_at(struct index_state *, int);
-void unmerge_index(struct index_state *, const struct pathspec *);
-void unmerge_marked_index(struct index_state *);
+int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned);
+void unmerge_index(struct index_state *, const struct pathspec *, unsigned);
 
 #endif
index b33cc1d106a207de3c5a42c413913877c129a28d..219dc76716fb0611ae8e7eb3dc10522d8779b213 100644 (file)
@@ -1,12 +1,11 @@
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object-name.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "tag.h"
 #include "blob.h"
 #include "tree.h"
@@ -31,7 +30,9 @@
 #include "bisect.h"
 #include "packfile.h"
 #include "worktree.h"
+#include "read-cache.h"
 #include "setup.h"
+#include "sparse-index.h"
 #include "strvec.h"
 #include "trace2.h"
 #include "commit-reach.h"
@@ -44,6 +45,7 @@
 #include "list-objects-filter-options.h"
 #include "resolve-undo.h"
 #include "parse-options.h"
+#include "wildmatch.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -1558,7 +1560,7 @@ void init_ref_exclusions(struct ref_exclusions *exclusions)
 void clear_ref_exclusions(struct ref_exclusions *exclusions)
 {
        string_list_clear(&exclusions->excluded_refs, 0);
-       string_list_clear(&exclusions->hidden_refs, 0);
+       strvec_clear(&exclusions->hidden_refs);
        exclusions->hidden_refs_configured = 0;
 }
 
@@ -1572,7 +1574,9 @@ struct exclude_hidden_refs_cb {
        const char *section;
 };
 
-static int hide_refs_config(const char *var, const char *value, void *cb_data)
+static int hide_refs_config(const char *var, const char *value,
+                           const struct config_context *ctx UNUSED,
+                           void *cb_data)
 {
        struct exclude_hidden_refs_cb *cb = cb_data;
        cb->exclusions->hidden_refs_configured = 1;
@@ -2195,39 +2199,6 @@ static void read_pathspec_from_stdin(struct strbuf *sb,
                strvec_push(prune, sb->buf);
 }
 
-static void read_revisions_from_stdin(struct rev_info *revs,
-                                     struct strvec *prune)
-{
-       struct strbuf sb;
-       int seen_dashdash = 0;
-       int save_warning;
-
-       save_warning = warn_on_object_refname_ambiguity;
-       warn_on_object_refname_ambiguity = 0;
-
-       strbuf_init(&sb, 1000);
-       while (strbuf_getline(&sb, stdin) != EOF) {
-               int len = sb.len;
-               if (!len)
-                       break;
-               if (sb.buf[0] == '-') {
-                       if (len == 2 && sb.buf[1] == '-') {
-                               seen_dashdash = 1;
-                               break;
-                       }
-                       die("options not supported in --stdin mode");
-               }
-               if (handle_revision_arg(sb.buf, revs, 0,
-                                       REVARG_CANNOT_BE_FILENAME))
-                       die("bad revision '%s'", sb.buf);
-       }
-       if (seen_dashdash)
-               read_pathspec_from_stdin(&sb, prune);
-
-       strbuf_release(&sb);
-       warn_on_object_refname_ambiguity = save_warning;
-}
-
 static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what)
 {
        append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what);
@@ -2513,6 +2484,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->break_bar = xstrdup(optarg);
                revs->track_linear = 1;
                revs->track_first_time = 1;
+       } else if (!strcmp(arg, "--show-notes-by-default")) {
+               revs->show_notes_by_default = 1;
        } else if (skip_prefix(arg, "--show-notes=", &optarg) ||
                   skip_prefix(arg, "--notes=", &optarg)) {
                if (starts_with(arg, "--show-notes=") &&
@@ -2670,7 +2643,7 @@ static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
        struct strbuf bisect_refs = STRBUF_INIT;
        int status;
        strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
-       status = refs_for_each_fullref_in(refs, bisect_refs.buf, fn, cb_data);
+       status = refs_for_each_fullref_in(refs, bisect_refs.buf, NULL, fn, cb_data);
        strbuf_release(&bisect_refs);
        return status;
 }
@@ -2816,6 +2789,53 @@ static int handle_revision_pseudo_opt(struct rev_info *revs,
        return 1;
 }
 
+static void read_revisions_from_stdin(struct rev_info *revs,
+                                     struct strvec *prune)
+{
+       struct strbuf sb;
+       int seen_dashdash = 0;
+       int seen_end_of_options = 0;
+       int save_warning;
+       int flags = 0;
+
+       save_warning = warn_on_object_refname_ambiguity;
+       warn_on_object_refname_ambiguity = 0;
+
+       strbuf_init(&sb, 1000);
+       while (strbuf_getline(&sb, stdin) != EOF) {
+               if (!sb.len)
+                       break;
+
+               if (!strcmp(sb.buf, "--")) {
+                       seen_dashdash = 1;
+                       break;
+               }
+
+               if (!seen_end_of_options && sb.buf[0] == '-') {
+                       const char *argv[] = { sb.buf, NULL };
+
+                       if (!strcmp(sb.buf, "--end-of-options")) {
+                               seen_end_of_options = 1;
+                               continue;
+                       }
+
+                       if (handle_revision_pseudo_opt(revs, argv, &flags) > 0)
+                               continue;
+
+                       die(_("invalid option '%s' in --stdin mode"), sb.buf);
+               }
+
+               if (handle_revision_arg(sb.buf, revs, flags,
+                                       REVARG_CANNOT_BE_FILENAME))
+                       die("bad revision '%s'", sb.buf);
+       }
+       if (seen_dashdash)
+               read_pathspec_from_stdin(&sb, prune);
+
+       strbuf_release(&sb);
+       warn_on_object_refname_ambiguity = save_warning;
+}
+
 static void NORETURN diagnose_missing_default(const char *def)
 {
        int flags;
@@ -2952,7 +2972,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (!revs->def)
                revs->def = opt ? opt->def : NULL;
        if (opt && opt->tweak)
-               opt->tweak(revs, opt);
+               opt->tweak(revs);
        if (revs->show_merge)
                prepare_show_merge(revs);
        if (revs->def && !revs->pending.nr && !revs->rev_input_given) {
@@ -3036,6 +3056,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (revs->expand_tabs_in_log < 0)
                revs->expand_tabs_in_log = revs->expand_tabs_in_log_default;
 
+       if (!revs->show_notes_given && revs->show_notes_by_default) {
+               enable_default_display_notes(&revs->notes_opt, &revs->show_notes);
+               revs->show_notes_given = 1;
+       }
+
        return left;
 }
 
@@ -3058,6 +3083,11 @@ static void release_revisions_mailmap(struct string_list *mailmap)
 
 static void release_revisions_topo_walk_info(struct topo_walk_info *info);
 
+static void free_void_commit_list(void *list)
+{
+       free_commit_list(list);
+}
+
 void release_revisions(struct rev_info *revs)
 {
        free_commit_list(revs->commits);
@@ -3075,6 +3105,10 @@ void release_revisions(struct rev_info *revs)
        diff_free(&revs->pruning);
        reflog_walk_info_release(revs->reflog_info);
        release_revisions_topo_walk_info(revs->topo_walk_info);
+       clear_decoration(&revs->children, free_void_commit_list);
+       clear_decoration(&revs->merge_simplification, free);
+       clear_decoration(&revs->treesame, free);
+       line_log_free(revs);
 }
 
 static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
index 31828748dc09af96afd24b965d037b70b37822ae..50091bbd13f07ffd633446c6e0c392c01bd4152f 100644 (file)
@@ -10,6 +10,7 @@
 #include "decorate.h"
 #include "ident.h"
 #include "list-objects-filter-options.h"
+#include "strvec.h"
 
 /**
  * The revision walking API offers functions to build a list of revisions
@@ -87,7 +88,7 @@ struct rev_cmdline_info {
 struct ref_exclusions {
        /*
         * Excluded refs is a list of wildmatch patterns. If any of the
-        * patterns matches, the reference will be excluded.
+        * patterns match, the reference will be excluded.
         */
        struct string_list excluded_refs;
 
@@ -95,7 +96,7 @@ struct ref_exclusions {
         * Hidden refs is a list of patterns that is to be hidden via
         * `ref_is_hidden()`.
         */
-       struct string_list hidden_refs;
+       struct strvec hidden_refs;
 
        /*
         * Indicates whether hidden refs have been configured. This is to
@@ -110,7 +111,7 @@ struct ref_exclusions {
  */
 #define REF_EXCLUSIONS_INIT { \
        .excluded_refs = STRING_LIST_INIT_DUP, \
-       .hidden_refs = STRING_LIST_INIT_DUP, \
+       .hidden_refs = STRVEC_INIT, \
 }
 
 struct oidset;
@@ -252,6 +253,7 @@ struct rev_info {
                        shown_dashes:1,
                        show_merge:1,
                        show_notes_given:1,
+                       show_notes_by_default:1,
                        show_signature:1,
                        pretty_given:1,
                        abbrev_commit:1,
@@ -428,7 +430,7 @@ void repo_init_revisions(struct repository *r,
  */
 struct setup_revision_opt {
        const char *def;
-       void (*tweak)(struct rev_info *, struct setup_revision_opt *);
+       void (*tweak)(struct rev_info *);
        unsigned int    assume_dashdash:1,
                        allow_exclude_promisor_objects:1,
                        free_removed_argv_elements:1;
index 60c94198664738159fbae86afeb49bccd15f25e3..a558042c876ad2baefcfcc111163bab9691f7f1c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "run-command.h"
 #include "environment.h"
 #include "exec-cmd.h"
@@ -170,6 +170,7 @@ int is_executable(const char *name)
        return st.st_mode & S_IXUSR;
 }
 
+#ifndef locate_in_PATH
 /*
  * Search $PATH for a command.  This emulates the path search that
  * execvp would perform, without actually executing the command so it
@@ -218,6 +219,7 @@ static char *locate_in_PATH(const char *file)
        strbuf_release(&buf);
        return NULL;
 }
+#endif
 
 int exists_in_PATH(const char *command)
 {
@@ -307,7 +309,6 @@ enum child_errcode {
        CHILD_ERR_DUP2,
        CHILD_ERR_CLOSE,
        CHILD_ERR_SIGPROCMASK,
-       CHILD_ERR_ENOENT,
        CHILD_ERR_SILENT,
        CHILD_ERR_ERRNO
 };
@@ -390,9 +391,6 @@ static void child_err_spew(struct child_process *cmd, struct child_err *cerr)
        case CHILD_ERR_SIGPROCMASK:
                error_errno("sigprocmask failed restoring signals");
                break;
-       case CHILD_ERR_ENOENT:
-               error_errno("cannot run %s", cmd->args.v[0]);
-               break;
        case CHILD_ERR_SILENT:
                break;
        case CHILD_ERR_ERRNO:
@@ -846,13 +844,9 @@ fail_pipe:
                        execve(argv.v[0], (char *const *) argv.v,
                               (char *const *) childenv);
 
-               if (errno == ENOENT) {
-                       if (cmd->silent_exec_failure)
-                               child_die(CHILD_ERR_SILENT);
-                       child_die(CHILD_ERR_ENOENT);
-               } else {
-                       child_die(CHILD_ERR_ERRNO);
-               }
+               if (cmd->silent_exec_failure && errno == ENOENT)
+                       child_die(CHILD_ERR_SILENT);
+               child_die(CHILD_ERR_ERRNO);
        }
        atfork_parent(&as);
        if (cmd->pid < 0)
index 072db56a4dff15996889bded735dd02f2bc52e73..1f22cc3827d7d0c53119d085c3ef53a6ab3c36fd 100644 (file)
@@ -503,7 +503,7 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts);
  * exception of GIT_CONFIG_PARAMETERS and GIT_CONFIG_COUNT (which cause the
  * corresponding environment variables to be unset in the subprocess) and adds
  * an environment variable pointing to new_git_dir. See local_repo_env in
- * cache.h for more information.
+ * environment.h for more information.
  */
 void prepare_other_repo_env(struct strvec *env, const char *new_git_dir);
 
@@ -564,4 +564,6 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
                                      void *cb_data,
                                      unsigned int timeout_sec);
 
+int sane_execvp(const char *file, char *const argv[]);
+
 #endif
diff --git a/sane-ctype.h b/sane-ctype.h
new file mode 100644 (file)
index 0000000..cbea1b2
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef SANE_CTYPE_H
+#define SANE_CTYPE_H
+
+/* Sane ctype - no locale, and works with signed chars */
+#undef isascii
+#undef isspace
+#undef isdigit
+#undef isalpha
+#undef isalnum
+#undef isprint
+#undef islower
+#undef isupper
+#undef tolower
+#undef toupper
+#undef iscntrl
+#undef ispunct
+#undef isxdigit
+
+extern const unsigned char sane_ctype[256];
+extern const signed char hexval_table[256];
+#define GIT_SPACE 0x01
+#define GIT_DIGIT 0x02
+#define GIT_ALPHA 0x04
+#define GIT_GLOB_SPECIAL 0x08
+#define GIT_REGEX_SPECIAL 0x10
+#define GIT_PATHSPEC_MAGIC 0x20
+#define GIT_CNTRL 0x40
+#define GIT_PUNCT 0x80
+#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
+#define isascii(x) (((x) & ~0x7f) == 0)
+#define isspace(x) sane_istest(x,GIT_SPACE)
+#define isdigit(x) sane_istest(x,GIT_DIGIT)
+#define isalpha(x) sane_istest(x,GIT_ALPHA)
+#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e)
+#define islower(x) sane_iscase(x, 1)
+#define isupper(x) sane_iscase(x, 0)
+#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
+#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
+#define iscntrl(x) (sane_istest(x,GIT_CNTRL))
+#define ispunct(x) sane_istest(x, GIT_PUNCT | GIT_REGEX_SPECIAL | \
+               GIT_GLOB_SPECIAL | GIT_PATHSPEC_MAGIC)
+#define isxdigit(x) (hexval_table[(unsigned char)(x)] != -1)
+#define tolower(x) sane_case((unsigned char)(x), 0x20)
+#define toupper(x) sane_case((unsigned char)(x), 0)
+#define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC)
+
+static inline int sane_case(int x, int high)
+{
+       if (sane_istest(x, GIT_ALPHA))
+               x = (x & ~0x20) | high;
+       return x;
+}
+
+static inline int sane_iscase(int x, int is_lower)
+{
+       if (!sane_istest(x, GIT_ALPHA))
+               return 0;
+
+       if (is_lower)
+               return (x & 0x20) != 0;
+       else
+               return (x & 0x20) == 0;
+}
+
+#endif
index 1326e1f608907247ca5304fc1838a1002bfc3b5f..fb2940c2a00c94d806319dc8d45e8ffed1231c17 100644 (file)
--- a/scalar.c
+++ b/scalar.c
@@ -409,6 +409,7 @@ static int cmd_clone(int argc, const char **argv)
 {
        const char *branch = NULL;
        int full_clone = 0, single_branch = 0, show_progress = isatty(2);
+       int src = 1;
        struct option clone_options[] = {
                OPT_STRING('b', "branch", &branch, N_("<branch>"),
                           N_("branch to checkout after clone")),
@@ -417,10 +418,13 @@ static int cmd_clone(int argc, const char **argv)
                OPT_BOOL(0, "single-branch", &single_branch,
                         N_("only download metadata for the branch that will "
                            "be checked out")),
+               OPT_BOOL(0, "src", &src,
+                        N_("create repository within 'src' directory")),
                OPT_END(),
        };
        const char * const clone_usage[] = {
-               N_("scalar clone [<options>] [--] <repo> [<dir>]"),
+               N_("scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]\n"
+                  "\t[--[no-]src] <url> [<enlistment>]"),
                NULL
        };
        const char *url;
@@ -456,7 +460,10 @@ static int cmd_clone(int argc, const char **argv)
        if (is_directory(enlistment))
                die(_("directory '%s' exists already"), enlistment);
 
-       dir = xstrfmt("%s/src", enlistment);
+       if (src)
+               dir = xstrfmt("%s/src", enlistment);
+       else
+               dir = xstrdup(enlistment);
 
        strbuf_reset(&buf);
        if (branch)
@@ -594,7 +601,9 @@ static int cmd_register(int argc, const char **argv)
        return register_dir();
 }
 
-static int get_scalar_repos(const char *key, const char *value, void *data)
+static int get_scalar_repos(const char *key, const char *value,
+                           const struct config_context *ctx UNUSED,
+                           void *data)
 {
        struct string_list *list = data;
 
@@ -655,6 +664,7 @@ static int cmd_reconfigure(int argc, const char **argv)
        git_config(get_scalar_repos, &scalar_repos);
 
        for (i = 0; i < scalar_repos.nr; i++) {
+               int succeeded = 0;
                const char *dir = scalar_repos.items[i].string;
 
                strbuf_reset(&commondir);
@@ -665,30 +675,56 @@ static int cmd_reconfigure(int argc, const char **argv)
 
                        if (errno != ENOENT) {
                                warning_errno(_("could not switch to '%s'"), dir);
-                               res = -1;
-                               continue;
+                               goto loop_end;
                        }
 
                        strbuf_addstr(&buf, dir);
                        if (remove_deleted_enlistment(&buf))
-                               res = error(_("could not remove stale "
-                                             "scalar.repo '%s'"), dir);
-                       else
-                               warning(_("removing stale scalar.repo '%s'"),
+                               error(_("could not remove stale "
+                                       "scalar.repo '%s'"), dir);
+                       else {
+                               warning(_("removed stale scalar.repo '%s'"),
                                        dir);
+                               succeeded = 1;
+                       }
                        strbuf_release(&buf);
-               } else if (discover_git_directory(&commondir, &gitdir) < 0) {
-                       warning_errno(_("git repository gone in '%s'"), dir);
-                       res = -1;
-               } else {
-                       git_config_clear();
+                       goto loop_end;
+               }
+
+               switch (discover_git_directory_reason(&commondir, &gitdir)) {
+               case GIT_DIR_INVALID_OWNERSHIP:
+                       warning(_("repository at '%s' has different owner"), dir);
+                       goto loop_end;
+
+               case GIT_DIR_INVALID_GITFILE:
+               case GIT_DIR_INVALID_FORMAT:
+                       warning(_("repository at '%s' has a format issue"), dir);
+                       goto loop_end;
+
+               case GIT_DIR_DISCOVERED:
+                       succeeded = 1;
+                       break;
+
+               default:
+                       warning(_("repository not found in '%s'"), dir);
+                       break;
+               }
 
-                       the_repository = &r;
-                       r.commondir = commondir.buf;
-                       r.gitdir = gitdir.buf;
+               git_config_clear();
 
-                       if (set_recommended_config(1) < 0)
-                               res = -1;
+               the_repository = &r;
+               r.commondir = commondir.buf;
+               r.gitdir = gitdir.buf;
+
+               if (set_recommended_config(1) >= 0)
+                       succeeded = 1;
+
+loop_end:
+               if (!succeeded) {
+                       res = -1;
+                       warning(_("to unregister this repository from Scalar, run\n"
+                                 "\tgit config --global --unset --fixed-value scalar.repo \"%s\""),
+                               dir);
                }
        }
 
index 0c7ccaef6805f1cffd5aa6246c885eb54fd258e5..89aca9d829ed046f532b87120f39d807c86ebcb9 100644 (file)
@@ -5,7 +5,7 @@
 #include "gettext.h"
 #include "hex.h"
 #include "refs.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pkt-line.h"
 #include "sideband.h"
 #include "run-command.h"
@@ -15,7 +15,6 @@
 #include "quote.h"
 #include "transport.h"
 #include "version.h"
-#include "wrapper.h"
 #include "oid-array.h"
 #include "gpg-interface.h"
 #include "shallow.h"
index bceb6abcb6c733808b3defb7c30b9857be5d6e8e..d584cac8ed9307caad0f8a9ede98d1f57ceab874 100644 (file)
@@ -1,7 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
 #include "advice.h"
-#include "alloc.h"
 #include "config.h"
 #include "copy.h"
 #include "environment.h"
@@ -11,7 +10,7 @@
 #include "dir.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "object.h"
 #include "pager.h"
 #include "commit.h"
 #include "utf8.h"
 #include "cache-tree.h"
 #include "diff.h"
+#include "path.h"
 #include "revision.h"
 #include "rerere.h"
+#include "merge.h"
 #include "merge-ort.h"
 #include "merge-ort-wrappers.h"
 #include "refs.h"
+#include "sparse-index.h"
 #include "strvec.h"
 #include "quote.h"
 #include "trailer.h"
 #include "rebase-interactive.h"
 #include "reset.h"
 #include "branch.h"
-#include "wrapper.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
+/*
+ * To accommodate common filesystem limitations, where the loose refs' file
+ * names must not exceed `NAME_MAX`, the labels generated by `git rebase
+ * --rebase-merges` need to be truncated if the corresponding commit subjects
+ * are too long.
+ * Add some margin to stay clear from reaching `NAME_MAX`.
+ */
+#define GIT_MAX_LABEL_LENGTH ((NAME_MAX) - (LOCK_SUFFIX_LEN) - 16)
+
 static const char sign_off_header[] = "Signed-off-by: ";
 static const char cherry_picked_prefix[] = "(cherry picked from commit ";
 
@@ -137,6 +147,11 @@ static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
  * the commit object name of the corresponding patch.
  */
 static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
+/*
+ * When we stop for the user to resolve conflicts this file contains
+ * the patch of the commit that is being picked.
+ */
+static GIT_PATH_FUNC(rebase_path_patch, "rebase-merge/patch")
 /*
  * For the post-rewrite hook, we make a list of rewritten commits and
  * their new sha1s.  The rewritten-pending list keeps the sha1s of
@@ -219,7 +234,8 @@ static struct update_ref_record *init_update_ref_record(const char *ref)
        return rec;
 }
 
-static int git_sequencer_config(const char *k, const char *v, void *cb)
+static int git_sequencer_config(const char *k, const char *v,
+                               const struct config_context *ctx, void *cb)
 {
        struct replay_opts *opts = cb;
        int status;
@@ -274,7 +290,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
        if (opts->action == REPLAY_REVERT && !strcmp(k, "revert.reference"))
                opts->commit_use_reference = git_config_bool(k, v);
 
-       return git_diff_basic_config(k, v, NULL);
+       return git_diff_basic_config(k, v, ctx, NULL);
 }
 
 void sequencer_init_config(struct replay_opts *opts)
@@ -422,10 +438,9 @@ struct commit_message {
        const char *message;
 };
 
-static const char *short_commit_name(struct commit *commit)
+static const char *short_commit_name(struct repository *r, struct commit *commit)
 {
-       return repo_find_unique_abbrev(the_repository, &commit->object.oid,
-                                      DEFAULT_ABBREV);
+       return repo_find_unique_abbrev(r, &commit->object.oid, DEFAULT_ABBREV);
 }
 
 static int get_message(struct commit *commit, struct commit_message *out)
@@ -435,7 +450,7 @@ static int get_message(struct commit *commit, struct commit_message *out)
 
        out->message = repo_logmsg_reencode(the_repository, commit, NULL,
                                            get_commit_output_encoding());
-       abbrev = short_commit_name(commit);
+       abbrev = short_commit_name(the_repository, commit);
 
        subject_len = find_commit_subject(out->message, &subject);
 
@@ -660,11 +675,12 @@ void append_conflicts_hint(struct index_state *istate,
        }
 
        strbuf_addch(msgbuf, '\n');
-       strbuf_commented_addf(msgbuf, "Conflicts:\n");
+       strbuf_commented_addf(msgbuf, comment_line_char, "Conflicts:\n");
        for (i = 0; i < istate->cache_nr;) {
                const struct cache_entry *ce = istate->cache[i++];
                if (ce_stage(ce)) {
-                       strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+                       strbuf_commented_addf(msgbuf, comment_line_char,
+                                             "\t%s\n", ce->name);
                        while (i < istate->cache_nr &&
                               !strcmp(ce->name, istate->cache[i]->name))
                                i++;
@@ -1143,7 +1159,8 @@ void cleanup_message(struct strbuf *msgbuf,
            cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
        if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
-               strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+               strbuf_stripspace(msgbuf,
+                 cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
 }
 
 /*
@@ -1174,7 +1191,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,
        if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
                return 0;
 
-       strbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+       strbuf_stripspace(&tmpl,
+         cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
        if (!skip_prefix(sb->buf, tmpl.buf, &start))
                start = sb->buf;
        strbuf_release(&tmpl);
@@ -1546,7 +1564,8 @@ static int try_to_commit(struct repository *r,
                cleanup = opts->default_msg_cleanup;
 
        if (cleanup != COMMIT_MSG_CLEANUP_NONE)
-               strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
+               strbuf_stripspace(msg,
+                 cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
        if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
                res = 1; /* run 'git commit' to display error message */
                goto out;
@@ -1840,7 +1859,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
                s += count;
                len -= count;
        }
-       strbuf_add_commented_lines(buf, s, len);
+       strbuf_add_commented_lines(buf, s, len, comment_line_char);
 }
 
 /* Does the current fixup chain contain a squash command? */
@@ -1939,7 +1958,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
        strbuf_addf(buf, _(nth_commit_msg_fmt),
                    ++opts->current_fixup_count + 1);
        strbuf_addstr(buf, "\n\n");
-       strbuf_add_commented_lines(buf, body, commented_len);
+       strbuf_add_commented_lines(buf, body, commented_len, comment_line_char);
        /* buf->buf may be reallocated so store an offset into the buffer */
        fixup_off = buf->len;
        strbuf_addstr(buf, body + commented_len);
@@ -2029,7 +2048,8 @@ static int update_squash_messages(struct repository *r,
                              _(first_commit_msg_str));
                strbuf_addstr(&buf, "\n\n");
                if (is_fixup_flag(command, flag))
-                       strbuf_add_commented_lines(&buf, body, strlen(body));
+                       strbuf_add_commented_lines(&buf, body, strlen(body),
+                                                  comment_line_char);
                else
                        strbuf_addstr(&buf, body);
 
@@ -2048,7 +2068,8 @@ static int update_squash_messages(struct repository *r,
                strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
                            ++opts->current_fixup_count + 1);
                strbuf_addstr(&buf, "\n\n");
-               strbuf_add_commented_lines(&buf, body, strlen(body));
+               strbuf_add_commented_lines(&buf, body, strlen(body),
+                                          comment_line_char);
        } else
                return error(_("unknown command: %d"), command);
        repo_unuse_commit_buffer(r, commit, message);
@@ -2241,6 +2262,8 @@ static int do_pick_commit(struct repository *r,
         */
 
        if (command == TODO_REVERT) {
+               const char *orig_subject;
+
                base = commit;
                base_label = msg.label;
                next = parent;
@@ -2248,6 +2271,15 @@ static int do_pick_commit(struct repository *r,
                if (opts->commit_use_reference) {
                        strbuf_addstr(&msgbuf,
                                "# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
+               } else if (skip_prefix(msg.subject, "Revert \"", &orig_subject) &&
+                          /*
+                           * We don't touch pre-existing repeated reverts, because
+                           * theoretically these can be nested arbitrarily deeply,
+                           * thus requiring excessive complexity to deal with.
+                           */
+                          !starts_with(orig_subject, "Revert \"")) {
+                       strbuf_addstr(&msgbuf, "Reapply \"");
+                       strbuf_addstr(&msgbuf, orig_subject);
                } else {
                        strbuf_addstr(&msgbuf, "Revert \"");
                        strbuf_addstr(&msgbuf, msg.subject);
@@ -2303,7 +2335,7 @@ static int do_pick_commit(struct repository *r,
                        const char *dest = git_path_squash_msg(r);
                        unlink(dest);
                        if (copy_file(dest, rebase_path_squash_msg(), 0666)) {
-                               res = error(_("could not rename '%s' to '%s'"),
+                               res = error(_("could not copy '%s' to '%s'"),
                                            rebase_path_squash_msg(), dest);
                                goto leave;
                        }
@@ -2366,7 +2398,7 @@ static int do_pick_commit(struct repository *r,
                error(command == TODO_REVERT
                      ? _("could not revert %s... %s")
                      : _("could not apply %s... %s"),
-                     short_commit_name(commit), msg.subject);
+                     short_commit_name(r, commit), msg.subject);
                print_advice(r, res == 1, opts);
                repo_rerere(r, opts->allow_rerere_auto);
                goto leave;
@@ -2633,7 +2665,7 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
        return item->commit ? 0 : -1;
 }
 
-int sequencer_get_last_command(struct repository *r, enum replay_action *action)
+int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action *action)
 {
        const char *todo_file, *bol;
        struct strbuf buf = STRBUF_INIT;
@@ -2694,7 +2726,7 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf,
                if (fixup_okay)
                        ; /* do nothing */
                else if (is_fixup(item->command))
-                       return error(_("cannot '%s' without a previous commit"),
+                       res = error(_("cannot '%s' without a previous commit"),
                                command_to_string(item->command));
                else if (!is_noop(item->command))
                        fixup_okay = 1;
@@ -2881,7 +2913,9 @@ static int git_config_string_dup(char **dest,
        return 0;
 }
 
-static int populate_opts_cb(const char *key, const char *value, void *data)
+static int populate_opts_cb(const char *key, const char *value,
+                           const struct config_context *ctx,
+                           void *data)
 {
        struct replay_opts *opts = data;
        int error_flag = 1;
@@ -2889,26 +2923,26 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
        if (!value)
                error_flag = 0;
        else if (!strcmp(key, "options.no-commit"))
-               opts->no_commit = git_config_bool_or_int(key, value, &error_flag);
+               opts->no_commit = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.edit"))
-               opts->edit = git_config_bool_or_int(key, value, &error_flag);
+               opts->edit = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.allow-empty"))
                opts->allow_empty =
-                       git_config_bool_or_int(key, value, &error_flag);
+                       git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.allow-empty-message"))
                opts->allow_empty_message =
-                       git_config_bool_or_int(key, value, &error_flag);
+                       git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.keep-redundant-commits"))
                opts->keep_redundant_commits =
-                       git_config_bool_or_int(key, value, &error_flag);
+                       git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.signoff"))
-               opts->signoff = git_config_bool_or_int(key, value, &error_flag);
+               opts->signoff = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.record-origin"))
-               opts->record_origin = git_config_bool_or_int(key, value, &error_flag);
+               opts->record_origin = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.allow-ff"))
-               opts->allow_ff = git_config_bool_or_int(key, value, &error_flag);
+               opts->allow_ff = git_config_bool_or_int(key, value, ctx->kvi, &error_flag);
        else if (!strcmp(key, "options.mainline"))
-               opts->mainline = git_config_int(key, value);
+               opts->mainline = git_config_int(key, value, ctx->kvi);
        else if (!strcmp(key, "options.strategy"))
                git_config_string_dup(&opts->strategy, key, value);
        else if (!strcmp(key, "options.gpg-sign"))
@@ -2917,7 +2951,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
                strvec_push(&opts->xopts, value);
        } else if (!strcmp(key, "options.allow-rerere-auto"))
                opts->allow_rerere_auto =
-                       git_config_bool_or_int(key, value, &error_flag) ?
+                       git_config_bool_or_int(key, value, ctx->kvi, &error_flag) ?
                                RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
        else if (!strcmp(key, "options.default-msg-cleanup")) {
                opts->explicit_cleanup = 1;
@@ -3153,7 +3187,8 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
                item->offset_in_buf = todo_list->buf.len;
                subject_len = find_commit_subject(commit_buffer, &subject);
                strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string,
-                       short_commit_name(commit), subject_len, subject);
+                       short_commit_name(the_repository, commit),
+                       subject_len, subject);
                repo_unuse_commit_buffer(the_repository, commit,
                                         commit_buffer);
        }
@@ -3382,7 +3417,8 @@ give_advice:
        return -1;
 }
 
-static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts,
+                    int reschedule)
 {
        struct lock_file todo_lock = LOCK_INIT;
        const char *todo_path = get_todo_path(opts);
@@ -3392,7 +3428,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
         * rebase -i writes "git-rebase-todo" without the currently executing
         * command, appending it to "done" instead.
         */
-       if (is_rebase_i(opts))
+       if (is_rebase_i(opts) && !reschedule)
                next++;
 
        fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
@@ -3405,7 +3441,7 @@ static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
        if (commit_lock_file(&todo_lock) < 0)
                return error(_("failed to finalize '%s'"), todo_path);
 
-       if (is_rebase_i(opts) && next > 0) {
+       if (is_rebase_i(opts) && !reschedule && next > 0) {
                const char *done = rebase_path_done();
                int fd = open(done, O_CREAT | O_WRONLY | O_APPEND, 0666);
                int ret = 0;
@@ -3486,18 +3522,19 @@ static int make_patch(struct repository *r,
                      struct commit *commit,
                      struct replay_opts *opts)
 {
-       struct strbuf buf = STRBUF_INIT;
        struct rev_info log_tree_opt;
        const char *subject;
        char hex[GIT_MAX_HEXSZ + 1];
        int res = 0;
 
+       if (!is_rebase_i(opts))
+               BUG("make_patch should only be called when rebasing");
+
        oid_to_hex_r(hex, &commit->object.oid);
        if (write_message(hex, strlen(hex), rebase_path_stopped_sha(), 1) < 0)
                return -1;
        res |= write_rebase_head(&commit->object.oid);
 
-       strbuf_addf(&buf, "%s/patch", get_dir(opts));
        memset(&log_tree_opt, 0, sizeof(log_tree_opt));
        repo_init_revisions(r, &log_tree_opt, NULL);
        log_tree_opt.abbrev = 0;
@@ -3505,28 +3542,26 @@ static int make_patch(struct repository *r,
        log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
        log_tree_opt.disable_stdin = 1;
        log_tree_opt.no_commit_id = 1;
-       log_tree_opt.diffopt.file = fopen(buf.buf, "w");
+       log_tree_opt.diffopt.file = fopen(rebase_path_patch(), "w");
        log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
        if (!log_tree_opt.diffopt.file)
-               res |= error_errno(_("could not open '%s'"), buf.buf);
+               res |= error_errno(_("could not open '%s'"),
+                                  rebase_path_patch());
        else {
                res |= log_tree_commit(&log_tree_opt, commit);
                fclose(log_tree_opt.diffopt.file);
        }
-       strbuf_reset(&buf);
 
-       strbuf_addf(&buf, "%s/message", get_dir(opts));
-       if (!file_exists(buf.buf)) {
+       if (!file_exists(rebase_path_message())) {
                const char *encoding = get_commit_output_encoding();
                const char *commit_buffer = repo_logmsg_reencode(r,
                                                                 commit, NULL,
                                                                 encoding);
                find_commit_subject(commit_buffer, &subject);
-               res |= write_message(subject, strlen(subject), buf.buf, 1);
+               res |= write_message(subject, strlen(subject), rebase_path_message(), 1);
                repo_unuse_commit_buffer(r, commit,
                                         commit_buffer);
        }
-       strbuf_release(&buf);
        release_revisions(&log_tree_opt);
 
        return res;
@@ -3574,7 +3609,7 @@ static int error_with_patch(struct repository *r,
        } else if (exit_code) {
                if (commit)
                        fprintf_ln(stderr, _("Could not apply %s... %.*s"),
-                                  short_commit_name(commit), subject_len, subject);
+                                  short_commit_name(r, commit), subject_len, subject);
                else
                        /*
                         * We don't have the hash of the parent so
@@ -4144,6 +4179,7 @@ static int do_merge(struct repository *r,
        if (ret < 0) {
                error(_("could not even attempt to merge '%.*s'"),
                      merge_arg_len, arg);
+               unlink(git_path_merge_msg(r));
                goto leave_merge;
        }
        /*
@@ -4631,6 +4667,68 @@ N_("Could not execute the todo command\n"
 "    git rebase --edit-todo\n"
 "    git rebase --continue\n");
 
+static int pick_one_commit(struct repository *r,
+                          struct todo_list *todo_list,
+                          struct replay_opts *opts,
+                          int *check_todo, int* reschedule)
+{
+       int res;
+       struct todo_item *item = todo_list->items + todo_list->current;
+       const char *arg = todo_item_get_arg(todo_list, item);
+       if (is_rebase_i(opts))
+               opts->reflog_message = reflog_message(
+                       opts, command_to_string(item->command), NULL);
+
+       res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
+                            check_todo);
+       if (is_rebase_i(opts) && res < 0) {
+               /* Reschedule */
+               *reschedule = 1;
+               return -1;
+       }
+       if (item->command == TODO_EDIT) {
+               struct commit *commit = item->commit;
+               if (!res) {
+                       if (!opts->verbose)
+                               term_clear_line();
+                       fprintf(stderr, _("Stopped at %s...  %.*s\n"),
+                               short_commit_name(r, commit), item->arg_len, arg);
+               }
+               return error_with_patch(r, commit,
+                                       arg, item->arg_len, opts, res, !res);
+       }
+       if (is_rebase_i(opts) && !res)
+               record_in_rewritten(&item->commit->object.oid,
+                                   peek_command(todo_list, 1));
+       if (res && is_fixup(item->command)) {
+               if (res == 1)
+                       intend_to_amend();
+               return error_failed_squash(r, item->commit, opts,
+                                          item->arg_len, arg);
+       } else if (res && is_rebase_i(opts) && item->commit) {
+               int to_amend = 0;
+               struct object_id oid;
+
+               /*
+                * If we are rewording and have either
+                * fast-forwarded already, or are about to
+                * create a new root commit, we want to amend,
+                * otherwise we do not.
+                */
+               if (item->command == TODO_REWORD &&
+                   !repo_get_oid(r, "HEAD", &oid) &&
+                   (oideq(&item->commit->object.oid, &oid) ||
+                    (opts->have_squash_onto &&
+                     oideq(&opts->squash_onto, &oid))))
+                       to_amend = 1;
+
+               return res | error_with_patch(r, item->commit,
+                                             arg, item->arg_len, opts,
+                                             res, to_amend);
+       }
+       return res;
+}
+
 static int pick_commits(struct repository *r,
                        struct todo_list *todo_list,
                        struct replay_opts *opts)
@@ -4646,12 +4744,17 @@ static int pick_commits(struct repository *r,
        if (read_and_refresh_cache(r, opts))
                return -1;
 
+       unlink(rebase_path_message());
+       unlink(rebase_path_stopped_sha());
+       unlink(rebase_path_amend());
+       unlink(rebase_path_patch());
+
        while (todo_list->current < todo_list->nr) {
                struct todo_item *item = todo_list->items + todo_list->current;
                const char *arg = todo_item_get_arg(todo_list, item);
                int check_todo = 0;
 
-               if (save_todo(todo_list, opts))
+               if (save_todo(todo_list, opts, reschedule))
                        return -1;
                if (is_rebase_i(opts)) {
                        if (item->command != TODO_COMMENT) {
@@ -4669,10 +4772,7 @@ static int pick_commits(struct repository *r,
                                                todo_list->total_nr,
                                                opts->verbose ? "\n" : "\r");
                        }
-                       unlink(rebase_path_message());
                        unlink(rebase_path_author_script());
-                       unlink(rebase_path_stopped_sha());
-                       unlink(rebase_path_amend());
                        unlink(git_path_merge_head(r));
                        unlink(git_path_auto_merge(r));
                        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
@@ -4684,66 +4784,10 @@ static int pick_commits(struct repository *r,
                        }
                }
                if (item->command <= TODO_SQUASH) {
-                       if (is_rebase_i(opts))
-                               opts->reflog_message = reflog_message(opts,
-                                     command_to_string(item->command), NULL);
-
-                       res = do_pick_commit(r, item, opts,
-                                            is_final_fixup(todo_list),
-                                            &check_todo);
-                       if (is_rebase_i(opts) && res < 0) {
-                               /* Reschedule */
-                               advise(_(rescheduled_advice),
-                                      get_item_line_length(todo_list,
-                                                           todo_list->current),
-                                      get_item_line(todo_list,
-                                                    todo_list->current));
-                               todo_list->current--;
-                               if (save_todo(todo_list, opts))
-                                       return -1;
-                       }
-                       if (item->command == TODO_EDIT) {
-                               struct commit *commit = item->commit;
-                               if (!res) {
-                                       if (!opts->verbose)
-                                               term_clear_line();
-                                       fprintf(stderr,
-                                               _("Stopped at %s...  %.*s\n"),
-                                               short_commit_name(commit),
-                                               item->arg_len, arg);
-                               }
-                               return error_with_patch(r, commit,
-                                       arg, item->arg_len, opts, res, !res);
-                       }
-                       if (is_rebase_i(opts) && !res)
-                               record_in_rewritten(&item->commit->object.oid,
-                                       peek_command(todo_list, 1));
-                       if (res && is_fixup(item->command)) {
-                               if (res == 1)
-                                       intend_to_amend();
-                               return error_failed_squash(r, item->commit, opts,
-                                       item->arg_len, arg);
-                       } else if (res && is_rebase_i(opts) && item->commit) {
-                               int to_amend = 0;
-                               struct object_id oid;
-
-                               /*
-                                * If we are rewording and have either
-                                * fast-forwarded already, or are about to
-                                * create a new root commit, we want to amend,
-                                * otherwise we do not.
-                                */
-                               if (item->command == TODO_REWORD &&
-                                   !repo_get_oid(r, "HEAD", &oid) &&
-                                   (oideq(&item->commit->object.oid, &oid) ||
-                                    (opts->have_squash_onto &&
-                                     oideq(&opts->squash_onto, &oid))))
-                                       to_amend = 1;
-
-                               return res | error_with_patch(r, item->commit,
-                                               arg, item->arg_len, opts,
-                                               res, to_amend);
-                       }
+                       res = pick_one_commit(r, todo_list, opts, &check_todo,
+                                             &reschedule);
+                       if (!res && item->command == TODO_EDIT)
+                               return 0;
                } else if (item->command == TODO_EXEC) {
                        char *end_of_arg = (char *)(arg + item->arg_len);
                        int saved = *end_of_arg;
@@ -4791,32 +4835,25 @@ static int pick_commits(struct repository *r,
                               get_item_line_length(todo_list,
                                                    todo_list->current),
                               get_item_line(todo_list, todo_list->current));
-                       todo_list->current--;
-                       if (save_todo(todo_list, opts))
+                       if (save_todo(todo_list, opts, reschedule))
                                return -1;
                        if (item->commit)
-                               return error_with_patch(r,
-                                                       item->commit,
-                                                       arg, item->arg_len,
-                                                       opts, res, 0);
+                               write_rebase_head(&item->commit->object.oid);
                } else if (is_rebase_i(opts) && check_todo && !res &&
                           reread_todo_if_changed(r, todo_list, opts)) {
                        return -1;
                }
 
-               todo_list->current++;
                if (res)
                        return res;
+
+               todo_list->current++;
        }
 
        if (is_rebase_i(opts)) {
                struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
                struct stat st;
 
-               /* Stopped in the middle, as planned? */
-               if (todo_list->current < todo_list->nr)
-                       return 0;
-
                if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
                                starts_with(head_ref.buf, "refs/")) {
                        const char *msg;
@@ -4959,6 +4996,11 @@ static int commit_staged_changes(struct repository *r,
 
        is_clean = !has_uncommitted_changes(r, 0);
 
+       if (!is_clean && !file_exists(rebase_path_message())) {
+               const char *gpg_opt = gpg_sign_opt_quoted(opts);
+
+               return error(_(staged_changes_advice), gpg_opt, gpg_opt);
+       }
        if (file_exists(rebase_path_amend())) {
                struct strbuf rev = STRBUF_INIT;
                struct object_id head, to_amend;
@@ -5038,19 +5080,31 @@ static int commit_staged_changes(struct repository *r,
                                 * We need to update the squash message to skip
                                 * the latest commit message.
                                 */
+                               int res = 0;
                                struct commit *commit;
+                               const char *msg;
                                const char *path = rebase_path_squash_msg();
                                const char *encoding = get_commit_output_encoding();
 
-                               if (parse_head(r, &commit) ||
-                                   !(p = repo_logmsg_reencode(r, commit, NULL, encoding)) ||
-                                   write_message(p, strlen(p), path, 0)) {
-                                       repo_unuse_commit_buffer(r, commit, p);
-                                       return error(_("could not write file: "
+                               if (parse_head(r, &commit))
+                                       return error(_("could not parse HEAD"));
+
+                               p = repo_logmsg_reencode(r, commit, NULL, encoding);
+                               if (!p)  {
+                                       res = error(_("could not parse commit %s"),
+                                                   oid_to_hex(&commit->object.oid));
+                                       goto unuse_commit_buffer;
+                               }
+                               find_commit_subject(p, &msg);
+                               if (write_message(msg, strlen(msg), path, 0)) {
+                                       res = error(_("could not write file: "
                                                       "'%s'"), path);
+                                       goto unuse_commit_buffer;
                                }
-                               repo_unuse_commit_buffer(r,
-                                                        commit, p);
+                       unuse_commit_buffer:
+                               repo_unuse_commit_buffer(r, commit, p);
+                               if (res)
+                                       return res;
                        }
                }
 
@@ -5330,6 +5384,7 @@ struct label_state {
        struct oidmap commit2label;
        struct hashmap labels;
        struct strbuf buf;
+       int max_label_length;
 };
 
 static const char *label_oid(struct object_id *oid, const char *label,
@@ -5386,6 +5441,8 @@ static const char *label_oid(struct object_id *oid, const char *label,
                }
        } else {
                struct strbuf *buf = &state->buf;
+               int label_is_utf8 = 1; /* start with this assumption */
+               size_t max_len = buf->len + state->max_label_length;
 
                /*
                 * Sanitize labels by replacing non-alpha-numeric characters
@@ -5394,14 +5451,34 @@ static const char *label_oid(struct object_id *oid, const char *label,
                 *
                 * Note that we retain non-ASCII UTF-8 characters (identified
                 * via the most significant bit). They should be all acceptable
-                * in file names. We do not validate the UTF-8 here, that's not
-                * the job of this function.
+                * in file names.
+                *
+                * As we will use the labels as names of (loose) refs, it is
+                * vital that the name not be longer than the maximum component
+                * size of the file system (`NAME_MAX`). We are careful to
+                * truncate the label accordingly, allowing for the `.lock`
+                * suffix and for the label to be UTF-8 encoded (i.e. we avoid
+                * truncating in the middle of a character).
                 */
-               for (; *label; label++)
-                       if ((*label & 0x80) || isalnum(*label))
+               for (; *label && buf->len + 1 < max_len; label++)
+                       if (isalnum(*label) ||
+                           (!label_is_utf8 && (*label & 0x80)))
                                strbuf_addch(buf, *label);
+                       else if (*label & 0x80) {
+                               const char *p = label;
+
+                               utf8_width(&p, NULL);
+                               if (p) {
+                                       if (buf->len + (p - label) > max_len)
+                                               break;
+                                       strbuf_add(buf, label, p - label);
+                                       label = p - 1;
+                               } else {
+                                       label_is_utf8 = 0;
+                                       strbuf_addch(buf, *label);
+                               }
                        /* avoid leading dash and double-dashes */
-                       else if (buf->len && buf->buf[buf->len - 1] != '-')
+                       else if (buf->len && buf->buf[buf->len - 1] != '-')
                                strbuf_addch(buf, '-');
                if (!buf->len) {
                        strbuf_addstr(buf, "rev-");
@@ -5463,7 +5540,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
        struct string_entry *entry;
        struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT,
                shown = OIDSET_INIT;
-       struct label_state state = { OIDMAP_INIT, { NULL }, STRBUF_INIT };
+       struct label_state state =
+               { OIDMAP_INIT, { NULL }, STRBUF_INIT, GIT_MAX_LABEL_LENGTH };
 
        int abbr = flags & TODO_LIST_ABBREVIATE_CMDS;
        const char *cmd_pick = abbr ? "p" : "pick",
@@ -5471,6 +5549,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                *cmd_reset = abbr ? "t" : "reset",
                *cmd_merge = abbr ? "m" : "merge";
 
+       git_config_get_int("rebase.maxlabellength", &state.max_label_length);
+
        oidmap_init(&commit2todo, 0);
        oidmap_init(&state.commit2label, 0);
        hashmap_init(&state.labels, labels_cmp, NULL, 0);
@@ -5507,7 +5587,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                if (!is_empty && (commit->object.flags & PATCHSAME)) {
                        if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
                                warning(_("skipped previously applied commit %s"),
-                                       short_commit_name(commit));
+                                       short_commit_name(the_repository, commit));
                        skipped_commit = 1;
                        continue;
                }
@@ -5743,7 +5823,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
                if (!is_empty && (commit->object.flags & PATCHSAME)) {
                        if (flags & TODO_LIST_WARN_SKIPPED_CHERRY_PICKS)
                                warning(_("skipped previously applied commit %s"),
-                                       short_commit_name(commit));
+                                       short_commit_name(r, commit));
                        skipped_commit = 1;
                        continue;
                }
@@ -5835,7 +5915,8 @@ static void todo_list_add_exec_commands(struct todo_list *todo_list,
        todo_list->alloc = alloc;
 }
 
-static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_list,
+static void todo_list_to_strbuf(struct repository *r,
+                               struct todo_list *todo_list,
                                struct strbuf *buf, int num, unsigned flags)
 {
        struct todo_item *item;
@@ -5864,7 +5945,7 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis
                /* add commit id */
                if (item->commit) {
                        const char *oid = flags & TODO_LIST_SHORTEN_IDS ?
-                                         short_commit_name(item->commit) :
+                                         short_commit_name(r, item->commit) :
                                          oid_to_hex(&item->commit->object.oid);
 
                        if (item->command == TODO_FIXUP) {
@@ -6172,7 +6253,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
        if (checkout_onto(r, opts, onto_name, &oid, orig_head))
                goto cleanup;
 
-       if (require_clean_work_tree(r, "rebase", "", 1, 1))
+       if (require_clean_work_tree(r, "rebase", NULL, 1, 1))
                goto cleanup;
 
        todo_list_write_total_nr(&new_todo);
@@ -6223,7 +6304,7 @@ static int skip_fixupish(const char *subject, const char **p) {
 int todo_list_rearrange_squash(struct todo_list *todo_list)
 {
        struct hashmap subject2item;
-       int rearranged = 0, *next, *tail, i, nr = 0, alloc = 0;
+       int rearranged = 0, *next, *tail, i, nr = 0;
        char **subjects;
        struct commit_todo_item commit_todo;
        struct todo_item *items = NULL;
@@ -6335,6 +6416,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
        }
 
        if (rearranged) {
+               ALLOC_ARRAY(items, todo_list->nr);
+
                for (i = 0; i < todo_list->nr; i++) {
                        enum todo_command command = todo_list->items[i].command;
                        int cur = i;
@@ -6347,16 +6430,15 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
                                continue;
 
                        while (cur >= 0) {
-                               ALLOC_GROW(items, nr + 1, alloc);
                                items[nr++] = todo_list->items[cur];
                                cur = next[cur];
                        }
                }
 
+               assert(nr == todo_list->nr);
+               todo_list->alloc = nr;
                FREE_AND_NULL(todo_list->items);
                todo_list->items = items;
-               todo_list->nr = nr;
-               todo_list->alloc = alloc;
        }
 
        free(next);
diff --git a/serve.c b/serve.c
index 5329c91011f2919fc24bcc3039c264a0c9e2c877..a1d71134d49cc88ead5af690315b27ae23215e56 100644 (file)
--- a/serve.c
+++ b/serve.c
@@ -1,6 +1,7 @@
 #include "git-compat-util.h"
 #include "repository.h"
 #include "config.h"
+#include "hash-ll.h"
 #include "pkt-line.h"
 #include "version.h"
 #include "ls-refs.h"
index 55aa04f00abe8f4d8a1a885e603964223bcd5cf7..e2fe0f91432d8089e74c7e562728aca329dec66c 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "dir.h"
 #include "environment.h"
 #include "hex.h"
@@ -9,11 +8,11 @@
 #include "commit.h"
 #include "tag.h"
 #include "packfile.h"
+#include "path.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "server-info.h"
 #include "strbuf.h"
-#include "wrapper.h"
 
 struct update_info_ctx {
        FILE *cur_fp;
diff --git a/setup.c b/setup.c
index 458582207ea7bd4aa328b94d531a98f413c7ca14..2e607632dbde807ae76566e282d8f122b1642cda 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1,18 +1,22 @@
 #include "git-compat-util.h"
 #include "abspath.h"
+#include "copy.h"
 #include "environment.h"
+#include "exec-cmd.h"
 #include "gettext.h"
 #include "object-name.h"
+#include "refs.h"
 #include "repository.h"
 #include "config.h"
 #include "dir.h"
 #include "setup.h"
 #include "string-list.h"
 #include "chdir-notify.h"
+#include "path.h"
 #include "promisor-remote.h"
 #include "quote.h"
 #include "trace2.h"
-#include "wrapper.h"
+#include "worktree.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -517,7 +521,9 @@ no_prevention_needed:
        startup_info->original_cwd = NULL;
 }
 
-static int read_worktree_config(const char *var, const char *value, void *vdata)
+static int read_worktree_config(const char *var, const char *value,
+                               const struct config_context *ctx UNUSED,
+                               void *vdata)
 {
        struct repository_format *data = vdata;
 
@@ -588,13 +594,14 @@ static enum extension_result handle_extension(const char *var,
        return EXTENSION_UNKNOWN;
 }
 
-static int check_repo_format(const char *var, const char *value, void *vdata)
+static int check_repo_format(const char *var, const char *value,
+                            const struct config_context *ctx, void *vdata)
 {
        struct repository_format *data = vdata;
        const char *ext;
 
        if (strcmp(var, "core.repositoryformatversion") == 0)
-               data->version = git_config_int(var, value);
+               data->version = git_config_int(var, value, ctx->kvi);
        else if (skip_prefix(var, "extensions.", &ext)) {
                switch (handle_extension_v0(var, value, ext, data)) {
                case EXTENSION_ERROR:
@@ -617,7 +624,7 @@ static int check_repo_format(const char *var, const char *value, void *vdata)
                }
        }
 
-       return read_worktree_config(var, value, vdata);
+       return read_worktree_config(var, value, ctx, vdata);
 }
 
 static int check_repository_format_gently(const char *gitdir, struct repository_format *candidate, int *nongit_ok)
@@ -650,11 +657,10 @@ static int check_repository_format_gently(const char *gitdir, struct repository_
        }
 
        repository_format_precious_objects = candidate->precious_objects;
-       repository_format_worktree_config = candidate->worktree_config;
        string_list_clear(&candidate->unknown_extensions, 0);
        string_list_clear(&candidate->v1_only_extensions, 0);
 
-       if (repository_format_worktree_config) {
+       if (candidate->worktree_config) {
                /*
                 * pick up core.bare and core.worktree from per-worktree
                 * config if present
@@ -1116,7 +1122,8 @@ struct safe_directory_data {
        int is_safe;
 };
 
-static int safe_directory_cb(const char *key, const char *value, void *d)
+static int safe_directory_cb(const char *key, const char *value,
+                            const struct config_context *ctx UNUSED, void *d)
 {
        struct safe_directory_data *data = d;
 
@@ -1172,7 +1179,9 @@ static int ensure_valid_ownership(const char *gitfile,
        return data.is_safe;
 }
 
-static int allowed_bare_repo_cb(const char *key, const char *value, void *d)
+static int allowed_bare_repo_cb(const char *key, const char *value,
+                               const struct config_context *ctx UNUSED,
+                               void *d)
 {
        enum allowed_bare_repo *allowed_bare_repo = d;
 
@@ -1212,19 +1221,6 @@ static const char *allowed_bare_repo_to_string(
        return NULL;
 }
 
-enum discovery_result {
-       GIT_DIR_NONE = 0,
-       GIT_DIR_EXPLICIT,
-       GIT_DIR_DISCOVERED,
-       GIT_DIR_BARE,
-       /* these are errors */
-       GIT_DIR_HIT_CEILING = -1,
-       GIT_DIR_HIT_MOUNT_POINT = -2,
-       GIT_DIR_INVALID_GITFILE = -3,
-       GIT_DIR_INVALID_OWNERSHIP = -4,
-       GIT_DIR_DISALLOWED_BARE = -5,
-};
-
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
@@ -1376,21 +1372,23 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
        }
 }
 
-int discover_git_directory(struct strbuf *commondir,
-                          struct strbuf *gitdir)
+enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
+                                                   struct strbuf *gitdir)
 {
        struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
        size_t gitdir_offset = gitdir->len, cwd_len;
        size_t commondir_offset = commondir->len;
        struct repository_format candidate = REPOSITORY_FORMAT_INIT;
+       enum discovery_result result;
 
        if (strbuf_getcwd(&dir))
-               return -1;
+               return GIT_DIR_CWD_FAILURE;
 
        cwd_len = dir.len;
-       if (setup_git_directory_gently_1(&dir, gitdir, NULL, 0) <= 0) {
+       result = setup_git_directory_gently_1(&dir, gitdir, NULL, 0);
+       if (result <= 0) {
                strbuf_release(&dir);
-               return -1;
+               return result;
        }
 
        /*
@@ -1420,16 +1418,11 @@ int discover_git_directory(struct strbuf *commondir,
                strbuf_setlen(commondir, commondir_offset);
                strbuf_setlen(gitdir, gitdir_offset);
                clear_repository_format(&candidate);
-               return -1;
+               return GIT_DIR_INVALID_FORMAT;
        }
 
-       /* take ownership of candidate.partial_clone */
-       the_repository->repository_format_partial_clone =
-               candidate.partial_clone;
-       candidate.partial_clone = NULL;
-
        clear_repository_format(&candidate);
-       return 0;
+       return result;
 }
 
 const char *setup_git_directory_gently(int *nongit_ok)
@@ -1511,10 +1504,11 @@ const char *setup_git_directory_gently(int *nongit_ok)
                }
                *nongit_ok = 1;
                break;
-       case GIT_DIR_NONE:
+       case GIT_DIR_CWD_FAILURE:
+       case GIT_DIR_INVALID_FORMAT:
                /*
                 * As a safeguard against setup_git_directory_gently_1 returning
-                * this value, fallthrough to BUG. Otherwise it is possible to
+                * these values, fallthrough to BUG. Otherwise it is possible to
                 * set startup_info->have_repository to 1 when we did nothing to
                 * find a repository.
                 */
@@ -1560,6 +1554,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
                }
                if (startup_info->have_repository) {
                        repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
+                       the_repository->repository_format_worktree_config =
+                               repo_fmt.worktree_config;
                        /* take ownership of repo_fmt.partial_clone */
                        the_repository->repository_format_partial_clone =
                                repo_fmt.partial_clone;
@@ -1651,6 +1647,8 @@ void check_repository_format(struct repository_format *fmt)
        check_repository_format_gently(get_git_dir(), fmt, NULL);
        startup_info->have_repository = 1;
        repo_set_hash_algo(the_repository, fmt->hash_algo);
+       the_repository->repository_format_worktree_config =
+               fmt->worktree_config;
        the_repository->repository_format_partial_clone =
                xstrdup_or_null(fmt->partial_clone);
        clear_repository_format(&repo_fmt);
@@ -1707,3 +1705,491 @@ int daemonize(void)
        return 0;
 #endif
 }
+
+#ifdef NO_TRUSTABLE_FILEMODE
+#define TEST_FILEMODE 0
+#else
+#define TEST_FILEMODE 1
+#endif
+
+#define GIT_DEFAULT_HASH_ENVIRONMENT "GIT_DEFAULT_HASH"
+
+static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
+                            DIR *dir)
+{
+       size_t path_baselen = path->len;
+       size_t template_baselen = template_path->len;
+       struct dirent *de;
+
+       /* Note: if ".git/hooks" file exists in the repository being
+        * re-initialized, /etc/core-git/templates/hooks/update would
+        * cause "git init" to fail here.  I think this is sane but
+        * it means that the set of templates we ship by default, along
+        * with the way the namespace under .git/ is organized, should
+        * be really carefully chosen.
+        */
+       safe_create_dir(path->buf, 1);
+       while ((de = readdir(dir)) != NULL) {
+               struct stat st_git, st_template;
+               int exists = 0;
+
+               strbuf_setlen(path, path_baselen);
+               strbuf_setlen(template_path, template_baselen);
+
+               if (de->d_name[0] == '.')
+                       continue;
+               strbuf_addstr(path, de->d_name);
+               strbuf_addstr(template_path, de->d_name);
+               if (lstat(path->buf, &st_git)) {
+                       if (errno != ENOENT)
+                               die_errno(_("cannot stat '%s'"), path->buf);
+               }
+               else
+                       exists = 1;
+
+               if (lstat(template_path->buf, &st_template))
+                       die_errno(_("cannot stat template '%s'"), template_path->buf);
+
+               if (S_ISDIR(st_template.st_mode)) {
+                       DIR *subdir = opendir(template_path->buf);
+                       if (!subdir)
+                               die_errno(_("cannot opendir '%s'"), template_path->buf);
+                       strbuf_addch(path, '/');
+                       strbuf_addch(template_path, '/');
+                       copy_templates_1(path, template_path, subdir);
+                       closedir(subdir);
+               }
+               else if (exists)
+                       continue;
+               else if (S_ISLNK(st_template.st_mode)) {
+                       struct strbuf lnk = STRBUF_INIT;
+                       if (strbuf_readlink(&lnk, template_path->buf,
+                                           st_template.st_size) < 0)
+                               die_errno(_("cannot readlink '%s'"), template_path->buf);
+                       if (symlink(lnk.buf, path->buf))
+                               die_errno(_("cannot symlink '%s' '%s'"),
+                                         lnk.buf, path->buf);
+                       strbuf_release(&lnk);
+               }
+               else if (S_ISREG(st_template.st_mode)) {
+                       if (copy_file(path->buf, template_path->buf, st_template.st_mode))
+                               die_errno(_("cannot copy '%s' to '%s'"),
+                                         template_path->buf, path->buf);
+               }
+               else
+                       error(_("ignoring template %s"), template_path->buf);
+       }
+}
+
+static void copy_templates(const char *template_dir, const char *init_template_dir)
+{
+       struct strbuf path = STRBUF_INIT;
+       struct strbuf template_path = STRBUF_INIT;
+       size_t template_len;
+       struct repository_format template_format = REPOSITORY_FORMAT_INIT;
+       struct strbuf err = STRBUF_INIT;
+       DIR *dir;
+       char *to_free = NULL;
+
+       if (!template_dir)
+               template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
+       if (!template_dir)
+               template_dir = init_template_dir;
+       if (!template_dir)
+               template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
+       if (!template_dir[0]) {
+               free(to_free);
+               return;
+       }
+
+       strbuf_addstr(&template_path, template_dir);
+       strbuf_complete(&template_path, '/');
+       template_len = template_path.len;
+
+       dir = opendir(template_path.buf);
+       if (!dir) {
+               warning(_("templates not found in %s"), template_dir);
+               goto free_return;
+       }
+
+       /* Make sure that template is from the correct vintage */
+       strbuf_addstr(&template_path, "config");
+       read_repository_format(&template_format, template_path.buf);
+       strbuf_setlen(&template_path, template_len);
+
+       /*
+        * No mention of version at all is OK, but anything else should be
+        * verified.
+        */
+       if (template_format.version >= 0 &&
+           verify_repository_format(&template_format, &err) < 0) {
+               warning(_("not copying templates from '%s': %s"),
+                         template_dir, err.buf);
+               strbuf_release(&err);
+               goto close_free_return;
+       }
+
+       strbuf_addstr(&path, get_git_common_dir());
+       strbuf_complete(&path, '/');
+       copy_templates_1(&path, &template_path, dir);
+close_free_return:
+       closedir(dir);
+free_return:
+       free(to_free);
+       strbuf_release(&path);
+       strbuf_release(&template_path);
+       clear_repository_format(&template_format);
+}
+
+/*
+ * If the git_dir is not directly inside the working tree, then git will not
+ * find it by default, and we need to set the worktree explicitly.
+ */
+static int needs_work_tree_config(const char *git_dir, const char *work_tree)
+{
+       if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
+               return 0;
+       if (skip_prefix(git_dir, work_tree, &git_dir) &&
+           !strcmp(git_dir, "/.git"))
+               return 0;
+       return 1;
+}
+
+void initialize_repository_version(int hash_algo, int reinit)
+{
+       char repo_version_string[10];
+       int repo_version = GIT_REPO_VERSION;
+
+       if (hash_algo != GIT_HASH_SHA1)
+               repo_version = GIT_REPO_VERSION_READ;
+
+       /* This forces creation of new config file */
+       xsnprintf(repo_version_string, sizeof(repo_version_string),
+                 "%d", repo_version);
+       git_config_set("core.repositoryformatversion", repo_version_string);
+
+       if (hash_algo != GIT_HASH_SHA1)
+               git_config_set("extensions.objectformat",
+                              hash_algos[hash_algo].name);
+       else if (reinit)
+               git_config_set_gently("extensions.objectformat", NULL);
+}
+
+static int create_default_files(const char *template_path,
+                               const char *original_git_dir,
+                               const char *initial_branch,
+                               const struct repository_format *fmt,
+                               int prev_bare_repository,
+                               int init_shared_repository,
+                               int quiet)
+{
+       struct stat st1;
+       struct strbuf buf = STRBUF_INIT;
+       char *path;
+       char junk[2];
+       int reinit;
+       int filemode;
+       struct strbuf err = STRBUF_INIT;
+       const char *init_template_dir = NULL;
+       const char *work_tree = get_git_work_tree();
+
+       /*
+        * First copy the templates -- we might have the default
+        * config file there, in which case we would want to read
+        * from it after installing.
+        *
+        * Before reading that config, we also need to clear out any cached
+        * values (since we've just potentially changed what's available on
+        * disk).
+        */
+       git_config_get_pathname("init.templatedir", &init_template_dir);
+       copy_templates(template_path, init_template_dir);
+       free((char *)init_template_dir);
+       git_config_clear();
+       reset_shared_repository();
+       git_config(git_default_config, NULL);
+
+       /*
+        * We must make sure command-line options continue to override any
+        * values we might have just re-read from the config.
+        */
+       if (init_shared_repository != -1)
+               set_shared_repository(init_shared_repository);
+       /*
+        * TODO: heed core.bare from config file in templates if no
+        *       command-line override given
+        */
+       is_bare_repository_cfg = prev_bare_repository || !work_tree;
+       /* TODO (continued):
+        *
+        * Unfortunately, the line above is equivalent to
+        *    is_bare_repository_cfg = !work_tree;
+        * which ignores the config entirely even if no `--[no-]bare`
+        * command line option was present.
+        *
+        * To see why, note that before this function, there was this call:
+        *    prev_bare_repository = is_bare_repository()
+        * expanding the right hand side:
+        *                 = is_bare_repository_cfg && !get_git_work_tree()
+        *                 = is_bare_repository_cfg && !work_tree
+        * note that the last simplification above is valid because nothing
+        * calls repo_init() or set_git_work_tree() between any of the
+        * relevant calls in the code, and thus the !get_git_work_tree()
+        * calls will return the same result each time.  So, what we are
+        * interested in computing is the right hand side of the line of
+        * code just above this comment:
+        *     prev_bare_repository || !work_tree
+        *        = is_bare_repository_cfg && !work_tree || !work_tree
+        *        = !work_tree
+        * because "A && !B || !B == !B" for all boolean values of A & B.
+        */
+
+       /*
+        * We would have created the above under user's umask -- under
+        * shared-repository settings, we would need to fix them up.
+        */
+       if (get_shared_repository()) {
+               adjust_shared_perm(get_git_dir());
+       }
+
+       /*
+        * We need to create a "refs" dir in any case so that older
+        * versions of git can tell that this is a repository.
+        */
+       safe_create_dir(git_path("refs"), 1);
+       adjust_shared_perm(git_path("refs"));
+
+       if (refs_init_db(&err))
+               die("failed to set up refs db: %s", err.buf);
+
+       /*
+        * Point the HEAD symref to the initial branch with if HEAD does
+        * not yet exist.
+        */
+       path = git_path_buf(&buf, "HEAD");
+       reinit = (!access(path, R_OK)
+                 || readlink(path, junk, sizeof(junk)-1) != -1);
+       if (!reinit) {
+               char *ref;
+
+               if (!initial_branch)
+                       initial_branch = git_default_branch_name(quiet);
+
+               ref = xstrfmt("refs/heads/%s", initial_branch);
+               if (check_refname_format(ref, 0) < 0)
+                       die(_("invalid initial branch name: '%s'"),
+                           initial_branch);
+
+               if (create_symref("HEAD", ref, NULL) < 0)
+                       exit(1);
+               free(ref);
+       }
+
+       initialize_repository_version(fmt->hash_algo, 0);
+
+       /* Check filemode trustability */
+       path = git_path_buf(&buf, "config");
+       filemode = TEST_FILEMODE;
+       if (TEST_FILEMODE && !lstat(path, &st1)) {
+               struct stat st2;
+               filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
+                               !lstat(path, &st2) &&
+                               st1.st_mode != st2.st_mode &&
+                               !chmod(path, st1.st_mode));
+               if (filemode && !reinit && (st1.st_mode & S_IXUSR))
+                       filemode = 0;
+       }
+       git_config_set("core.filemode", filemode ? "true" : "false");
+
+       if (is_bare_repository())
+               git_config_set("core.bare", "true");
+       else {
+               git_config_set("core.bare", "false");
+               /* allow template config file to override the default */
+               if (log_all_ref_updates == LOG_REFS_UNSET)
+                       git_config_set("core.logallrefupdates", "true");
+               if (needs_work_tree_config(original_git_dir, work_tree))
+                       git_config_set("core.worktree", work_tree);
+       }
+
+       if (!reinit) {
+               /* Check if symlink is supported in the work tree */
+               path = git_path_buf(&buf, "tXXXXXX");
+               if (!close(xmkstemp(path)) &&
+                   !unlink(path) &&
+                   !symlink("testing", path) &&
+                   !lstat(path, &st1) &&
+                   S_ISLNK(st1.st_mode))
+                       unlink(path); /* good */
+               else
+                       git_config_set("core.symlinks", "false");
+
+               /* Check if the filesystem is case-insensitive */
+               path = git_path_buf(&buf, "CoNfIg");
+               if (!access(path, F_OK))
+                       git_config_set("core.ignorecase", "true");
+               probe_utf8_pathname_composition();
+       }
+
+       strbuf_release(&buf);
+       return reinit;
+}
+
+static void create_object_directory(void)
+{
+       struct strbuf path = STRBUF_INIT;
+       size_t baselen;
+
+       strbuf_addstr(&path, get_object_directory());
+       baselen = path.len;
+
+       safe_create_dir(path.buf, 1);
+
+       strbuf_setlen(&path, baselen);
+       strbuf_addstr(&path, "/pack");
+       safe_create_dir(path.buf, 1);
+
+       strbuf_setlen(&path, baselen);
+       strbuf_addstr(&path, "/info");
+       safe_create_dir(path.buf, 1);
+
+       strbuf_release(&path);
+}
+
+static void separate_git_dir(const char *git_dir, const char *git_link)
+{
+       struct stat st;
+
+       if (!stat(git_link, &st)) {
+               const char *src;
+
+               if (S_ISREG(st.st_mode))
+                       src = read_gitfile(git_link);
+               else if (S_ISDIR(st.st_mode))
+                       src = git_link;
+               else
+                       die(_("unable to handle file type %d"), (int)st.st_mode);
+
+               if (rename(src, git_dir))
+                       die_errno(_("unable to move %s to %s"), src, git_dir);
+               repair_worktrees(NULL, NULL);
+       }
+
+       write_file(git_link, "gitdir: %s", git_dir);
+}
+
+static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
+{
+       const char *env = getenv(GIT_DEFAULT_HASH_ENVIRONMENT);
+       /*
+        * If we already have an initialized repo, don't allow the user to
+        * specify a different algorithm, as that could cause corruption.
+        * Otherwise, if the user has specified one on the command line, use it.
+        */
+       if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
+               die(_("attempt to reinitialize repository with different hash"));
+       else if (hash != GIT_HASH_UNKNOWN)
+               repo_fmt->hash_algo = hash;
+       else if (env) {
+               int env_algo = hash_algo_by_name(env);
+               if (env_algo == GIT_HASH_UNKNOWN)
+                       die(_("unknown hash algorithm '%s'"), env);
+               repo_fmt->hash_algo = env_algo;
+       }
+}
+
+int init_db(const char *git_dir, const char *real_git_dir,
+           const char *template_dir, int hash, const char *initial_branch,
+           int init_shared_repository, unsigned int flags)
+{
+       int reinit;
+       int exist_ok = flags & INIT_DB_EXIST_OK;
+       char *original_git_dir = real_pathdup(git_dir, 1);
+       struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+       int prev_bare_repository;
+
+       if (real_git_dir) {
+               struct stat st;
+
+               if (!exist_ok && !stat(git_dir, &st))
+                       die(_("%s already exists"), git_dir);
+
+               if (!exist_ok && !stat(real_git_dir, &st))
+                       die(_("%s already exists"), real_git_dir);
+
+               set_git_dir(real_git_dir, 1);
+               git_dir = get_git_dir();
+               separate_git_dir(git_dir, original_git_dir);
+       }
+       else {
+               set_git_dir(git_dir, 1);
+               git_dir = get_git_dir();
+       }
+       startup_info->have_repository = 1;
+
+       /* Ensure `core.hidedotfiles` is processed */
+       git_config(platform_core_config, NULL);
+
+       safe_create_dir(git_dir, 0);
+
+       prev_bare_repository = is_bare_repository();
+
+       /* Check to see if the repository version is right.
+        * Note that a newly created repository does not have
+        * config file, so this will not fail.  What we are catching
+        * is an attempt to reinitialize new repository with an old tool.
+        */
+       check_repository_format(&repo_fmt);
+
+       validate_hash_algorithm(&repo_fmt, hash);
+
+       reinit = create_default_files(template_dir, original_git_dir,
+                                     initial_branch, &repo_fmt,
+                                     prev_bare_repository,
+                                     init_shared_repository,
+                                     flags & INIT_DB_QUIET);
+       if (reinit && initial_branch)
+               warning(_("re-init: ignored --initial-branch=%s"),
+                       initial_branch);
+
+       create_object_directory();
+
+       if (get_shared_repository()) {
+               char buf[10];
+               /* We do not spell "group" and such, so that
+                * the configuration can be read by older version
+                * of git. Note, we use octal numbers for new share modes,
+                * and compatibility values for PERM_GROUP and
+                * PERM_EVERYBODY.
+                */
+               if (get_shared_repository() < 0)
+                       /* force to the mode value */
+                       xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
+               else if (get_shared_repository() == PERM_GROUP)
+                       xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
+               else if (get_shared_repository() == PERM_EVERYBODY)
+                       xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
+               else
+                       BUG("invalid value for shared_repository");
+               git_config_set("core.sharedrepository", buf);
+               git_config_set("receive.denyNonFastforwards", "true");
+       }
+
+       if (!(flags & INIT_DB_QUIET)) {
+               int len = strlen(git_dir);
+
+               if (reinit)
+                       printf(get_shared_repository()
+                              ? _("Reinitialized existing shared Git repository in %s%s\n")
+                              : _("Reinitialized existing Git repository in %s%s\n"),
+                              git_dir, len && git_dir[len-1] != '/' ? "/" : "");
+               else
+                       printf(get_shared_repository()
+                              ? _("Initialized empty shared Git repository in %s%s\n")
+                              : _("Initialized empty Git repository in %s%s\n"),
+                              git_dir, len && git_dir[len-1] != '/' ? "/" : "");
+       }
+
+       free(original_git_dir);
+       return 0;
+}
diff --git a/setup.h b/setup.h
index 4c1ca9d0c94b88060033de50294da4d2e242bf15..b48cf1c43b5a559057a2e92d2fe4250c15255344 100644 (file)
--- a/setup.h
+++ b/setup.h
@@ -42,16 +42,45 @@ const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
 #define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
 
 void setup_work_tree(void);
+
+/*
+ * discover_git_directory_reason() is similar to discover_git_directory(),
+ * except it returns an enum value instead. It is important to note that
+ * a zero-valued return here is actually GIT_DIR_NONE, which is different
+ * from discover_git_directory.
+ */
+enum discovery_result {
+       GIT_DIR_EXPLICIT = 1,
+       GIT_DIR_DISCOVERED = 2,
+       GIT_DIR_BARE = 3,
+       /* these are errors */
+       GIT_DIR_HIT_CEILING = -1,
+       GIT_DIR_HIT_MOUNT_POINT = -2,
+       GIT_DIR_INVALID_GITFILE = -3,
+       GIT_DIR_INVALID_OWNERSHIP = -4,
+       GIT_DIR_DISALLOWED_BARE = -5,
+       GIT_DIR_INVALID_FORMAT = -6,
+       GIT_DIR_CWD_FAILURE = -7,
+};
+enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
+                                                   struct strbuf *gitdir);
+
 /*
  * Find the commondir and gitdir of the repository that contains the current
  * working directory, without changing the working directory or other global
  * state. The result is appended to commondir and gitdir.  If the discovered
  * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
  * both have the same result appended to the buffer.  The return value is
- * either 0 upon success and non-zero if no repository was found.
+ * either 0 upon success and -1 if no repository was found.
  */
-int discover_git_directory(struct strbuf *commondir,
-                          struct strbuf *gitdir);
+static inline int discover_git_directory(struct strbuf *commondir,
+                                        struct strbuf *gitdir)
+{
+       if (discover_git_directory_reason(commondir, gitdir) <= 0)
+               return -1;
+       return 0;
+}
+
 const char *setup_git_directory_gently(int *);
 const char *setup_git_directory(void);
 char *prefix_path(const char *prefix, int len, const char *path);
@@ -140,6 +169,15 @@ int verify_repository_format(const struct repository_format *format,
  */
 void check_repository_format(struct repository_format *fmt);
 
+#define INIT_DB_QUIET 0x0001
+#define INIT_DB_EXIST_OK 0x0002
+
+int init_db(const char *git_dir, const char *real_git_dir,
+           const char *template_dir, int hash_algo,
+           const char *initial_branch, int init_shared_repository,
+           unsigned int flags);
+void initialize_repository_version(int hash_algo, int reinit);
+
 /*
  * NOTE NOTE NOTE!!
  *
diff --git a/sha1/openssl.h b/sha1/openssl.h
new file mode 100644 (file)
index 0000000..006c1f4
--- /dev/null
@@ -0,0 +1,49 @@
+/* wrappers for the EVP API of OpenSSL 3+ */
+#ifndef SHA1_OPENSSL_H
+#define SHA1_OPENSSL_H
+#include <openssl/evp.h>
+
+struct openssl_SHA1_CTX {
+       EVP_MD_CTX *ectx;
+};
+
+typedef struct openssl_SHA1_CTX openssl_SHA1_CTX;
+
+static inline void openssl_SHA1_Init(struct openssl_SHA1_CTX *ctx)
+{
+       const EVP_MD *type = EVP_sha1();
+
+       ctx->ectx = EVP_MD_CTX_new();
+       if (!ctx->ectx)
+               die("EVP_MD_CTX_new: out of memory");
+
+       EVP_DigestInit_ex(ctx->ectx, type, NULL);
+}
+
+static inline void openssl_SHA1_Update(struct openssl_SHA1_CTX *ctx,
+                                       const void *data,
+                                       size_t len)
+{
+       EVP_DigestUpdate(ctx->ectx, data, len);
+}
+
+static inline void openssl_SHA1_Final(unsigned char *digest,
+                                      struct openssl_SHA1_CTX *ctx)
+{
+       EVP_DigestFinal_ex(ctx->ectx, digest, NULL);
+       EVP_MD_CTX_free(ctx->ectx);
+}
+
+static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst,
+                                       const struct openssl_SHA1_CTX *src)
+{
+       EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
+}
+
+#define platform_SHA_CTX openssl_SHA1_CTX
+#define platform_SHA1_Init openssl_SHA1_Init
+#define platform_SHA1_Clone openssl_SHA1_Clone
+#define platform_SHA1_Update openssl_SHA1_Update
+#define platform_SHA1_Final openssl_SHA1_Final
+
+#endif /* SHA1_OPENSSL_H */
index 501da5ed9197ec61497e244879c7f60ba58617c1..17a90f1052526c84847aa6d530a3e54e2558329f 100644 (file)
@@ -7,22 +7,25 @@
 
 typedef gcry_md_hd_t gcrypt_SHA256_CTX;
 
-inline void gcrypt_SHA256_Init(gcrypt_SHA256_CTX *ctx)
+static inline void gcrypt_SHA256_Init(gcrypt_SHA256_CTX *ctx)
 {
-       gcry_md_open(ctx, GCRY_MD_SHA256, 0);
+       gcry_error_t err = gcry_md_open(ctx, GCRY_MD_SHA256, 0);
+       if (err)
+               die("gcry_md_open: %s", gcry_strerror(err));
 }
 
-inline void gcrypt_SHA256_Update(gcrypt_SHA256_CTX *ctx, const void *data, size_t len)
+static inline void gcrypt_SHA256_Update(gcrypt_SHA256_CTX *ctx, const void *data, size_t len)
 {
        gcry_md_write(*ctx, data, len);
 }
 
-inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX *ctx)
+static inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX *ctx)
 {
        memcpy(digest, gcry_md_read(*ctx, GCRY_MD_SHA256), SHA256_DIGEST_SIZE);
+       gcry_md_close(*ctx);
 }
 
-inline void gcrypt_SHA256_Clone(gcrypt_SHA256_CTX *dst, const gcrypt_SHA256_CTX *src)
+static inline void gcrypt_SHA256_Clone(gcrypt_SHA256_CTX *dst, const gcrypt_SHA256_CTX *src)
 {
        gcry_md_copy(dst, *src);
 }
diff --git a/sha256/openssl.h b/sha256/openssl.h
new file mode 100644 (file)
index 0000000..c1083d9
--- /dev/null
@@ -0,0 +1,49 @@
+/* wrappers for the EVP API of OpenSSL 3+ */
+#ifndef SHA256_OPENSSL_H
+#define SHA256_OPENSSL_H
+#include <openssl/evp.h>
+
+struct openssl_SHA256_CTX {
+       EVP_MD_CTX *ectx;
+};
+
+typedef struct openssl_SHA256_CTX openssl_SHA256_CTX;
+
+static inline void openssl_SHA256_Init(struct openssl_SHA256_CTX *ctx)
+{
+       const EVP_MD *type = EVP_sha256();
+
+       ctx->ectx = EVP_MD_CTX_new();
+       if (!ctx->ectx)
+               die("EVP_MD_CTX_new: out of memory");
+
+       EVP_DigestInit_ex(ctx->ectx, type, NULL);
+}
+
+static inline void openssl_SHA256_Update(struct openssl_SHA256_CTX *ctx,
+                                       const void *data,
+                                       size_t len)
+{
+       EVP_DigestUpdate(ctx->ectx, data, len);
+}
+
+static inline void openssl_SHA256_Final(unsigned char *digest,
+                                      struct openssl_SHA256_CTX *ctx)
+{
+       EVP_DigestFinal_ex(ctx->ectx, digest, NULL);
+       EVP_MD_CTX_free(ctx->ectx);
+}
+
+static inline void openssl_SHA256_Clone(struct openssl_SHA256_CTX *dst,
+                                       const struct openssl_SHA256_CTX *src)
+{
+       EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
+}
+
+#define platform_SHA256_CTX openssl_SHA256_CTX
+#define platform_SHA256_Init openssl_SHA256_Init
+#define platform_SHA256_Clone openssl_SHA256_Clone
+#define platform_SHA256_Update openssl_SHA256_Update
+#define platform_SHA256_Final openssl_SHA256_Final
+
+#endif /* SHA256_OPENSSL_H */
index 128f56179edefa7d223508217e5c73aa427e647b..5413719fd4ef16c130117440c4d4687f9c1c5525 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -1,24 +1,24 @@
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "hex.h"
 #include "repository.h"
 #include "tempfile.h"
 #include "lockfile.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "tag.h"
 #include "pkt-line.h"
 #include "remote.h"
 #include "refs.h"
 #include "oid-array.h"
+#include "path.h"
 #include "diff.h"
 #include "revision.h"
 #include "commit-slab.h"
 #include "list-objects.h"
 #include "commit-reach.h"
 #include "shallow.h"
+#include "statinfo.h"
 #include "trace.h"
-#include "wrapper.h"
 
 void set_alternate_shallow_file(struct repository *r, const char *path, int override)
 {
index ee778c0580b6d9eb47ebc0d5f1ea7a9d7637a96c..66123bdbabb04123c6f0f4b64a8262584e3d2555 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "sigchain.h"
 
 #define SIGCHAIN_MAX_SIGNALS 32
index 886054729e5e343f664d81da5c5ad6b48cf06e8a..3578feb28376e308ebb1ab1adc069c6860bbe72b 100644 (file)
@@ -1,7 +1,8 @@
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "environment.h"
 #include "gettext.h"
+#include "name-hash.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "sparse-index.h"
 #include "tree.h"
@@ -10,7 +11,7 @@
 #include "cache-tree.h"
 #include "config.h"
 #include "dir.h"
-#include "fsmonitor.h"
+#include "fsmonitor-ll.h"
 
 struct modify_index_context {
        struct index_state *write;
@@ -390,7 +391,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
                strbuf_setlen(&base, 0);
                strbuf_add(&base, ce->name, strlen(ce->name));
 
-               read_tree_at(istate->repo, tree, &base, &ps,
+               read_tree_at(istate->repo, tree, &base, 0, &ps,
                             add_path_to_index, &ctx);
 
                /* free directory entries. full entries are re-used */
index 59a92d819ecdac1430b69db081b79cfc7e8ca84a..a16f3e67d75913daffc7ded0e08118ca233d1f5d 100644 (file)
@@ -37,4 +37,6 @@ struct pattern_list;
  */
 void expand_index(struct index_state *istate, struct pattern_list *pl);
 
+void ensure_full_index(struct index_state *istate);
+
 #endif
index 40e54760b35135d582346f41d1c6e8958f595143..8c38687c04b81ceaa57746a96daf670874e31643 100644 (file)
@@ -1,8 +1,8 @@
-#include "cache.h"
-#include "alloc.h"
+#include "git-compat-util.h"
 #include "gettext.h"
 #include "hash.h"
 #include "mem-pool.h"
+#include "read-cache-ll.h"
 #include "split-index.h"
 #include "strbuf.h"
 #include "ewah/ewok.h"
diff --git a/statinfo.c b/statinfo.c
new file mode 100644 (file)
index 0000000..9367ca0
--- /dev/null
@@ -0,0 +1,103 @@
+#include "git-compat-util.h"
+#include "environment.h"
+#include "statinfo.h"
+
+/*
+ * Munge st_size into an unsigned int.
+ */
+static unsigned int munge_st_size(off_t st_size) {
+       unsigned int sd_size = st_size;
+
+       /*
+        * If the file is an exact multiple of 4 GiB, modify the value so it
+        * doesn't get marked as racily clean (zero).
+        */
+       if (!sd_size && st_size)
+               return 0x80000000;
+       else
+               return sd_size;
+}
+
+void fill_stat_data(struct stat_data *sd, struct stat *st)
+{
+       sd->sd_ctime.sec = (unsigned int)st->st_ctime;
+       sd->sd_mtime.sec = (unsigned int)st->st_mtime;
+       sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
+       sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
+       sd->sd_dev = st->st_dev;
+       sd->sd_ino = st->st_ino;
+       sd->sd_uid = st->st_uid;
+       sd->sd_gid = st->st_gid;
+       sd->sd_size = munge_st_size(st->st_size);
+}
+
+int match_stat_data(const struct stat_data *sd, struct stat *st)
+{
+       int changed = 0;
+
+       if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
+               changed |= MTIME_CHANGED;
+       if (trust_ctime && check_stat &&
+           sd->sd_ctime.sec != (unsigned int)st->st_ctime)
+               changed |= CTIME_CHANGED;
+
+#ifdef USE_NSEC
+       if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+               changed |= MTIME_CHANGED;
+       if (trust_ctime && check_stat &&
+           sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+               changed |= CTIME_CHANGED;
+#endif
+
+       if (check_stat) {
+               if (sd->sd_uid != (unsigned int) st->st_uid ||
+                       sd->sd_gid != (unsigned int) st->st_gid)
+                       changed |= OWNER_CHANGED;
+               if (sd->sd_ino != (unsigned int) st->st_ino)
+                       changed |= INODE_CHANGED;
+       }
+
+#ifdef USE_STDEV
+       /*
+        * st_dev breaks on network filesystems where different
+        * clients will have different views of what "device"
+        * the filesystem is on
+        */
+       if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
+                       changed |= INODE_CHANGED;
+#endif
+
+       if (sd->sd_size != munge_st_size(st->st_size))
+               changed |= DATA_CHANGED;
+
+       return changed;
+}
+
+void stat_validity_clear(struct stat_validity *sv)
+{
+       FREE_AND_NULL(sv->sd);
+}
+
+int stat_validity_check(struct stat_validity *sv, const char *path)
+{
+       struct stat st;
+
+       if (stat(path, &st) < 0)
+               return sv->sd == NULL;
+       if (!sv->sd)
+               return 0;
+       return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
+}
+
+void stat_validity_update(struct stat_validity *sv, int fd)
+{
+       struct stat st;
+
+       if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
+               stat_validity_clear(sv);
+       else {
+               if (!sv->sd)
+                       CALLOC_ARRAY(sv->sd, 1);
+               fill_stat_data(sv->sd, &st);
+       }
+}
index e49e3054eaaa54f9916ae2a01fa9a1ca987b339a..700f502ac0b3cb938c2f376653dc1e91ac4e6d24 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef STATINFO_H
 #define STATINFO_H
 
+struct index_state;
+
 /*
  * The "cache_time" is just the low 32 bits of the
  * time. It doesn't matter if it overflows - we only
@@ -21,4 +23,67 @@ struct stat_data {
        unsigned int sd_size;
 };
 
+/*
+ * A struct to encapsulate the concept of whether a file has changed
+ * since we last checked it. This uses criteria similar to those used
+ * for the index.
+ */
+struct stat_validity {
+       struct stat_data *sd;
+};
+
+#define MTIME_CHANGED  0x0001
+#define CTIME_CHANGED  0x0002
+#define OWNER_CHANGED  0x0004
+#define MODE_CHANGED    0x0008
+#define INODE_CHANGED   0x0010
+#define DATA_CHANGED    0x0020
+#define TYPE_CHANGED    0x0040
+
+/*
+ * Record to sd the data from st that we use to check whether a file
+ * might have changed.
+ */
+void fill_stat_data(struct stat_data *sd, struct stat *st);
+
+/*
+ * Return 0 if st is consistent with a file not having been changed
+ * since sd was filled.  If there are differences, return a
+ * combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
+ * INODE_CHANGED, and DATA_CHANGED.
+ */
+int match_stat_data(const struct stat_data *sd, struct stat *st);
+
+void stat_validity_clear(struct stat_validity *sv);
+
+/*
+ * Returns 1 if the path is a regular file (or a symlink to a regular
+ * file) and matches the saved stat_validity, 0 otherwise.  A missing
+ * or inaccessible file is considered a match if the struct was just
+ * initialized, or if the previous update found an inaccessible file.
+ */
+int stat_validity_check(struct stat_validity *sv, const char *path);
+
+/*
+ * Update the stat_validity from a file opened at descriptor fd. If
+ * the file is missing, inaccessible, or not a regular file, then
+ * future calls to stat_validity_check will match iff one of those
+ * conditions continues to be true.
+ */
+void stat_validity_update(struct stat_validity *sv, int fd);
+
+#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
+#define DTYPE(de)      ((de)->d_type)
+#else
+#undef DT_UNKNOWN
+#undef DT_DIR
+#undef DT_REG
+#undef DT_LNK
+#define DT_UNKNOWN     0
+#define DT_DIR         1
+#define DT_REG         2
+#define DT_LNK         3
+#define DTYPE(de)      DT_UNKNOWN
+#endif
+
 #endif
index 08eec8f1d8b488fe9040b219edae353b4d199077..7827178d8e5e374582357f48a14a77bb15d98320 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,16 +1,10 @@
 #include "git-compat-util.h"
-#include "abspath.h"
-#include "alloc.h"
-#include "environment.h"
 #include "gettext.h"
-#include "hex.h"
-#include "object-name.h"
-#include "refs.h"
-#include "repository.h"
+#include "hex-ll.h"
+#include "strbuf.h"
 #include "string-list.h"
 #include "utf8.h"
 #include "date.h"
-#include "wrapper.h"
 
 int starts_with(const char *str, const char *prefix)
 {
@@ -365,7 +359,8 @@ static void add_lines(struct strbuf *out,
        strbuf_complete_line(out);
 }
 
-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)
+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,
+                               size_t size, char comment_line_char)
 {
        static char prefix1[3];
        static char prefix2[2];
@@ -377,7 +372,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size
        add_lines(out, prefix1, prefix2, buf, size);
 }
 
-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,
+                          const char *fmt, ...)
 {
        va_list params;
        struct strbuf buf = STRBUF_INIT;
@@ -387,7 +383,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
        strbuf_vaddf(&buf, fmt, params);
        va_end(params);
 
-       strbuf_add_commented_lines(sb, buf.buf, buf.len);
+       strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);
        if (incomplete_line)
                sb->buf[--sb->len] = '\0';
 
@@ -415,36 +411,19 @@ void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
        strbuf_setlen(sb, sb->len + len);
 }
 
-void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
-                  void *context)
+int strbuf_expand_step(struct strbuf *sb, const char **formatp)
 {
-       for (;;) {
-               const char *percent;
-               size_t consumed;
-
-               percent = strchrnul(format, '%');
-               strbuf_add(sb, format, percent - format);
-               if (!*percent)
-                       break;
-               format = percent + 1;
+       const char *format = *formatp;
+       const char *percent = strchrnul(format, '%');
 
-               if (*format == '%') {
-                       strbuf_addch(sb, '%');
-                       format++;
-                       continue;
-               }
-
-               consumed = fn(sb, format, context);
-               if (consumed)
-                       format += consumed;
-               else
-                       strbuf_addch(sb, '%');
-       }
+       strbuf_add(sb, format, percent - format);
+       if (!*percent)
+               return 0;
+       *formatp = percent + 1;
+       return 1;
 }
 
-size_t strbuf_expand_literal_cb(struct strbuf *sb,
-                               const char *placeholder,
-                               void *context UNUSED)
+size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder)
 {
        int ch;
 
@@ -463,22 +442,6 @@ size_t strbuf_expand_literal_cb(struct strbuf *sb,
        return 0;
 }
 
-size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
-               void *context)
-{
-       struct strbuf_expand_dict_entry *e = context;
-       size_t len;
-
-       for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
-               if (!strncmp(placeholder, e->placeholder, len)) {
-                       if (e->value)
-                               strbuf_addstr(sb, e->value);
-                       return len;
-               }
-       }
-       return 0;
-}
-
 void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
 {
        size_t i, len = src->len;
@@ -721,11 +684,11 @@ static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)
        return 0;
 }
 
-int strbuf_getline(struct strbuf *sb, FILE *fp)
+int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term)
 {
-       if (strbuf_getwholeline(sb, fp, '\n'))
+       if (strbuf_getwholeline(sb, fp, term))
                return EOF;
-       if (sb->buf[sb->len - 1] == '\n') {
+       if (term == '\n' && sb->buf[sb->len - 1] == '\n') {
                strbuf_setlen(sb, sb->len - 1);
                if (sb->len && sb->buf[sb->len - 1] == '\r')
                        strbuf_setlen(sb, sb->len - 1);
@@ -733,6 +696,11 @@ int strbuf_getline(struct strbuf *sb, FILE *fp)
        return 0;
 }
 
+int strbuf_getline(struct strbuf *sb, FILE *fp)
+{
+       return strbuf_getdelim_strip_crlf(sb, fp, '\n');
+}
+
 int strbuf_getline_lf(struct strbuf *sb, FILE *fp)
 {
        return strbuf_getdelim(sb, fp, '\n');
@@ -811,25 +779,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
        }
 }
 
-int is_rfc3986_reserved_or_unreserved(char ch)
-{
-       if (is_rfc3986_unreserved(ch))
-               return 1;
-       switch (ch) {
-               case '!': case '*': case '\'': case '(': case ')': case ';':
-               case ':': case '@': case '&': case '=': case '+': case '$':
-               case ',': case '/': case '?': case '#': case '[': case ']':
-                       return 1;
-       }
-       return 0;
-}
-
-int is_rfc3986_unreserved(char ch)
-{
-       return isalnum(ch) ||
-               ch == '-' || ch == '_' || ch == '.' || ch == '~';
-}
-
 static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
                                 char_predicate allow_unencoded_fn)
 {
@@ -900,42 +849,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)
        strbuf_humanise(buf, bytes, 1);
 }
 
-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
-{
-       if (!*path)
-               die("The empty string is not a valid path");
-       if (!is_absolute_path(path)) {
-               struct stat cwd_stat, pwd_stat;
-               size_t orig_len = sb->len;
-               char *cwd = xgetcwd();
-               char *pwd = getenv("PWD");
-               if (pwd && strcmp(pwd, cwd) &&
-                   !stat(cwd, &cwd_stat) &&
-                   (cwd_stat.st_dev || cwd_stat.st_ino) &&
-                   !stat(pwd, &pwd_stat) &&
-                   pwd_stat.st_dev == cwd_stat.st_dev &&
-                   pwd_stat.st_ino == cwd_stat.st_ino)
-                       strbuf_addstr(sb, pwd);
-               else
-                       strbuf_addstr(sb, cwd);
-               if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
-                       strbuf_addch(sb, '/');
-               free(cwd);
-       }
-       strbuf_addstr(sb, path);
-}
-
-void strbuf_add_real_path(struct strbuf *sb, const char *path)
-{
-       if (sb->len) {
-               struct strbuf resolved = STRBUF_INIT;
-               strbuf_realpath(&resolved, path, 1);
-               strbuf_addbuf(sb, &resolved);
-               strbuf_release(&resolved);
-       } else
-               strbuf_realpath(sb, path, 1);
-}
-
 int printf_ln(const char *fmt, ...)
 {
        int ret;
@@ -1022,37 +935,20 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
         * we want for %z, but the computation for %s has to convert to number
         * of seconds.
         */
-       for (;;) {
-               const char *percent = strchrnul(fmt, '%');
-               strbuf_add(&munged_fmt, fmt, percent - fmt);
-               if (!*percent)
-                       break;
-               fmt = percent + 1;
-               switch (*fmt) {
-               case '%':
+       while (strbuf_expand_step(&munged_fmt, &fmt)) {
+               if (skip_prefix(fmt, "%", &fmt))
                        strbuf_addstr(&munged_fmt, "%%");
-                       fmt++;
-                       break;
-               case 's':
+               else if (skip_prefix(fmt, "s", &fmt))
                        strbuf_addf(&munged_fmt, "%"PRItime,
                                    (timestamp_t)tm_to_time_t(tm) -
                                    3600 * (tz_offset / 100) -
                                    60 * (tz_offset % 100));
-                       fmt++;
-                       break;
-               case 'z':
+               else if (skip_prefix(fmt, "z", &fmt))
                        strbuf_addf(&munged_fmt, "%+05d", tz_offset);
-                       fmt++;
-                       break;
-               case 'Z':
-                       if (suppress_tz_name) {
-                               fmt++;
-                               break;
-                       }
-                       /* FALLTHROUGH */
-               default:
+               else if (suppress_tz_name && skip_prefix(fmt, "Z", &fmt))
+                       ; /* nothing */
+               else
                        strbuf_addch(&munged_fmt, '%');
-               }
        }
        fmt = munged_fmt.buf;
 
@@ -1080,21 +976,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
        strbuf_setlen(sb, sb->len + len);
 }
 
-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
-                                  const struct object_id *oid, int abbrev_len)
-{
-       int r;
-       strbuf_grow(sb, GIT_MAX_HEXSZ + 1);
-       r = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);
-       strbuf_setlen(sb, sb->len + r);
-}
-
-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
-                             int abbrev_len)
-{
-       strbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);
-}
-
 /*
  * Returns the length of a line, without trailing spaces.
  *
@@ -1124,10 +1005,10 @@ static size_t cleanup(char *line, size_t len)
  *
  * If last line does not have a newline at the end, one is added.
  *
- * Enable skip_comments to skip every line starting with comment
- * character.
+ * Pass a non-NUL comment_line_char to skip every line starting
+ * with it.
  */
-void strbuf_stripspace(struct strbuf *sb, int skip_comments)
+void strbuf_stripspace(struct strbuf *sb, char comment_line_char)
 {
        size_t empties = 0;
        size_t i, j, len, newlen;
@@ -1140,7 +1021,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)
                eol = memchr(sb->buf + i, '\n', sb->len - i);
                len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
 
-               if (skip_comments && len && sb->buf[i] == comment_line_char) {
+               if (comment_line_char && len &&
+                   sb->buf[i] == comment_line_char) {
                        newlen = 0;
                        continue;
                }
@@ -1161,26 +1043,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)
        strbuf_setlen(sb, j);
 }
 
-int strbuf_normalize_path(struct strbuf *src)
-{
-       struct strbuf dst = STRBUF_INIT;
-
-       strbuf_grow(&dst, src->len);
-       if (normalize_path_copy(dst.buf, src->buf) < 0) {
-               strbuf_release(&dst);
-               return -1;
-       }
-
-       /*
-        * normalize_path does not tell us the new length, so we have to
-        * compute it by looking for the new NUL it placed
-        */
-       strbuf_setlen(&dst, strlen(dst.buf));
-       strbuf_swap(src, &dst);
-       strbuf_release(&dst);
-       return 0;
-}
-
 void strbuf_strip_file_from_path(struct strbuf *sb)
 {
        char *path_sep = find_last_dir_sep(sb->buf);
index 3dfeadb44c2e93e3e47cd448eaf8fd9133ac47bc..e959caca876ac759debb0c77cd7c6d1046cbc25d 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,12 +1,20 @@
 #ifndef STRBUF_H
 #define STRBUF_H
 
+/*
+ * NOTE FOR STRBUF DEVELOPERS
+ *
+ * strbuf is a low-level primitive; as such it should interact only
+ * with other low-level primitives. Do not introduce new functions
+ * which interact with higher-level APIs.
+ */
+
 struct string_list;
 
 /**
- * strbuf's are meant to be used with all the usual C string and memory
+ * strbufs are meant to be used with all the usual C string and memory
  * APIs. Given that the length of the buffer is known, it's often better to
- * use the mem* functions than a str* one (memchr vs. strchr e.g.).
+ * use the mem* functions than a str* one (e.g., memchr vs. strchr).
  * Though, one has to be careful about the fact that str* functions often
  * stop on NULs and that strbufs may have embedded NULs.
  *
@@ -16,7 +24,7 @@ struct string_list;
  * strbufs have some invariants that are very important to keep in mind:
  *
  *  - The `buf` member is never NULL, so it can be used in any usual C
- *    string operations safely. strbuf's _have_ to be initialized either by
+ *    string operations safely. strbufs _have_ to be initialized either by
  *    `strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
  *
  *    Do *not* assume anything on what `buf` really is (e.g. if it is
@@ -29,7 +37,7 @@ struct string_list;
  *
  *  - The `buf` member is a byte array that has at least `len + 1` bytes
  *    allocated. The extra byte is used to store a `'\0'`, allowing the
- *    `buf` member to be a valid C-string. Every strbuf function ensure this
+ *    `buf` member to be a valid C-string. All strbuf functions ensure this
  *    invariant is preserved.
  *
  *    NOTE: It is OK to "play" with the buffer directly if you work it this
@@ -72,10 +80,6 @@ struct strbuf {
 extern char strbuf_slopbuf[];
 #define STRBUF_INIT  { .buf = strbuf_slopbuf }
 
-/*
- * Predeclare this here, since cache.h includes this file before it defines the
- * struct.
- */
 struct object_id;
 
 /**
@@ -283,7 +287,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
  * by a comment character and a blank.
  */
 void strbuf_add_commented_lines(struct strbuf *out,
-                               const char *buf, size_t size);
+                               const char *buf, size_t size,
+                               char comment_line_char);
 
 
 /**
@@ -318,58 +323,19 @@ const char *strbuf_join_argv(struct strbuf *buf, int argc,
                             const char **argv, char delim);
 
 /**
- * This function can be used to expand a format string containing
- * placeholders. To that end, it parses the string and calls the specified
- * function for every percent sign found.
- *
- * The callback function is given a pointer to the character after the `%`
- * and a pointer to the struct strbuf.  It is expected to add the expanded
- * version of the placeholder to the strbuf, e.g. to add a newline
- * character if the letter `n` appears after a `%`.  The function returns
- * the length of the placeholder recognized and `strbuf_expand()` skips
- * over it.
- *
- * The format `%%` is automatically expanded to a single `%` as a quoting
- * mechanism; callers do not need to handle the `%` placeholder themselves,
- * and the callback function will not be invoked for this placeholder.
- *
- * All other characters (non-percent and not skipped ones) are copied
- * verbatim to the strbuf.  If the callback returned zero, meaning that the
- * placeholder is unknown, then the percent sign is copied, too.
- *
- * In order to facilitate caching and to make it possible to give
- * parameters to the callback, `strbuf_expand()` passes a context
- * pointer with any kind of data.
+ * Used with `strbuf_expand_step` to expand the literals %n and %x
+ * followed by two hexadecimal digits. Returns the number of recognized
+ * characters.
  */
-typedef size_t (*expand_fn_t) (struct strbuf *sb,
-                              const char *placeholder,
-                              void *context);
-void strbuf_expand(struct strbuf *sb,
-                  const char *format,
-                  expand_fn_t fn,
-                  void *context);
+size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder);
 
 /**
- * Used as callback for `strbuf_expand` to only expand literals
- * (i.e. %n and %xNN). The context argument is ignored.
+ * If the string pointed to by `formatp` contains a percent sign ("%"),
+ * advance it to point to the character following the next one and
+ * return 1, otherwise return 0.  Append the substring before that
+ * percent sign to `sb`, or the whole string if there is none.
  */
-size_t strbuf_expand_literal_cb(struct strbuf *sb,
-                               const char *placeholder,
-                               void *context);
-
-/**
- * Used as callback for `strbuf_expand()`, expects an array of
- * struct strbuf_expand_dict_entry as context, i.e. pairs of
- * placeholder and replacement string.  The array needs to be
- * terminated by an entry with placeholder set to NULL.
- */
-struct strbuf_expand_dict_entry {
-       const char *placeholder;
-       const char *value;
-};
-size_t strbuf_expand_dict_cb(struct strbuf *sb,
-                            const char *placeholder,
-                            void *context);
+int strbuf_expand_step(struct strbuf *sb, const char **formatp);
 
 /**
  * Append the contents of one strbuf to another, quoting any
@@ -412,8 +378,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
  * Add a formatted string prepended by a comment character and a
  * blank to the buffer.
  */
-__attribute__((format (printf, 2, 3)))
-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
+__attribute__((format (printf, 3, 4)))
+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);
 
 __attribute__((format (printf,2,0)))
 void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
@@ -475,6 +441,18 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
  */
 ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
 
+/**
+ * Read from a FILE * until the specified terminator is encountered,
+ * overwriting the existing contents of the strbuf.
+ *
+ * Reading stops after the terminator or at EOF.  The terminator is
+ * removed from the buffer before returning.  If the terminator is LF
+ * and if it is preceded by a CR, then the whole CRLF is stripped.
+ * Returns 0 unless there was nothing left before EOF, in which case
+ * it returns `EOF`.
+ */
+int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term);
+
 /**
  * Read a line from a FILE *, overwriting the existing contents of
  * the strbuf.  The strbuf_getline*() family of functions share
@@ -527,28 +505,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);
  */
 int strbuf_getcwd(struct strbuf *sb);
 
-/**
- * Add a path to a buffer, converting a relative path to an
- * absolute one in the process.  Symbolic links are not
- * resolved.
- */
-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
-
-/**
- * Canonize `path` (make it absolute, resolve symlinks, remove extra
- * slashes) and append it to `sb`.  Die with an informative error
- * message if there is a problem.
- *
- * The directory part of `path` (i.e., everything up to the last
- * dir_sep) must denote a valid, existing directory, but the last
- * component need not exist.
- *
- * Callers that don't mind links should use the more lightweight
- * strbuf_add_absolute_path() instead.
- */
-void strbuf_add_real_path(struct strbuf *sb, const char *path);
-
-
 /**
  * Normalize in-place the path contained in the strbuf. See
  * normalize_path_copy() for details. If an error occurs, the contents of "sb"
@@ -557,10 +513,11 @@ void strbuf_add_real_path(struct strbuf *sb, const char *path);
 int strbuf_normalize_path(struct strbuf *sb);
 
 /**
- * Strip whitespace from a buffer. The second parameter controls if
- * comments are considered contents to be removed or not.
+ * Strip whitespace from a buffer. If comment_line_char is non-NUL,
+ * then lines beginning with that character are considered comments,
+ * thus removed.
  */
-void strbuf_stripspace(struct strbuf *buf, int skip_comments);
+void strbuf_stripspace(struct strbuf *buf, char comment_line_char);
 
 static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
 {
@@ -630,16 +587,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,
  */
 void strbuf_list_free(struct strbuf **list);
 
-/**
- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to
- * the strbuf `sb`.
- */
-struct repository;
-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
-                                  const struct object_id *oid, int abbrev_len);
-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
-                             int abbrev_len);
-
 /*
  * Remove the filename from the provided path string. If the path
  * contains a trailing separator, then the path is considered a directory
@@ -704,9 +651,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
 typedef int (*char_predicate)(char ch);
 
-int is_rfc3986_unreserved(char ch);
-int is_rfc3986_reserved_or_unreserved(char ch);
-
 void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,
                             char_predicate allow_unencoded_fn);
 
@@ -727,4 +671,36 @@ char *xstrvfmt(const char *fmt, va_list ap);
 __attribute__((format (printf, 1, 2)))
 char *xstrfmt(const char *fmt, ...);
 
+int starts_with(const char *str, const char *prefix);
+int istarts_with(const char *str, const char *prefix);
+
+/*
+ * If the string "str" is the same as the string in "prefix", then the "arg"
+ * parameter is set to the "def" parameter and 1 is returned.
+ * If the string "str" begins with the string found in "prefix" and then a
+ * "=" sign, then the "arg" parameter is set to "str + strlen(prefix) + 1"
+ * (i.e., to the point in the string right after the prefix and the "=" sign),
+ * and 1 is returned.
+ *
+ * Otherwise, return 0 and leave "arg" untouched.
+ *
+ * When we accept both a "--key" and a "--key=<val>" option, this function
+ * can be used instead of !strcmp(arg, "--key") and then
+ * skip_prefix(arg, "--key=", &arg) to parse such an option.
+ */
+int skip_to_optional_arg_default(const char *str, const char *prefix,
+                                const char **arg, const char *def);
+
+static inline int skip_to_optional_arg(const char *str, const char *prefix,
+                                      const char **arg)
+{
+       return skip_to_optional_arg_default(str, prefix, arg, "");
+}
+
+static inline int ends_with(const char *str, const char *suffix)
+{
+       size_t len;
+       return strip_suffix(str, suffix, &len);
+}
+
 #endif /* STRBUF_H */
index 21e39585e8906e8463c9765c044ecb4399b9603c..10adf625b2e7ab23ffde1c8c826f6c10691792d8 100644 (file)
@@ -7,10 +7,9 @@
 #include "streaming.h"
 #include "repository.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "replace-object.h"
 #include "packfile.h"
-#include "wrapper.h"
 
 typedef int (*open_istream_fn)(struct git_istream *,
                               struct repository *,
index 0f8ac117fd584828978568ff96ce21a63a8b160f..954569f381d8d7ea2e1c6f1333b1e8379ffe2fe8 100644 (file)
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "string-list.h"
-#include "alloc.h"
 
 void string_list_init_nodup(struct string_list *list)
 {
index 17d54b6c3bc500f7c8f927a702e1ec26ba66b7a1..89dc9e7e753313acbb0a5dc83b7705f3538a4c45 100644 (file)
--- a/strvec.c
+++ b/strvec.c
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "strvec.h"
-#include "alloc.h"
 #include "hex.h"
 #include "strbuf.h"
 
index 58dfbde9ae5883f755e88809faf3871859024730..6a48fd12f66f93d132aab6745d67effd482a168f 100644 (file)
@@ -1,16 +1,16 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
+#include "path.h"
 #include "repository.h"
 #include "config.h"
 #include "submodule-config.h"
 #include "submodule.h"
 #include "strbuf.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "parse-options.h"
 #include "thread-utils.h"
 #include "tree-walk.h"
@@ -304,9 +304,10 @@ static int parse_fetch_recurse(const char *opt, const char *arg,
        }
 }
 
-int parse_submodule_fetchjobs(const char *var, const char *value)
+int parse_submodule_fetchjobs(const char *var, const char *value,
+                             const struct key_value_info *kvi)
 {
-       int fetchjobs = git_config_int(var, value);
+       int fetchjobs = git_config_int(var, value, kvi);
        if (fetchjobs < 0)
                die(_("negative values not allowed for submodule.fetchJobs"));
        if (!fetchjobs)
@@ -426,7 +427,8 @@ struct parse_config_parameter {
  * config store (.git/config, etc).  Callers are responsible for
  * checking for overrides in the main config store when appropriate.
  */
-static int parse_config(const char *var, const char *value, void *data)
+static int parse_config(const char *var, const char *value,
+                       const struct config_context *ctx UNUSED, void *data)
 {
        struct parse_config_parameter *me = data;
        struct submodule *submodule;
@@ -605,7 +607,7 @@ static const struct submodule *config_from(struct submodule_cache *cache,
        parameter.gitmodules_oid = &oid;
        parameter.overwrite = 0;
        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
-                       config, config_size, &parameter, NULL);
+                           config, config_size, &parameter, CONFIG_SCOPE_UNKNOWN, NULL);
        strbuf_release(&rev);
        free(config);
 
@@ -659,7 +661,6 @@ static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void
                        config_source.file = file;
                } else if (repo_get_oid(repo, GITMODULES_INDEX, &oid) >= 0 ||
                           repo_get_oid(repo, GITMODULES_HEAD, &oid) >= 0) {
-                       config_source.repo = repo;
                        config_source.blob = oidstr = xstrdup(oid_to_hex(&oid));
                        if (repo != the_repository)
                                add_submodule_odb_by_path(repo->objects->odb->path);
@@ -667,7 +668,7 @@ static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void
                        goto out;
                }
 
-               config_with_options(fn, data, &config_source, &opts);
+               config_with_options(fn, data, &config_source, repo, &opts);
 
 out:
                free(oidstr);
@@ -675,7 +676,8 @@ out:
        }
 }
 
-static int gitmodules_cb(const char *var, const char *value, void *data)
+static int gitmodules_cb(const char *var, const char *value,
+                        const struct config_context *ctx, void *data)
 {
        struct repository *repo = data;
        struct parse_config_parameter parameter;
@@ -685,7 +687,7 @@ static int gitmodules_cb(const char *var, const char *value, void *data)
        parameter.gitmodules_oid = null_oid();
        parameter.overwrite = 1;
 
-       return parse_config(var, value, &parameter);
+       return parse_config(var, value, ctx, &parameter);
 }
 
 void repo_read_gitmodules(struct repository *repo, int skip_if_read)
@@ -713,7 +715,8 @@ void gitmodules_config_oid(const struct object_id *commit_oid)
 
        if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
                git_config_from_blob_oid(gitmodules_cb, rev.buf,
-                                        the_repository, &oid, the_repository);
+                                        the_repository, &oid, the_repository,
+                                        CONFIG_SCOPE_UNKNOWN);
        }
        strbuf_release(&rev);
 
@@ -802,7 +805,9 @@ void submodule_free(struct repository *r)
                submodule_cache_clear(r->submodule_cache);
 }
 
-static int config_print_callback(const char *var, const char *value, void *cb_data)
+static int config_print_callback(const char *var, const char *value,
+                                const struct config_context *ctx UNUSED,
+                                void *cb_data)
 {
        char *wanted_key = cb_data;
 
@@ -844,13 +849,15 @@ struct fetch_config {
        int *recurse_submodules;
 };
 
-static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
+static int gitmodules_fetch_config(const char *var, const char *value,
+                                  const struct config_context *ctx,
+                                  void *cb)
 {
        struct fetch_config *config = cb;
        if (!strcmp(var, "submodule.fetchjobs")) {
                if (config->max_children)
                        *(config->max_children) =
-                               parse_submodule_fetchjobs(var, value);
+                               parse_submodule_fetchjobs(var, value, ctx->kvi);
                return 0;
        } else if (!strcmp(var, "fetch.recursesubmodules")) {
                if (config->recurse_submodules)
@@ -872,11 +879,12 @@ void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules)
 }
 
 static int gitmodules_update_clone_config(const char *var, const char *value,
+                                         const struct config_context *ctx,
                                          void *cb)
 {
        int *max_jobs = cb;
        if (!strcmp(var, "submodule.fetchjobs"))
-               *max_jobs = parse_submodule_fetchjobs(var, value);
+               *max_jobs = parse_submodule_fetchjobs(var, value, ctx->kvi);
        return 0;
 }
 
index c2045875bbb4caa271e30d8318e8af353c525e37..2a37689cc272e30fa6f5dc9cfbbde044a52068c3 100644 (file)
@@ -50,7 +50,8 @@ struct repository;
 
 void submodule_cache_free(struct submodule_cache *cache);
 
-int parse_submodule_fetchjobs(const char *var, const char *value);
+int parse_submodule_fetchjobs(const char *var, const char *value,
+                             const struct key_value_info *kvi);
 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
 struct option;
 int option_fetch_parse_recurse_submodules(const struct option *opt,
index 2e78f5134964ffc60d94ee5d3a793a3624e214ba..e603a19a876c88c59f18da33caa1541b15ded9f3 100644 (file)
@@ -1,6 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "repository.h"
 #include "config.h"
 #include "submodule-config.h"
 #include "strvec.h"
 #include "blob.h"
 #include "thread-utils.h"
+#include "path.h"
 #include "quote.h"
 #include "remote.h"
 #include "worktree.h"
 #include "parse-options.h"
 #include "object-file.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit-reach.h"
+#include "read-cache-ll.h"
 #include "setup.h"
 #include "shallow.h"
 #include "trace2.h"
index 9930e283512b663133161fd474fc2101c19ec283..b9cea1795d84e3c4e334a89822e059e8d67512ef 100644 (file)
@@ -22,3 +22,4 @@ t[0-9][0-9][0-9][0-9]/* -whitespace
 /t7500/* eol=lf
 /t8005/*.txt eol=lf
 /t9*/*.dump eol=lf
+/t0040*.sh whitespace=-indent-with-non-tab
index bdfac4cceb2cef503070bdefc338ed73264e40b0..a0ebe294848ddc3ea6abdd7b9308edce34f7a876 100644 (file)
--- a/t/README
+++ b/t/README
@@ -262,8 +262,8 @@ The argument for --run, <test-selector>, is a list of description
 substrings or globs or individual test numbers or ranges with an
 optional negation prefix (of '!') that define what tests in a test
 suite to include (or exclude, if negated) in the run.  A range is two
-numbers separated with a dash and matches a range of tests with both
-ends been included.  You may omit the first or the second number to
+numbers separated with a dash and specifies an inclusive range of tests
+to run.  You may omit the first or the second number to
 mean "from the first test" or "up to the very last test" respectively.
 
 The argument to --run is split on commas into separate strings,
@@ -274,10 +274,10 @@ text that you want to match includes a comma, use the glob character
 on all tests that match either the glob *rebase* or the glob
 *merge?cherry-pick*.
 
-If --run starts with an unprefixed number or range the initial
-set of tests to run is empty. If the first item starts with '!'
+If --run starts with an unprefixed number or range, the initial
+set of tests to run is empty.  If the first item starts with '!',
 all the tests are added to the initial set.  After initial set is
-determined every test number or range is added or excluded from
+determined, every test number or range is added or excluded from
 the set one by one, from left to right.
 
 For example, to run only tests up to a specific test (21), one
@@ -442,6 +442,10 @@ GIT_TEST_INDEX_VERSION=<n> exercises the index read/write code path
 for the index version specified.  Can be set to any valid version
 (currently 2, 3, or 4).
 
+GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=<boolean> if enabled will
+use the boundary-based bitmap traversal algorithm. See the documentation
+of `pack.useBitmapBoundaryTraversal` for more details.
+
 GIT_TEST_PACK_SPARSE=<boolean> if disabled will default the pack-objects
 builtin to use the non-sparse object walk. This can still be overridden by
 the --sparse command-line argument.
@@ -575,11 +579,11 @@ This test harness library does the following things:
 
 Recommended style
 -----------------
-Here are some recommented styles when writing test case.
 
- - Keep test title the same line with test helper function itself.
+ - Keep the test_expect_* function call and test title on
+   the same line.
 
-   Take test_expect_success helper for example, write it like:
+   For example, with test_expect_success, write it like:
 
   test_expect_success 'test title' '
       ... test body ...
@@ -591,10 +595,9 @@ Here are some recommented styles when writing test case.
       'test title' \
       '... test body ...'
 
+ - End the line with an opening single quote.
 
- - End the line with a single quote.
-
- - Indent the body of here-document, and use "<<-" instead of "<<"
+ - Indent here-document bodies, and use "<<-" instead of "<<"
    to strip leading TABs used for indentation:
 
   test_expect_success 'test something' '
@@ -620,7 +623,7 @@ Here are some recommented styles when writing test case.
   '
 
  - Quote or escape the EOF delimiter that begins a here-document if
-   there is no parameter and other expansion in it, to signal readers
+   there is no parameter or other expansion in it, to signal readers
    that they can skim it more casually:
 
   cmd <<-\EOF
@@ -634,7 +637,7 @@ Do's & don'ts
 Here are a few examples of things you probably should and shouldn't do
 when writing tests.
 
-Here are the "do's:"
+The "do's:"
 
  - Put all code inside test_expect_success and other assertions.
 
@@ -884,7 +887,7 @@ see test-lib-functions.sh for the full list and their options.
    rare case where your test depends on more than one:
 
        test_expect_success PERL,PYTHON 'yo dawg' \
-           ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" '
+           ' test $(perl -E '\''print eval "1 +" . qx[python -c "print(2)"]'\'') = "4" '
 
  - test_expect_failure [<prereq>] <message> <script>
 
@@ -1098,6 +1101,12 @@ see test-lib-functions.sh for the full list and their options.
    the symbolic link in the file system and a part that does; then only
    the latter part need be protected by a SYMLINKS prerequisite (see below).
 
+ - test_path_is_executable
+
+   This tests whether a file is executable and prints an error message
+   if not. This must be used only under the POSIXPERM prerequisite
+   (see below).
+
  - test_oid_init
 
    This function loads facts and useful object IDs related to the hash
@@ -1227,8 +1236,8 @@ and it knows that the object ID of an empty tree is a certain
 because the things the very basic core test tries to achieve is
 to serve as a basis for people who are changing the Git internals
 drastically.  For these people, after making certain changes,
-not seeing failures from the basic test _is_ a failure.  And
-such drastic changes to the core Git that even changes these
+not seeing failures from the basic test _is_ a failure.  Any
+Git core changes so drastic that they change even these
 otherwise supposedly stable object IDs should be accompanied by
 an update to t0000-basic.sh.
 
@@ -1238,7 +1247,7 @@ knowledge of the core Git internals.  If all the test scripts
 hardcoded the object IDs like t0000-basic.sh does, that defeats
 the purpose of t0000-basic.sh, which is to isolate that level of
 validation in one place.  Your test also ends up needing
-updating when such a change to the internal happens, so do _not_
+an update whenever the internals change, so do _not_
 do it and leave the low level of validation to t0000-basic.sh.
 
 Test coverage
index 2ef70235b1010b1179e083e1e390b3ae7afabea4..5e21e84f3884eb8c787ab82a5d1360d2b7cffb74 100644 (file)
@@ -83,6 +83,15 @@ test_expect_success 'blame with --contents' '
        check_count --contents=file A 2
 '
 
+test_expect_success 'blame with --contents in a bare repo' '
+       git clone --bare . bare-contents.git &&
+       (
+               cd bare-contents.git &&
+               echo "1A quick brown fox jumps over the" >contents &&
+               check_count --contents=contents A 1
+       )
+'
+
 test_expect_success 'blame with --contents changed' '
        echo "1A quick brown fox jumps over the" >contents &&
        echo "another lazy dog" >>contents &&
index 9507b356e22f15ceb70841dee5f3a547cb38ed37..e7236392c8132a3720f55148d6c2acbf5de01a41 100644 (file)
@@ -1,11 +1,11 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "gettext.h"
 #include "hex.h"
 #include "tree.h"
 #include "cache-tree.h"
 #include "parse-options.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 
index ad78fc17683d99b53b6ced2e67a72a6387051dbf..ed444ca4c25fbf2c581d5f950609c218b53a341c 100644 (file)
  *
  */
 
-static int iterate_cb(const char *var, const char *value, void *data UNUSED)
+static int iterate_cb(const char *var, const char *value,
+                     const struct config_context *ctx,
+                     void *data UNUSED)
 {
+       const struct key_value_info *kvi = ctx->kvi;
        static int nr;
 
        if (nr++)
@@ -51,26 +54,29 @@ static int iterate_cb(const char *var, const char *value, void *data UNUSED)
 
        printf("key=%s\n", var);
        printf("value=%s\n", value ? value : "(null)");
-       printf("origin=%s\n", current_config_origin_type());
-       printf("name=%s\n", current_config_name());
-       printf("lno=%d\n", current_config_line());
-       printf("scope=%s\n", config_scope_name(current_config_scope()));
+       printf("origin=%s\n", config_origin_type_name(kvi->origin_type));
+       printf("name=%s\n", kvi->filename ? kvi->filename : "");
+       printf("lno=%d\n", kvi->linenr);
+       printf("scope=%s\n", config_scope_name(kvi->scope));
 
        return 0;
 }
 
-static int parse_int_cb(const char *var, const char *value, void *data)
+static int parse_int_cb(const char *var, const char *value,
+                       const struct config_context *ctx, void *data)
 {
        const char *key_to_match = data;
 
        if (!strcmp(key_to_match, var)) {
-               int parsed = git_config_int(value, value);
+               int parsed = git_config_int(value, value, ctx->kvi);
                printf("%d\n", parsed);
        }
        return 0;
 }
 
-static int early_config_cb(const char *var, const char *value, void *vdata)
+static int early_config_cb(const char *var, const char *value,
+                          const struct config_context *ctx UNUSED,
+                          void *vdata)
 {
        const char *key = vdata;
 
@@ -176,7 +182,7 @@ int cmd__config(int argc, const char **argv)
                                goto exit2;
                        }
                }
-               if (!git_configset_get_value(&cs, argv[2], &v)) {
+               if (!git_configset_get_value(&cs, argv[2], &v, NULL)) {
                        if (!v)
                                printf("(NULL)\n");
                        else
index e7d134ec251e01405a6f854bbd496d797980172f..6bc787a4743be08fcd1b977ced58273c3bf274d0 100644 (file)
@@ -11,7 +11,6 @@
 #include "test-tool.h"
 #include "git-compat-util.h"
 #include "delta.h"
-#include "wrapper.h"
 
 static const char usage_str[] =
        "test-tool delta (-d|-p) <from_file> <data_file> <out_file>";
index f22f7bd84a914f2c338ffb4e9f4fbc85d669fbde..c38f546e4f096fbd3e9b6cb13ab96bb800f56504 100644 (file)
@@ -1,10 +1,10 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "hash.h"
 #include "hex.h"
 #include "tree.h"
 #include "cache-tree.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 
index 9a098a25cba7f32381d1a96459eb39434c1e5c16..4f215fea025290f868defcae8bdca5aeefc627ba 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 
index d1badd711263f9192c72854de6de73dd4bc76a88..f29d18ef9490b7a0dd8fd689082a68b4cd5332b0 100644 (file)
@@ -1,12 +1,13 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "hex.h"
+#include "read-cache-ll.h"
+#include "repository.h"
 #include "setup.h"
 #include "split-index.h"
 #include "ewah/ewok.h"
 
-static void show_bit(size_t pos, void *data)
+static void show_bit(size_t pos, void *data UNUSED)
 {
        printf(" %d", (int)pos);
 }
index df70be549fdd5a93980373871ecf6602a8176bf7..b4af9712fe5f2cfb815e22dc41a588890faecea5 100644 (file)
@@ -1,8 +1,8 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "dir.h"
 #include "hex.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 
index 66c88b8ff3d311573db482035aa143a0c1ad136f..1c486888a42d0da490f6b9a4d90941b09eda754b 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "config.h"
+#include "parse.h"
 #include "parse-options.h"
 
 static char const * const env__helper_usage[] = {
index 2ed910adaa3da3b5db771679ccb1eefb0a8da2f5..8f59f6be4cff6c53da68ebb4ea7201e71793cbe1 100644 (file)
@@ -72,5 +72,7 @@ int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
        if (objects_noticed != 2)
                BUG("should have 2 objects");
 
+       clear_decoration(&n, NULL);
+
        return 0;
 }
index d1d63feaa9e299ace44d228176cd2b4335193569..cac20a72b3fcb52c5ccb66cbbb1679ecb8f39f97 100644 (file)
 
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "cache-tree.h"
 #include "commit.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "lockfile.h"
 #include "merge-ort.h"
 #include "object-name.h"
+#include "read-cache-ll.h"
 #include "refs.h"
 #include "revision.h"
 #include "sequencer.h"
diff --git a/t/helper/test-find-pack.c b/t/helper/test-find-pack.c
new file mode 100644 (file)
index 0000000..e8bd793
--- /dev/null
@@ -0,0 +1,50 @@
+#include "test-tool.h"
+#include "object-name.h"
+#include "object-store.h"
+#include "packfile.h"
+#include "parse-options.h"
+#include "setup.h"
+
+/*
+ * Display the path(s), one per line, of the packfile(s) containing
+ * the given object.
+ *
+ * If '--check-count <n>' is passed, then error out if the number of
+ * packfiles containing the object is not <n>.
+ */
+
+static const char *find_pack_usage[] = {
+       "test-tool find-pack [--check-count <n>] <object>",
+       NULL
+};
+
+int cmd__find_pack(int argc, const char **argv)
+{
+       struct object_id oid;
+       struct packed_git *p;
+       int count = -1, actual_count = 0;
+       const char *prefix = setup_git_directory();
+
+       struct option options[] = {
+               OPT_INTEGER('c', "check-count", &count, "expected number of packs"),
+               OPT_END(),
+       };
+
+       argc = parse_options(argc, argv, prefix, options, find_pack_usage, 0);
+       if (argc != 1)
+               usage(find_pack_usage[0]);
+
+       if (repo_get_oid(the_repository, argv[0], &oid))
+               die("cannot parse %s as an object name", argv[0]);
+
+       for (p = get_all_packs(the_repository); p; p = p->next)
+               if (find_pack_entry_one(oid.hash, p)) {
+                       printf("%s\n", p->pack_name);
+                       actual_count++;
+               }
+
+       if (count > -1 && count != actual_count)
+               die("bad packfile count %d instead of %d", actual_count, count);
+
+       return 0;
+}
index 9f18c685b7f05cb0fc56c4a69017ea6b64248045..8280984d08fe84b23722948709e83252e5d40895 100644 (file)
@@ -4,14 +4,13 @@
  */
 
 #include "test-tool.h"
-#include "cache.h"
 #include "parse-options.h"
 #include "fsmonitor-ipc.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 #include "thread-utils.h"
 #include "trace2.h"
-#include "wrapper.h"
 
 #ifndef HAVE_FSMONITOR_DAEMON_BACKEND
 int cmd__fsmonitor_client(int argc UNUSED, const char **argv UNUSED)
index f40d9ad0c2ddd293f2b1a1e7e142885ede078ae6..b235da594f749b1a6b680d0b674c5bb822b1b978 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
 
 #define NUM_SECONDS 3
 
diff --git a/t/helper/test-index-version.c b/t/helper/test-index-version.c
deleted file mode 100644 (file)
index a06c45c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "test-tool.h"
-#include "cache.h"
-
-int cmd__index_version(int argc UNUSED, const char **argv UNUSED)
-{
-       struct cache_header hdr;
-       int version;
-
-       memset(&hdr,0,sizeof(hdr));
-       if (read(0, &hdr, sizeof(hdr)) != sizeof(hdr))
-               return 0;
-       version = ntohl(hdr.hdr_version);
-       printf("%d\n", version);
-       return 0;
-}
index b83a75d19f6c3d665219361bb15f5512ebb0e357..187a115d5743f39f7b93e0bf128ead62262a12bb 100644 (file)
@@ -1,8 +1,9 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "environment.h"
+#include "name-hash.h"
 #include "parse-options.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 #include "trace.h"
index eef68833b7fb0607eebf336e1ee9627aed7390d8..aafe398ef07e538ef774fedc72cd27189391f2fb 100644 (file)
@@ -4,7 +4,7 @@
 #include "setup.h"
 #include "strbuf.h"
 
-static int print_oid(const struct object_id *oid, void *data)
+static int print_oid(const struct object_id *oid, void *data UNUSED)
 {
        puts(oid_to_hex(oid));
        return 0;
index 0f3fbeec5325922a83e0d15382b940e6afddcb51..67a964ef9041a061497c0b10698413d360f561e1 100644 (file)
@@ -1,7 +1,7 @@
 #include "test-tool.h"
 #include "hex.h"
 #include "strbuf.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "packfile.h"
 #include "pack-mtimes.h"
 #include "setup.h"
index 00fa281a9c9342d2ec4213665bac8f6b789c8b90..ded8116cc5119f9d22d2d083cb8fa189e3783904 100644 (file)
@@ -21,6 +21,19 @@ static struct {
        int unset;
 } length_cb;
 
+static int mode34_callback(const struct option *opt, const char *arg, int unset)
+{
+       if (unset)
+               *(int *)opt->value = 0;
+       else if (!strcmp(arg, "3"))
+               *(int *)opt->value = 3;
+       else if (!strcmp(arg, "4"))
+               *(int *)opt->value = 4;
+       else
+               return error("invalid value for '%s': '%s'", "--mode34", arg);
+       return 0;
+}
+
 static int length_callback(const struct option *opt, const char *arg, int unset)
 {
        length_cb.called = 1;
@@ -124,6 +137,9 @@ int cmd__parse_options(int argc, const char **argv)
                OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
                OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
                OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
+               OPT_CALLBACK_F(0, "mode34", &integer, "(3|4)",
+                       "set integer to 3 or 4 (cmdmode option)",
+                       PARSE_OPT_CMDMODE, mode34_callback),
                OPT_CALLBACK('L', "length", &integer, "str",
                        "get length of <str>", length_callback),
                OPT_FILENAME('F', "file", &file, "set file to <file>"),
@@ -133,6 +149,8 @@ int cmd__parse_options(int argc, const char **argv)
                OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
                OPT_STRING('o', NULL, &string, "str", "get another string"),
                OPT_NOOP_NOARG(0, "obsolete"),
+               OPT_SET_INT_F(0, "longhelp", &integer, "help text of this entry\n"
+                             "spans multiple lines", 0, PARSE_OPT_NONEG),
                OPT_STRING_LIST(0, "list", &list, "str", "add str to list"),
                OPT_GROUP("Magic arguments"),
                OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
index 362bd64a4c21a632e27a53a4154355803400a9de..910a12861442264ca951a1a2ef27e6fb20eb7985 100644 (file)
@@ -1,7 +1,7 @@
 #include "test-tool.h"
 #include "hex.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "setup.h"
 
 /*
index 2ef53d5f7a27badae6dac4baaa64829bea3f85dd..70396fa38454e86d661b9a4857e3ef463ee40f63 100644 (file)
@@ -1,8 +1,8 @@
 #include "test-tool.h"
-#include "cache.h"
 #include "abspath.h"
 #include "environment.h"
 #include "path.h"
+#include "read-cache-ll.h"
 #include "setup.h"
 #include "string-list.h"
 #include "trace.h"
index 5b6f2174418101575302a7fd083349414d6f283e..3e173399a00f5296a70aa293107dfb4db94b1633 100644 (file)
@@ -1,5 +1,4 @@
 #include "test-tool.h"
-#include "alloc.h"
 #include "commit.h"
 #include "commit-reach.h"
 #include "config.h"
@@ -139,7 +138,7 @@ int cmd__reach(int ac, const char **av)
 
                printf("%s(X,_,_,0,0):%d\n", av[1], can_all_from_reach_with_flag(&X_obj, 2, 4, 0, 0));
        } else if (!strcmp(av[1], "commit_contains")) {
-               struct ref_filter filter;
+               struct ref_filter filter = REF_FILTER_INIT;
                struct contains_cache cache;
                init_contains_cache(&cache);
 
index c1ae2763954b0587f3187fc9769f9d47a98f8fdd..1acd3623465283e4751a75bce0cbb8bf1926bcd7 100644 (file)
@@ -1,10 +1,9 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "config.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
-#include "wrapper.h"
 
 int cmd__read_cache(int argc, const char **argv)
 {
index 3ac496e27e497df4d3ba800409c0117fbb8ded1f..8c7a83f578f41c3d90bcb17628bd5307e5927636 100644 (file)
@@ -1,7 +1,7 @@
 #include "test-tool.h"
 #include "commit-graph.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "bloom.h"
 #include "setup.h"
 
index 211addaa005c9f13d09eac2277984fb9403134c8..e9a444ddba55b49c9c47ceb3b27a31d3e022a8dc 100644 (file)
@@ -2,7 +2,7 @@
 #include "hex.h"
 #include "midx.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "pack-bitmap.h"
 #include "packfile.h"
 #include "setup.h"
index 6d8f844e9c7dc4889d6670e86a26fcb59f87bbb1..48552e6a9e0049365185499c02d9b1c7d1069d0c 100644 (file)
@@ -3,8 +3,11 @@
 #include "refs.h"
 #include "setup.h"
 #include "worktree.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "path.h"
 #include "repository.h"
+#include "strbuf.h"
+#include "revision.h"
 
 struct flag_definition {
        const char *name;
@@ -116,8 +119,16 @@ static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
 static int cmd_pack_refs(struct ref_store *refs, const char **argv)
 {
        unsigned int flags = arg_flags(*argv++, "flags", pack_flags);
+       static struct ref_exclusions exclusions = REF_EXCLUSIONS_INIT;
+       static struct string_list included_refs = STRING_LIST_INIT_NODUP;
+       struct pack_refs_opts pack_opts = { .flags = flags,
+                                           .exclusions = &exclusions,
+                                           .includes = &included_refs };
 
-       return refs_pack_refs(refs, flags);
+       if (pack_opts.flags & PACK_REFS_ALL)
+               string_list_append(pack_opts.includes, "*");
+
+       return refs_pack_refs(refs, &pack_opts);
 }
 
 static int cmd_create_symref(struct ref_store *refs, const char **argv)
@@ -175,6 +186,15 @@ static int cmd_for_each_ref(struct ref_store *refs, const char **argv)
        return refs_for_each_ref_in(refs, prefix, each_ref, NULL);
 }
 
+static int cmd_for_each_ref__exclude(struct ref_store *refs, const char **argv)
+{
+       const char *prefix = notnull(*argv++, "prefix");
+       const char **exclude_patterns = argv;
+
+       return refs_for_each_fullref_in(refs, prefix, exclude_patterns, each_ref,
+                                       NULL);
+}
+
 static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
 {
        struct object_id oid = *null_oid();
@@ -257,11 +277,6 @@ static int cmd_delete_reflog(struct ref_store *refs, const char **argv)
        return refs_delete_reflog(refs, refname);
 }
 
-static int cmd_reflog_expire(struct ref_store *refs, const char **argv)
-{
-       die("not supported yet");
-}
-
 static int cmd_delete_ref(struct ref_store *refs, const char **argv)
 {
        const char *msg = notnull(*argv++, "msg");
@@ -307,6 +322,7 @@ static struct command commands[] = {
        { "delete-refs", cmd_delete_refs },
        { "rename-ref", cmd_rename_ref },
        { "for-each-ref", cmd_for_each_ref },
+       { "for-each-ref--exclude", cmd_for_each_ref__exclude },
        { "resolve-ref", cmd_resolve_ref },
        { "verify-ref", cmd_verify_ref },
        { "for-each-reflog", cmd_for_each_reflog },
@@ -315,7 +331,6 @@ static struct command commands[] = {
        { "reflog-exists", cmd_reflog_exists },
        { "create-reflog", cmd_create_reflog },
        { "delete-reflog", cmd_delete_reflog },
-       { "reflog-expire", cmd_reflog_expire },
        /*
         * backend transaction functions can't be tested separately
         */
index bafd2a5bf95b3e31cab6397d623329e835f5e0fc..4cd8a952e5c6f55fbb3cfdbffe8c3be07bf008d7 100644 (file)
@@ -4,7 +4,7 @@
 #include "config.h"
 #include "environment.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "object.h"
 #include "repository.h"
 #include "setup.h"
index 0c62b9de1850b1409313395df3a76f8d591bf910..f346951bc28c99e4791d841fac0d873a128cc973 100644 (file)
@@ -11,6 +11,7 @@
 #include "test-tool.h"
 #include "commit.h"
 #include "diff.h"
+#include "repository.h"
 #include "revision.h"
 #include "setup.h"
 
index 6e17f50d2259e55014ac8bc6cf948eed334c0116..0a816a96e28b6c43a0b4927418c97bb11ba5298c 100644 (file)
@@ -1,7 +1,7 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "lockfile.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 #include "tree.h"
index 71fe5c61455a89eddd6363a87e3c4eb7968f09b6..dcb7f6c0032b556959c6635db3c89fd49e8790d0 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
 
 int cmd__sha1(int ac, const char **av)
 {
index 0ac6a99d5f2a38d89317564185e91ee5126fd3ac..08cf14900140d37733e5afcad7c9fdc97c3b7eae 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "hash-ll.h"
 
 int cmd__sha256(int ac, const char **av)
 {
index 3d1436da59872fcfe7551a5586c7720893221ddb..941ae7e3bcf3eda6e88148d9ff9d923aea707ada 100644 (file)
@@ -278,7 +278,8 @@ static int daemon__run_server(void)
 
 static start_bg_wait_cb bg_wait_cb;
 
-static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+                     void *cb_data UNUSED)
 {
        int s = ipc_get_active_state(cl_args.path);
 
index 96b9a5b5291a637a7effff289ecf1d96860e6c24..d8473cf2fcfeb61bdbced865455dd2e3a35b71bb 100644 (file)
@@ -1,5 +1,5 @@
 #include "test-tool.h"
-#include "cache.h"
+#include "read-cache-ll.h"
 
 int cmd__strcmp_offset(int argc UNUSED, const char **argv)
 {
index abe8a785eb651017ce2336eed7fa3bda06d4658c..876cd2dc313a73e48b55ba79488dbf2ea5887fa1 100644 (file)
@@ -31,6 +31,7 @@ static struct test_cmd cmds[] = {
        { "env-helper", cmd__env_helper },
        { "example-decorate", cmd__example_decorate },
        { "fast-rebase", cmd__fast_rebase },
+       { "find-pack", cmd__find_pack },
        { "fsmonitor-client", cmd__fsmonitor_client },
        { "genrandom", cmd__genrandom },
        { "genzeros", cmd__genzeros },
@@ -38,7 +39,6 @@ static struct test_cmd cmds[] = {
        { "hashmap", cmd__hashmap },
        { "hash-speed", cmd__hash_speed },
        { "hexdump", cmd__hexdump },
-       { "index-version", cmd__index_version },
        { "json-writer", cmd__json_writer },
        { "lazy-init-name-hash", cmd__lazy_init_name_hash },
        { "match-trees", cmd__match_trees },
@@ -86,6 +86,7 @@ static struct test_cmd cmds[] = {
        { "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
        { "subprocess", cmd__subprocess },
        { "trace2", cmd__trace2 },
+       { "truncate", cmd__truncate },
        { "userdiff", cmd__userdiff },
        { "urlmatch-normalization", cmd__urlmatch_normalization },
        { "xml-encode", cmd__xml_encode },
index ea2672436c9ab56ed544d0a3ff414c366de5fdc0..70dd4eba11905083f325409955b1b0f8ec18a883 100644 (file)
@@ -25,6 +25,7 @@ int cmd__dump_reftable(int argc, const char **argv);
 int cmd__env_helper(int argc, const char **argv);
 int cmd__example_decorate(int argc, const char **argv);
 int cmd__fast_rebase(int argc, const char **argv);
+int cmd__find_pack(int argc, const char **argv);
 int cmd__fsmonitor_client(int argc, const char **argv);
 int cmd__genrandom(int argc, const char **argv);
 int cmd__genzeros(int argc, const char **argv);
@@ -32,7 +33,6 @@ int cmd__getcwd(int argc, const char **argv);
 int cmd__hashmap(int argc, const char **argv);
 int cmd__hash_speed(int argc, const char **argv);
 int cmd__hexdump(int argc, const char **argv);
-int cmd__index_version(int argc, const char **argv);
 int cmd__json_writer(int argc, const char **argv);
 int cmd__lazy_init_name_hash(int argc, const char **argv);
 int cmd__match_trees(int argc, const char **argv);
@@ -79,6 +79,7 @@ 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);
 int cmd__trace2(int argc, const char **argv);
+int cmd__truncate(int argc, const char **argv);
 int cmd__userdiff(int argc, const char **argv);
 int cmd__urlmatch_normalization(int argc, const char **argv);
 int cmd__xml_encode(int argc, const char **argv);
index 20c7495f38593550a8a4dd35a957cc62cf3a2ded..d5ca0046c89fd434e5b4c5c4f28cb24d6a076bd2 100644 (file)
@@ -45,7 +45,7 @@ static int get_i(int *p_value, const char *data)
  * [] "def_param" events for all of the "interesting" pre-defined
  * config settings.
  */
-static int ut_001return(int argc, const char **argv)
+static int ut_001return(int argc UNUSED, const char **argv)
 {
        int rc;
 
@@ -65,7 +65,7 @@ static int ut_001return(int argc, const char **argv)
  * [] "def_param" events for all of the "interesting" pre-defined
  * config settings.
  */
-static int ut_002exit(int argc, const char **argv)
+static int ut_002exit(int argc UNUSED, const char **argv)
 {
        int rc;
 
@@ -201,7 +201,7 @@ static int ut_006data(int argc, const char **argv)
        return 0;
 }
 
-static int ut_007BUG(int argc, const char **argv)
+static int ut_007BUG(int argc UNUSED, const char **argv UNUSED)
 {
        /*
         * Exercise BUG() to ensure that the message is printed to trace2.
diff --git a/t/helper/test-truncate.c b/t/helper/test-truncate.c
new file mode 100644 (file)
index 0000000..3931dea
--- /dev/null
@@ -0,0 +1,25 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+
+/*
+ * Truncate a file to the given size.
+ */
+int cmd__truncate(int argc, const char **argv)
+{
+       char *p = NULL;
+       uintmax_t sz = 0;
+       int fd = -1;
+
+       if (argc != 3)
+               die("expected filename and size");
+
+       sz = strtoumax(argv[2], &p, 0);
+       if (*p)
+               die("invalid size");
+
+       fd = xopen(argv[1], O_WRONLY | O_CREAT, 0600);
+
+       if (ftruncate(fd, (off_t) sz) < 0)
+               die_errno("failed to truncate file");
+       return 0;
+}
index 680124a676087c65606ca6b750cd3f63c7cd44b0..0ce31ce59f54fe972b2d8c1fd16af6bb5a2c24fd 100644 (file)
@@ -12,7 +12,9 @@ static int driver_cb(struct userdiff_driver *driver,
        return 0;
 }
 
-static int cmd__userdiff_config(const char *var, const char *value, void *cb UNUSED)
+static int cmd__userdiff_config(const char *var, const char *value,
+                               const struct config_context *ctx UNUSED,
+                               void *cb UNUSED)
 {
        if (userdiff_config(var, value) < 0)
                return -1;
index a95bb4da9b174e547b41eb2c57dee9fd9273c5ea..b4ff5f986ae00b099ead5d75e5e8b196de88f67c 100644 (file)
@@ -1,4 +1,5 @@
 #include "test-tool.h"
+#include "wildmatch.h"
 
 int cmd__wildmatch(int argc, const char **argv)
 {
index eace08072d783dfddee00d128422c0c69b9544c2..f084034d38e0328e0792d096225c31ddd91d74c7 100644 (file)
@@ -1,7 +1,7 @@
 #define USE_THE_INDEX_VARIABLE
 #include "test-tool.h"
-#include "cache.h"
 #include "lockfile.h"
+#include "read-cache-ll.h"
 #include "repository.h"
 #include "setup.h"
 
diff --git a/t/lib-chunk.sh b/t/lib-chunk.sh
new file mode 100644 (file)
index 0000000..a7cd9c3
--- /dev/null
@@ -0,0 +1,17 @@
+# Shell library for working with "chunk" files (commit-graph, midx, etc).
+
+# corrupt_chunk_file <fn> <chunk> <offset> <bytes>
+#
+# Corrupt a chunk-based file (like a commit-graph) by overwriting the bytes
+# found in the chunk specified by the 4-byte <chunk> identifier. If <offset> is
+# "clear", replace the chunk entirely. Otherwise, overwrite data <offset> bytes
+# into the chunk.
+#
+# The <bytes> are interpreted as pairs of hex digits (so "000000FE" would be
+# big-endian 254).
+corrupt_chunk_file () {
+       fn=$1; shift
+       perl "$TEST_DIRECTORY"/lib-chunk/corrupt-chunk-file.pl \
+               "$@" <"$fn" >"$fn.tmp" &&
+       mv "$fn.tmp" "$fn"
+}
diff --git a/t/lib-chunk/corrupt-chunk-file.pl b/t/lib-chunk/corrupt-chunk-file.pl
new file mode 100644 (file)
index 0000000..cd6d386
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+
+my ($chunk, $seek, $bytes) = @ARGV;
+$bytes =~ s/../chr(hex($&))/ge;
+
+binmode STDIN;
+binmode STDOUT;
+
+# A few helpers to read bytes, or read and copy them to the
+# output.
+sub get {
+       my $n = shift;
+       return unless $n;
+       read(STDIN, my $buf, $n)
+               or die "read error or eof: $!\n";
+       return $buf;
+}
+sub copy {
+       my $buf = get(@_);
+       print $buf;
+       return $buf;
+}
+
+# read until we find table-of-contents entry for chunk;
+# note that we cheat a bit by assuming 4-byte alignment and
+# that no ToC entry will accidentally look like a header.
+#
+# If we don't find the entry, copy() will hit EOF and exit
+# (which should cause the caller to fail the test).
+while (copy(4) ne $chunk) { }
+my $offset = unpack("Q>", copy(8));
+
+# In clear mode, our length will change. So figure out
+# the length by comparing to the offset of the next chunk, and
+# then adjust that offset (and all subsequent) ones.
+my $len;
+if ($seek eq "clear") {
+       my $id;
+       do {
+               $id = copy(4);
+               my $next = unpack("Q>", get(8));
+               if (!defined $len) {
+                       $len = $next - $offset;
+               }
+               print pack("Q>", $next - $len + length($bytes));
+       } while (unpack("N", $id));
+}
+
+# and now copy up to our existing chunk data
+copy($offset - tell(STDIN));
+if ($seek eq "clear") {
+       # if clearing, skip past existing data
+       get($len);
+} else {
+       # otherwise, copy up to the requested offset,
+       # and skip past the overwritten bytes
+       copy($seek);
+       get(length($bytes));
+}
+
+# now write out the requested bytes, along
+# with any other remaining data
+print $bytes;
+while (read(STDIN, my $buf, 4096)) {
+       print $buf;
+}
index 5d79e1a4e967619125a06ae1a2ecf38c0fe3fcab..89b26676fbb94b0b4f570ec9a51ca74cce7620c5 100755 (executable)
@@ -14,24 +14,37 @@ graph_git_two_modes() {
        test_cmp expect output
 }
 
+# graph_git_behavior <name> <directory> <branch> <compare>
+#
+# Ensures that a handful of traversal operations produce the same
+# results with and without the commit-graph in use.
+#
+# NOTE: it is a bug to call this function with <directory> containing
+# any characters in $IFS.
 graph_git_behavior() {
        MSG=$1
        DIR=$2
        BRANCH=$3
        COMPARE=$4
        test_expect_success "check normal git operations: $MSG" '
-               cd "$TRASH_DIRECTORY/$DIR" &&
-               graph_git_two_modes "log --oneline $BRANCH" &&
-               graph_git_two_modes "log --topo-order $BRANCH" &&
-               graph_git_two_modes "log --graph $COMPARE..$BRANCH" &&
-               graph_git_two_modes "branch -vv" &&
-               graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
+               graph_git_two_modes "${DIR:+-C $DIR} log --oneline $BRANCH" &&
+               graph_git_two_modes "${DIR:+-C $DIR} log --topo-order $BRANCH" &&
+               graph_git_two_modes "${DIR:+-C $DIR} log --graph $COMPARE..$BRANCH" &&
+               graph_git_two_modes "${DIR:+-C $DIR} branch -vv" &&
+               graph_git_two_modes "${DIR:+-C $DIR} merge-base -a $BRANCH $COMPARE"
        '
 }
 
 graph_read_expect() {
        OPTIONAL=""
        NUM_CHUNKS=3
+       DIR="."
+       if test "$1" = -C
+       then
+               shift
+               DIR="$1"
+               shift
+       fi
        if test -n "$2"
        then
                OPTIONAL=" $2"
@@ -47,12 +60,15 @@ graph_read_expect() {
        then
                OPTIONS=" read_generation_data"
        fi
-       cat >expect <<- EOF
+       cat >"$DIR/expect" <<-EOF
        header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
        num_commits: $1
        chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
        options:$OPTIONS
        EOF
-       test-tool read-graph >output &&
-       test_cmp expect output
+       (
+               cd "$DIR" &&
+               test-tool read-graph >output &&
+               test_cmp expect output
+       )
 }
index f1ab92ba35c432052e1f903750795443122869ad..15fc9a31e2cc03689e76876693e39367626784ff 100644 (file)
@@ -43,7 +43,13 @@ helper_test_clean() {
        reject $1 https example.com store-user
        reject $1 https example.com user1
        reject $1 https example.com user2
+       reject $1 https example.com user-expiry
+       reject $1 https example.com user-expiry-overwrite
        reject $1 https example.com user4
+       reject $1 https example.com user-distinct-pass
+       reject $1 https example.com user-overwrite
+       reject $1 https example.com user-erase1
+       reject $1 https example.com user-erase2
        reject $1 http path.tld user
        reject $1 https timeout.tld user
        reject $1 https sso.tld
@@ -167,6 +173,49 @@ helper_test() {
                EOF
        '
 
+       test_expect_success "helper ($HELPER) overwrites on store" '
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               password=pass1
+               EOF
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               password=pass2
+               EOF
+               check fill $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               --
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               password=pass2
+               EOF
+               check reject $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               password=pass2
+               EOF
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               --
+               protocol=https
+               host=example.com
+               username=user-overwrite
+               password=askpass-password
+               --
+               askpass: Password for '\''https://user-overwrite@example.com'\'':
+               EOF
+       '
+
        test_expect_success "helper ($HELPER) can forget host" '
                check reject $HELPER <<-\EOF &&
                protocol=https
@@ -221,6 +270,31 @@ helper_test() {
                EOF
        '
 
+       test_expect_success "helper ($HELPER) does not erase a password distinct from input" '
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-distinct-pass
+               password=pass1
+               EOF
+               check reject $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-distinct-pass
+               password=pass2
+               EOF
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user-distinct-pass
+               --
+               protocol=https
+               host=example.com
+               username=user-distinct-pass
+               password=pass1
+               EOF
+       '
+
        test_expect_success "helper ($HELPER) can forget user" '
                check reject $HELPER <<-\EOF &&
                protocol=https
@@ -272,6 +346,37 @@ helper_test() {
                EOF
        '
 
+       test_expect_success "helper ($HELPER) erases all matching credentials" '
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-erase1
+               password=pass1
+               EOF
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-erase2
+               password=pass1
+               EOF
+               check reject $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               EOF
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               --
+               protocol=https
+               host=example.com
+               username=askpass-username
+               password=askpass-password
+               --
+               askpass: Username for '\''https://example.com'\'':
+               askpass: Password for '\''https://askpass-username@example.com'\'':
+               EOF
+       '
+
        : ${GIT_TEST_LONG_CRED_BUFFER:=1024}
        # 23 bytes accounts for "wwwauth[]=basic realm=" plus NUL
        LONG_VALUE_LEN=$((GIT_TEST_LONG_CRED_BUFFER - 23))
@@ -328,6 +433,81 @@ helper_test_timeout() {
        '
 }
 
+helper_test_password_expiry_utc() {
+       HELPER=$1
+
+       test_expect_success "helper ($HELPER) stores password_expiry_utc" '
+               check approve $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user-expiry
+               password=pass
+               password_expiry_utc=9999999999
+               EOF
+       '
+
+       test_expect_success "helper ($HELPER) gets password_expiry_utc" '
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user-expiry
+               --
+               protocol=https
+               host=example.com
+               username=user-expiry
+               password=pass
+               password_expiry_utc=9999999999
+               --
+               EOF
+       '
+
+       test_expect_success "helper ($HELPER) overwrites when password_expiry_utc changes" '
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               password=pass1
+               password_expiry_utc=9999999998
+               EOF
+               check approve $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               password=pass2
+               password_expiry_utc=9999999999
+               EOF
+               check fill $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               --
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               password=pass2
+               password_expiry_utc=9999999999
+               EOF
+               check reject $HELPER <<-\EOF &&
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               password=pass2
+               EOF
+               check fill $HELPER <<-\EOF
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               --
+               protocol=https
+               host=example.com
+               username=user-expiry-overwrite
+               password=askpass-password
+               --
+               askpass: Password for '\''https://user-expiry-overwrite@example.com'\'':
+               EOF
+       '
+}
+
 helper_test_oauth_refresh_token() {
        HELPER=$1
 
index 114785586abde524fb13cb29e4b1f357ae9a3286..83b83c9abb5089186adfd4ac0b647b6f4c673820 100644 (file)
@@ -40,6 +40,28 @@ test_lazy_prereq GPG '
                #               > lib-gpg/ownertrust
                mkdir "$GNUPGHOME" &&
                chmod 0700 "$GNUPGHOME" &&
+               (gpgconf --kill all || : ) &&
+               gpg --homedir "${GNUPGHOME}" --import \
+                       "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
+               gpg --homedir "${GNUPGHOME}" --import-ownertrust \
+                       "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
+               gpg --homedir "${GNUPGHOME}" --update-trustdb &&
+               gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null \
+                       --sign -u committer@example.com
+               ;;
+       esac
+'
+
+test_lazy_prereq GPG2 '
+       gpg_version=$(gpg --version 2>&1)
+       test $? != 127 || exit 1
+
+       case "$gpg_version" in
+       "gpg (GnuPG) "[01].*)
+               say "This test requires a GPG version >= v2.0.0"
+               exit 1
+               ;;
+       *)
                (gpgconf --kill all || : ) &&
                gpg --homedir "${GNUPGHOME}" --import \
                        "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
@@ -135,8 +157,9 @@ test_lazy_prereq GPGSSH '
 '
 
 test_lazy_prereq GPGSSH_VERIFYTIME '
+       test_have_prereq GPGSSH &&
        # Check if ssh-keygen has a verify-time option by passing an invalid date to it
-       ssh-keygen -Overify-time=INVALID -Y check-novalidate -s doesnotmatter 2>&1 | grep -q -F "Invalid \"verify-time\"" &&
+       ssh-keygen -Overify-time=INVALID -Y check-novalidate -n "git" -s doesnotmatter 2>&1 | grep -q -F "Invalid \"verify-time\"" &&
 
        # Set up keys with key lifetimes
        ssh-keygen -t ed25519 -N "" -C "timeboxed valid key" -f "${GPGSSH_KEY_TIMEBOXEDVALID}" >/dev/null &&
index a22d1386052b40334ddec013ec230af6655fb086..022276a6b9ace5565211327053f9900ff4a1fb06 100644 (file)
@@ -92,6 +92,7 @@ PassEnv GIT_VALGRIND_OPTIONS
 PassEnv GNUPGHOME
 PassEnv ASAN_OPTIONS
 PassEnv LSAN_OPTIONS
+PassEnv UBSAN_OPTIONS
 PassEnv GIT_TRACE
 PassEnv GIT_CONFIG_NOSYSTEM
 PassEnv GIT_TEST_SIDEBAND_ALL
index 7ca5b918f0445cbb3097e531883861f5574e29a1..11d2dc9fe341b61d22c467ea8ae6a9d13ff1ac18 100644 (file)
@@ -8,18 +8,21 @@
 # - check that non-commit messages have a certain line count with $EXPECT_COUNT
 # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT
 # - rewrite a rebase -i script as directed by $FAKE_LINES.
-#   $FAKE_LINES consists of a sequence of words separated by spaces.
-#   The following word combinations are possible:
+#   $FAKE_LINES consists of a sequence of words separated by spaces;
+#   spaces inside the words are encoded as underscores.
+#   The following words are possible:
 #
-#   "<lineno>" -- add a "pick" line with the SHA1 taken from the
-#       specified line.
+#   "<cmd>" -- override the command for the next line specification. Can be
+#       "pick", "squash", "fixup[_-(c|C)]", "edit", "reword", "drop",
+#       "merge[_-(c|C)_<rev>]", or "bad" for an invalid command.
 #
-#   "<cmd> <lineno>" -- add a line with the specified command
-#       ("pick", "squash", "fixup"|"fixup_-C"|"fixup_-c", "edit", "reword" or "drop")
-#       and the SHA1 taken from the specified line.
+#   "<lineno>" -- add a command, using the specified line as a template.
+#       If the command has not been overridden, the line will be copied
+#       verbatim, usually resulting in a "pick" line.
 #
-#   "_" -- add a space, like "fixup_-C" implies "fixup -C" and
-#       "exec_cmd_with_args" add an "exec cmd with args" line.
+#   "fakesha" -- add a command ("pick" by default), using a fake SHA1.
+#
+#   "exec_[command...]", "break" -- add the specified command.
 #
 #   "#" -- Add a comment line.
 #
@@ -49,7 +52,7 @@ set_fake_editor () {
        action=\&
        for line in $FAKE_LINES; do
                case $line in
-               pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d|label|l|reset|r|merge|m)
+               pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d|label|l|reset|t|merge|m)
                        action="$line";;
                exec_*|x_*|break|b)
                        echo "$line" | sed 's/_/ /g' >> "$1";;
@@ -64,7 +67,7 @@ set_fake_editor () {
                fakesha)
                        test \& != "$action" || action=pick
                        echo "$action XXXXXXX False commit" >> "$1"
-                       action=pick;;
+                       action=\&;;
                *)
                        sed -n "${line}s/^[a-z][a-z]*/$action/p" < "$1".tmp >> "$1"
                        action=\&;;
index 901cc493ef19e10941ca93a920344f4ff52a59ca..39e92b0841437bee9cbd939de6e216fae81a7ff2 100755 (executable)
@@ -131,5 +131,9 @@ test_perf_on_all git describe --dirty
 test_perf_on_all 'echo >>new && git describe --dirty'
 test_perf_on_all git diff-files
 test_perf_on_all git diff-files -- $SPARSE_CONE/a
+test_perf_on_all git diff-tree HEAD
+test_perf_on_all git diff-tree HEAD -- $SPARSE_CONE/a
+test_perf_on_all "git worktree add ../temp && git worktree remove ../temp"
+test_perf_on_all git check-attr -a -- $SPARSE_CONE/a
 
 test_done
index 8ea31d187a91ee4df52203cbd72a1fac7dd4140e..6e300be2ac55aff51ed0e2d8ef16a978f5efedb9 100755 (executable)
@@ -1014,7 +1014,7 @@ test_expect_success 'validate object ID for a known tree' '
 '
 
 test_expect_success 'showing tree with git ls-tree' '
-    git ls-tree $tree >current
+       git ls-tree $tree >current
 '
 
 test_expect_success 'git ls-tree output for a known tree' '
index 26e082f05b4473a553b4de9b7747b928179439cd..ecf43ab54545a22ad52495af7cd728b04ac245bb 100755 (executable)
@@ -40,6 +40,10 @@ attr_check_source () {
        test_cmp expect actual &&
        test_must_be_empty err
 
+       git $git_opts -c "attr.tree=$source" check-attr test -- "$path" >actual 2>err &&
+       test_cmp expect actual &&
+       test_must_be_empty err
+
        GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err &&
        test_cmp expect actual &&
        test_must_be_empty err
@@ -342,6 +346,74 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' '
        )
 '
 
+bad_attr_source_err="fatal: bad --attr-source or GIT_ATTR_SOURCE"
+
+test_expect_success '--attr-source is bad' '
+       test_when_finished rm -rf empty &&
+       git init empty &&
+       (
+               cd empty &&
+               echo "$bad_attr_source_err" >expect_err &&
+               test_must_fail git --attr-source=HEAD check-attr test -- f/path 2>err &&
+               test_cmp expect_err err
+       )
+'
+
+test_expect_success 'attr.tree when HEAD is unborn' '
+       test_when_finished rm -rf empty &&
+       git init empty &&
+       (
+               cd empty &&
+               echo "f/path: test: unspecified" >expect &&
+               git -c attr.tree=HEAD check-attr test -- f/path >actual 2>err &&
+               test_must_be_empty err &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'bad attr source defaults to reading .gitattributes file' '
+       test_when_finished rm -rf empty &&
+       git init empty &&
+       (
+               cd empty &&
+               echo "f/path test=val" >.gitattributes &&
+               echo "f/path: test: val" >expect &&
+               git -c attr.tree=HEAD check-attr test -- f/path >actual 2>err &&
+               test_must_be_empty err &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'bare repo defaults to reading .gitattributes from HEAD' '
+       test_when_finished rm -rf test bare_with_gitattribute &&
+       git init test &&
+       test_commit -C test gitattributes .gitattributes "f/path test=val" &&
+       git clone --bare test bare_with_gitattribute &&
+       echo "f/path: test: val" >expect &&
+       git -C bare_with_gitattribute check-attr test -- f/path >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'precedence of --attr-source, GIT_ATTR_SOURCE, then attr.tree' '
+       test_when_finished rm -rf empty &&
+       git init empty &&
+       (
+               cd empty &&
+               git checkout -b attr-source &&
+               test_commit "val1" .gitattributes "f/path test=val1" &&
+               git checkout -b attr-tree &&
+               test_commit "val2" .gitattributes "f/path test=val2" &&
+               git checkout attr-source &&
+               echo "f/path: test: val1" >expect &&
+               GIT_ATTR_SOURCE=attr-source git -c attr.tree=attr-tree --attr-source=attr-source \
+               check-attr test -- f/path >actual &&
+               test_cmp expect actual &&
+               GIT_ATTR_SOURCE=attr-source git -c attr.tree=attr-tree \
+               check-attr test -- f/path >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_expect_success 'bare repository: with --source' '
        (
                cd bare.git &&
index eeb8539c1bcb2df86a5aff1fa2c78fc555598d14..ff4fd9348cca6470f4dbacbc4c9a3d775f15c06d 100755 (executable)
@@ -147,6 +147,84 @@ test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment
        )
 '
 
+test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' '
+       shellpath=$(git var GIT_SHELL_PATH) &&
+       test_path_is_executable "$shellpath"
+'
+
+# We know in this environment that our shell will be one of a few fixed values
+# that all end in "sh".
+test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' '
+       shellpath=$(git var GIT_SHELL_PATH) &&
+       case "$shellpath" in
+       *sh) ;;
+       *) return 1;;
+       esac
+'
+
+test_expect_success 'GIT_ATTR_SYSTEM produces expected output' '
+       test_must_fail env GIT_ATTR_NOSYSTEM=1 git var GIT_ATTR_SYSTEM &&
+       (
+               sane_unset GIT_ATTR_NOSYSTEM &&
+               systempath=$(git var GIT_ATTR_SYSTEM) &&
+               test "$systempath" != ""
+       )
+'
+
+test_expect_success 'GIT_ATTR_GLOBAL points to the correct location' '
+       TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+       globalpath=$(XDG_CONFIG_HOME="$TRASHDIR/.config" git var GIT_ATTR_GLOBAL) &&
+       test "$globalpath" = "$TRASHDIR/.config/git/attributes" &&
+       (
+               sane_unset XDG_CONFIG_HOME &&
+               globalpath=$(HOME="$TRASHDIR" git var GIT_ATTR_GLOBAL) &&
+               test "$globalpath" = "$TRASHDIR/.config/git/attributes"
+       )
+'
+
+test_expect_success 'GIT_CONFIG_SYSTEM points to the correct location' '
+       TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+       test_must_fail env GIT_CONFIG_NOSYSTEM=1 git var GIT_CONFIG_SYSTEM &&
+       (
+               sane_unset GIT_CONFIG_NOSYSTEM &&
+               systempath=$(git var GIT_CONFIG_SYSTEM) &&
+               test "$systempath" != "" &&
+               systempath=$(GIT_CONFIG_SYSTEM=/dev/null git var GIT_CONFIG_SYSTEM) &&
+               if test_have_prereq MINGW
+               then
+                       test "$systempath" = "nul"
+               else
+                       test "$systempath" = "/dev/null"
+               fi &&
+               systempath=$(GIT_CONFIG_SYSTEM="$TRASHDIR/gitconfig" git var GIT_CONFIG_SYSTEM) &&
+               test "$systempath" = "$TRASHDIR/gitconfig"
+       )
+'
+
+test_expect_success 'GIT_CONFIG_GLOBAL points to the correct location' '
+       TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+       HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var GIT_CONFIG_GLOBAL >actual &&
+       echo "$TRASHDIR/foo/git/config" >expected &&
+       echo "$TRASHDIR/.gitconfig" >>expected &&
+       test_cmp expected actual &&
+       (
+               sane_unset XDG_CONFIG_HOME &&
+               HOME="$TRASHDIR" git var GIT_CONFIG_GLOBAL >actual &&
+               echo "$TRASHDIR/.config/git/config" >expected &&
+               echo "$TRASHDIR/.gitconfig" >>expected &&
+               test_cmp expected actual &&
+               globalpath=$(GIT_CONFIG_GLOBAL=/dev/null git var GIT_CONFIG_GLOBAL) &&
+               if test_have_prereq MINGW
+               then
+                       test "$globalpath" = "nul"
+               else
+                       test "$globalpath" = "/dev/null"
+               fi &&
+               globalpath=$(GIT_CONFIG_GLOBAL="$TRASHDIR/gitconfig" git var GIT_CONFIG_GLOBAL) &&
+               test "$globalpath" = "$TRASHDIR/gitconfig"
+       )
+'
+
 # For git var -l, we check only a representative variable;
 # testing the whole output would make our test too brittle with
 # respect to unrelated changes in the test suite's environment.
@@ -164,8 +242,39 @@ test_expect_success 'git var -l lists config' '
        test_cmp expect actual.bare
 '
 
+test_expect_success 'git var -l lists multiple global configs' '
+       TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
+       HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var -l >actual &&
+       grep "^GIT_CONFIG_GLOBAL=" actual >filtered &&
+       echo "GIT_CONFIG_GLOBAL=$TRASHDIR/foo/git/config" >expected &&
+       echo "GIT_CONFIG_GLOBAL=$TRASHDIR/.gitconfig" >>expected &&
+       test_cmp expected filtered
+'
+
+test_expect_success 'git var -l does not split multiline editors' '
+       (
+               GIT_EDITOR="!f() {
+                       echo Hello!
+               }; f" &&
+               export GIT_EDITOR &&
+               echo "GIT_EDITOR=$GIT_EDITOR" >expected &&
+               git var -l >var &&
+               sed -n -e "/^GIT_EDITOR/,\$p" var | head -n 3 >actual &&
+               test_cmp expected actual
+       )
+'
+
 test_expect_success 'listing and asking for variables are exclusive' '
        test_must_fail git var -l GIT_COMMITTER_IDENT
 '
 
+test_expect_success '`git var -l` works even without HOME' '
+       (
+               XDG_CONFIG_HOME= &&
+               export XDG_CONFIG_HOME &&
+               unset HOME &&
+               git var -l
+       )
+'
+
 test_done
index 0a5713c5248280d88a241b8027b5c98e4f321718..d1b3be872576789541410fa66d4473a006db99b2 100755 (executable)
@@ -17,396 +17,378 @@ printf_git_stripspace () {
     printf "$1" | git stripspace
 }
 
-test_expect_success \
-    'long lines without spaces should be unchanged' '
-    echo "$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual &&
-
-    echo "$ttt$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual &&
-
-    echo "$ttt$ttt$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual &&
-
-    echo "$ttt$ttt$ttt$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual
+test_expect_success 'long lines without spaces should be unchanged' '
+       echo "$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual &&
+
+       echo "$ttt$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual &&
+
+       echo "$ttt$ttt$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual &&
+
+       echo "$ttt$ttt$ttt$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'lines with spaces at the beginning should be unchanged' '
-    echo "$sss$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual &&
+test_expect_success 'lines with spaces at the beginning should be unchanged' '
+       echo "$sss$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual &&
 
-    echo "$sss$sss$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual &&
+       echo "$sss$sss$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual &&
 
-    echo "$sss$sss$sss$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual
+       echo "$sss$sss$sss$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'lines with intermediate spaces should be unchanged' '
-    echo "$ttt$sss$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual &&
+test_expect_success 'lines with intermediate spaces should be unchanged' '
+       echo "$ttt$sss$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual &&
 
-    echo "$ttt$sss$sss$ttt" >expect &&
-    git stripspace <expect >actual &&
-    test_cmp expect actual
+       echo "$ttt$sss$sss$ttt" >expect &&
+       git stripspace <expect >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'consecutive blank lines should be unified' '
-    printf "$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+test_expect_success 'consecutive blank lines should be unified' '
+       printf "$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt$ttt\n" > expect &&
-    printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$ttt$ttt\n" > expect &&
+       printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
-    printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
+       printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt$ttt$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt$ttt$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt\n" > expect &&
-    printf "$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$ttt\n" > expect &&
+       printf "$ttt\n\t\n \n\n  \t\t\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt$ttt\n" > expect &&
-    printf "$ttt\n\t\n \n\n  \t\t\n$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$ttt$ttt\n" > expect &&
+       printf "$ttt\n\t\n \n\n  \t\t\n$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
-    printf "$ttt\n\t\n \n\n  \t\t\n$ttt$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual
+       printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
+       printf "$ttt\n\t\n \n\n  \t\t\n$ttt$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'only consecutive blank lines should be completely removed' '
+test_expect_success 'only consecutive blank lines should be completely removed' '
+       printf "\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "\n\n\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "\n\n\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "$sss\n$sss\n$sss\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "$sss\n$sss\n$sss\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "$sss$sss\n$sss\n\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "$sss$sss\n$sss\n\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "\n$sss\n$sss$sss\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "\n$sss\n$sss$sss\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "$sss$sss$sss$sss\n\n\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "$sss$sss$sss$sss\n\n\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "\n$sss$sss$sss$sss\n\n" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "\n$sss$sss$sss$sss\n\n" | git stripspace >actual &&
-    test_must_be_empty actual &&
-
-    printf "\n\n$sss$sss$sss$sss\n" | git stripspace >actual &&
-    test_must_be_empty actual
+       printf "\n\n$sss$sss$sss$sss\n" | git stripspace >actual &&
+       test_must_be_empty actual
 '
 
-test_expect_success \
-    'consecutive blank lines at the beginning should be removed' '
-    printf "$ttt\n" > expect &&
-    printf "\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+test_expect_success 'consecutive blank lines at the beginning should be removed' '
+       printf "$ttt\n" > expect &&
+       printf "\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n" > expect &&
-    printf "\n\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n" > expect &&
+       printf "\n\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n" > expect &&
-    printf "\n\n\n$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n" > expect &&
+       printf "\n\n\n$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt\n" > expect &&
-    printf "\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt$ttt\n" > expect &&
+       printf "\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt$ttt\n" > expect &&
-    printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt$ttt$ttt\n" > expect &&
+       printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n" > expect &&
+       printf "$ttt\n" > expect &&
 
-    printf "$sss\n$sss\n$sss\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$sss\n$sss\n$sss\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "\n$sss\n$sss$sss\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "\n$sss\n$sss$sss\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$sss$sss\n$sss\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$sss$sss\n$sss\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$sss$sss$sss\n\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$sss$sss$sss\n\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "\n$sss$sss$sss\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "\n$sss$sss$sss\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "\n\n$sss$sss$sss\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual
+       printf "\n\n$sss$sss$sss\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'consecutive blank lines at the end should be removed' '
-    printf "$ttt\n" > expect &&
-    printf "$ttt\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+test_expect_success 'consecutive blank lines at the end should be removed' '
+       printf "$ttt\n" > expect &&
+       printf "$ttt\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n" > expect &&
-    printf "$ttt\n\n\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n" > expect &&
+       printf "$ttt\n\n\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n" > expect &&
-    printf "$ttt$ttt\n\n\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n" > expect &&
+       printf "$ttt$ttt\n\n\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt\n" > expect &&
-    printf "$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt$ttt\n" > expect &&
+       printf "$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt$ttt\n" > expect &&
-    printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt$ttt$ttt\n" > expect &&
+       printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n" > expect &&
+       printf "$ttt\n" > expect &&
 
-    printf "$ttt\n$sss\n$sss\n$sss\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n$sss\n$sss\n$sss\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$sss\n$sss$sss\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$sss\n$sss$sss\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n$sss$sss\n$sss\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n$sss$sss\n$sss\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n$sss$sss$sss\n\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n$sss$sss$sss\n\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n$sss$sss$sss\n\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n\n$sss$sss$sss\n\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n\n\n$sss$sss$sss\n" | git stripspace >actual &&
-    test_cmp expect actual
+       printf "$ttt\n\n\n$sss$sss$sss\n" | git stripspace >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'text without newline at end should end with newline' '
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$ttt"
+test_expect_success 'text without newline at end should end with newline' '
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$ttt"
 '
 
 # text plus spaces at the end:
 
-test_expect_success \
-    'text plus spaces without newline at end should end with newline' '
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$sss" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss$sss" &&
-    test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss$sss"
+test_expect_success 'text plus spaces without newline at end should end with newline' '
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$sss" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss$sss" &&
+       test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss$sss"
 '
 
-test_expect_success \
-    'text plus spaces without newline at end should not show spaces' '
-    printf "$ttt$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    printf "$ttt$ttt$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    printf "$ttt$ttt$ttt$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    printf "$ttt$sss$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    printf "$ttt$ttt$sss$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    printf "$ttt$sss$sss$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null
+test_expect_success 'text plus spaces without newline at end should not show spaces' '
+       printf "$ttt$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       printf "$ttt$ttt$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       printf "$ttt$ttt$ttt$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       printf "$ttt$sss$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       printf "$ttt$ttt$sss$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       printf "$ttt$sss$sss$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null
 '
 
-test_expect_success \
-    'text plus spaces without newline should show the correct lines' '
-    printf "$ttt\n" >expect &&
-    printf "$ttt$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+test_expect_success 'text plus spaces without newline should show the correct lines' '
+       printf "$ttt\n" >expect &&
+       printf "$ttt$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n" >expect &&
-    printf "$ttt$sss$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n" >expect &&
+       printf "$ttt$sss$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n" >expect &&
-    printf "$ttt$sss$sss$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n" >expect &&
+       printf "$ttt$sss$sss$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n" >expect &&
-    printf "$ttt$ttt$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n" >expect &&
+       printf "$ttt$ttt$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n" >expect &&
-    printf "$ttt$ttt$sss$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n" >expect &&
+       printf "$ttt$ttt$sss$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt$ttt\n" >expect &&
-    printf "$ttt$ttt$ttt$sss" | git stripspace >actual &&
-    test_cmp expect actual
+       printf "$ttt$ttt$ttt\n" >expect &&
+       printf "$ttt$ttt$ttt$sss" | git stripspace >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success \
-    'text plus spaces at end should not show spaces' '
-    echo "$ttt$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    echo "$ttt$ttt$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    echo "$ttt$ttt$ttt$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    echo "$ttt$sss$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    echo "$ttt$ttt$sss$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null &&
-    echo "$ttt$sss$sss$sss" | git stripspace >tmp &&
-    ! grep "  " tmp >/dev/null
+test_expect_success 'text plus spaces at end should not show spaces' '
+       echo "$ttt$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       echo "$ttt$ttt$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       echo "$ttt$ttt$ttt$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       echo "$ttt$sss$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       echo "$ttt$ttt$sss$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null &&
+       echo "$ttt$sss$sss$sss" | git stripspace >tmp &&
+       ! grep "  " tmp >/dev/null
 '
 
-test_expect_success \
-    'text plus spaces at end should be cleaned and newline must remain' '
-    echo "$ttt" >expect &&
-    echo "$ttt$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+test_expect_success 'text plus spaces at end should be cleaned and newline must remain' '
+       echo "$ttt" >expect &&
+       echo "$ttt$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    echo "$ttt" >expect &&
-    echo "$ttt$sss$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       echo "$ttt" >expect &&
+       echo "$ttt$sss$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    echo "$ttt" >expect &&
-    echo "$ttt$sss$sss$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       echo "$ttt" >expect &&
+       echo "$ttt$sss$sss$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    echo "$ttt$ttt" >expect &&
-    echo "$ttt$ttt$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       echo "$ttt$ttt" >expect &&
+       echo "$ttt$ttt$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    echo "$ttt$ttt" >expect &&
-    echo "$ttt$ttt$sss$sss" | git stripspace >actual &&
-    test_cmp expect actual &&
+       echo "$ttt$ttt" >expect &&
+       echo "$ttt$ttt$sss$sss" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    echo "$ttt$ttt$ttt" >expect &&
-    echo "$ttt$ttt$ttt$sss" | git stripspace >actual &&
-    test_cmp expect actual
+       echo "$ttt$ttt$ttt" >expect &&
+       echo "$ttt$ttt$ttt$sss" | git stripspace >actual &&
+       test_cmp expect actual
 '
 
 # spaces only:
 
-test_expect_success \
-    'spaces with newline at end should be replaced with empty string' '
-    echo | git stripspace >actual &&
-    test_must_be_empty actual &&
+test_expect_success 'spaces with newline at end should be replaced with empty string' '
+       echo | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    echo "$sss" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       echo "$sss" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    echo "$sss$sss" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       echo "$sss$sss" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    echo "$sss$sss$sss" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       echo "$sss$sss$sss" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    echo "$sss$sss$sss$sss" | git stripspace >actual &&
-    test_must_be_empty actual
+       echo "$sss$sss$sss$sss" | git stripspace >actual &&
+       test_must_be_empty actual
 '
 
-test_expect_success \
-    'spaces without newline at end should not show spaces' '
-    printf "" | git stripspace >tmp &&
-    ! grep " " tmp >/dev/null &&
-    printf "$sss" | git stripspace >tmp &&
-    ! grep " " tmp >/dev/null &&
-    printf "$sss$sss" | git stripspace >tmp &&
-    ! grep " " tmp >/dev/null &&
-    printf "$sss$sss$sss" | git stripspace >tmp &&
-    ! grep " " tmp >/dev/null &&
-    printf "$sss$sss$sss$sss" | git stripspace >tmp &&
-    ! grep " " tmp >/dev/null
+test_expect_success 'spaces without newline at end should not show spaces' '
+       printf "" | git stripspace >tmp &&
+       ! grep " " tmp >/dev/null &&
+       printf "$sss" | git stripspace >tmp &&
+       ! grep " " tmp >/dev/null &&
+       printf "$sss$sss" | git stripspace >tmp &&
+       ! grep " " tmp >/dev/null &&
+       printf "$sss$sss$sss" | git stripspace >tmp &&
+       ! grep " " tmp >/dev/null &&
+       printf "$sss$sss$sss$sss" | git stripspace >tmp &&
+       ! grep " " tmp >/dev/null
 '
 
-test_expect_success \
-    'spaces without newline at end should be replaced with empty string' '
-    printf "" | git stripspace >actual &&
-    test_must_be_empty actual &&
+test_expect_success 'spaces without newline at end should be replaced with empty string' '
+       printf "" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "$sss$sss" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "$sss$sss" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "$sss$sss$sss" | git stripspace >actual &&
-    test_must_be_empty actual &&
+       printf "$sss$sss$sss" | git stripspace >actual &&
+       test_must_be_empty actual &&
 
-    printf "$sss$sss$sss$sss" | git stripspace >actual &&
-    test_must_be_empty actual
+       printf "$sss$sss$sss$sss" | git stripspace >actual &&
+       test_must_be_empty actual
 '
 
-test_expect_success \
-    'consecutive text lines should be unchanged' '
-    printf "$ttt$ttt\n$ttt\n" >expect &&
-    printf "$ttt$ttt\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+test_expect_success 'consecutive text lines should be unchanged' '
+       printf "$ttt$ttt\n$ttt\n" >expect &&
+       printf "$ttt$ttt\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n$ttt$ttt\n$ttt\n" >expect &&
-    printf "$ttt\n$ttt$ttt\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n$ttt$ttt\n$ttt\n" >expect &&
+       printf "$ttt\n$ttt$ttt\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" >expect &&
-    printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" >expect &&
+       printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" >expect &&
-    printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" >expect &&
+       printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" >expect &&
-    printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual &&
+       printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" >expect &&
+       printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual &&
 
-    printf "$ttt\n$ttt$ttt\n\n$ttt\n" >expect &&
-    printf "$ttt\n$ttt$ttt\n\n$ttt\n" | git stripspace >actual &&
-    test_cmp expect actual
+       printf "$ttt\n$ttt$ttt\n\n$ttt\n" >expect &&
+       printf "$ttt\n$ttt$ttt\n\n$ttt\n" | git stripspace >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'strip comments, too' '
index 7d7ecfd57162cf9cde2e74007a6323c635a3b2a9..06fb9e64576de8fa4c44a20cb86c4cf690569afd 100755 (executable)
@@ -13,29 +13,36 @@ usage: test-tool parse-options <options>
 
     A helper function for the parse-options API.
 
-    --yes                 get a boolean
+    --[no-]yes            get a boolean
     -D, --no-doubt        begins with 'no-'
+    --doubt               opposite of --no-doubt
     -B, --no-fear         be brave
-    -b, --boolean         increment by one
-    -4, --or4             bitwise-or boolean with ...0100
-    --neg-or4             same as --no-or4
+    -b, --[no-]boolean    increment by one
+    -4, --[no-]or4        bitwise-or boolean with ...0100
+    --[no-]neg-or4        same as --no-or4
 
-    -i, --integer <n>     get a integer
+    -i, --[no-]integer <n>
+                          get a integer
     -j <n>                get a integer, too
     -m, --magnitude <n>   get a magnitude
-    --set23               set integer to 23
+    --[no-]set23          set integer to 23
     --mode1               set integer to 1 (cmdmode option)
     --mode2               set integer to 2 (cmdmode option)
-    -L, --length <str>    get length of <str>
-    -F, --file <file>     set file to <file>
+    --[no-]mode34 (3|4)   set integer to 3 or 4 (cmdmode option)
+    -L, --[no-]length <str>
+                          get length of <str>
+    -F, --[no-]file <file>
+                          set file to <file>
 
 String options
-    -s, --string <string>
+    -s, --[no-]string <string>
                           get a string
-    --string2 <str>       get another string
-    --st <st>             get another string (pervert ordering)
+    --[no-]string2 <str>  get another string
+    --[no-]st <st>        get another string (pervert ordering)
     -o <str>              get another string
-    --list <str>          add str to list
+    --longhelp            help text of this entry
+                          spans multiple lines
+    --[no-]list <str>     add str to list
 
 Magic arguments
     -NUM                  set integer to NUM
@@ -44,16 +51,17 @@ Magic arguments
     --no-ambiguous        negative ambiguity
 
 Standard options
-    --abbrev[=<n>]        use <n> digits to display object names
-    -v, --verbose         be verbose
-    -n, --dry-run         dry run
-    -q, --quiet           be quiet
-    --expect <string>     expected output in the variable dump
+    --[no-]abbrev[=<n>]   use <n> digits to display object names
+    -v, --[no-]verbose    be verbose
+    -n, --[no-]dry-run    dry run
+    -q, --[no-]quiet      be quiet
+    --[no-]expect <string>
+                          expected output in the variable dump
 
 Alias
-    -A, --alias-source <string>
+    -A, --[no-]alias-source <string>
                           get a string
-    -Z, --alias-target <string>
+    -Z, --[no-]alias-target <string>
                           alias of --alias-source
 
 EOF
@@ -359,19 +367,41 @@ test_expect_success 'OPT_NEGBIT() works' '
 '
 
 test_expect_success 'OPT_CMDMODE() works' '
-       test-tool parse-options --expect="integer: 1" --mode1
+       test-tool parse-options --expect="integer: 1" --mode1 &&
+       test-tool parse-options --expect="integer: 3" --mode34=3
 '
 
-test_expect_success 'OPT_CMDMODE() detects incompatibility' '
+test_expect_success 'OPT_CMDMODE() detects incompatibility (1)' '
        test_must_fail test-tool parse-options --mode1 --mode2 >output 2>output.err &&
        test_must_be_empty output &&
-       test_i18ngrep "incompatible with --mode" output.err
+       test_i18ngrep "mode1" output.err &&
+       test_i18ngrep "mode2" output.err &&
+       test_i18ngrep "is incompatible with" output.err
 '
 
-test_expect_success 'OPT_CMDMODE() detects incompatibility with something else' '
+test_expect_success 'OPT_CMDMODE() detects incompatibility (2)' '
        test_must_fail test-tool parse-options --set23 --mode2 >output 2>output.err &&
        test_must_be_empty output &&
-       test_i18ngrep "incompatible with something else" output.err
+       test_i18ngrep "mode2" output.err &&
+       test_i18ngrep "set23" output.err &&
+       test_i18ngrep "is incompatible with" output.err
+'
+
+test_expect_success 'OPT_CMDMODE() detects incompatibility (3)' '
+       test_must_fail test-tool parse-options --mode2 --set23 >output 2>output.err &&
+       test_must_be_empty output &&
+       test_i18ngrep "mode2" output.err &&
+       test_i18ngrep "set23" output.err &&
+       test_i18ngrep "is incompatible with" output.err
+'
+
+test_expect_success 'OPT_CMDMODE() detects incompatibility (4)' '
+       test_must_fail test-tool parse-options --mode2 --mode34=3 \
+               >output 2>output.err &&
+       test_must_be_empty output &&
+       test_i18ngrep "mode2" output.err &&
+       test_i18ngrep "mode34.3" output.err &&
+       test_i18ngrep "is incompatible with" output.err
 '
 
 test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
index c4fc34eb18eb1401c5331667408c496e663c9c69..9ea974b0c6c68a247ddd3f1b7cae806a4c79fbc4 100755 (executable)
@@ -5,6 +5,7 @@ test_description='Test commands behavior when given invalid argument value'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup ' '
diff --git a/t/t0081-find-pack.sh b/t/t0081-find-pack.sh
new file mode 100755 (executable)
index 0000000..67b1121
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='test `test-tool find-pack`'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit one &&
+       test_commit two &&
+       test_commit three &&
+       test_commit four &&
+       test_commit five
+'
+
+test_expect_success 'repack everything into a single packfile' '
+       git repack -a -d --no-write-bitmap-index &&
+
+       head_commit_pack=$(test-tool find-pack HEAD) &&
+       head_tree_pack=$(test-tool find-pack HEAD^{tree}) &&
+       one_pack=$(test-tool find-pack HEAD:one.t) &&
+       three_pack=$(test-tool find-pack HEAD:three.t) &&
+       old_commit_pack=$(test-tool find-pack HEAD~4) &&
+
+       test-tool find-pack --check-count 1 HEAD &&
+       test-tool find-pack --check-count=1 HEAD^{tree} &&
+       ! test-tool find-pack --check-count=0 HEAD:one.t &&
+       ! test-tool find-pack -c 2 HEAD:one.t &&
+       test-tool find-pack -c 1 HEAD:three.t &&
+
+       # Packfile exists at the right path
+       case "$head_commit_pack" in
+               ".git/objects/pack/pack-"*".pack") true ;;
+               *) false ;;
+       esac &&
+       test -f "$head_commit_pack" &&
+
+       # Everything is in the same pack
+       test "$head_commit_pack" = "$head_tree_pack" &&
+       test "$head_commit_pack" = "$one_pack" &&
+       test "$head_commit_pack" = "$three_pack" &&
+       test "$head_commit_pack" = "$old_commit_pack"
+'
+
+test_expect_success 'add more packfiles' '
+       git rev-parse HEAD^{tree} HEAD:two.t HEAD:four.t >objects &&
+       git pack-objects .git/objects/pack/mypackname1 >packhash1 <objects &&
+
+       git rev-parse HEAD~ HEAD~^{tree} HEAD:five.t >objects &&
+       git pack-objects .git/objects/pack/mypackname2 >packhash2 <objects &&
+
+       head_commit_pack=$(test-tool find-pack HEAD) &&
+
+       # HEAD^{tree} is in 2 packfiles
+       test-tool find-pack HEAD^{tree} >head_tree_packs &&
+       grep "$head_commit_pack" head_tree_packs &&
+       grep mypackname1 head_tree_packs &&
+       ! grep mypackname2 head_tree_packs &&
+       test-tool find-pack --check-count 2 HEAD^{tree} &&
+       ! test-tool find-pack --check-count 1 HEAD^{tree} &&
+
+       # HEAD:five.t is also in 2 packfiles
+       test-tool find-pack HEAD:five.t >five_packs &&
+       grep "$head_commit_pack" five_packs &&
+       ! grep mypackname1 five_packs &&
+       grep mypackname2 five_packs &&
+       test-tool find-pack -c 2 HEAD:five.t &&
+       ! test-tool find-pack --check-count=0 HEAD:five.t
+'
+
+test_expect_success 'add more commits (as loose objects)' '
+       test_commit six &&
+       test_commit seven &&
+
+       test -z "$(test-tool find-pack HEAD)" &&
+       test -z "$(test-tool find-pack HEAD:six.t)" &&
+       test-tool find-pack --check-count 0 HEAD &&
+       test-tool find-pack -c 0 HEAD:six.t &&
+       ! test-tool find-pack -c 1 HEAD:seven.t
+'
+
+test_done
index b6d2f591acdd999483b2d28af8bbbe3d30008ea7..f6998269beb4fea3f68f14ffae22b541a066e6b3 100755 (executable)
@@ -5,29 +5,50 @@ test_description='git bugreport'
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
-# Headers "[System Info]" will be followed by a non-empty line if we put some
-# information there; we can make sure all our headers were followed by some
-# information to check if the command was successful.
-HEADER_PATTERN="^\[.*\]$"
-
-check_all_headers_populated () {
-       while read -r line
-       do
-               if test "$(grep "$HEADER_PATTERN" "$line")"
-               then
-                       echo "$line"
-                       read -r nextline
-                       if test -z "$nextline"; then
-                               return 1;
-                       fi
-               fi
-       done
-}
-
-test_expect_success 'creates a report with content in the right places' '
-       test_when_finished rm git-bugreport-check-headers.txt &&
-       git bugreport -s check-headers &&
-       check_all_headers_populated <git-bugreport-check-headers.txt
+test_expect_success 'create a report' '
+       git bugreport -s format &&
+       test_file_not_empty git-bugreport-format.txt
+'
+
+test_expect_success 'report contains wanted template (before first section)' '
+       sed -ne "/^\[/q;p" git-bugreport-format.txt >actual &&
+       cat >expect <<-\EOF &&
+       Thank you for filling out a Git bug report!
+       Please answer the following questions to help us understand your issue.
+
+       What did you do before the bug happened? (Steps to reproduce your issue)
+
+       What did you expect to happen? (Expected behavior)
+
+       What happened instead? (Actual behavior)
+
+       What'\''s different between what you expected and what actually happened?
+
+       Anything else you want to add:
+
+       Please review the rest of the bug report below.
+       You can delete any lines you don'\''t wish to share.
+
+
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'sanity check "System Info" section' '
+       test_when_finished rm -f git-bugreport-format.txt &&
+
+       sed -ne "/^\[System Info\]$/,/^$/p" <git-bugreport-format.txt >system &&
+
+       # The beginning should match "git version --build-info" verbatim,
+       # but rather than checking bit-for-bit equality, just test some basics.
+       grep "git version [0-9]." system &&
+       grep "shell-path: ." system &&
+
+       # After the version, there should be some more info.
+       # This is bound to differ from environment to environment,
+       # so we just do some rather high-level checks.
+       grep "uname: ." system &&
+       grep "compiler info: ." system
 '
 
 test_expect_success 'dies if file with same name as report already exists' '
index b4e91351181bcbe767f9681a689e570025dd4f53..cfba6861322e373c64897e4c543838b7879cf3e0 100755 (executable)
@@ -203,7 +203,7 @@ test_expect_success 'stopwatch timer test/test1' '
        have_timer_event "main" "timer" "test" "test1" 5 actual
 '
 
-test_expect_success PTHREAD 'stopwatch timer test/test2' '
+test_expect_success PTHREADS 'stopwatch timer test/test2' '
        test_when_finished "rm trace.perf actual" &&
        test_config_global trace2.perfBrief 1 &&
        test_config_global trace2.perfTarget "$(pwd)/trace.perf" &&
@@ -249,7 +249,7 @@ test_expect_success 'global counter test/test1' '
        have_counter_event "main" "counter" "test" "test1" 15 actual
 '
 
-test_expect_success PTHREAD 'global counter test/test2' '
+test_expect_success PTHREADS 'global counter test/test2' '
        test_when_finished "rm trace.perf actual" &&
        test_config_global trace2.perfBrief 1 &&
        test_config_global trace2.perfTarget "$(pwd)/trace.perf" &&
index c02a3b5969c3d2265d1552132464df7135cd522b..8300faadea9a76f19e3d2c82f5ff600f38bfe18f 100755 (executable)
@@ -29,6 +29,7 @@ test_atexit 'git credential-cache exit'
 
 # test that the daemon works with no special setup
 helper_test cache
+helper_test_password_expiry_utc cache
 helper_test_oauth_refresh_token cache
 
 test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
index f028fd1418285107a90e170a6ea1cd7657e31bb8..095574bfc6edf2aaf835b2ff43bb8cd35f792591 100755 (executable)
@@ -45,6 +45,8 @@ test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" ||
 helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER"
 
 helper_test "$GIT_TEST_CREDENTIAL_HELPER"
+helper_test_password_expiry_utc "$GIT_TEST_CREDENTIAL_HELPER"
+helper_test_oauth_refresh_token "$GIT_TEST_CREDENTIAL_HELPER"
 
 if test -z "$GIT_TEST_CREDENTIAL_HELPER_TIMEOUT"; then
        say "# skipping timeout tests (GIT_TEST_CREDENTIAL_HELPER_TIMEOUT not set)"
index 3fb1b0c162ded2a5d78767dbd62de97fc59e5d29..88c524f6558eedd0775da7500d84a90ba19edeba 100755 (executable)
@@ -26,7 +26,7 @@ TEST_PASSES_SANITIZE_LEAK=true
 . "$TEST_DIRECTORY"/lib-read-tree.sh
 
 read_tree_twoway () {
-    git read-tree -m "$1" "$2" && git ls-files --stage
+       git read-tree -m "$1" "$2" && git ls-files --stage
 }
 
 compare_change () {
index cdc077ce12d46603171f2a97c65a63e873e86733..a7c2ed0d7c0a31180e6af1abe9dcc6366e62e2c5 100755 (executable)
@@ -37,315 +37,312 @@ check_cache_at () {
        esac
 }
 
-test_expect_success \
-    setup \
-    'echo frotz >frotz &&
-     echo nitfol >nitfol &&
-     echo bozbar >bozbar &&
-     echo rezrov >rezrov &&
-     git update-index --add nitfol bozbar rezrov &&
-     treeH=$(git write-tree) &&
-     echo treeH $treeH &&
-     git ls-tree $treeH &&
-
-     echo gnusto >bozbar &&
-     git update-index --add frotz bozbar --force-remove rezrov &&
-     git ls-files --stage >M.out &&
-     treeM=$(git write-tree) &&
-     echo treeM $treeM &&
-     git ls-tree $treeM &&
-     cp bozbar bozbar.M &&
-     cp frotz frotz.M &&
-     cp nitfol nitfol.M &&
-     git diff-tree $treeH $treeM'
-
-test_expect_success \
-    '1, 2, 3 - no carry forward' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >1-3.out &&
-     cmp M.out 1-3.out &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol &&
-     check_cache_at bozbar clean &&
-     check_cache_at frotz clean &&
-     check_cache_at nitfol clean'
-
-test_expect_success \
-    '4 - carry forward local addition.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo "+100644 X 0 yomin" >expected &&
-     echo yomin >yomin &&
-     git update-index --add yomin &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >4.out &&
-     test_might_fail git diff -U0 --no-index M.out 4.out >4diff.out &&
-     compare_change 4diff.out expected &&
-     check_cache_at yomin clean &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol &&
-     echo yomin >yomin1 &&
-     diff yomin yomin1 &&
-     rm -f yomin1'
-
-test_expect_success \
-    '5 - carry forward local addition.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     read_tree_u_must_succeed -m -u $treeH &&
-     echo yomin >yomin &&
-     git update-index --add yomin &&
-     echo yomin yomin >yomin &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >5.out &&
-     test_might_fail git diff -U0 --no-index M.out 5.out >5diff.out &&
-     compare_change 5diff.out expected &&
-     check_cache_at yomin dirty &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol &&
-     : dirty index should have prevented -u from checking it out. &&
-     echo yomin yomin >yomin1 &&
-     diff yomin yomin1 &&
-     rm -f yomin1'
-
-test_expect_success \
-    '6 - local addition already has the same.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo frotz >frotz &&
-     git update-index --add frotz &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >6.out &&
-     test_cmp M.out 6.out &&
-     check_cache_at frotz clean &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol &&
-     echo frotz >frotz1 &&
-     diff frotz frotz1 &&
-     rm -f frotz1'
-
-test_expect_success \
-    '7 - local addition already has the same.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo frotz >frotz &&
-     git update-index --add frotz &&
-     echo frotz frotz >frotz &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >7.out &&
-     test_cmp M.out 7.out &&
-     check_cache_at frotz dirty &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp nitfol.M nitfol &&
-     : dirty index should have prevented -u from checking it out. &&
-     echo frotz frotz >frotz1 &&
-     diff frotz frotz1 &&
-     rm -f frotz1'
-
-test_expect_success \
-    '8 - conflicting addition.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo frotz frotz >frotz &&
-     git update-index --add frotz &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
-
-test_expect_success \
-    '9 - conflicting addition.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo frotz frotz >frotz &&
-     git update-index --add frotz &&
-     echo frotz >frotz &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
-
-test_expect_success \
-    '10 - path removed.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo rezrov >rezrov &&
-     git update-index --add rezrov &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >10.out &&
-     cmp M.out 10.out &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol
+test_expect_success setup '
+       echo frotz >frotz &&
+       echo nitfol >nitfol &&
+       echo bozbar >bozbar &&
+       echo rezrov >rezrov &&
+       git update-index --add nitfol bozbar rezrov &&
+       treeH=$(git write-tree) &&
+       echo treeH $treeH &&
+       git ls-tree $treeH &&
+
+       echo gnusto >bozbar &&
+       git update-index --add frotz bozbar --force-remove rezrov &&
+       git ls-files --stage >M.out &&
+       treeM=$(git write-tree) &&
+       echo treeM $treeM &&
+       git ls-tree $treeM &&
+       cp bozbar bozbar.M &&
+       cp frotz frotz.M &&
+       cp nitfol nitfol.M &&
+       git diff-tree $treeH $treeM
 '
 
-test_expect_success \
-    '11 - dirty path removed.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo rezrov >rezrov &&
-     git update-index --add rezrov &&
-     echo rezrov rezrov >rezrov &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
-
-test_expect_success \
-    '12 - unmatching local changes being removed.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo rezrov rezrov >rezrov &&
-     git update-index --add rezrov &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
-
-test_expect_success \
-    '13 - unmatching local changes being removed.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo rezrov rezrov >rezrov &&
-     git update-index --add rezrov &&
-     echo rezrov >rezrov &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
+test_expect_success '1, 2, 3 - no carry forward' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >1-3.out &&
+       cmp M.out 1-3.out &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol &&
+       check_cache_at bozbar clean &&
+       check_cache_at frotz clean &&
+       check_cache_at nitfol clean
+'
+
+test_expect_success '4 - carry forward local addition.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo "+100644 X 0       yomin" >expected &&
+       echo yomin >yomin &&
+       git update-index --add yomin &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >4.out &&
+       test_might_fail git diff -U0 --no-index M.out 4.out >4diff.out &&
+       compare_change 4diff.out expected &&
+       check_cache_at yomin clean &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol &&
+       echo yomin >yomin1 &&
+       diff yomin yomin1 &&
+       rm -f yomin1
+'
+
+test_expect_success '5 - carry forward local addition.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       read_tree_u_must_succeed -m -u $treeH &&
+       echo yomin >yomin &&
+       git update-index --add yomin &&
+       echo yomin yomin >yomin &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >5.out &&
+       test_might_fail git diff -U0 --no-index M.out 5.out >5diff.out &&
+       compare_change 5diff.out expected &&
+       check_cache_at yomin dirty &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol &&
+       : dirty index should have prevented -u from checking it out. &&
+       echo yomin yomin >yomin1 &&
+       diff yomin yomin1 &&
+       rm -f yomin1
+'
+
+test_expect_success '6 - local addition already has the same.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo frotz >frotz &&
+       git update-index --add frotz &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >6.out &&
+       test_cmp M.out 6.out &&
+       check_cache_at frotz clean &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol &&
+       echo frotz >frotz1 &&
+       diff frotz frotz1 &&
+       rm -f frotz1
+'
+
+test_expect_success '7 - local addition already has the same.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo frotz >frotz &&
+       git update-index --add frotz &&
+       echo frotz frotz >frotz &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >7.out &&
+       test_cmp M.out 7.out &&
+       check_cache_at frotz dirty &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp nitfol.M nitfol &&
+       : dirty index should have prevented -u from checking it out. &&
+       echo frotz frotz >frotz1 &&
+       diff frotz frotz1 &&
+       rm -f frotz1
+'
+
+test_expect_success '8 - conflicting addition.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo frotz frotz >frotz &&
+       git update-index --add frotz &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
+
+test_expect_success '9 - conflicting addition.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo frotz frotz >frotz &&
+       git update-index --add frotz &&
+       echo frotz >frotz &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
+
+test_expect_success '10 - path removed.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo rezrov >rezrov &&
+       git update-index --add rezrov &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >10.out &&
+       cmp M.out 10.out &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol
+'
+
+test_expect_success '11 - dirty path removed.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo rezrov >rezrov &&
+       git update-index --add rezrov &&
+       echo rezrov rezrov >rezrov &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
+
+test_expect_success '12 - unmatching local changes being removed.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo rezrov rezrov >rezrov &&
+       git update-index --add rezrov &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
+
+test_expect_success '13 - unmatching local changes being removed.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo rezrov rezrov >rezrov &&
+       git update-index --add rezrov &&
+       echo rezrov >rezrov &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
 
 cat >expected <<EOF
 -100644 X 0    nitfol
 +100644 X 0    nitfol
 EOF
 
-test_expect_success \
-    '14 - unchanged in two heads.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo nitfol nitfol >nitfol &&
-     git update-index --add nitfol &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >14.out &&
-     test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out &&
-     compare_change 14diff.out expected &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     check_cache_at nitfol clean &&
-     echo nitfol nitfol >nitfol1 &&
-     diff nitfol nitfol1 &&
-     rm -f nitfol1'
-
-test_expect_success \
-    '15 - unchanged in two heads.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo nitfol nitfol >nitfol &&
-     git update-index --add nitfol &&
-     echo nitfol nitfol nitfol >nitfol &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >15.out &&
-     test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out &&
-     compare_change 15diff.out expected &&
-     check_cache_at nitfol dirty &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     echo nitfol nitfol nitfol >nitfol1 &&
-     diff nitfol nitfol1 &&
-     rm -f nitfol1'
-
-test_expect_success \
-    '16 - conflicting local change.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo bozbar bozbar >bozbar &&
-     git update-index --add bozbar &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
-
-test_expect_success \
-    '17 - conflicting local change.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo bozbar bozbar >bozbar &&
-     git update-index --add bozbar &&
-     echo bozbar bozbar bozbar >bozbar &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
-
-test_expect_success \
-    '18 - local change already having a good result.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo gnusto >bozbar &&
-     git update-index --add bozbar &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >18.out &&
-     test_cmp M.out 18.out &&
-     check_cache_at bozbar clean &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol
+test_expect_success '14 - unchanged in two heads.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo nitfol nitfol >nitfol &&
+       git update-index --add nitfol &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >14.out &&
+       test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out &&
+       compare_change 14diff.out expected &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       check_cache_at nitfol clean &&
+       echo nitfol nitfol >nitfol1 &&
+       diff nitfol nitfol1 &&
+       rm -f nitfol1
 '
 
-test_expect_success \
-    '19 - local change already having a good result, further modified.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo gnusto >bozbar &&
-     git update-index --add bozbar &&
-     echo gnusto gnusto >bozbar &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >19.out &&
-     test_cmp M.out 19.out &&
-     check_cache_at bozbar dirty &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol &&
-     echo gnusto gnusto >bozbar1 &&
-     diff bozbar bozbar1 &&
-     rm -f bozbar1'
-
-test_expect_success \
-    '20 - no local change, use new tree.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo bozbar >bozbar &&
-     git update-index --add bozbar &&
-     read_tree_u_must_succeed -m -u $treeH $treeM &&
-     git ls-files --stage >20.out &&
-     test_cmp M.out 20.out &&
-     check_cache_at bozbar clean &&
-     test_cmp bozbar.M bozbar &&
-     test_cmp frotz.M frotz &&
-     test_cmp nitfol.M nitfol
+test_expect_success '15 - unchanged in two heads.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo nitfol nitfol >nitfol &&
+       git update-index --add nitfol &&
+       echo nitfol nitfol nitfol >nitfol &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >15.out &&
+       test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out &&
+       compare_change 15diff.out expected &&
+       check_cache_at nitfol dirty &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       echo nitfol nitfol nitfol >nitfol1 &&
+       diff nitfol nitfol1 &&
+       rm -f nitfol1
 '
 
-test_expect_success \
-    '21 - no local change, dirty cache.' \
-    'rm -f .git/index nitfol bozbar rezrov frotz &&
-     read_tree_u_must_succeed --reset -u $treeH &&
-     echo bozbar >bozbar &&
-     git update-index --add bozbar &&
-     echo gnusto gnusto >bozbar &&
-     ! read_tree_u_must_succeed -m -u $treeH $treeM'
+test_expect_success '16 - conflicting local change.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo bozbar bozbar >bozbar &&
+       git update-index --add bozbar &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
+
+test_expect_success '17 - conflicting local change.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo bozbar bozbar >bozbar &&
+       git update-index --add bozbar &&
+       echo bozbar bozbar bozbar >bozbar &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
+
+test_expect_success '18 - local change already having a good result.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo gnusto >bozbar &&
+       git update-index --add bozbar &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >18.out &&
+       test_cmp M.out 18.out &&
+       check_cache_at bozbar clean &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol
+'
+
+test_expect_success '19 - local change already having a good result, further modified.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo gnusto >bozbar &&
+       git update-index --add bozbar &&
+       echo gnusto gnusto >bozbar &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >19.out &&
+       test_cmp M.out 19.out &&
+       check_cache_at bozbar dirty &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol &&
+       echo gnusto gnusto >bozbar1 &&
+       diff bozbar bozbar1 &&
+       rm -f bozbar1
+'
+
+test_expect_success '20 - no local change, use new tree.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo bozbar >bozbar &&
+       git update-index --add bozbar &&
+       read_tree_u_must_succeed -m -u $treeH $treeM &&
+       git ls-files --stage >20.out &&
+       test_cmp M.out 20.out &&
+       check_cache_at bozbar clean &&
+       test_cmp bozbar.M bozbar &&
+       test_cmp frotz.M frotz &&
+       test_cmp nitfol.M nitfol
+'
+
+test_expect_success '21 - no local change, dirty cache.' '
+       rm -f .git/index nitfol bozbar rezrov frotz &&
+       read_tree_u_must_succeed --reset -u $treeH &&
+       echo bozbar >bozbar &&
+       git update-index --add bozbar &&
+       echo gnusto gnusto >bozbar &&
+       ! read_tree_u_must_succeed -m -u $treeH $treeM
+'
 
 # Also make sure we did not break DF vs DF/DF case.
-test_expect_success \
-    'DF vs DF/DF case setup.' \
-    'rm -f .git/index &&
-     echo DF >DF &&
-     git update-index --add DF &&
-     treeDF=$(git write-tree) &&
-     echo treeDF $treeDF &&
-     git ls-tree $treeDF &&
-
-     rm -f DF &&
-     mkdir DF &&
-     echo DF/DF >DF/DF &&
-     git update-index --add --remove DF DF/DF &&
-     treeDFDF=$(git write-tree) &&
-     echo treeDFDF $treeDFDF &&
-     git ls-tree $treeDFDF &&
-     git ls-files --stage >DFDF.out'
-
-test_expect_success \
-    'DF vs DF/DF case test.' \
-    'rm -f .git/index &&
-     rm -fr DF &&
-     echo DF >DF &&
-     git update-index --add DF &&
-     read_tree_u_must_succeed -m -u $treeDF $treeDFDF &&
-     git ls-files --stage >DFDFcheck.out &&
-     test_cmp DFDF.out DFDFcheck.out &&
-     check_cache_at DF/DF clean'
+test_expect_success 'DF vs DF/DF case setup.' '
+       rm -f .git/index &&
+       echo DF >DF &&
+       git update-index --add DF &&
+       treeDF=$(git write-tree) &&
+       echo treeDF $treeDF &&
+       git ls-tree $treeDF &&
+
+       rm -f DF &&
+       mkdir DF &&
+       echo DF/DF >DF/DF &&
+       git update-index --add --remove DF DF/DF &&
+       treeDFDF=$(git write-tree) &&
+       echo treeDFDF $treeDFDF &&
+       git ls-tree $treeDFDF &&
+       git ls-files --stage >DFDF.out
+'
+
+test_expect_success 'DF vs DF/DF case test.' '
+       rm -f .git/index &&
+       rm -fr DF &&
+       echo DF >DF &&
+       git update-index --add DF &&
+       read_tree_u_must_succeed -m -u $treeDF $treeDFDF &&
+       git ls-files --stage >DFDFcheck.out &&
+       test_cmp DFDF.out DFDFcheck.out &&
+       check_cache_at DF/DF clean
+'
 
 test_done
index 8eac74b59c2faa9c6e9f2396214264861c8416c1..d73a0be1b9d1bfa3e0f1fd96e69c0e78ad2dec06 100755 (executable)
@@ -89,7 +89,8 @@ done
 for opt in --buffer \
        --follow-symlinks \
        --batch-all-objects \
-       -z
+       -z \
+       -Z
 do
        test_expect_success "usage: bad option combination: $opt without batch mode" '
                test_incompatible_usage git cat-file $opt &&
@@ -109,26 +110,12 @@ strlen () {
     echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
 }
 
-maybe_remove_timestamp () {
-       if test -z "$2"; then
-               echo_without_newline "$1"
-       else
-               echo_without_newline "$(printf '%s\n' "$1" | remove_timestamp)"
-       fi
-}
-
-remove_timestamp () {
-       sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//'
-}
-
-
 run_tests () {
     type=$1
     sha1=$2
     size=$3
     content=$4
     pretty_content=$5
-    no_ts=$6
 
     batch_output="$sha1 $type $size
 $content"
@@ -163,21 +150,21 @@ $content"
 
     test -z "$content" ||
     test_expect_success "Content of $type is correct" '
-       maybe_remove_timestamp "$content" $no_ts >expect &&
-       maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual &&
+       echo_without_newline "$content" >expect &&
+       git cat-file $type $sha1 >actual &&
        test_cmp expect actual
     '
 
     test_expect_success "Pretty content of $type is correct" '
-       maybe_remove_timestamp "$pretty_content" $no_ts >expect &&
-       maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual &&
+       echo_without_newline "$pretty_content" >expect &&
+       git cat-file -p $sha1 >actual &&
        test_cmp expect actual
     '
 
     test -z "$content" ||
     test_expect_success "--batch output of $type is correct" '
-       maybe_remove_timestamp "$batch_output" $no_ts >expect &&
-       maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual &&
+       echo "$batch_output" >expect &&
+       echo $sha1 | git cat-file --batch >actual &&
        test_cmp expect actual
     '
 
@@ -191,9 +178,8 @@ $content"
     do
        test -z "$content" ||
                test_expect_success "--batch-command $opt output of $type content is correct" '
-               maybe_remove_timestamp "$batch_output" $no_ts >expect &&
-               maybe_remove_timestamp "$(test_write_lines "contents $sha1" |
-               git cat-file --batch-command $opt)" $no_ts >actual &&
+               echo "$batch_output" >expect &&
+               test_write_lines "contents $sha1" | git cat-file --batch-command $opt >actual &&
                test_cmp expect actual
        '
 
@@ -228,10 +214,9 @@ $content"
     test_expect_success "--batch without type ($type)" '
        {
                echo "$size" &&
-               maybe_remove_timestamp "$content" $no_ts
+               echo "$content"
        } >expect &&
-       echo $sha1 | git cat-file --batch="%(objectsize)" >actual.full &&
-       maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
+       echo $sha1 | git cat-file --batch="%(objectsize)" >actual &&
        test_cmp expect actual
     '
 
@@ -239,10 +224,9 @@ $content"
     test_expect_success "--batch without size ($type)" '
        {
                echo "$type" &&
-               maybe_remove_timestamp "$content" $no_ts
+               echo "$content"
        } >expect &&
-       echo $sha1 | git cat-file --batch="%(objecttype)" >actual.full &&
-       maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
+       echo $sha1 | git cat-file --batch="%(objecttype)" >actual &&
        test_cmp expect actual
     '
 }
@@ -284,7 +268,7 @@ test_expect_success '--batch-check without %(rest) considers whole line' '
 
 tree_sha1=$(git write-tree)
 tree_size=$(($(test_oid rawsz) + 13))
-tree_pretty_content="100644 blob $hello_sha1   hello"
+tree_pretty_content="100644 blob $hello_sha1   hello${LF}"
 
 run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
 
@@ -292,12 +276,12 @@ commit_message="Initial commit"
 commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
 commit_size=$(($(test_oid hexsz) + 137))
 commit_content="tree $tree_sha1
-author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0 +0000
-committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0 +0000
+author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 
 $commit_message"
 
-run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" 1
+run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content"
 
 tag_header_without_timestamp="object $hello_sha1
 type blob
@@ -311,11 +295,13 @@ $tag_description"
 tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
 tag_size=$(strlen "$tag_content")
 
-run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1
+run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content"
 
-test_expect_success \
-    "Reach a blob from a tag pointing to it" \
-    "test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
+test_expect_success "Reach a blob from a tag pointing to it" '
+       echo_without_newline "$hello_content" >expect &&
+       git cat-file blob $tag_sha1 >actual &&
+       test_cmp expect actual
+'
 
 for batch in batch batch-check batch-command
 do
@@ -351,30 +337,47 @@ do
 done
 
 test_expect_success "--batch-check for a non-existent named object" '
-    test "foobar42 missing
-foobar84 missing" = \
-    "$( ( echo foobar42 && echo_without_newline foobar84 ) | git cat-file --batch-check)"
+       cat >expect <<-EOF &&
+       foobar42 missing
+       foobar84 missing
+       EOF
+
+       printf "foobar42\nfoobar84" >in &&
+       git cat-file --batch-check <in >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success "--batch-check for a non-existent hash" '
-    test "0000000000000000000000000000000000000042 missing
-0000000000000000000000000000000000000084 missing" = \
-    "$( ( echo 0000000000000000000000000000000000000042 &&
-        echo_without_newline 0000000000000000000000000000000000000084 ) |
-       git cat-file --batch-check)"
+       cat >expect <<-EOF &&
+       0000000000000000000000000000000000000042 missing
+       0000000000000000000000000000000000000084 missing
+       EOF
+
+       printf "0000000000000000000000000000000000000042\n0000000000000000000000000000000000000084" >in &&
+       git cat-file --batch-check <in >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success "--batch for an existent and a non-existent hash" '
-    test "$tag_sha1 tag $tag_size
-$tag_content
-0000000000000000000000000000000000000000 missing" = \
-    "$( ( echo $tag_sha1 &&
-        echo_without_newline 0000000000000000000000000000000000000000 ) |
-       git cat-file --batch)"
+       cat >expect <<-EOF &&
+       $tag_sha1 tag $tag_size
+       $tag_content
+       0000000000000000000000000000000000000000 missing
+       EOF
+
+       printf "$tag_sha1\n0000000000000000000000000000000000000000" >in &&
+       git cat-file --batch <in >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success "--batch-check for an empty line" '
-    test " missing" = "$(echo | git cat-file --batch-check)"
+       cat >expect <<-EOF &&
+        missing
+       EOF
+
+       echo >in &&
+       git cat-file --batch-check <in >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'empty --batch-check notices missing object' '
@@ -390,23 +393,34 @@ deadbeef
 
 "
 
-batch_output="$hello_sha1 blob $hello_size
-$hello_content
-$commit_sha1 commit $commit_size
-$commit_content
-$tag_sha1 tag $tag_size
-$tag_content
-deadbeef missing
- missing"
+printf "%s\0" \
+       "$hello_sha1 blob $hello_size" \
+       "$hello_content" \
+       "$commit_sha1 commit $commit_size" \
+       "$commit_content" \
+       "$tag_sha1 tag $tag_size" \
+       "$tag_content" \
+       "deadbeef missing" \
+       " missing" >batch_output
 
 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)"
+       tr "\0" "\n" <batch_output >expect &&
+       echo_without_newline "$batch_input" >in &&
+       git cat-file --batch <in >actual &&
+       test_cmp expect actual
 '
 
 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)"
+       tr "\0" "\n" <batch_output >expect &&
+       git cat-file --batch -z <in >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--batch, -Z with multiple sha1s gives correct format' '
+       echo_without_newline_nul "$batch_input" >in &&
+       git cat-file --batch -Z <in >actual &&
+       test_cmp batch_output actual
 '
 
 batch_check_input="$hello_sha1
@@ -417,36 +431,55 @@ deadbeef
 
 "
 
-batch_check_output="$hello_sha1 blob $hello_size
-$tree_sha1 tree $tree_size
-$commit_sha1 commit $commit_size
-$tag_sha1 tag $tag_size
-deadbeef missing
- missing"
+printf "%s\0" \
+       "$hello_sha1 blob $hello_size" \
+       "$tree_sha1 tree $tree_size" \
+       "$commit_sha1 commit $commit_size" \
+       "$tag_sha1 tag $tag_size" \
+       "deadbeef missing" \
+       " missing" >batch_check_output
 
 test_expect_success "--batch-check with multiple sha1s gives correct format" '
-    test "$batch_check_output" = \
-    "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
+       tr "\0" "\n" <batch_check_output >expect &&
+       echo_without_newline "$batch_check_input" >in &&
+       git cat-file --batch-check <in >actual &&
+       test_cmp expect actual
 '
 
 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)"
+       tr "\0" "\n" <batch_check_output >expect &&
+       echo_without_newline_nul "$batch_check_input" >in &&
+       git cat-file --batch-check -z <in >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
+test_expect_success "--batch-check, -Z with multiple sha1s gives correct format" '
+       echo_without_newline_nul "$batch_check_input" >in &&
+       git cat-file --batch-check -Z <in >actual &&
+       test_cmp batch_check_output actual
+'
+
+test_expect_success FUNNYNAMES 'setup 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 &&
+       printf "HEAD:newline${LF}embedded" >in
+'
 
+test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
+       git cat-file --batch-check -z <in >actual &&
        echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
        test_cmp expect actual
 '
 
+test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' '
+       git cat-file --batch-check -Z <in >actual &&
+       printf "%s\0" "$(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
@@ -470,7 +503,13 @@ test_expect_success '--batch-command with multiple info calls gives correct form
        echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
        git cat-file --batch-command --buffer -z <in >actual &&
 
-       test_cmp expect actual
+       test_cmp expect actual &&
+
+       echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
+       tr "\n" "\0" <expect >expect_nul &&
+       git cat-file --batch-command --buffer -Z <in >actual &&
+
+       test_cmp expect_nul actual
 '
 
 batch_command_multiple_contents="contents $hello_sha1
@@ -480,27 +519,30 @@ contents deadbeef
 flush"
 
 test_expect_success '--batch-command with multiple command calls gives correct format' '
-       remove_timestamp >expect <<-EOF &&
-       $hello_sha1 blob $hello_size
-       $hello_content
-       $commit_sha1 commit $commit_size
-       $commit_content
-       $tag_sha1 tag $tag_size
-       $tag_content
-       deadbeef missing
-       EOF
+       printf "%s\0" \
+               "$hello_sha1 blob $hello_size" \
+               "$hello_content" \
+               "$commit_sha1 commit $commit_size" \
+               "$commit_content" \
+               "$tag_sha1 tag $tag_size" \
+               "$tag_content" \
+               "deadbeef missing" >expect_nul &&
+       tr "\0" "\n" <expect_nul >expect &&
 
        echo "$batch_command_multiple_contents" >in &&
-       git cat-file --batch-command --buffer <in >actual_raw &&
+       git cat-file --batch-command --buffer <in >actual &&
 
-       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 &&
+       git cat-file --batch-command --buffer -z <in >actual &&
 
-       remove_timestamp <actual_raw >actual &&
-       test_cmp expect actual
+       test_cmp expect actual &&
+
+       echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
+       git cat-file --batch-command --buffer -Z <in >actual &&
+
+       test_cmp expect_nul actual
 '
 
 test_expect_success 'setup blobs which are likely to delta' '
@@ -840,6 +882,13 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for brok
        test_cmp expect actual
 '
 
+test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for broken in-repo, same-dir links' '
+       printf "HEAD:broken-same-dir-link\0" >in &&
+       printf "dangling 25\0HEAD:broken-same-dir-link\0" >expect &&
+       git cat-file --batch-check --follow-symlinks -Z <in >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' '
        echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
        test_cmp found actual
@@ -854,6 +903,15 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for pare
        test_cmp expect actual
 '
 
+test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for parent-dir links' '
+       echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
+       test_cmp found actual &&
+       printf "notdir 29\0HEAD:dir/parent-dir-link/nope\0" >expect &&
+       printf "HEAD:dir/parent-dir-link/nope\0" >in &&
+       git cat-file --batch-check --follow-symlinks -Z <in >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' '
        echo dangling 22 >expect &&
        echo HEAD:dir/link-dir/nope >>expect &&
@@ -968,6 +1026,13 @@ test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' '
        test_cmp expect actual
 '
 
+test_expect_success 'git cat-file --batch-check --follow-symlink -Z breaks loops' '
+       printf "loop 10\0HEAD:loop1\0" >expect &&
+       printf "HEAD:loop1\0" >in &&
+       git cat-file --batch-check --follow-symlinks -Z <in >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' '
        echo HEAD:morx | git cat-file --batch >expect &&
        echo HEAD:morx | git cat-file --batch --follow-symlinks >actual &&
index a63d0cc222102b0e3fa9e4dcf0d733076b534294..2a4f35e98450f8ab499f11a1bafa777a82101136 100755 (executable)
@@ -2180,4 +2180,155 @@ test_expect_success 'sparse index is not expanded: diff-files' '
        ensure_not_expanded diff-files -- "deep/*"
 '
 
+test_expect_success 'diff-tree' '
+       init_repos &&
+
+       # Test change inside sparse cone
+       tree1=$(git -C sparse-index rev-parse HEAD^{tree}) &&
+       tree2=$(git -C sparse-index rev-parse update-deep^{tree}) &&
+       test_all_match git diff-tree $tree1 $tree2 &&
+       test_all_match git diff-tree $tree1 $tree2 -- deep/a &&
+       test_all_match git diff-tree HEAD update-deep &&
+       test_all_match git diff-tree HEAD update-deep -- deep/a &&
+
+       # Test change outside sparse cone
+       tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) &&
+       test_all_match git diff-tree $tree1 $tree3 &&
+       test_all_match git diff-tree $tree1 $tree3 -- folder1/a &&
+       test_all_match git diff-tree HEAD update-folder1 &&
+       test_all_match git diff-tree HEAD update-folder1 -- folder1/a &&
+
+       # Check that SKIP_WORKTREE files are not materialized
+       test_path_is_missing sparse-checkout/folder1/a &&
+       test_path_is_missing sparse-index/folder1/a &&
+       test_path_is_missing sparse-checkout/folder2/a &&
+       test_path_is_missing sparse-index/folder2/a
+'
+
+test_expect_success 'sparse-index is not expanded: diff-tree' '
+       init_repos &&
+
+       tree1=$(git -C sparse-index rev-parse HEAD^{tree}) &&
+       tree2=$(git -C sparse-index rev-parse update-deep^{tree}) &&
+       tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) &&
+
+       ensure_not_expanded diff-tree $tree1 $tree2 &&
+       ensure_not_expanded diff-tree $tree1 $tree2 -- deep/a &&
+       ensure_not_expanded diff-tree HEAD update-deep &&
+       ensure_not_expanded diff-tree HEAD update-deep -- deep/a &&
+       ensure_not_expanded diff-tree $tree1 $tree3 &&
+       ensure_not_expanded diff-tree $tree1 $tree3 -- folder1/a &&
+       ensure_not_expanded diff-tree HEAD update-folder1 &&
+       ensure_not_expanded diff-tree HEAD update-folder1 -- folder1/a
+'
+
+test_expect_success 'worktree' '
+       init_repos &&
+
+       write_script edit-contents <<-\EOF &&
+       echo text >>"$1"
+       EOF
+
+       for repo in full-checkout sparse-checkout sparse-index
+       do
+               worktree=${repo}-wt &&
+               git -C $repo worktree add ../$worktree &&
+
+               # Compare worktree content with "ls"
+               (cd $repo && ls) >worktree_contents &&
+               (cd $worktree && ls) >new_worktree_contents &&
+               test_cmp worktree_contents new_worktree_contents &&
+
+               # Compare index content with "ls-files --sparse"
+               git -C $repo ls-files --sparse >index_contents &&
+               git -C $worktree ls-files --sparse >new_index_contents &&
+               test_cmp index_contents new_index_contents &&
+
+               git -C $repo worktree remove ../$worktree || return 1
+       done &&
+
+       test_all_match git worktree add .worktrees/hotfix &&
+       run_on_all ../edit-contents .worktrees/hotfix/deep/a &&
+       test_all_match test_must_fail git worktree remove .worktrees/hotfix
+'
+
+test_expect_success 'worktree is not expanded' '
+       init_repos &&
+
+       ensure_not_expanded worktree add .worktrees/hotfix &&
+       ensure_not_expanded worktree remove .worktrees/hotfix
+'
+
+test_expect_success 'check-attr with pathspec inside sparse definition' '
+       init_repos &&
+
+       echo "a -crlf myAttr" >>.gitattributes &&
+       run_on_all cp ../.gitattributes ./deep &&
+
+       test_all_match git check-attr -a -- deep/a &&
+
+       test_all_match git add deep/.gitattributes &&
+       test_all_match git check-attr -a --cached -- deep/a
+'
+
+test_expect_success 'check-attr with pathspec outside sparse definition' '
+       init_repos &&
+
+       echo "a -crlf myAttr" >>.gitattributes &&
+       run_on_sparse mkdir folder1 &&
+       run_on_all cp ../.gitattributes ./folder1 &&
+       run_on_all cp a folder1/a &&
+
+       test_all_match git check-attr -a -- folder1/a &&
+
+       git -C full-checkout add folder1/.gitattributes &&
+       test_sparse_match git add --sparse folder1/.gitattributes &&
+       test_all_match git commit -m "add .gitattributes" &&
+       test_sparse_match git sparse-checkout reapply &&
+       test_all_match git check-attr -a --cached -- folder1/a
+'
+
+# NEEDSWORK: The 'diff --check' test is left as 'test_expect_failure' due
+# to an underlying issue in oneway_diff() within diff-lib.c.
+# 'do_oneway_diff()' is not called as expected for paths that could match
+# inside of a sparse directory. Specifically, the 'ce_path_match()' function
+# fails to recognize files inside a sparse directory (e.g., when 'folder1/'
+# is a sparse directory, 'folder1/a' cannot be recognized). The goal is to
+# proceed with 'do_oneway_diff()' if the pathspec could match inside of a
+# sparse directory.
+test_expect_failure 'diff --check with pathspec outside sparse definition' '
+       init_repos &&
+
+       write_script edit-contents <<-\EOF &&
+       echo "a " >"$1"
+       EOF
+
+       test_all_match git config core.whitespace -trailing-space,-space-before-tab &&
+
+       echo "a whitespace=trailing-space,space-before-tab" >>.gitattributes &&
+       run_on_all mkdir -p folder1 &&
+       run_on_all cp ../.gitattributes ./folder1 &&
+       test_all_match git add --sparse folder1/.gitattributes &&
+       run_on_all ../edit-contents folder1/a &&
+       test_all_match git add --sparse folder1/a &&
+
+       test_sparse_match git sparse-checkout reapply &&
+       test_all_match test_must_fail git diff --check --cached -- folder1/a
+'
+
+test_expect_success 'sparse-index is not expanded: check-attr' '
+       init_repos &&
+
+       echo "a -crlf myAttr" >>.gitattributes &&
+       mkdir ./sparse-index/folder1 &&
+       cp ./sparse-index/a ./sparse-index/folder1/a &&
+       cp .gitattributes ./sparse-index/deep &&
+       cp .gitattributes ./sparse-index/folder1 &&
+
+       git -C sparse-index add deep/.gitattributes &&
+       git -C sparse-index add --sparse folder1/.gitattributes &&
+       ensure_not_expanded check-attr -a --cached -- deep/a &&
+       ensure_not_expanded check-attr -a --cached -- folder1/a
+'
+
 test_done
index 86bfbc2b3642da97083e25c5cff280c0431a0dc2..387d336c91f44e58d1e5073febdae266156212c8 100755 (executable)
@@ -1668,6 +1668,21 @@ test_expect_success 'urlmatch' '
        test_cmp expect actual
 '
 
+test_expect_success 'urlmatch with --show-scope' '
+       cat >.git/config <<-\EOF &&
+       [http "https://weak.example.com"]
+               sslVerify = false
+               cookieFile = /tmp/cookie.txt
+       EOF
+
+       cat >expect <<-EOF &&
+       local   http.cookiefile /tmp/cookie.txt
+       local   http.sslverify false
+       EOF
+       git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'urlmatch favors more specific URLs' '
        cat >.git/config <<-\EOF &&
        [http "https://example.com/"]
@@ -2055,6 +2070,12 @@ test_expect_success '--show-origin blob ref' '
        test_cmp expect output
 '
 
+test_expect_success '--show-origin with --default' '
+       git config --show-origin --default foo some.key >actual &&
+       echo "command line:     foo" >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success '--show-scope with --list' '
        cat >expect <<-EOF &&
        global  user.global=true
@@ -2123,6 +2144,12 @@ test_expect_success '--show-scope with --show-origin' '
        test_cmp expect output
 '
 
+test_expect_success '--show-scope with --default' '
+       git config --show-scope --default foo some.key >actual &&
+       echo "command   foo" >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success 'override global and system config' '
        test_when_finished rm -f \"\$HOME\"/.gitconfig &&
        cat >"$HOME"/.gitconfig <<-EOF &&
index ae5cd3f5a0e1b9fc8a109b60260b22b0351665f7..e5a0d65caa3e4cc363319826f37a4254bfc99b33 100755 (executable)
@@ -52,6 +52,28 @@ test_expect_success 'shared=all' '
        test 2 = $(git config core.sharedrepository)
 '
 
+test_expect_failure 'template can set core.bare' '
+       test_when_finished "rm -rf subdir" &&
+       test_when_finished "rm -rf templates" &&
+       test_config core.bare true &&
+       umask 0022 &&
+       mkdir -p templates/ &&
+       cp .git/config templates/config &&
+       git init --template=templates subdir &&
+       test_path_exists subdir/HEAD
+'
+
+test_expect_success 'template can set core.bare but overridden by command line' '
+       test_when_finished "rm -rf subdir" &&
+       test_when_finished "rm -rf templates" &&
+       test_config core.bare true &&
+       umask 0022 &&
+       mkdir -p templates/ &&
+       cp .git/config templates/config &&
+       git init --no-bare --template=templates subdir &&
+       test_path_exists subdir/.git/HEAD
+'
+
 test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository' '
        : > a1 &&
        git add a1 &&
index 6c45965b1e4bef9652a1bc876f28605ad213b261..09e7f3cdac8afcfebdf0558cd12159b7e367e26f 100755 (executable)
@@ -446,6 +446,29 @@ test_expect_success 'expire with multiple worktrees' '
        )
 '
 
+test_expect_success 'expire one of multiple worktrees' '
+       git init main-wt2 &&
+       (
+               cd main-wt2 &&
+               test_tick &&
+               test_commit foo &&
+               git worktree add link-wt &&
+               test_tick &&
+               test_commit -C link-wt foobar &&
+               test_tick &&
+               test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \
+                       >expect-link-wt &&
+               git reflog expire --verbose --all --expire=$test_tick \
+                       --single-worktree &&
+               test-tool ref-store worktree:main for-each-reflog-ent HEAD \
+                       >actual-main &&
+               test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \
+                       >actual-link-wt &&
+               test_must_be_empty actual-main &&
+               test_cmp expect-link-wt actual-link-wt
+       )
+'
+
 test_expect_success REFFILES 'empty reflog' '
        test_when_finished "rm -rf empty" &&
        git init empty &&
diff --git a/t/t1419-exclude-refs.sh b/t/t1419-exclude-refs.sh
new file mode 100755 (executable)
index 0000000..5d8c86b
--- /dev/null
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+test_description='test exclude_patterns functionality in main ref store'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+for_each_ref__exclude () {
+       GIT_TRACE2_PERF=1 test-tool ref-store main \
+               for-each-ref--exclude "$@" >actual.raw
+       cut -d ' ' -f 2 actual.raw
+}
+
+for_each_ref () {
+       git for-each-ref --format='%(refname)' "$@"
+}
+
+assert_jumps () {
+       local nr="$1"
+       local trace="$2"
+
+       grep -q "name:jumps_made value:$nr$" $trace
+}
+
+assert_no_jumps () {
+       ! assert_jumps ".*" "$1"
+}
+
+test_expect_success 'setup' '
+       test_commit --no-tag base &&
+       base="$(git rev-parse HEAD)" &&
+
+       for name in foo bar baz quux
+       do
+               for i in 1 2 3
+               do
+                       echo "create refs/heads/$name/$i $base" || return 1
+               done || return 1
+       done >in &&
+       echo "delete refs/heads/main" >>in &&
+
+       git update-ref --stdin <in &&
+       git pack-refs --all
+'
+
+test_expect_success 'excluded region in middle' '
+       for_each_ref__exclude refs/heads refs/heads/foo >actual 2>perf &&
+       for_each_ref refs/heads/bar refs/heads/baz refs/heads/quux >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 1 perf
+'
+
+test_expect_success 'excluded region at beginning' '
+       for_each_ref__exclude refs/heads refs/heads/bar >actual 2>perf &&
+       for_each_ref refs/heads/baz refs/heads/foo refs/heads/quux >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 1 perf
+'
+
+test_expect_success 'excluded region at end' '
+       for_each_ref__exclude refs/heads refs/heads/quux >actual 2>perf &&
+       for_each_ref refs/heads/foo refs/heads/bar refs/heads/baz >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 1 perf
+'
+
+test_expect_success 'disjoint excluded regions' '
+       for_each_ref__exclude refs/heads refs/heads/bar refs/heads/quux >actual 2>perf &&
+       for_each_ref refs/heads/baz refs/heads/foo >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 2 perf
+'
+
+test_expect_success 'adjacent, non-overlapping excluded regions' '
+       for_each_ref__exclude refs/heads refs/heads/bar refs/heads/baz >actual 2>perf &&
+       for_each_ref refs/heads/foo refs/heads/quux >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 1 perf
+'
+
+test_expect_success 'overlapping excluded regions' '
+       for_each_ref__exclude refs/heads refs/heads/ba refs/heads/baz >actual 2>perf &&
+       for_each_ref refs/heads/foo refs/heads/quux >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 1 perf
+'
+
+test_expect_success 'several overlapping excluded regions' '
+       for_each_ref__exclude refs/heads \
+               refs/heads/bar refs/heads/baz refs/heads/foo >actual 2>perf &&
+       for_each_ref refs/heads/quux >expect &&
+
+       test_cmp expect actual &&
+       assert_jumps 1 perf
+'
+
+test_expect_success 'non-matching excluded section' '
+       for_each_ref__exclude refs/heads refs/heads/does/not/exist >actual 2>perf &&
+       for_each_ref >expect &&
+
+       test_cmp expect actual &&
+       assert_no_jumps perf
+'
+
+test_expect_success 'meta-characters are discarded' '
+       for_each_ref__exclude refs/heads "refs/heads/ba*" >actual 2>perf &&
+       for_each_ref >expect &&
+
+       test_cmp expect actual &&
+       assert_no_jumps perf
+'
+
+test_done
index 8c442adb1ae8296a75e04e5a6b5b79482ec6ca35..10a539158c42ef7d5a7cdf0d602b0c92f43b7d6a 100755 (executable)
@@ -589,6 +589,16 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' '
        )
 '
 
+test_expect_success 'fsck notices excessively large tree entry name' '
+       git init large-name &&
+       (
+               cd large-name &&
+               test_commit a-long-name &&
+               git -c fsck.largePathname=warn:10 fsck 2>out &&
+               grep "warning.*large pathname" out
+       )
+'
+
 while read name path pretty; do
        while read mode type; do
                : ${pretty:=$path}
@@ -1036,9 +1046,9 @@ test_expect_success 'fsck detects problems in worktree index' '
        test_cmp expect actual
 '
 
-test_expect_success 'fsck reports problems in main index without filename' '
+test_expect_success 'fsck reports problems in current worktree index without filename' '
        test_when_finished "rm -f .git/index && git read-tree HEAD" &&
-       echo "this object will be removed to break the main index" >file &&
+       echo "this object will be removed to break current worktree index" >file &&
        git add file &&
        blob=$(git rev-parse :file) &&
        remove_object $blob &&
index 37ee5091b5caa7c087663cbb51f701084227c414..3f9e7f62e458c4db06a686700a15c5e08f47fad9 100755 (executable)
@@ -264,4 +264,27 @@ test_expect_success 'rev-parse --since= unsqueezed ordering' '
        test_cmp expect actual
 '
 
+test_expect_success 'rev-parse --bisect includes bad, excludes good' '
+       test_commit_bulk 6 &&
+
+       git update-ref refs/bisect/bad-1 HEAD~1 &&
+       git update-ref refs/bisect/b HEAD~2 &&
+       git update-ref refs/bisect/bad-3 HEAD~3 &&
+       git update-ref refs/bisect/good-3 HEAD~3 &&
+       git update-ref refs/bisect/bad-4 HEAD~4 &&
+       git update-ref refs/bisect/go HEAD~4 &&
+
+       # Note: refs/bisect/b and refs/bisect/go should be ignored because they
+       # do not match the refs/bisect/bad or refs/bisect/good prefixes.
+       cat >expect <<-EOF &&
+       refs/bisect/bad-1
+       refs/bisect/bad-3
+       refs/bisect/bad-4
+       ^refs/bisect/good-3
+       EOF
+
+       git rev-parse --symbolic-full-name --bisect >actual &&
+       test_cmp expect actual
+'
+
 test_done
index dd811b7fb467c4f3f27ef1be14427e022f73caeb..f0737593c3fda734060fa9509d1b9561086a7376 100755 (executable)
@@ -3,13 +3,29 @@
 test_description='test git rev-parse --parseopt'
 . ./test-lib.sh
 
+check_invalid_long_option () {
+       spec="$1"
+       opt="$2"
+       test_expect_success "test --parseopt invalid switch $opt help output for $spec" '
+               {
+                       cat <<-\EOF &&
+                       error: unknown option `'${opt#--}\''
+                       EOF
+                       sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/$spec.help"
+               } >expect &&
+               test_expect_code 129 git rev-parse --parseopt -- $opt \
+                       2>output <"$TEST_DIRECTORY/t1502/$spec" &&
+               test_cmp expect output
+       '
+}
+
 test_expect_success 'setup optionspec' '
        sed -e "s/^|//" >optionspec <<\EOF
 |some-command [options] <args>...
 |
 |some-command does foo and bar!
 |--
-|h,help    show the help
+|h,help!   show the help
 |
 |foo       some nifty option --foo
 |bar=      some cool option --bar with an argument
@@ -58,44 +74,8 @@ EOF
 '
 
 test_expect_success 'test --parseopt help output' '
-       sed -e "s/^|//" >expect <<\END_EXPECT &&
-|cat <<\EOF
-|usage: some-command [options] <args>...
-|
-|    some-command does foo and bar!
-|
-|    -h, --help            show the help
-|    --foo                 some nifty option --foo
-|    --bar ...             some cool option --bar with an argument
-|    -b, --baz             a short and long option
-|
-|An option group Header
-|    -C[...]               option C with an optional argument
-|    -d, --data[=...]      short and long option with an optional argument
-|
-|Argument hints
-|    -B <arg>              short option required argument
-|    --bar2 <arg>          long option required argument
-|    -e, --fuz <with-space>
-|                          short and long option required argument
-|    -s[<some>]            short option optional argument
-|    --long[=<data>]       long option optional argument
-|    -g, --fluf[=<path>]   short and long option optional argument
-|    --longest <very-long-argument-hint>
-|                          a very long argument hint
-|    --pair <key=value>    with an equals sign in the hint
-|    --aswitch             help te=t contains? fl*g characters!`
-|    --bswitch <hint>      hint has trailing tab character
-|    --cswitch             switch has trailing tab character
-|    --short-hint <a>      with a one symbol hint
-|
-|Extras
-|    --extra1              line above used to cause a segfault but no longer does
-|
-|EOF
-END_EXPECT
        test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
-       test_cmp expect output
+       test_cmp "$TEST_DIRECTORY/t1502/optionspec.help" output
 '
 
 test_expect_success 'test --parseopt help output no switches' '
@@ -131,7 +111,7 @@ test_expect_success 'test --parseopt help-all output hidden switches' '
 |
 |    some-command does foo and bar!
 |
-|    --hidden1             A hidden switch
+|    --[no-]hidden1        A hidden switch
 |
 |EOF
 END_EXPECT
@@ -140,41 +120,12 @@ END_EXPECT
 '
 
 test_expect_success 'test --parseopt invalid switch help output' '
-       sed -e "s/^|//" >expect <<\END_EXPECT &&
-|error: unknown option `does-not-exist'\''
-|usage: some-command [options] <args>...
-|
-|    some-command does foo and bar!
-|
-|    -h, --help            show the help
-|    --foo                 some nifty option --foo
-|    --bar ...             some cool option --bar with an argument
-|    -b, --baz             a short and long option
-|
-|An option group Header
-|    -C[...]               option C with an optional argument
-|    -d, --data[=...]      short and long option with an optional argument
-|
-|Argument hints
-|    -B <arg>              short option required argument
-|    --bar2 <arg>          long option required argument
-|    -e, --fuz <with-space>
-|                          short and long option required argument
-|    -s[<some>]            short option optional argument
-|    --long[=<data>]       long option optional argument
-|    -g, --fluf[=<path>]   short and long option optional argument
-|    --longest <very-long-argument-hint>
-|                          a very long argument hint
-|    --pair <key=value>    with an equals sign in the hint
-|    --aswitch             help te=t contains? fl*g characters!`
-|    --bswitch <hint>      hint has trailing tab character
-|    --cswitch             switch has trailing tab character
-|    --short-hint <a>      with a one symbol hint
-|
-|Extras
-|    --extra1              line above used to cause a segfault but no longer does
-|
-END_EXPECT
+       {
+               cat <<-\EOF &&
+               error: unknown option `does-not-exist'\''
+               EOF
+               sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/optionspec.help"
+       } >expect &&
        test_expect_code 129 git rev-parse --parseopt -- --does-not-exist 1>/dev/null 2>output < optionspec &&
        test_cmp expect output
 '
@@ -288,7 +239,7 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
        |    [--another-option]
        |cmd [--yet-another-option]
        |--
-       |h,help    show the help
+       |h,help!   show the help
        EOF
 
        sed -e "s/^|//" >expect <<-\END_EXPECT &&
@@ -322,7 +273,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
        |line
        |blurb
        |--
-       |h,help    show the help
+       |h,help!   show the help
        EOF
 
        sed -e "s/^|//" >expect <<-\END_EXPECT &&
@@ -343,4 +294,32 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
        test_cmp expect actual
 '
 
+test_expect_success 'test --parseopt help output for optionspec-neg' '
+       test_expect_code 129 git rev-parse --parseopt -- \
+               -h >output <"$TEST_DIRECTORY/t1502/optionspec-neg" &&
+       test_cmp "$TEST_DIRECTORY/t1502/optionspec-neg.help" output
+'
+
+test_expect_success 'test --parseopt valid options for optionspec-neg' '
+       cat >expect <<-\EOF &&
+       set -- --foo --no-foo --no-bar --positive-only --no-negative --
+       EOF
+       git rev-parse --parseopt -- <"$TEST_DIRECTORY/t1502/optionspec-neg" >output \
+              --foo --no-foo --no-bar --positive-only --no-negative &&
+       test_cmp expect output
+'
+
+test_expect_success 'test --parseopt positivated option for optionspec-neg' '
+       cat >expect <<-\EOF &&
+       set -- --no-no-bar --no-no-bar --
+       EOF
+       git rev-parse --parseopt -- <"$TEST_DIRECTORY/t1502/optionspec-neg" >output \
+              --no-no-bar --bar &&
+       test_cmp expect output
+'
+
+check_invalid_long_option optionspec-neg --no-positive-only
+check_invalid_long_option optionspec-neg --negative
+check_invalid_long_option optionspec-neg --no-no-negative
+
 test_done
diff --git a/t/t1502/.gitattributes b/t/t1502/.gitattributes
new file mode 100644 (file)
index 0000000..562b12e
--- /dev/null
@@ -0,0 +1 @@
+* -whitespace
diff --git a/t/t1502/optionspec-neg b/t/t1502/optionspec-neg
new file mode 100644 (file)
index 0000000..392f43e
--- /dev/null
@@ -0,0 +1,8 @@
+some-command [options] <args>...
+
+some-command does foo and bar!
+--
+foo            can be negated
+no-bar         can be positivated
+positive-only! cannot be negated
+no-negative!   cannot be positivated
diff --git a/t/t1502/optionspec-neg.help b/t/t1502/optionspec-neg.help
new file mode 100644 (file)
index 0000000..7a29f8c
--- /dev/null
@@ -0,0 +1,12 @@
+cat <<\EOF
+usage: some-command [options] <args>...
+
+    some-command does foo and bar!
+
+    --[no-]foo            can be negated
+    --no-bar              can be positivated
+    --bar                 opposite of --no-bar
+    --positive-only       cannot be negated
+    --no-negative         cannot be positivated
+
+EOF
diff --git a/t/t1502/optionspec.help b/t/t1502/optionspec.help
new file mode 100755 (executable)
index 0000000..cbdd54d
--- /dev/null
@@ -0,0 +1,36 @@
+cat <<\EOF
+usage: some-command [options] <args>...
+
+    some-command does foo and bar!
+
+    -h, --help            show the help
+    --[no-]foo            some nifty option --foo
+    --[no-]bar ...        some cool option --bar with an argument
+    -b, --[no-]baz        a short and long option
+
+An option group Header
+    -C[...]               option C with an optional argument
+    -d, --[no-]data[=...] short and long option with an optional argument
+
+Argument hints
+    -B <arg>              short option required argument
+    --[no-]bar2 <arg>     long option required argument
+    -e, --[no-]fuz <with-space>
+                          short and long option required argument
+    -s[<some>]            short option optional argument
+    --[no-]long[=<data>]  long option optional argument
+    -g, --[no-]fluf[=<path>]
+                          short and long option optional argument
+    --[no-]longest <very-long-argument-hint>
+                          a very long argument hint
+    --[no-]pair <key=value>
+                          with an equals sign in the hint
+    --[no-]aswitch        help te=t contains? fl*g characters!`
+    --[no-]bswitch <hint> hint has trailing tab character
+    --[no-]cswitch        switch has trailing tab character
+    --[no-]short-hint <a> with a one symbol hint
+
+Extras
+    --[no-]extra1         line above used to cause a segfault but no longer does
+
+EOF
index cb9ef7e329eb06a693ead9ab747f9efd37021c94..b9af6b3ac035a04858ae0c7e0963166af665bd81 100755 (executable)
@@ -5,6 +5,7 @@ test_description='test <branch>@{upstream} syntax'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 
index 87a42864145f85ed539b9d1cbb9a3dd5f71fc708..e841309d0eab1022f3442c23795f884ad98a8280 100755 (executable)
@@ -4,6 +4,7 @@ test_description='test various @{X} syntax combinations together'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check() {
index d868a0811056c83810bdd468d85e6f3a90622da7..a835a196aa81be9e7aa79f38c3977a03b71b5336 100755 (executable)
@@ -4,6 +4,7 @@ test_description='test <branch>@{push} syntax'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 resolve () {
index 9368d82f7d70ca8133616ed40f167ae4344266c4..62e7fd15964bba7cbc8904471879027219368951 100755 (executable)
@@ -118,7 +118,7 @@ test_index_version () {
                fi &&
                git add a &&
                echo $EXPECTED_OUTPUT_VERSION >expect &&
-               test-tool index-version <.git/index >actual &&
+               git update-index --show-index-version >actual &&
                test_cmp expect actual
        )
 }
index b4ab166369ec06c69add33eb240d69531459276c..a7b7263b35d1d8f142eec5311c9e42c25e398878 100755 (executable)
@@ -43,7 +43,7 @@ test_expect_success 'enable split index' '
        git config splitIndex.maxPercentChange 100 &&
        git update-index --split-index &&
        test-tool dump-split-index .git/index >actual &&
-       indexversion=$(test-tool index-version <.git/index) &&
+       indexversion=$(git update-index --show-index-version) &&
 
        # NEEDSWORK: Stop hard-coding checksums.
        if test "$indexversion" = "4"
index 3506f627b6cf20f11e4cfd78b309e9e9acc07148..8b0234cf2d5d96980403d65b844639715acfe91b 100755 (executable)
@@ -156,25 +156,15 @@ test_expect_success 'git hook run a hook with a bad shebang' '
        mkdir bad-hooks &&
        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 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: ...
-               EOF
-       else
-               cat >expect <<-\EOF
-               error: cannot spawn bad-hooks/test-hook: ...
-               EOF
-       fi &&
        test_expect_code 1 git \
                -c core.hooksPath=bad-hooks \
                hook run test-hook >out 2>err &&
        test_must_be_empty out &&
-       sed -e "s/test-hook: .*/test-hook: .../" <err >actual &&
-       test_cmp expect actual
+
+       # TODO: We should emit the same (or at least a more similar)
+       # error on MINGW (essentially Git for Windows) and all other
+       # platforms.. See the OS-specific code in start_command()
+       grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err
 '
 
 test_expect_success 'stdin to hooks' '
index b16d69ca4ae0e8b61ce00a085273d8ad6f40f104..45dd1bc8582142db6d35c7e1d708c8a27c243a34 100755 (executable)
@@ -117,6 +117,26 @@ test_expect_success 'checkout all stages/one file to temporary files' '
        test $(cat $s3) = tree3path1)
 '
 
+test_expect_success '--stage=all implies --temp' '
+       rm -f path* .merge_* actual &&
+       git checkout-index --stage=all -- path1 &&
+       test_path_is_missing path1
+'
+
+test_expect_success 'overriding --stage=all resets implied --temp' '
+       rm -f path* .merge_* actual &&
+       git checkout-index --stage=all --stage=2 -- path1 &&
+       echo tree2path1 >expect &&
+       test_cmp expect path1
+'
+
+test_expect_success '--stage=all --no-temp is rejected' '
+       rm -f path* .merge_* actual &&
+       test_must_fail git checkout-index --stage=all --no-temp -- path1 2>err &&
+       grep -v "already exists" err &&
+       grep "options .--stage=all. and .--no-temp. cannot be used together" err
+'
+
 test_expect_success 'checkout some stages/one file to temporary files' '
        rm -f path* .merge_* actual &&
        git checkout-index --stage=all --temp -- path2 >actual &&
index dca35aa3e3e264002703932e56add4322b475fcf..a8bbc60954f5f0d41815582a32d85f70e4dc2b8c 100755 (executable)
@@ -5,6 +5,7 @@ test_description='tests for git branch --track'
 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 2d8c70b03a50e9ca082f7343d78dbcf6ad456159..3eda385ca207578996164500a8ee168342682376 100755 (executable)
@@ -37,11 +37,17 @@ prime_resolve_undo () {
        git checkout second^0 &&
        test_tick &&
        test_must_fail git merge third^0 &&
-       echo merge does not leave anything &&
        check_resolve_undo empty &&
-       echo different >fi/le &&
-       git add fi/le &&
-       echo resolving records &&
+
+       # how should the conflict be resolved?
+       case "$1" in
+       remove)
+               rm -f file/le && git rm fi/le
+               ;;
+       *) # modify
+               echo different >fi/le && git add fi/le
+               ;;
+       esac
        check_resolve_undo recorded fi/le initial:fi/le second:fi/le third:fi/le
 }
 
@@ -122,6 +128,37 @@ test_expect_success 'add records checkout -m undoes' '
 test_expect_success 'unmerge with plumbing' '
        prime_resolve_undo &&
        git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
+       git ls-files -u >actual &&
+       test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge can be done even after committing' '
+       prime_resolve_undo &&
+       git commit -m "record to nuke MERGE_HEAD" &&
+       git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
+       git ls-files -u >actual &&
+       test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge removal' '
+       prime_resolve_undo remove &&
+       git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
+       git ls-files -u >actual &&
+       test_line_count = 3 actual
+'
+
+test_expect_success 'unmerge removal after committing' '
+       prime_resolve_undo remove &&
+       git commit -m "record to nuke MERGE_HEAD" &&
+       git update-index --unresolve fi/le &&
+       git ls-files --resolve-undo fi/le >actual &&
+       test_must_be_empty actual &&
        git ls-files -u >actual &&
        test_line_count = 3 actual
 '
index c5d19dd973d7f4ea7a3a496d7df92a5c74fa667d..16d6348b692806ab25faf89d77a73cd62fab4d93 100755 (executable)
@@ -137,11 +137,78 @@ test_expect_success 'restore --staged invalidates cache tree for deletions' '
        test_must_fail git rev-parse HEAD:new1
 '
 
-test_expect_success 'restore with merge options rejects --staged' '
+test_expect_success 'restore --merge to unresolve' '
+       O=$(echo original | git hash-object -w --stdin) &&
+       A=$(echo ourside | git hash-object -w --stdin) &&
+       B=$(echo theirside | git hash-object -w --stdin) &&
+       {
+               echo "100644 $O 1       file" &&
+               echo "100644 $A 2       file" &&
+               echo "100644 $B 3       file"
+       } | git update-index --index-info &&
+       echo nothing >file &&
+       git restore --worktree --merge file &&
+       cat >expect <<-\EOF &&
+       <<<<<<< ours
+       ourside
+       =======
+       theirside
+       >>>>>>> theirs
+       EOF
+       test_cmp expect file
+'
+
+test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
+       O=$(echo original | git hash-object -w --stdin) &&
+       A=$(echo ourside | git hash-object -w --stdin) &&
+       B=$(echo theirside | git hash-object -w --stdin) &&
+       {
+               echo "100644 $O 1       file" &&
+               echo "100644 $A 2       file" &&
+               echo "100644 $B 3       file"
+       } | git update-index --index-info &&
+       echo nothing >file &&
+       git add file &&
+       git restore --worktree --merge file &&
+       cat >expect <<-\EOF &&
+       <<<<<<< ours
+       ourside
+       =======
+       theirside
+       >>>>>>> theirs
+       EOF
+       test_cmp expect file
+'
+
+test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
+       O=$(echo original | git hash-object -w --stdin) &&
+       A=$(echo ourside | git hash-object -w --stdin) &&
+       B=$(echo theirside | git hash-object -w --stdin) &&
+       {
+               echo "100644 $O 1       file" &&
+               echo "100644 $A 2       file" &&
+               echo "100644 $B 3       file"
+       } | git update-index --index-info &&
+       git rm -f file &&
+       git restore --worktree --merge file &&
+       cat >expect <<-\EOF &&
+       <<<<<<< ours
+       ourside
+       =======
+       theirside
+       >>>>>>> theirs
+       EOF
+       test_cmp expect file
+'
+
+test_expect_success 'restore with merge options are incompatible with certain options' '
        for opts in \
                "--staged --ours" \
                "--staged --theirs" \
                "--staged --merge" \
+               "--source=HEAD --ours" \
+               "--source=HEAD --theirs" \
+               "--source=HEAD --merge" \
                "--staged --conflict=diff3" \
                "--staged --worktree --ours" \
                "--staged --worktree --theirs" \
@@ -149,7 +216,7 @@ test_expect_success 'restore with merge options rejects --staged' '
                "--staged --worktree --conflict=zdiff3"
        do
                test_must_fail git restore $opts . 2>err &&
-               grep "cannot be used with --staged" err || return
+               grep "cannot be used" err || return
        done
 '
 
index b8686aabd38b5ac8a60753bff80fddd4e91a5102..0bab134d71d3e785194562779ef63085de4e6545 100755 (executable)
@@ -39,7 +39,7 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'index is at version 2' '
-       test "$(test-tool index-version < .git/index)" = 2
+       test "$(git update-index --show-index-version)" = 2
 '
 
 test_expect_success 'update-index --skip-worktree' '
@@ -48,7 +48,7 @@ test_expect_success 'update-index --skip-worktree' '
 '
 
 test_expect_success 'index is at version 3 after having some skip-worktree entries' '
-       test "$(test-tool index-version < .git/index)" = 3
+       test "$(git update-index --show-index-version)" = 3
 '
 
 test_expect_success 'ls-files -t' '
@@ -61,7 +61,7 @@ test_expect_success 'update-index --no-skip-worktree' '
 '
 
 test_expect_success 'index version is back to 2 when there is no skip-worktree entry' '
-       test "$(test-tool index-version < .git/index)" = 2
+       test "$(git update-index --show-index-version)" = 2
 '
 
 test_done
index 89b285fa3a608f917a269c56ee2f44fa51f5d01f..22f4c923998619f8ebd5f1dc85e0ffa917dbb4d3 100755 (executable)
@@ -111,4 +111,35 @@ test_expect_success '--chmod=+x and chmod=-x in the same argument list' '
        test_cmp expect actual
 '
 
+test_expect_success '--index-version' '
+       git commit --allow-empty -m snap &&
+       git reset --hard &&
+       git rm -f -r --cached . &&
+
+       # The default index version is 2 --- update this test
+       # when you change it in the code
+       git update-index --show-index-version >actual &&
+       echo 2 >expect &&
+       test_cmp expect actual &&
+
+       # The next test wants us to be using version 2
+       git update-index --index-version 2 &&
+
+       git update-index --index-version 4 --verbose >actual &&
+       echo "index-version: was 2, set to 4" >expect &&
+       test_cmp expect actual &&
+
+       git update-index --index-version 4 --verbose >actual &&
+       echo "index-version: was 4, set to 4" >expect &&
+       test_cmp expect actual &&
+
+       git update-index --index-version 2 --verbose >actual &&
+       echo "index-version: was 4, set to 2" >expect &&
+       test_cmp expect actual &&
+
+       # non-verbose should be silent
+       git update-index --index-version 4 >actual &&
+       test_must_be_empty actual
+'
+
 test_done
index be394f1131ac191476dfa228be6fc6f35e0cecd0..c01492f33f860db2d6ae8764c94c084429abeef5 100755 (executable)
@@ -197,4 +197,15 @@ test_expect_success '"add -u non-existent" should fail' '
        ! grep "non-existent" actual
 '
 
+test_expect_success '"commit -a" implies "add -u" if index becomes empty' '
+       git rm -rf \* &&
+       git commit -m clean-slate &&
+       test_commit file1 &&
+       rm file1.t &&
+       test_tick &&
+       git commit -a -m remove &&
+       git ls-tree HEAD: >out &&
+       test_must_be_empty out
+'
+
 test_done
index d587e0b20db22423ef1a1d204076c50b769e0375..df4aff7825c9f8430d7449d1bdf2b0d5045d397a 100755 (executable)
@@ -121,7 +121,8 @@ test_expect_success '"add" worktree creating new branch' '
 test_expect_success 'die the same branch is already checked out' '
        (
                cd here &&
-               test_must_fail git checkout newmain
+               test_must_fail git checkout newmain 2>actual &&
+               grep "already used by worktree at" actual
        )
 '
 
@@ -298,17 +299,24 @@ test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
        test_must_fail git -C mish/mash symbolic-ref HEAD
 '
 
-test_expect_success '"add" -b/-B mutually exclusive' '
-       test_must_fail git worktree add -b poodle -B poodle bamboo main
-'
-
-test_expect_success '"add" -b/--detach mutually exclusive' '
-       test_must_fail git worktree add -b poodle --detach bamboo main
-'
+# Helper function to test mutually exclusive options.
+#
+# Note: Quoted arguments containing spaces are not supported.
+test_wt_add_excl () {
+       local opts="$*" &&
+       test_expect_success "'worktree add' with '$opts' has mutually exclusive options" '
+               test_must_fail git worktree add $opts 2>actual &&
+               grep -E "fatal:( options)? .* cannot be used together" actual
+       '
+}
 
-test_expect_success '"add" -B/--detach mutually exclusive' '
-       test_must_fail git worktree add -B poodle --detach bamboo main
-'
+test_wt_add_excl -b poodle -B poodle bamboo main
+test_wt_add_excl -b poodle --detach bamboo main
+test_wt_add_excl -B poodle --detach bamboo main
+test_wt_add_excl --orphan --detach bamboo
+test_wt_add_excl --orphan --no-checkout bamboo
+test_wt_add_excl --orphan bamboo main
+test_wt_add_excl --orphan -b bamboo wtdir/ main
 
 test_expect_success '"add -B" fails if the branch is checked out' '
        git rev-parse newmain >before &&
@@ -326,10 +334,111 @@ test_expect_success 'add -B' '
 '
 
 test_expect_success 'add --quiet' '
+       test_when_finished "git worktree remove -f -f another-worktree" &&
        git worktree add --quiet another-worktree main 2>actual &&
        test_must_be_empty actual
 '
 
+test_expect_success 'add --quiet -b' '
+       test_when_finished "git branch -D quietnewbranch" &&
+       test_when_finished "git worktree remove -f -f another-worktree" &&
+       git worktree add --quiet -b quietnewbranch another-worktree 2>actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success '"add --orphan"' '
+       test_when_finished "git worktree remove -f -f orphandir" &&
+       git worktree add --orphan -b neworphan orphandir &&
+       echo refs/heads/neworphan >expected &&
+       git -C orphandir symbolic-ref HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '"add --orphan (no -b)"' '
+       test_when_finished "git worktree remove -f -f neworphan" &&
+       git worktree add --orphan neworphan &&
+       echo refs/heads/neworphan >expected &&
+       git -C neworphan symbolic-ref HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '"add --orphan --quiet"' '
+       test_when_finished "git worktree remove -f -f orphandir" &&
+       git worktree add --quiet --orphan -b neworphan orphandir 2>log.actual &&
+       test_must_be_empty log.actual &&
+       echo refs/heads/neworphan >expected &&
+       git -C orphandir symbolic-ref HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '"add --orphan" fails if the branch already exists' '
+       test_when_finished "git branch -D existingbranch" &&
+       git worktree add -b existingbranch orphandir main &&
+       git worktree remove orphandir &&
+       test_must_fail git worktree add --orphan -b existingbranch orphandir
+'
+
+test_expect_success '"add --orphan" with empty repository' '
+       test_when_finished "rm -rf empty_repo" &&
+       echo refs/heads/newbranch >expected &&
+       GIT_DIR="empty_repo" git init --bare &&
+       git -C empty_repo worktree add --orphan -b newbranch worktreedir &&
+       git -C empty_repo/worktreedir symbolic-ref HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '"add" worktree with orphan branch and lock' '
+       git worktree add --lock --orphan -b orphanbr orphan-with-lock &&
+       test_when_finished "git worktree unlock orphan-with-lock || :" &&
+       test -f .git/worktrees/orphan-with-lock/locked
+'
+
+test_expect_success '"add" worktree with orphan branch, lock, and reason' '
+       lock_reason="why not" &&
+       git worktree add --detach --lock --reason "$lock_reason" orphan-with-lock-reason main &&
+       test_when_finished "git worktree unlock orphan-with-lock-reason || :" &&
+       test -f .git/worktrees/orphan-with-lock-reason/locked &&
+       echo "$lock_reason" >expect &&
+       test_cmp expect .git/worktrees/orphan-with-lock-reason/locked
+'
+
+# Note: Quoted arguments containing spaces are not supported.
+test_wt_add_orphan_hint () {
+       local context="$1" &&
+       local use_branch=$2 &&
+       shift 2 &&
+       local opts="$*" &&
+       test_expect_success "'worktree add' show orphan hint in bad/orphan HEAD w/ $context" '
+               test_when_finished "rm -rf repo" &&
+               git init repo &&
+               (cd repo && test_commit commit) &&
+               git -C repo switch --orphan noref &&
+               test_must_fail git -C repo worktree add $opts foobar/ 2>actual &&
+               ! grep "error: unknown switch" actual &&
+               grep "hint: If you meant to create a worktree containing a new orphan branch" actual &&
+               if [ $use_branch -eq 1 ]
+               then
+                       grep -E "^hint: +git worktree add --orphan -b [^ ]+ [^ ]+$" actual
+               else
+                       grep -E "^hint: +git worktree add --orphan [^ ]+$" actual
+               fi
+
+       '
+}
+
+test_wt_add_orphan_hint 'no opts' 0
+test_wt_add_orphan_hint '-b' 1 -b foobar_branch
+test_wt_add_orphan_hint '-B' 1 -B foobar_branch
+
+test_expect_success "'worktree add' doesn't show orphan hint in bad/orphan HEAD w/ --quiet" '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       (cd repo && test_commit commit) &&
+       test_must_fail git -C repo worktree add --quiet foobar_branch foobar/ 2>actual &&
+       ! grep "error: unknown switch" actual &&
+       ! grep "hint: If you meant to create a worktree containing a new orphan branch" actual
+'
+
 test_expect_success 'local clone from linked checkout' '
        git clone --local here here-clone &&
        ( cd here-clone && git fsck )
@@ -446,6 +555,14 @@ setup_remote_repo () {
        )
 }
 
+test_expect_success '"add" <path> <remote/branch> w/ no HEAD' '
+       test_when_finished rm -rf repo_upstream repo_local foo &&
+       setup_remote_repo repo_upstream repo_local &&
+       git -C repo_local config --bool core.bare true &&
+       git -C repo_local branch -D main &&
+       git -C repo_local worktree add ./foo repo_upstream/foo
+'
+
 test_expect_success '--no-track avoids setting up tracking' '
        test_when_finished rm -rf repo_upstream repo_local foo &&
        setup_remote_repo repo_upstream repo_local &&
@@ -528,6 +645,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' '
                test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
        )
 '
+test_expect_success 'git worktree add --guess-remote sets up tracking (quiet)' '
+       test_when_finished rm -rf repo_a repo_b foo &&
+       setup_remote_repo repo_a repo_b &&
+       (
+               cd repo_b &&
+               git worktree add --quiet --guess-remote ../foo 2>actual &&
+               test_must_be_empty actual
+       ) &&
+       (
+               cd foo &&
+               test_branch_upstream foo repo_a foo &&
+               test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo
+       )
+'
+
+test_expect_success 'git worktree --no-guess-remote (quiet)' '
+       test_when_finished rm -rf repo_a repo_b foo &&
+       setup_remote_repo repo_a repo_b &&
+       (
+               cd repo_b &&
+               git worktree add --quiet --no-guess-remote ../foo
+       ) &&
+       (
+               cd foo &&
+               test_must_fail git config "branch.foo.remote" &&
+               test_must_fail git config "branch.foo.merge" &&
+               test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo
+       )
+'
 
 test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' '
        test_when_finished rm -rf repo_a repo_b foo &&
@@ -560,6 +706,348 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
        )
 '
 
+test_dwim_orphan () {
+       local info_text="No possible source branch, inferring '--orphan'" &&
+       local fetch_error_text="fatal: No local or remote refs exist despite at least one remote" &&
+       local orphan_hint="hint: If you meant to create a worktree containing a new orphan branch" &&
+       local invalid_ref_regex="^fatal: invalid reference: " &&
+       local bad_combo_regex="^fatal: '[-a-z]*' and '[-a-z]*' cannot be used together" &&
+
+       local git_ns="repo" &&
+       local dashc_args="-C $git_ns" &&
+       local use_cd=0 &&
+
+       local bad_head=0 &&
+       local empty_repo=1 &&
+       local local_ref=0 &&
+       local use_quiet=0 &&
+       local remote=0 &&
+       local remote_ref=0 &&
+       local use_detach=0 &&
+       local use_new_branch=0 &&
+
+       local outcome="$1" &&
+       local outcome_text &&
+       local success &&
+       shift &&
+       local args="" &&
+       local context="" &&
+       case "$outcome" in
+       "infer")
+               success=1 &&
+               outcome_text='"add" DWIM infer --orphan'
+               ;;
+       "no_infer")
+               success=1 &&
+               outcome_text='"add" DWIM doesnt infer --orphan'
+               ;;
+       "fetch_error")
+               success=0 &&
+               outcome_text='"add" error need fetch'
+               ;;
+       "fatal_orphan_bad_combo")
+               success=0 &&
+               outcome_text='"add" error inferred "--orphan" gives illegal opts combo'
+               ;;
+       "warn_bad_head")
+               success=0 &&
+               outcome_text='"add" error, warn on bad HEAD, hint use orphan'
+               ;;
+       *)
+               echo "test_dwim_orphan(): invalid outcome: '$outcome'" >&2 &&
+               return 1
+               ;;
+       esac &&
+       while [ $# -gt 0 ]
+       do
+               case "$1" in
+               # How and from where to create the worktree
+               "-C_repo")
+                       use_cd=0 &&
+                       git_ns="repo" &&
+                       dashc_args="-C $git_ns" &&
+                       context="$context, 'git -C repo'"
+                       ;;
+               "-C_wt")
+                       use_cd=0 &&
+                       git_ns="wt" &&
+                       dashc_args="-C $git_ns" &&
+                       context="$context, 'git -C wt'"
+                       ;;
+               "cd_repo")
+                       use_cd=1 &&
+                       git_ns="repo" &&
+                       dashc_args="" &&
+                       context="$context, 'cd repo && git'"
+                       ;;
+               "cd_wt")
+                       use_cd=1 &&
+                       git_ns="wt" &&
+                       dashc_args="" &&
+                       context="$context, 'cd wt && git'"
+                       ;;
+
+               # Bypass the "pull first" warning
+               "force")
+                       args="$args --force" &&
+                       context="$context, --force"
+                       ;;
+
+               # Try to use remote refs when DWIM
+               "guess_remote")
+                       args="$args --guess-remote" &&
+                       context="$context, --guess-remote"
+                       ;;
+               "no_guess_remote")
+                       args="$args --no-guess-remote" &&
+                       context="$context, --no-guess-remote"
+                       ;;
+
+               # Whether there is at least one local branch present
+               "local_ref")
+                       empty_repo=0 &&
+                       local_ref=1 &&
+                       context="$context, >=1 local branches"
+                       ;;
+               "no_local_ref")
+                       empty_repo=0 &&
+                       context="$context, 0 local branches"
+                       ;;
+
+               # Whether the HEAD points at a valid ref (skip this opt when no refs)
+               "good_head")
+                       # requires: local_ref
+                       context="$context, valid HEAD"
+                       ;;
+               "bad_head")
+                       bad_head=1 &&
+                       context="$context, invalid (or orphan) HEAD"
+                       ;;
+
+               # Whether the code path is tested with the base add command, -b, or --detach
+               "no_-b")
+                       use_new_branch=0 &&
+                       context="$context, no --branch"
+                       ;;
+               "-b")
+                       use_new_branch=1 &&
+                       context="$context, --branch"
+                       ;;
+               "detach")
+                       use_detach=1 &&
+                       context="$context, --detach"
+                       ;;
+
+               # Whether to check that all output is suppressed (except errors)
+               # or that the output is as expected
+               "quiet")
+                       use_quiet=1 &&
+                       args="$args --quiet" &&
+                       context="$context, --quiet"
+                       ;;
+               "no_quiet")
+                       use_quiet=0 &&
+                       context="$context, no --quiet (expect output)"
+                       ;;
+
+               # Whether there is at least one remote attached to the repo
+               "remote")
+                       empty_repo=0 &&
+                       remote=1 &&
+                       context="$context, >=1 remotes"
+                       ;;
+               "no_remote")
+                       empty_repo=0 &&
+                       remote=0 &&
+                       context="$context, 0 remotes"
+                       ;;
+
+               # Whether there is at least one valid remote ref
+               "remote_ref")
+                       # requires: remote
+                       empty_repo=0 &&
+                       remote_ref=1 &&
+                       context="$context, >=1 fetched remote branches"
+                       ;;
+               "no_remote_ref")
+                       empty_repo=0 &&
+                       remote_ref=0 &&
+                       context="$context, 0 fetched remote branches"
+                       ;;
+
+               # Options or flags that become illegal when --orphan is inferred
+               "no_checkout")
+                       args="$args --no-checkout" &&
+                       context="$context, --no-checkout"
+                       ;;
+               "track")
+                       args="$args --track" &&
+                       context="$context, --track"
+                       ;;
+
+               # All other options are illegal
+               *)
+                       echo "test_dwim_orphan(): invalid arg: '$1'" >&2 &&
+                       return 1
+                       ;;
+               esac &&
+               shift
+       done &&
+       context="${context#', '}" &&
+       if [ $use_new_branch -eq 1 ]
+       then
+               args="$args -b foo"
+       elif [ $use_detach -eq 1 ]
+       then
+               args="$args --detach"
+       else
+               context="DWIM (no --branch), $context"
+       fi &&
+       if [ $empty_repo -eq 1 ]
+       then
+               context="empty repo, $context"
+       fi &&
+       args="$args ../foo" &&
+       context="${context%', '}" &&
+       test_expect_success "$outcome_text w/ $context" '
+               test_when_finished "rm -rf repo" &&
+               git init repo &&
+               if [ $local_ref -eq 1 ] && [ "$git_ns" = "repo" ]
+               then
+                       (cd repo && test_commit commit) &&
+                       if [ $bad_head -eq 1 ]
+                       then
+                               git -C repo symbolic-ref HEAD refs/heads/badbranch
+                       fi
+               elif [ $local_ref -eq 1 ] && [ "$git_ns" = "wt" ]
+               then
+                       test_when_finished "git -C repo worktree remove -f ../wt" &&
+                       git -C repo worktree add --orphan -b main ../wt &&
+                       (cd wt && test_commit commit) &&
+                       if [ $bad_head -eq 1 ]
+                       then
+                               git -C wt symbolic-ref HEAD refs/heads/badbranch
+                       fi
+               elif [ $local_ref -eq 0 ] && [ "$git_ns" = "wt" ]
+               then
+                       test_when_finished "git -C repo worktree remove -f ../wt" &&
+                       git -C repo worktree add --orphan -b orphanbranch ../wt
+               fi &&
+
+               if [ $remote -eq 1 ]
+               then
+                       test_when_finished "rm -rf upstream" &&
+                       git init upstream &&
+                       (cd upstream && test_commit commit) &&
+                       git -C upstream switch -c foo &&
+                       git -C repo remote add upstream ../upstream
+               fi &&
+
+               if [ $remote_ref -eq 1 ]
+               then
+                       git -C repo fetch
+               fi &&
+               if [ $success -eq 1 ]
+               then
+                       test_when_finished git -C repo worktree remove ../foo
+               fi &&
+               (
+                       if [ $use_cd -eq 1 ]
+                       then
+                               cd $git_ns
+                       fi &&
+                       if [ "$outcome" = "infer" ]
+                       then
+                               git $dashc_args worktree add $args 2>actual &&
+                               if [ $use_quiet -eq 1 ]
+                               then
+                                       test_must_be_empty actual
+                               else
+                                       grep "$info_text" actual
+                               fi
+                       elif [ "$outcome" = "no_infer" ]
+                       then
+                               git $dashc_args worktree add $args 2>actual &&
+                               if [ $use_quiet -eq 1 ]
+                               then
+                                       test_must_be_empty actual
+                               else
+                                       ! grep "$info_text" actual
+                               fi
+                       elif [ "$outcome" = "fetch_error" ]
+                       then
+                               test_must_fail git $dashc_args worktree add $args 2>actual &&
+                               grep "$fetch_error_text" actual
+                       elif [ "$outcome" = "fatal_orphan_bad_combo" ]
+                       then
+                               test_must_fail git $dashc_args worktree add $args 2>actual &&
+                               if [ $use_quiet -eq 1 ]
+                               then
+                                       ! grep "$info_text" actual
+                               else
+                                       grep "$info_text" actual
+                               fi &&
+                               grep "$bad_combo_regex" actual
+                       elif [ "$outcome" = "warn_bad_head" ]
+                       then
+                               test_must_fail git $dashc_args worktree add $args 2>actual &&
+                               if [ $use_quiet -eq 1 ]
+                               then
+                                       grep "$invalid_ref_regex" actual &&
+                                       ! grep "$orphan_hint" actual
+                               else
+                                       headpath=$(git $dashc_args rev-parse --path-format=absolute --git-path HEAD) &&
+                                       headcontents=$(cat "$headpath") &&
+                                       grep "HEAD points to an invalid (or orphaned) reference" actual &&
+                                       grep "HEAD path: .$headpath." actual &&
+                                       grep "HEAD contents: .$headcontents." actual &&
+                                       grep "$orphan_hint" actual &&
+                                       ! grep "$info_text" actual
+                               fi &&
+                               grep "$invalid_ref_regex" actual
+                       else
+                               # Unreachable
+                               false
+                       fi
+               ) &&
+               if [ $success -ne 1 ]
+               then
+                       test_path_is_missing foo
+               fi
+       '
+}
+
+for quiet_mode in "no_quiet" "quiet"
+do
+       for changedir_type in "cd_repo" "cd_wt" "-C_repo" "-C_wt"
+       do
+               dwim_test_args="$quiet_mode $changedir_type"
+               test_dwim_orphan 'infer' $dwim_test_args no_-b
+               test_dwim_orphan 'no_infer' $dwim_test_args no_-b local_ref good_head
+               test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref no_remote no_remote_ref no_guess_remote
+               test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref no_guess_remote
+               test_dwim_orphan 'fetch_error' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote
+               test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote force
+               test_dwim_orphan 'no_infer' $dwim_test_args no_-b no_local_ref remote remote_ref guess_remote
+
+               test_dwim_orphan 'infer' $dwim_test_args -b
+               test_dwim_orphan 'no_infer' $dwim_test_args -b local_ref good_head
+               test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref no_remote no_remote_ref no_guess_remote
+               test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref no_guess_remote
+               test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref guess_remote
+               test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote remote_ref guess_remote
+
+               test_dwim_orphan 'warn_bad_head' $dwim_test_args no_-b local_ref bad_head
+               test_dwim_orphan 'warn_bad_head' $dwim_test_args -b local_ref bad_head
+               test_dwim_orphan 'warn_bad_head' $dwim_test_args detach local_ref bad_head
+       done
+
+       test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b no_checkout
+       test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b track
+       test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b no_checkout
+       test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b track
+done
+
 post_checkout_hook () {
        test_when_finished "rm -rf .git/hooks" &&
        mkdir .git/hooks &&
index 019a40df2ca99480c547910026bf97102d54a23c..f6835c91dcc49cfeb23881fe0ef7a96629bfb2e6 100755 (executable)
@@ -45,7 +45,7 @@ test_expect_success 'refuse to overwrite: checked out in worktree' '
                grep "cannot force update the branch" err &&
 
                test_must_fail git branch -D wt-$i 2>err &&
-               grep "Cannot delete branch" err || return 1
+               grep "cannot delete branch" err || return 1
        done
 '
 
@@ -58,7 +58,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in bisect' '
        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
+       grep "cannot force update the branch '\''wt-4'\'' used by worktree at.*wt-4" err
 '
 
 test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (apply)' '
@@ -68,7 +68,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (app
        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
+       grep "cannot force update the branch '\''wt-2'\'' used by worktree at.*wt-2" err
 '
 
 test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (merge)' '
@@ -78,7 +78,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (mer
        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
+       grep "cannot force update the branch '\''wt-2'\'' used by worktree at.*wt-2" err
 '
 
 test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase with --update-refs' '
@@ -90,7 +90,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase with
        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 ||
+               grep "cannot force update the branch '\''can-be-updated'\'' used by worktree at.*wt-3" err ||
                        return 1
        done
 '
@@ -150,7 +150,7 @@ test_expect_success 'refuse to overwrite when in error states' '
        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 ||
+               grep "cannot force update the branch '\''fake-$i'\'' used by worktree at" err ||
                        return 1
        done
 '
index dd7770e85de8660061116d42aa32b8d20fe52f95..7308a3d4e25a8be915c6e2157b31c21a3585bd0c 100755 (executable)
@@ -299,6 +299,39 @@ test_expect_success '--recurse-submodules does not support --error-unmatch' '
        test_i18ngrep "does not support --error-unmatch" actual
 '
 
+test_expect_success '--recurse-submodules parses submodule repo config' '
+       test_config -C submodule index.sparse "invalid non-boolean value" &&
+       test_must_fail git ls-files --recurse-submodules 2>err &&
+       grep "bad boolean config value" err
+'
+
+test_expect_success '--recurse-submodules parses submodule worktree config' '
+       test_config -C submodule extensions.worktreeConfig true &&
+       test_config -C submodule --worktree index.sparse "invalid non-boolean value" &&
+
+       test_must_fail git ls-files --recurse-submodules 2>err &&
+       grep "bad boolean config value" err
+'
+
+test_expect_success '--recurse-submodules submodules ignore super project worktreeConfig extension' '
+       # Enable worktree config in both super project & submodule, set an
+       # invalid config in the submodule worktree config
+       test_config extensions.worktreeConfig true &&
+       test_config -C submodule extensions.worktreeConfig true &&
+       test_config -C submodule --worktree index.sparse "invalid non-boolean value" &&
+
+       # Now, disable the worktree config in the submodule. Note that we need
+       # to manually re-enable extensions.worktreeConfig when the test is
+       # finished, otherwise the test_unconfig of index.sparse will not work.
+       test_unconfig -C submodule extensions.worktreeConfig &&
+       test_when_finished "git -C submodule config extensions.worktreeConfig true" &&
+
+       # With extensions.worktreeConfig disabled in the submodule, the invalid
+       # worktree config is not picked up.
+       git ls-files --recurse-submodules 2>err &&
+       ! grep "bad boolean config value" err
+'
+
 test_incompatible_with_recurse_submodules () {
        test_expect_success "--recurse-submodules and $1 are incompatible" "
                test_must_fail git ls-files --recurse-submodules $1 2>actual &&
index ef6fb53f7f1cf53f6cf8c3727bc0b957ea7d9484..6e6ea0b6f3ca256eb3903b08ca7025e3508ecb0b 100755 (executable)
@@ -38,6 +38,41 @@ test_expect_success 'git ls-files --format objectname v.s. -s' '
        test_cmp expect actual
 '
 
+test_expect_success 'git ls-files --format objecttype' '
+       git ls-files --format="%(objectname)" o1.txt o4.txt o6.txt >objectname &&
+       git cat-file --batch-check="%(objecttype)" >expect <objectname &&
+       git ls-files --format="%(objecttype)" o1.txt o4.txt o6.txt >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format objectsize' '
+       cat>expect <<-\EOF &&
+26
+29
+27
+26
+-
+26
+       EOF
+       git ls-files --format="%(objectsize)" >actual &&
+
+       test_cmp expect actual
+'
+
+test_expect_success 'git ls-files --format objectsize:padded' '
+       cat>expect <<-\EOF &&
+     26
+     29
+     27
+     26
+      -
+     26
+       EOF
+       git ls-files --format="%(objectsize:padded)" >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 &&
index 217006d1bfb55df9f1e5874641226c9ad703b828..5af2dac0e4b8d5fde4d6a11dae240086473e0571 100755 (executable)
@@ -154,6 +154,14 @@ EOF
        test_output
 '
 
+test_expect_success 'ls-tree --no-full-name' '
+       git -C path0 ls-tree --no-full-name $tree a >current &&
+       cat >expected <<-EOF &&
+       040000 tree X   a
+       EOF
+       test_output
+'
+
 test_expect_success 'ls-tree --full-tree' '
        (
                cd path1/b/c &&
index 98b6c8ac34da94aef19220ff4e3f728075cb70db..3182abde27f45e35e93bf25d5b079f6901c298fb 100755 (executable)
@@ -8,6 +8,7 @@ test_description='git branch assorted tests'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
@@ -290,10 +291,10 @@ test_expect_success 'git branch -M topic topic should work when main is checked
 test_expect_success 'git branch -M and -C fail on detached HEAD' '
        git checkout HEAD^{} &&
        test_when_finished git checkout - &&
-       echo "fatal: cannot rename the current branch while not on any." >expect &&
+       echo "fatal: cannot rename the current branch while not on any" >expect &&
        test_must_fail git branch -M must-fail 2>err &&
        test_cmp expect err &&
-       echo "fatal: cannot copy the current branch while not on any." >expect &&
+       echo "fatal: cannot copy the current branch while not on any" >expect &&
        test_must_fail git branch -C must-fail 2>err &&
        test_cmp expect err
 '
@@ -941,7 +942,19 @@ test_expect_success 'test deleting branch without config' '
 test_expect_success 'deleting currently checked out branch fails' '
        git worktree add -b my7 my7 &&
        test_must_fail git -C my7 branch -d my7 &&
-       test_must_fail git branch -d my7 &&
+       test_must_fail git branch -d my7 2>actual &&
+       grep "^error: cannot delete branch .my7. used by worktree at " actual &&
+       rm -r my7 &&
+       git worktree prune
+'
+
+test_expect_success 'deleting in-use branch fails' '
+       git worktree add my7 &&
+       test_commit -C my7 bt7 &&
+       git -C my7 bisect start HEAD HEAD~2 &&
+       test_must_fail git -C my7 branch -d my7 &&
+       test_must_fail git branch -d my7 2>actual &&
+       grep "^error: cannot delete branch .my7. used by worktree at " actual &&
        rm -r my7 &&
        git worktree prune
 '
@@ -1011,7 +1024,7 @@ test_expect_success '--set-upstream-to fails on multiple branches' '
 test_expect_success '--set-upstream-to fails on detached HEAD' '
        git checkout HEAD^{} &&
        test_when_finished git checkout - &&
-       echo "fatal: could not set upstream of HEAD to main when it does not point to any branch." >expect &&
+       echo "fatal: could not set upstream of HEAD to main when it does not point to any branch" >expect &&
        test_must_fail git branch --set-upstream-to main 2>err &&
        test_cmp expect err
 '
@@ -1059,7 +1072,7 @@ test_expect_success 'use --set-upstream-to modify a particular branch' '
 '
 
 test_expect_success '--unset-upstream should fail if given a non-existent branch' '
-       echo "fatal: Branch '"'"'i-dont-exist'"'"' has no upstream information" >expect &&
+       echo "fatal: branch '"'"'i-dont-exist'"'"' has no upstream information" >expect &&
        test_must_fail git branch --unset-upstream i-dont-exist 2>err &&
        test_cmp expect err
 '
@@ -1081,7 +1094,7 @@ test_expect_success 'test --unset-upstream on HEAD' '
        test_must_fail git config branch.main.remote &&
        test_must_fail git config branch.main.merge &&
        # fail for a branch without upstream set
-       echo "fatal: Branch '"'"'main'"'"' has no upstream information" >expect &&
+       echo "fatal: branch '"'"'main'"'"' has no upstream information" >expect &&
        test_must_fail git branch --unset-upstream 2>err &&
        test_cmp expect err
 '
@@ -1095,7 +1108,7 @@ test_expect_success '--unset-upstream should fail on multiple branches' '
 test_expect_success '--unset-upstream should fail on detached HEAD' '
        git checkout HEAD^{} &&
        test_when_finished git checkout - &&
-       echo "fatal: could not unset upstream of HEAD when it does not point to any branch." >expect &&
+       echo "fatal: could not unset upstream of HEAD when it does not point to any branch" >expect &&
        test_must_fail git branch --unset-upstream 2>err &&
        test_cmp expect err
 '
index be20ebe1d5c673bc04160dd95704b2b0f722ae26..2cdb834b37e65bdc0d1bf74109def557dc3bb675 100755 (executable)
@@ -10,7 +10,7 @@ GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW
 test_expect_success 'error descriptions on empty repository' '
        current=$(git branch --show-current) &&
        cat >expect <<-EOF &&
-       error: No commit on branch '\''$current'\'' yet.
+       error: no commit on branch '\''$current'\'' yet
        EOF
        test_must_fail git branch --edit-description 2>actual &&
        test_cmp expect actual &&
@@ -21,7 +21,7 @@ test_expect_success 'error descriptions on empty repository' '
 test_expect_success 'fatal descriptions on empty repository' '
        current=$(git branch --show-current) &&
        cat >expect <<-EOF &&
-       fatal: No commit on branch '\''$current'\'' yet.
+       fatal: no commit on branch '\''$current'\'' yet
        EOF
        test_must_fail git branch --set-upstream-to=non-existent 2>actual &&
        test_cmp expect actual &&
@@ -119,6 +119,22 @@ test_expect_success 'show branch --remotes' '
        test_must_be_empty actual.out
 '
 
+test_expect_success 'show-branch --sparse' '
+       test_when_finished "git checkout branch10 && git branch -D branchA" &&
+       git checkout -b branchA branch10 &&
+       git merge -s ours -m "merge 1 and 10 to make A" branch1 &&
+       git commit --allow-empty -m "another" &&
+
+       git show-branch --sparse >out &&
+       grep "merge 1 and 10 to make A" out &&
+
+       git show-branch >out &&
+       ! grep "merge 1 and 10 to make A" out &&
+
+       git show-branch --no-sparse >out &&
+       ! grep "merge 1 and 10 to make A" out
+'
+
 test_expect_success 'setup show branch --list' '
        sed "s/^> //" >expect <<-\EOF
        >   [branch1] branch1
@@ -197,9 +213,18 @@ done <<\EOF
 --reflog --current
 EOF
 
+# unnegatable options
+for opt in topo-order date-order reflog
+do
+       test_expect_success "show-branch --no-$opt (should fail)" '
+               test_must_fail git show-branch --no-$opt 2>err &&
+               grep "unknown option .no-$opt." err
+       '
+done
+
 test_expect_success 'error descriptions on non-existent branch' '
        cat >expect <<-EOF &&
-       error: No branch named '\''non-existent'\'.'
+       error: no branch named '\''non-existent'\''
        EOF
        test_must_fail git branch --edit-description non-existent 2>actual &&
        test_cmp expect actual
@@ -213,7 +238,7 @@ test_expect_success 'fatal descriptions on non-existent branch' '
        test_cmp expect actual &&
 
        cat >expect <<-EOF &&
-       fatal: No branch named '\''non-existent'\''.
+       fatal: no branch named '\''non-existent'\''
        EOF
        test_must_fail git branch -c non-existent new-branch 2>actual &&
        test_cmp expect actual &&
@@ -228,7 +253,7 @@ test_expect_success 'error descriptions on orphan branch' '
        test_branch_op_in_wt() {
                test_orphan_error() {
                        test_must_fail git $* 2>actual &&
-                       test_i18ngrep "No commit on branch .orphan-branch. yet.$" actual
+                       test_i18ngrep "no commit on branch .orphan-branch. yet$" actual
                } &&
                test_orphan_error -C wt branch $1 $2 &&                # implicit branch
                test_orphan_error -C wt branch $1 orphan-branch $2 &&  # explicit branch
index 93f8295339cfcd018dd7b8c28e1dc726b0c96157..758963b189d8d9fc7ad50f4fa06bf431c4fe6e80 100755 (executable)
@@ -55,9 +55,17 @@ cat >expect <<'EOF'
 EOF
 test_expect_success 'git branch -r shows remote branches' '
        git branch -r >actual &&
+       test_cmp expect actual &&
+
+       git branch --remotes >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'git branch --no-remotes is rejected' '
+       test_must_fail git branch --no-remotes 2>err &&
+       grep "unknown option .no-remotes." err
+'
+
 cat >expect <<'EOF'
   branch-one
   branch-two
@@ -68,9 +76,17 @@ cat >expect <<'EOF'
 EOF
 test_expect_success 'git branch -a shows local and remote branches' '
        git branch -a >actual &&
+       test_cmp expect actual &&
+
+       git branch --all >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'git branch --no-all is rejected' '
+       test_must_fail git branch --no-all 2>err &&
+       grep "unknown option .no-all." err
+'
+
 cat >expect <<'EOF'
 two
 one
index 3399344f25dc859ad743b3914a3f5c37e92bffbb..594e3e43e129a8848b5f2e65538087ca978743d6 100755 (executable)
@@ -9,6 +9,7 @@ This script aims to check the behavior of those corner cases.
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 expect_branch() {
index b5f4d6a653045dafa7c2317036196866f78b9ca5..b33afa1c6aa9bcc33faaa117780bc45e91525a19 100755 (executable)
@@ -662,6 +662,20 @@ test_expect_success 'range-diff with multiple --notes' '
        test_cmp expect actual
 '
 
+# `range-diff` should act like `log` with regards to notes
+test_expect_success 'range-diff with --notes=custom does not show default notes' '
+       git notes add -m "topic note" topic &&
+       git notes add -m "unmodified note" unmodified &&
+       git notes --ref=custom add -m "topic note" topic &&
+       git notes --ref=custom add -m "unmodified note" unmodified &&
+       test_when_finished git notes remove topic unmodified &&
+       test_when_finished git notes --ref=custom remove topic unmodified &&
+       git range-diff --notes=custom main..topic main..unmodified \
+               >actual &&
+       ! grep "## Notes ##" actual &&
+       grep "## Notes (custom) ##" actual
+'
+
 test_expect_success 'format-patch --range-diff does not compare notes by default' '
        git notes add -m "topic note" topic &&
        git notes add -m "unmodified note" unmodified &&
@@ -679,6 +693,20 @@ test_expect_success 'format-patch --range-diff does not compare notes by default
        ! grep "note" 0000-*
 '
 
+test_expect_success 'format-patch --notes=custom --range-diff only compares custom notes' '
+       git notes add -m "topic note" topic &&
+       git notes --ref=custom add -m "topic note (custom)" topic &&
+       git notes add -m "unmodified note" unmodified &&
+       git notes --ref=custom add -m "unmodified note (custom)" unmodified &&
+       test_when_finished git notes remove topic unmodified &&
+       test_when_finished git notes --ref=custom remove topic unmodified &&
+       git format-patch --notes=custom --cover-letter --range-diff=$prev \
+               main..unmodified >actual &&
+       test_when_finished "rm 000?-*" &&
+       grep "## Notes (custom) ##" 0000-* &&
+       ! grep "## Notes ##" 0000-*
+'
+
 test_expect_success 'format-patch --range-diff with --no-notes' '
        git notes add -m "topic note" topic &&
        git notes add -m "unmodified note" unmodified &&
index 07a0ff93defebe395fe49344834b2fc627c7f81d..7326adb70f743c422d75386320febf2d8ecaab84 100755 (executable)
@@ -19,101 +19,138 @@ test_expect_success 'enable reflogs' '
        git config core.logallrefupdates true
 '
 
-test_expect_success \
-    'prepare a trivial repository' \
-    'echo Hello > A &&
-     git update-index --add A &&
-     git commit -m "Initial commit." &&
-     HEAD=$(git rev-parse --verify HEAD)'
+test_expect_success 'prepare a trivial repository' '
+       echo Hello > A &&
+       git update-index --add A &&
+       git commit -m "Initial commit." &&
+       HEAD=$(git rev-parse --verify HEAD)
+'
 
 SHA1=
 
-test_expect_success \
-    'see if git show-ref works as expected' \
-    'git branch a &&
-     SHA1=$(cat .git/refs/heads/a) &&
-     echo "$SHA1 refs/heads/a" >expect &&
-     git show-ref a >result &&
-     test_cmp expect result'
-
-test_expect_success \
-    'see if a branch still exists when packed' \
-    'git branch b &&
-     git pack-refs --all &&
-     rm -f .git/refs/heads/b &&
-     echo "$SHA1 refs/heads/b" >expect &&
-     git show-ref b >result &&
-     test_cmp expect result'
+test_expect_success 'see if git show-ref works as expected' '
+       git branch a &&
+       SHA1=$(cat .git/refs/heads/a) &&
+       echo "$SHA1 refs/heads/a" >expect &&
+       git show-ref a >result &&
+       test_cmp expect result
+'
+
+test_expect_success 'see if a branch still exists when packed' '
+       git branch b &&
+       git pack-refs --all &&
+       rm -f .git/refs/heads/b &&
+       echo "$SHA1 refs/heads/b" >expect &&
+       git show-ref b >result &&
+       test_cmp expect result
+'
 
 test_expect_success 'git branch c/d should barf if branch c exists' '
-     git branch c &&
-     git pack-refs --all &&
-     rm -f .git/refs/heads/c &&
-     test_must_fail git branch c/d
+       git branch c &&
+       git pack-refs --all &&
+       rm -f .git/refs/heads/c &&
+       test_must_fail git branch c/d
 '
 
-test_expect_success \
-    'see if a branch still exists after git pack-refs --prune' \
-    'git branch e &&
-     git pack-refs --all --prune &&
-     echo "$SHA1 refs/heads/e" >expect &&
-     git show-ref e >result &&
-     test_cmp expect result'
+test_expect_success 'see if a branch still exists after git pack-refs --prune' '
+       git branch e &&
+       git pack-refs --all --prune &&
+       echo "$SHA1 refs/heads/e" >expect &&
+       git show-ref e >result &&
+       test_cmp expect result
+'
 
 test_expect_success 'see if git pack-refs --prune remove ref files' '
-     git branch f &&
-     git pack-refs --all --prune &&
-     ! test -f .git/refs/heads/f
+       git branch f &&
+       git pack-refs --all --prune &&
+       ! test -f .git/refs/heads/f
 '
 
 test_expect_success 'see if git pack-refs --prune removes empty dirs' '
-     git branch r/s/t &&
-     git pack-refs --all --prune &&
-     ! test -e .git/refs/heads/r
+       git branch r/s/t &&
+       git pack-refs --all --prune &&
+       ! test -e .git/refs/heads/r
 '
 
-test_expect_success \
-    'git branch g should work when git branch g/h has been deleted' \
-    'git branch g/h &&
-     git pack-refs --all --prune &&
-     git branch -d g/h &&
-     git branch g &&
-     git pack-refs --all &&
-     git branch -d g'
+test_expect_success 'git branch g should work when git branch g/h has been deleted' '
+       git branch g/h &&
+       git pack-refs --all --prune &&
+       git branch -d g/h &&
+       git branch g &&
+       git pack-refs --all &&
+       git branch -d g
+'
 
 test_expect_success 'git branch i/j/k should barf if branch i exists' '
-     git branch i &&
-     git pack-refs --all --prune &&
-     test_must_fail git branch i/j/k
+       git branch i &&
+       git pack-refs --all --prune &&
+       test_must_fail git branch i/j/k
+'
+
+test_expect_success 'test git branch k after branch k/l/m and k/lm have been deleted' '
+       git branch k/l &&
+       git branch k/lm &&
+       git branch -d k/l &&
+       git branch k/l/m &&
+       git branch -d k/l/m &&
+       git branch -d k/lm &&
+       git branch k
 '
 
-test_expect_success \
-    'test git branch k after branch k/l/m and k/lm have been deleted' \
-    'git branch k/l &&
-     git branch k/lm &&
-     git branch -d k/l &&
-     git branch k/l/m &&
-     git branch -d k/l/m &&
-     git branch -d k/lm &&
-     git branch k'
-
-test_expect_success \
-    'test git branch n after some branch deletion and pruning' \
-    'git branch n/o &&
-     git branch n/op &&
-     git branch -d n/o &&
-     git branch n/o/p &&
-     git branch -d n/op &&
-     git pack-refs --all --prune &&
-     git branch -d n/o/p &&
-     git branch n'
-
-test_expect_success \
-       'see if up-to-date packed refs are preserved' \
-       'git branch q &&
-        git pack-refs --all --prune &&
-        git update-ref refs/heads/q refs/heads/q &&
-        ! test -f .git/refs/heads/q'
+test_expect_success 'test git branch n after some branch deletion and pruning' '
+       git branch n/o &&
+       git branch n/op &&
+       git branch -d n/o &&
+       git branch n/o/p &&
+       git branch -d n/op &&
+       git pack-refs --all --prune &&
+       git branch -d n/o/p &&
+       git branch n
+'
+
+test_expect_success 'test excluded refs are not packed' '
+       git branch dont_pack1 &&
+       git branch dont_pack2 &&
+       git branch pack_this &&
+       git pack-refs --all --exclude "refs/heads/dont_pack*" &&
+       test -f .git/refs/heads/dont_pack1 &&
+       test -f .git/refs/heads/dont_pack2 &&
+       ! test -f .git/refs/heads/pack_this'
+
+test_expect_success 'test --no-exclude refs clears excluded refs' '
+       git branch dont_pack3 &&
+       git branch dont_pack4 &&
+       git pack-refs --all --exclude "refs/heads/dont_pack*" --no-exclude &&
+       ! test -f .git/refs/heads/dont_pack3 &&
+       ! test -f .git/refs/heads/dont_pack4'
+
+test_expect_success 'test only included refs are packed' '
+       git branch pack_this1 &&
+       git branch pack_this2 &&
+       git tag dont_pack5 &&
+       git pack-refs --include "refs/heads/pack_this*" &&
+       test -f .git/refs/tags/dont_pack5 &&
+       ! test -f .git/refs/heads/pack_this1 &&
+       ! test -f .git/refs/heads/pack_this2'
+
+test_expect_success 'test --no-include refs clears included refs' '
+       git branch pack1 &&
+       git branch pack2 &&
+       git pack-refs --include "refs/heads/pack*" --no-include &&
+       test -f .git/refs/heads/pack1 &&
+       test -f .git/refs/heads/pack2'
+
+test_expect_success 'test --exclude takes precedence over --include' '
+       git branch dont_pack5 &&
+       git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
+       test -f .git/refs/heads/dont_pack5'
+
+test_expect_success 'see if up-to-date packed refs are preserved' '
+       git branch q &&
+       git pack-refs --all --prune &&
+       git update-ref refs/heads/q refs/heads/q &&
+       ! test -f .git/refs/heads/q
+'
 
 test_expect_success 'pack, prune and repack' '
        git tag foo &&
index 3288aaec7dc9362dc923b963e31ccd05005ba351..d734000d2fca6ab25568b392ea57a05678915344 100755 (executable)
@@ -362,6 +362,7 @@ test_expect_success 'do not create empty note with -m ""' '
 '
 
 test_expect_success 'create note with combination of -m and -F' '
+       test_when_finished git notes remove HEAD &&
        cat >expect-combine_m_and_F <<-EOF &&
                foo
 
@@ -380,6 +381,41 @@ test_expect_success 'create note with combination of -m and -F' '
        test_cmp expect-combine_m_and_F actual
 '
 
+test_expect_success 'create note with combination of -m and -F and --separator' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect-combine_m_and_F <<-\EOF &&
+       foo
+       -------
+       xyzzy
+       -------
+       bar
+       -------
+       zyxxy
+       -------
+       baz
+       EOF
+       echo "xyzzy" >note_a &&
+       echo "zyxxy" >note_b &&
+       git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --separator="-------" &&
+       git notes show >actual &&
+       test_cmp expect-combine_m_and_F actual
+'
+
+test_expect_success 'create note with combination of -m and -F and --no-separator' '
+       cat >expect-combine_m_and_F <<-\EOF &&
+       foo
+       xyzzy
+       bar
+       zyxxy
+       baz
+       EOF
+       echo "xyzzy" >note_a &&
+       echo "zyxxy" >note_b &&
+       git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --no-separator &&
+       git notes show >actual &&
+       test_cmp expect-combine_m_and_F actual
+'
+
 test_expect_success 'remove note with "git notes remove"' '
        git notes remove HEAD^ &&
        git notes remove &&
@@ -521,6 +557,112 @@ test_expect_success 'listing non-existing notes fails' '
        test_must_be_empty actual
 '
 
+test_expect_success 'append: specify a separator with an empty arg' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect <<-\EOF &&
+       notes-1
+
+       notes-2
+       EOF
+
+       git notes add -m "notes-1" &&
+       git notes append --separator="" -m "notes-2" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append: specify a separator without arg' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect <<-\EOF &&
+       notes-1
+
+       notes-2
+       EOF
+
+       git notes add -m "notes-1" &&
+       git notes append --separator -m "notes-2" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append: specify as --no-separator' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect <<-\EOF &&
+       notes-1
+       notes-2
+       EOF
+
+       git notes add -m "notes-1" &&
+       git notes append --no-separator -m "notes-2" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator with line break' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect <<-\EOF &&
+       notes-1
+       -------
+       notes-2
+       EOF
+
+       git notes add -m "notes-1" &&
+       git notes append --separator="-------$LF" -m "notes-2" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator without line break' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect <<-\EOF &&
+       notes-1
+       -------
+       notes-2
+       EOF
+
+       git notes add -m "notes-1" &&
+       git notes append --separator="-------" -m "notes-2" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator with multiple messages' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect <<-\EOF &&
+       notes-1
+       -------
+       notes-2
+       -------
+       notes-3
+       EOF
+
+       git notes add -m "notes-1" &&
+       git notes append --separator="-------" -m "notes-2" -m "notes-3" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append note with combination of -m and -F and --separator' '
+       test_when_finished git notes remove HEAD &&
+       cat >expect-combine_m_and_F <<-\EOF &&
+       m-notes-1
+       -------
+       f-notes-1
+       -------
+       m-notes-2
+       -------
+       f-notes-2
+       -------
+       m-notes-3
+       EOF
+
+       echo "f-notes-1" >note_a &&
+       echo "f-notes-2" >note_b &&
+       git notes append -m "m-notes-1" -F note_a -m "m-notes-2" -F note_b -m "m-notes-3" --separator="-------" &&
+       git notes show >actual &&
+       test_cmp expect-combine_m_and_F actual
+'
+
 test_expect_success 'append to existing note with "git notes append"' '
        cat >expect <<-EOF &&
                Initial set of notes
@@ -818,6 +960,33 @@ test_expect_success 'create note from blob with "git notes add -C" reuses blob i
        test_cmp blob actual
 '
 
+test_expect_success 'create note from blob with "-C", also specify "-m", "-F" and "--separator"' '
+       # 8th will be reuseed in following tests, so rollback when the test is done
+       test_when_finished "git notes remove && git notes add -C $(cat blob)" &&
+       commit=$(git rev-parse HEAD) &&
+       cat >expect <<-EOF &&
+               commit $commit
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:20:13 2005 -0700
+
+               ${indent}8th
+
+               Notes:
+               ${indent}This is a blob object
+               ${indent}-------
+               ${indent}This is created by -m
+               ${indent}-------
+               ${indent}This is created by -F
+       EOF
+
+       git notes remove &&
+       echo "This is a blob object" | git hash-object -w --stdin >blob &&
+       echo "This is created by -F" >note_a &&
+       git notes add -C $(cat blob) -m "This is created by -m" -F note_a --separator="-------" &&
+       git log -1 >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'create note from other note with "git notes add -c"' '
        test_commit 9th &&
        commit=$(git rev-parse HEAD) &&
diff --git a/t/t3321-notes-stripspace.sh b/t/t3321-notes-stripspace.sh
new file mode 100755 (executable)
index 0000000..36abdca
--- /dev/null
@@ -0,0 +1,578 @@
+#!/bin/sh
+#
+# Copyright (c) 2023 Teng Long
+#
+
+test_description='Test commit notes with stripspace behavior'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+MULTI_LF="$LF$LF$LF"
+write_script fake_editor <<\EOF
+echo "$MSG" >"$1"
+echo "$MSG" >&2
+EOF
+GIT_EDITOR=./fake_editor
+export GIT_EDITOR
+
+test_expect_success 'setup the commit' '
+       test_commit 1st
+'
+
+test_expect_success 'add note by editor' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add  &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-m", "--stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       git notes add -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       git notes add --stripspace -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-m" and "--no-stripspace" ' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}first-line${MULTI_LF}second-line
+       EOF
+
+       git notes add --no-stripspace \
+                     -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-m", "--stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       git notes add -m "${LF}" \
+                     -m "first-line" \
+                     -m "${MULTI_LF}" \
+                     -m "second-line" \
+                     -m "${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       git notes add --stripspace -m "${LF}" \
+                     -m "first-line" \
+                     -m "${MULTI_LF}" \
+                     -m "second-line" \
+                     -m "${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add notes by specifying multiple "-m" and "--no-stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line${LF}
+       EOF
+
+       git notes add --no-stripspace \
+                     -m "${LF}" \
+                     -m "first-line" \
+                     -m "${MULTI_LF}" \
+                     -m "second-line" \
+                     -m "${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-F", "--stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       cat >note-file <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       git notes add -F note-file &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       git notes add --stripspace -F note-file &&
+       git notes show >actual
+'
+
+test_expect_success 'add note by specifying single "-F" and "--no-stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       cat >note-file <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       git notes add --no-stripspace -F note-file &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-F", "--stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       file-1-first-line
+
+       file-1-second-line
+
+       file-2-first-line
+
+       file-2-second-line
+       EOF
+
+       cat >note-file-1 <<-EOF &&
+       ${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-2 <<-EOF &&
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       git notes add -F note-file-1 -F note-file-2 &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       git notes add --stripspace -F note-file-1 -F note-file-2 &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-F" with "--no-stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-1 <<-EOF &&
+       ${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-2 <<-EOF &&
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       git notes add --no-stripspace -F note-file-1 -F note-file-2 &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append note by editor' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       git notes add -m "first-line" &&
+       MSG="${MULTI_LF}second-line${LF}" git notes append  &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying single "-m"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       git notes add -m "${LF}first-line" &&
+       git notes append -m "${MULTI_LF}second-line${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying multiple "-m"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       git notes add -m "${LF}first-line" &&
+       git notes append -m "${MULTI_LF}" \
+                     -m "second-line" \
+                     -m "${LF}" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-F"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       cat >note-file <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       git notes add -F note-file &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add notes by specifying multiple "-F"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       file-1-first-line
+
+       file-1-second-line
+
+       file-2-first-line
+
+       file-2-second-line
+       EOF
+
+       cat >note-file-1 <<-EOF &&
+       ${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-2 <<-EOF &&
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       git notes add -F note-file-1 -F note-file-2 &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying single "-F"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       initial-line
+
+       first-line
+
+       second-line
+       EOF
+
+       cat >note-file <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       git notes add -m "initial-line" &&
+       git notes append -F note-file &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append notes by specifying multiple "-F"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       initial-line
+
+       file-1-first-line
+
+       file-1-second-line
+
+       file-2-first-line
+
+       file-2-second-line
+       EOF
+
+       cat >note-file-1 <<-EOF &&
+       ${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-2 <<-EOF &&
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       git notes add -m "initial-line" &&
+       git notes append -F note-file-1 -F note-file-2 &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying multiple "-F" with "--no-stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       initial-line
+       ${LF}${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-1 <<-EOF &&
+       ${LF}
+       file-1-first-line
+       ${MULTI_LF}
+       file-1-second-line
+       ${LF}
+       EOF
+
+       cat >note-file-2 <<-EOF &&
+       ${LF}
+       file-2-first-line
+       ${MULTI_LF}
+       file-2-second-line
+       ${LF}
+       EOF
+
+       git notes add -m "initial-line" &&
+       git notes append --no-stripspace -F note-file-1 -F note-file-2 &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add notes with empty messages' '
+       rev=$(git rev-parse HEAD) &&
+       git notes add -m "${LF}" \
+                     -m "${MULTI_LF}" \
+                     -m "${LF}" >actual 2>&1 &&
+       test_i18ngrep "Removing note for object" actual
+'
+
+test_expect_success 'add note by specifying "-C", "--no-stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       cat expect | git hash-object -w --stdin >blob &&
+       git notes add -C $(cat blob) &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       git notes add --no-stripspace -C $(cat blob) &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'reuse note by specifying "-C" and "--stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >data <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       cat data | git hash-object -w --stdin >blob &&
+       git notes add --stripspace -C $(cat blob) &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'reuse with "-C" and add note with "-m", "-m" will stripspace all together' '
+       test_when_finished "git notes remove" &&
+       cat >data <<-EOF &&
+       ${LF}
+       first-line
+       ${MULTI_LF}
+       second-line
+       ${LF}
+       EOF
+
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+
+       third-line
+       EOF
+
+       cat data | git hash-object -w --stdin >blob &&
+       git notes add -C $(cat blob) -m "third-line" &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note with "-m" and reuse note with "-C", "-C" will not stripspace all together' '
+       test_when_finished "git notes remove" &&
+       cat >data <<-EOF &&
+
+       second-line
+       EOF
+
+       cat >expect <<-EOF &&
+       first-line
+       ${LF}
+       second-line
+       EOF
+
+       cat data | git hash-object -w --stdin >blob &&
+       git notes add -m "first-line" -C $(cat blob)  &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying "-c", "--stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       echo "initial-line" | git hash-object -w --stdin >blob &&
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add -c $(cat blob) &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --stripspace -c $(cat blob) &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying "-c" with "--no-stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}first-line${MULTI_LF}second-line${LF}
+       EOF
+
+       echo "initial-line" | git hash-object -w --stdin >blob &&
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace -c $(cat blob) &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'edit note by specifying "-c", "--stripspace" is the default behavior' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       first-line
+
+       second-line
+       EOF
+
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit &&
+       git notes show >actual &&
+       test_cmp expect actual &&
+       git notes remove &&
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit --stripspace &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'edit note by specifying "-c" with "--no-stripspace"' '
+       test_when_finished "git notes remove" &&
+       cat >expect <<-EOF &&
+       ${LF}first-line${MULTI_LF}second-line${LF}
+       EOF
+
+       MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace &&
+       git notes show >actual &&
+       test_cmp expect actual
+'
+
+test_done
index 3ce918fdb8062fc5f720bb890ad58a2676547218..d3df19a51f83a9193916c3812d1ca152644b470f 100755 (executable)
@@ -421,7 +421,7 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' '
        git checkout main &&
        git worktree add wt &&
        test_must_fail git -C wt rebase main main 2>err &&
-       test_i18ngrep "already checked out" err
+       test_i18ngrep "already used by worktree at" err
 '
 
 test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' '
index 79b0640c004e23f5346d9bfe1ba9998791633887..e9e03ca4b5eb16e6c40815a25197e3e22bb37561 100755 (executable)
@@ -8,6 +8,7 @@ test_description='git rebase --merge test'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 T="A quick brown fox
index ff0afad63e2c5b1c03495046961eb27e2a593ed0..8ea2bf13026c1c29d04bfdc715c0901b0c062cf6 100755 (executable)
@@ -604,7 +604,8 @@ test_expect_success 'clean error after failed "exec"' '
        echo "edited again" > file7 &&
        git add file7 &&
        test_must_fail git rebase --continue 2>error &&
-       test_i18ngrep "you have staged changes in your working tree" error
+       test_i18ngrep "you have staged changes in your working tree" error &&
+       test_i18ngrep ! "could not open.*for reading" error
 '
 
 test_expect_success 'rebase a detached HEAD' '
@@ -758,7 +759,7 @@ test_expect_success 'reword' '
        git show HEAD~2 | grep "C changed"
 '
 
-test_expect_success 'no uncommited changes when rewording the todo list is reloaded' '
+test_expect_success 'no uncommitted changes when rewording and the todo list is reloaded' '
        git checkout E &&
        test_when_finished "git checkout @{-1}" &&
        (
@@ -1276,20 +1277,34 @@ test_expect_success 'todo count' '
 '
 
 test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
-       git checkout --force branch2 &&
+       git checkout --force A &&
        git clean -f &&
+       cat >todo <<-EOF &&
+       exec >file2
+       pick $(git rev-parse B) B
+       pick $(git rev-parse C) C
+       pick $(git rev-parse D) D
+       exec cat .git/rebase-merge/done >actual
+       EOF
        (
-               set_fake_editor &&
-               FAKE_LINES="edit 1 2" git rebase -i A
-       ) &&
-       test_cmp_rev HEAD F &&
-       test_path_is_missing file6 &&
-       >file6 &&
-       test_must_fail git rebase --continue &&
-       test_cmp_rev HEAD F &&
-       rm file6 &&
+               set_replace_editor todo &&
+               test_must_fail git rebase -i A
+       ) &&
+       test_cmp_rev HEAD B &&
+       test_cmp_rev REBASE_HEAD C &&
+       head -n3 todo >expect &&
+       test_cmp expect .git/rebase-merge/done &&
+       rm file2 &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
+       git reset --hard HEAD &&
        git rebase --continue &&
-       test_cmp_rev HEAD I
+       test_cmp_rev HEAD D &&
+       tail -n3 todo >>expect &&
+       test_cmp expect actual
 '
 
 test_expect_success 'rebase -i commits that overwrite untracked files (squash)' '
@@ -1305,7 +1320,14 @@ test_expect_success 'rebase -i commits that overwrite untracked files (squash)'
        >file6 &&
        test_must_fail git rebase --continue &&
        test_cmp_rev HEAD F &&
+       test_cmp_rev REBASE_HEAD I &&
        rm file6 &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
+       git reset --hard HEAD &&
        git rebase --continue &&
        test $(git cat-file commit HEAD | sed -ne \$p) = I &&
        git reset --hard original-branch2
@@ -1323,7 +1345,14 @@ test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' '
        >file6 &&
        test_must_fail git rebase --continue &&
        test $(git cat-file commit HEAD | sed -ne \$p) = F &&
+       test_cmp_rev REBASE_HEAD I &&
        rm file6 &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
+       git reset --hard HEAD &&
        git rebase --continue &&
        test $(git cat-file commit HEAD | sed -ne \$p) = I
 '
@@ -1596,6 +1625,32 @@ test_expect_success 'static check of bad command' '
        test C = $(git cat-file commit HEAD^ | sed -ne \$p)
 '
 
+test_expect_success 'the first command cannot be a fixup' '
+       rebase_setup_and_clean fixup-first &&
+
+       cat >orig <<-EOF &&
+       fixup $(git log -1 --format="%h %s" B)
+       pick $(git log -1 --format="%h %s" C)
+       EOF
+
+       (
+               set_replace_editor orig &&
+               test_must_fail git rebase -i A 2>actual
+       ) &&
+       grep "cannot .fixup. without a previous commit" actual &&
+       grep "You can fix this with .git rebase --edit-todo.." actual &&
+       # verify that the todo list has not been truncated
+       grep -v "^#" .git/rebase-merge/git-rebase-todo >actual &&
+       test_cmp orig actual &&
+
+       test_must_fail git rebase --edit-todo 2>actual &&
+       grep "cannot .fixup. without a previous commit" actual &&
+       grep "You can fix this with .git rebase --edit-todo.." actual &&
+       # verify that the todo list has not been truncated
+       grep -v "^#" .git/rebase-merge/git-rebase-todo >actual &&
+       test_cmp orig actual
+'
+
 test_expect_success 'tabs and spaces are accepted in the todolist' '
        rebase_setup_and_clean indented-comment &&
        write_script add-indent.sh <<-\EOF &&
index 2d0789e554bf00a604a347ab0e9c7b3781e4a96a..c4e2fcac67e5886d47a392097dd14e2bd0141a73 100755 (executable)
@@ -115,15 +115,23 @@ test_expect_success '--skip after failed fixup cleans commit message' '
        test_when_finished "test_might_fail git rebase --abort" &&
        git checkout -b with-conflicting-fixup &&
        test_commit wants-fixup &&
-       test_commit "fixup! wants-fixup" wants-fixup.t 1 wants-fixup-1 &&
-       test_commit "fixup! wants-fixup" wants-fixup.t 2 wants-fixup-2 &&
-       test_commit "fixup! wants-fixup" wants-fixup.t 3 wants-fixup-3 &&
+       test_commit "fixup 1" wants-fixup.t 1 wants-fixup-1 &&
+       test_commit "fixup 2" wants-fixup.t 2 wants-fixup-2 &&
+       test_commit "fixup 3" wants-fixup.t 3 wants-fixup-3 &&
        test_must_fail env FAKE_LINES="1 fixup 2 squash 4" \
                git rebase -i HEAD~4 &&
 
        : now there is a conflict, and comments in the commit message &&
-       git show HEAD >out &&
-       grep "fixup! wants-fixup" out &&
+       test_commit_message HEAD <<-\EOF &&
+       # This is a combination of 2 commits.
+       # This is the 1st commit message:
+
+       wants-fixup
+
+       # The commit message #2 will be skipped:
+
+       # fixup 1
+       EOF
 
        : skip and continue &&
        echo "cp \"\$1\" .git/copy.txt" | write_script copy-editor.sh &&
@@ -133,33 +141,49 @@ test_expect_success '--skip after failed fixup cleans commit message' '
        test_path_is_missing .git/copy.txt &&
 
        : now the comments in the commit message should have been cleaned up &&
-       git show HEAD >out &&
-       ! grep "fixup! wants-fixup" out &&
+       test_commit_message HEAD -m wants-fixup &&
 
        : now, let us ensure that "squash" is handled correctly &&
        git reset --hard wants-fixup-3 &&
-       test_must_fail env FAKE_LINES="1 squash 4 squash 2 squash 4" \
+       test_must_fail env FAKE_LINES="1 squash 2 squash 1 squash 3 squash 1" \
                git rebase -i HEAD~4 &&
 
-       : the first squash failed, but there are two more in the chain &&
+       : the second squash failed, but there are two more in the chain &&
        (test_set_editor "$PWD/copy-editor.sh" &&
         test_must_fail git rebase --skip) &&
 
        : not the final squash, no need to edit the commit message &&
        test_path_is_missing .git/copy.txt &&
 
-       : The first squash was skipped, therefore: &&
-       git show HEAD >out &&
-       test_i18ngrep "# This is a combination of 2 commits" out &&
-       test_i18ngrep "# This is the commit message #2:" out &&
+       : The first and third squashes succeeded, therefore: &&
+       test_commit_message HEAD <<-\EOF &&
+       # This is a combination of 3 commits.
+       # This is the 1st commit message:
+
+       wants-fixup
+
+       # This is the commit message #2:
+
+       fixup 1
+
+       # This is the commit message #3:
+
+       fixup 2
+       EOF
 
        (test_set_editor "$PWD/copy-editor.sh" && git rebase --skip) &&
-       git show HEAD >out &&
-       test_i18ngrep ! "# This is a combination" out &&
+       test_commit_message HEAD <<-\EOF &&
+       wants-fixup
+
+       fixup 1
+
+       fixup 2
+       EOF
 
        : Final squash failed, but there was still a squash &&
-       test_i18ngrep "# This is a combination of 2 commits" .git/copy.txt &&
-       test_i18ngrep "# This is the commit message #2:" .git/copy.txt
+       head -n1 .git/copy.txt >first-line &&
+       test_i18ngrep "# This is a combination of 3 commits" first-line &&
+       test_i18ngrep "# This is the commit message #3:" .git/copy.txt
 '
 
 test_expect_success 'setup rerere database' '
@@ -244,6 +268,24 @@ test_expect_success 'the todo command "break" works' '
        test_path_is_file execed
 '
 
+test_expect_success 'patch file is removed before break command' '
+       test_when_finished "git rebase --abort" &&
+       cat >todo <<-\EOF &&
+       pick commit-new-file-F2-on-topic-branch
+       break
+       EOF
+
+       (
+               set_replace_editor todo &&
+               test_must_fail git rebase -i --onto commit-new-file-F2 HEAD
+       ) &&
+       test_path_is_file .git/rebase-merge/patch &&
+       echo 22>F2 &&
+       git add F2 &&
+       git rebase --continue &&
+       test_path_is_missing .git/rebase-merge/patch
+'
+
 test_expect_success '--reschedule-failed-exec' '
        test_when_finished "git rebase --abort" &&
        test_must_fail git rebase -x false --reschedule-failed-exec HEAD^ &&
index 96ae0edf1e17275825c2f6fdd57f09431834ed77..59b5d6b6f276c367862df92f847db37906715004 100755 (executable)
@@ -128,14 +128,24 @@ test_expect_success 'generate correct todo list' '
 '
 
 test_expect_success '`reset` refuses to overwrite untracked files' '
-       git checkout -b refuse-to-reset &&
+       git checkout B &&
        test_commit dont-overwrite-untracked &&
-       git checkout @{-1} &&
-       : >dont-overwrite-untracked.t &&
-       echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
+       cat >script-from-scratch <<-EOF &&
+       exec >dont-overwrite-untracked.t
+       pick $(git rev-parse B) B
+       reset refs/tags/dont-overwrite-untracked
+       pick $(git rev-parse C) C
+       exec cat .git/rebase-merge/done >actual
+       EOF
        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
-       test_must_fail git rebase -ir HEAD &&
-       git rebase --abort
+       test_must_fail git rebase -ir A &&
+       test_cmp_rev HEAD B &&
+       head -n3 script-from-scratch >expect &&
+       test_cmp expect .git/rebase-merge/done &&
+       rm dont-overwrite-untracked.t &&
+       git rebase --continue &&
+       tail -n3 script-from-scratch >>expect &&
+       test_cmp expect actual
 '
 
 test_expect_success '`reset` rejects trees' '
@@ -165,12 +175,16 @@ test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' '
        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
        test_tick &&
        test_must_fail git rebase -ir HEAD &&
+       test_cmp_rev REBASE_HEAD H^0 &&
        grep "^merge -C .* G$" .git/rebase-merge/done &&
        grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
-       test_path_is_file .git/rebase-merge/patch &&
+       test_path_is_missing .git/rebase-merge/patch &&
+       echo changed >file1 &&
+       git add file1 &&
+       test_must_fail git rebase --continue 2>err &&
+       grep "error: you have staged changes in your working tree" err &&
 
        : fail because of merge conflict &&
-       rm G.t .git/rebase-merge/patch &&
        git reset --hard conflicting-G &&
        test_must_fail git rebase --continue &&
        ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
@@ -586,4 +600,15 @@ test_expect_success 'progress shows the correct total' '
        test_line_count = 14 progress
 '
 
+test_expect_success 'truncate label names' '
+       commit=$(git commit-tree -p HEAD^ -p HEAD -m "0123456789 我 123" HEAD^{tree}) &&
+       git merge --ff-only $commit &&
+
+       done="$(git rev-parse --git-path rebase-merge/done)" &&
+       git -c rebase.maxLabelLength=14 rebase --rebase-merges -x "cp \"$done\" out" --root &&
+       grep "label 0123456789-我$" out &&
+       git -c rebase.maxLabelLength=13 rebase --rebase-merges -x "cp \"$done\" out" --root &&
+       grep "label 0123456789-$" out
+'
+
 test_done
index dd3b301fa7ab2bbd48297bc26d1b21b8b00fa82b..7929e2e2e3a8fc1240af3991f85172c16dcbd2cf 100755 (executable)
@@ -21,21 +21,6 @@ TEST_PASSES_SANITIZE_LEAK=true
 
 EMPTY=""
 
-# test_commit_message <rev> -m <msg>
-# test_commit_message <rev> <path>
-# Verify that the commit message of <rev> matches
-# <msg> or the content of <path>.
-test_commit_message () {
-       git show --no-patch --pretty=format:%B "$1" >actual &&
-       case "$2" in
-       -m)
-               echo "$3" >expect &&
-               test_cmp expect actual ;;
-       *)
-               test_cmp "$2" actual ;;
-       esac
-}
-
 get_author () {
        rev="$1" &&
        git log -1 --pretty=format:"%an %ae %at" "$rev"
index 0458a58b4b58ccb5a7fb5af378a5e2908126c111..78c3eac54b599ef9cded9a042f4346621798b645 100755 (executable)
@@ -16,46 +16,43 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 GIT_AUTHOR_EMAIL=bogus_email_address
 export GIT_AUTHOR_EMAIL
 
-test_expect_success \
-    'prepare repository with topic branch, and check cherry finds the 2 patches from there' \
-    'echo First > A &&
-     git update-index --add A &&
-     test_tick &&
-     git commit -m "Add A." &&
-
-     git checkout -b my-topic-branch &&
-
-     echo Second > B &&
-     git update-index --add B &&
-     test_tick &&
-     git commit -m "Add B." &&
-
-     echo AnotherSecond > C &&
-     git update-index --add C &&
-     test_tick &&
-     git commit -m "Add C." &&
-
-     git checkout -f main &&
-     rm -f B C &&
-
-     echo Third >> A &&
-     git update-index A &&
-     test_tick &&
-     git commit -m "Modify A." &&
-
-     expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* + .*"
+test_expect_success 'prepare repository with topic branch, and check cherry finds the 2 patches from there' '
+       echo First > A &&
+       git update-index --add A &&
+       test_tick &&
+       git commit -m "Add A." &&
+
+       git checkout -b my-topic-branch &&
+
+       echo Second > B &&
+       git update-index --add B &&
+       test_tick &&
+       git commit -m "Add B." &&
+
+       echo AnotherSecond > C &&
+       git update-index --add C &&
+       test_tick &&
+       git commit -m "Add C." &&
+
+       git checkout -f main &&
+       rm -f B C &&
+
+       echo Third >> A &&
+       git update-index A &&
+       test_tick &&
+       git commit -m "Modify A." &&
+
+       expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* + .*"
 '
 
-test_expect_success \
-    'check that cherry with limit returns only the top patch'\
-    'expr "$(echo $(git cherry main my-topic-branch my-topic-branch^1) )" : "+ [^ ]*"
+test_expect_success 'check that cherry with limit returns only the top patch' '
+       expr "$(echo $(git cherry main my-topic-branch my-topic-branch^1) )" : "+ [^ ]*"
 '
 
-test_expect_success \
-    'cherry-pick one of the 2 patches, and check cherry recognized one and only one as new' \
-    'git cherry-pick my-topic-branch^0 &&
-     echo $(git cherry main my-topic-branch) &&
-     expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* - .*"
+test_expect_success 'cherry-pick one of the 2 patches, and check cherry recognized one and only one as new' '
+       git cherry-pick my-topic-branch^0 &&
+       echo $(git cherry main my-topic-branch) &&
+       expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* - .*"
 '
 
 test_expect_success 'cherry ignores whitespace' '
index e2ef6193233dd0b7a2341c391695aabd73d03200..4158590322321742dcc0fef90d43591db3c0ab09 100755 (executable)
@@ -176,6 +176,29 @@ test_expect_success 'advice from failed revert' '
        test_cmp expected actual
 '
 
+test_expect_subject () {
+       echo "$1" >expect &&
+       git log -1 --pretty=%s >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'titles of fresh reverts' '
+       test_commit --no-tag A file1 &&
+       test_commit --no-tag B file1 &&
+       git revert --no-edit HEAD &&
+       test_expect_subject "Revert \"B\"" &&
+       git revert --no-edit HEAD &&
+       test_expect_subject "Reapply \"B\"" &&
+       git revert --no-edit HEAD &&
+       test_expect_subject "Revert \"Reapply \"B\"\""
+'
+
+test_expect_success 'title of legacy double revert' '
+       test_commit --no-tag "Revert \"Revert \"B\"\"" file1 &&
+       git revert --no-edit HEAD &&
+       test_expect_subject "Revert \"Revert \"Revert \"B\"\"\""
+'
+
 test_expect_success 'identification of reverted commit (default)' '
        test_commit to-ident &&
        test_when_finished "git reset --hard to-ident" &&
index 82dd768944fa5d566f32d7076ad2e36bd0f53cf7..7623689da24501a7bb7cd7224035f854eeab43ff 100755 (executable)
@@ -24,17 +24,17 @@ test_mode_in_index () {
        esac
 }
 
-test_expect_success \
-    'Test of git add' \
-    'touch foo && git add foo'
+test_expect_success 'Test of git add' '
+       touch foo && git add foo
+'
 
-test_expect_success \
-    'Post-check that foo is in the index' \
-    'git ls-files foo | grep foo'
+test_expect_success 'Post-check that foo is in the index' '
+       git ls-files foo | grep foo
+'
 
-test_expect_success \
-    'Test that "git add -- -q" works' \
-    'touch -- -q && git add -- -q'
+test_expect_success 'Test that "git add -- -q" works' '
+       touch -- -q && git add -- -q
+'
 
 BATCH_CONFIGURATION='-c core.fsync=loose-object -c core.fsyncmethod=batch'
 
@@ -284,14 +284,14 @@ test_expect_success POSIXPERM,SANITY 'git add (add.ignore-errors = false)' '
 rm -f foo2
 
 test_expect_success POSIXPERM,SANITY '--no-ignore-errors overrides config' '
-       git config add.ignore-errors 1 &&
-       git reset --hard &&
-       date >foo1 &&
-       date >foo2 &&
-       chmod 0 foo2 &&
-       test_must_fail git add --verbose --no-ignore-errors . &&
-       ! ( git ls-files foo1 | grep foo1 ) &&
-       git config add.ignore-errors 0
+       git config add.ignore-errors 1 &&
+       git reset --hard &&
+       date >foo1 &&
+       date >foo2 &&
+       chmod 0 foo2 &&
+       test_must_fail git add --verbose --no-ignore-errors . &&
+       ! ( git ls-files foo1 | grep foo1 ) &&
+       git config add.ignore-errors 0
 '
 rm -f foo2
 
index 3982b6b49dc45673bf6dcf1cb984a2ff8fedf252..34aabb7f5f6a543b31f89650f63b8783e9071271 100755 (executable)
@@ -734,6 +734,44 @@ test_expect_success 'colors can be overridden' '
        test_cmp expect actual
 '
 
+test_expect_success 'brackets appear without color' '
+       git reset --hard &&
+       test_when_finished "git rm -f bracket-test" &&
+       test_write_lines context old more-context >bracket-test &&
+       git add bracket-test &&
+       test_write_lines context new more-context another-one >bracket-test &&
+
+       test_write_lines quit >input &&
+       git add -i >actual <input &&
+
+       sed "s/^|//" >expect <<-\EOF &&
+       |           staged     unstaged path
+       |  1:        +3/-0        +2/-1 bracket-test
+       |
+       |*** Commands ***
+       |  1: [s]tatus    2: [u]pdate     3: [r]evert     4: [a]dd untracked
+       |  5: [p]atch     6: [d]iff       7: [q]uit       8: [h]elp
+       |What now> Bye.
+       EOF
+
+       test_cmp expect actual
+'
+
+test_expect_success 'colors can be skipped with color.ui=false' '
+       git reset --hard &&
+       test_when_finished "git rm -f color-test" &&
+       test_write_lines context old more-context >color-test &&
+       git add color-test &&
+       test_write_lines context new more-context another-one >color-test &&
+
+       test_write_lines help quit >input &&
+       force_color git \
+               -c color.ui=false \
+               add -i >actual.raw <input &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp actual.raw actual
+'
+
 test_expect_success 'colorized diffs respect diff.wsErrorHighlight' '
        git reset --hard &&
 
index 376cc8f4ab8429b0488ad23b0f9731c9af237124..30b64260a8a943305d6d798deda056ec6b9617c2 100755 (executable)
@@ -931,6 +931,10 @@ test_expect_success 'store called with invalid commit' '
        test_must_fail git stash store foo
 '
 
+test_expect_success 'store called with non-stash commit' '
+       test_must_fail git stash store HEAD
+'
+
 test_expect_success 'store updates stash ref and reflog' '
        git stash clear &&
        git reset --hard &&
@@ -1211,19 +1215,19 @@ test_expect_success 'stash with file including $IFS character' '
 '
 
 test_expect_success 'stash with pathspec matching multiple paths' '
-       echo original >file &&
-       echo original >other-file &&
-       git commit -m "two" file other-file &&
-       echo modified >file &&
-       echo modified >other-file &&
-       git stash push -- "*file" &&
-       echo original >expect &&
-       test_cmp expect file &&
-       test_cmp expect other-file &&
-       git stash pop &&
-       echo modified >expect &&
-       test_cmp expect file &&
-       test_cmp expect other-file
+       echo original >file &&
+       echo original >other-file &&
+       git commit -m "two" file other-file &&
+       echo modified >file &&
+       echo modified >other-file &&
+       git stash push -- "*file" &&
+       echo original >expect &&
+       test_cmp expect file &&
+       test_cmp expect other-file &&
+       git stash pop &&
+       echo modified >expect &&
+       test_cmp expect file &&
+       test_cmp expect other-file
 '
 
 test_expect_success 'stash push -p with pathspec shows no changes only once' '
index bfcaae390f3ad95584ce9cf78b62cc81c33adf67..8d50331b8c8e431853bbdf377813ed288007961b 100755 (executable)
@@ -5,6 +5,9 @@
 
 test_description='Test built-in diff output engine.
 
+We happen to know that all diff plumbing and diff Porcelain share the
+same command line parser, so testing one should be sufficient; pick
+diff-files as a representative.
 '
 
 TEST_PASSES_SANITIZE_LEAK=true
@@ -16,9 +19,11 @@ Line 2
 line 3'
 cat path0 >path1
 chmod +x path1
+mkdir path2
+>path2/path3
 
 test_expect_success 'update-index --add two files with and without +x.' '
-       git update-index --add path0 path1
+       git update-index --add path0 path1 path2/path3
 '
 
 mv path0 path0-
@@ -91,4 +96,31 @@ test_expect_success 'git diff-files --patch --no-patch does not show the patch'
        test_must_be_empty err
 '
 
+
+# Smudge path2/path3 so that dirstat has something to show
+date >path2/path3
+
+for format in stat raw numstat shortstat summary \
+       dirstat cumulative dirstat-by-file \
+       patch-with-raw patch-with-stat compact-summary
+do
+       test_expect_success "--no-patch in 'git diff-files --no-patch --$format' is a no-op" '
+               git diff-files --no-patch "--$format" >actual &&
+               git diff-files "--$format" >expect &&
+               test_cmp expect actual
+       '
+
+       test_expect_success "--no-patch clears all previous ones" '
+               git diff-files --$format -s -p >actual &&
+               git diff-files -p >expect &&
+               test_cmp expect actual
+       '
+
+       test_expect_success "--no-patch in 'git diff --no-patch --$format' is a no-op" '
+               git diff --no-patch "--$format" >actual &&
+               git diff "--$format" >expect &&
+               test_cmp expect actual
+       '
+done
+
 test_done
index ea52e5b91b75e3df741cbc12b927cacd6ee08afb..7afc883ec374e1c4b747ed80ba64575d05017502 100755 (executable)
@@ -284,132 +284,131 @@ cmp_diff_files_output () {
     test_cmp "$1" .test-tmp
 }
 
-test_expect_success \
-    'diff-tree of known trees.' \
-    'git diff-tree $tree_O $tree_A >.test-a &&
-     cmp -s .test-a .test-plain-OA'
-
-test_expect_success \
-    'diff-tree of known trees.' \
-    'git diff-tree -r $tree_O $tree_A >.test-a &&
-     cmp -s .test-a .test-recursive-OA'
-
-test_expect_success \
-    'diff-tree of known trees.' \
-    'git diff-tree $tree_O $tree_B >.test-a &&
-     cmp -s .test-a .test-plain-OB'
-
-test_expect_success \
-    'diff-tree of known trees.' \
-    'git diff-tree -r $tree_O $tree_B >.test-a &&
-     cmp -s .test-a .test-recursive-OB'
-
-test_expect_success \
-    'diff-tree of known trees.' \
-    'git diff-tree $tree_A $tree_B >.test-a &&
-     cmp -s .test-a .test-plain-AB'
-
-test_expect_success \
-    'diff-tree of known trees.' \
-    'git diff-tree -r $tree_A $tree_B >.test-a &&
-     cmp -s .test-a .test-recursive-AB'
-
-test_expect_success \
-    'diff-tree --stdin of known trees.' \
-    'echo $tree_A $tree_B | git diff-tree --stdin > .test-a &&
-     echo $tree_A $tree_B > .test-plain-ABx &&
-     cat .test-plain-AB >> .test-plain-ABx &&
-     cmp -s .test-a .test-plain-ABx'
-
-test_expect_success \
-    'diff-tree --stdin of known trees.' \
-    'echo $tree_A $tree_B | git diff-tree -r --stdin > .test-a &&
-     echo $tree_A $tree_B > .test-recursive-ABx &&
-     cat .test-recursive-AB >> .test-recursive-ABx &&
-     cmp -s .test-a .test-recursive-ABx'
-
-test_expect_success \
-    'diff-cache O with A in cache' \
-    'git read-tree $tree_A &&
-     git diff-index --cached $tree_O >.test-a &&
-     cmp -s .test-a .test-recursive-OA'
-
-test_expect_success \
-    'diff-cache O with B in cache' \
-    'git read-tree $tree_B &&
-     git diff-index --cached $tree_O >.test-a &&
-     cmp -s .test-a .test-recursive-OB'
-
-test_expect_success \
-    'diff-cache A with B in cache' \
-    'git read-tree $tree_B &&
-     git diff-index --cached $tree_A >.test-a &&
-     cmp -s .test-a .test-recursive-AB'
-
-test_expect_success \
-    'diff-files with O in cache and A checked out' \
-    'rm -fr Z [A-Z][A-Z] &&
-     git read-tree $tree_A &&
-     git checkout-index -f -a &&
-     git read-tree --reset $tree_O &&
-     test_must_fail git update-index --refresh -q &&
-     git diff-files >.test-a &&
-     cmp_diff_files_output .test-a .test-recursive-OA'
-
-test_expect_success \
-    'diff-files with O in cache and B checked out' \
-    'rm -fr Z [A-Z][A-Z] &&
-     git read-tree $tree_B &&
-     git checkout-index -f -a &&
-     git read-tree --reset $tree_O &&
-     test_must_fail git update-index --refresh -q &&
-     git diff-files >.test-a &&
-     cmp_diff_files_output .test-a .test-recursive-OB'
-
-test_expect_success \
-    'diff-files with A in cache and B checked out' \
-    'rm -fr Z [A-Z][A-Z] &&
-     git read-tree $tree_B &&
-     git checkout-index -f -a &&
-     git read-tree --reset $tree_A &&
-     test_must_fail git update-index --refresh -q &&
-     git diff-files >.test-a &&
-     cmp_diff_files_output .test-a .test-recursive-AB'
+test_expect_success 'diff-tree of known trees.' '
+       git diff-tree $tree_O $tree_A >.test-a &&
+       cmp -s .test-a .test-plain-OA
+'
+
+test_expect_success 'diff-tree of known trees.' '
+       git diff-tree -r $tree_O $tree_A >.test-a &&
+       cmp -s .test-a .test-recursive-OA
+'
+
+test_expect_success 'diff-tree of known trees.' '
+       git diff-tree $tree_O $tree_B >.test-a &&
+       cmp -s .test-a .test-plain-OB
+'
+
+test_expect_success 'diff-tree of known trees.' '
+       git diff-tree -r $tree_O $tree_B >.test-a &&
+       cmp -s .test-a .test-recursive-OB
+'
+
+test_expect_success 'diff-tree of known trees.' '
+       git diff-tree $tree_A $tree_B >.test-a &&
+       cmp -s .test-a .test-plain-AB
+'
+
+test_expect_success 'diff-tree of known trees.' '
+       git diff-tree -r $tree_A $tree_B >.test-a &&
+       cmp -s .test-a .test-recursive-AB
+'
+
+test_expect_success 'diff-tree --stdin of known trees.' '
+       echo $tree_A $tree_B | git diff-tree --stdin > .test-a &&
+       echo $tree_A $tree_B > .test-plain-ABx &&
+       cat .test-plain-AB >> .test-plain-ABx &&
+       cmp -s .test-a .test-plain-ABx
+'
+
+test_expect_success 'diff-tree --stdin of known trees.' '
+       echo $tree_A $tree_B | git diff-tree -r --stdin > .test-a &&
+       echo $tree_A $tree_B > .test-recursive-ABx &&
+       cat .test-recursive-AB >> .test-recursive-ABx &&
+       cmp -s .test-a .test-recursive-ABx
+'
+
+test_expect_success 'diff-cache O with A in cache' '
+       git read-tree $tree_A &&
+       git diff-index --cached $tree_O >.test-a &&
+       cmp -s .test-a .test-recursive-OA
+'
+
+test_expect_success 'diff-cache O with B in cache' '
+       git read-tree $tree_B &&
+       git diff-index --cached $tree_O >.test-a &&
+       cmp -s .test-a .test-recursive-OB
+'
+
+test_expect_success 'diff-cache A with B in cache' '
+       git read-tree $tree_B &&
+       git diff-index --cached $tree_A >.test-a &&
+       cmp -s .test-a .test-recursive-AB
+'
+
+test_expect_success 'diff-files with O in cache and A checked out' '
+       rm -fr Z [A-Z][A-Z] &&
+       git read-tree $tree_A &&
+       git checkout-index -f -a &&
+       git read-tree --reset $tree_O &&
+       test_must_fail git update-index --refresh -q &&
+       git diff-files >.test-a &&
+       cmp_diff_files_output .test-a .test-recursive-OA
+'
+
+test_expect_success 'diff-files with O in cache and B checked out' '
+       rm -fr Z [A-Z][A-Z] &&
+       git read-tree $tree_B &&
+       git checkout-index -f -a &&
+       git read-tree --reset $tree_O &&
+       test_must_fail git update-index --refresh -q &&
+       git diff-files >.test-a &&
+       cmp_diff_files_output .test-a .test-recursive-OB
+'
+
+test_expect_success 'diff-files with A in cache and B checked out' '
+       rm -fr Z [A-Z][A-Z] &&
+       git read-tree $tree_B &&
+       git checkout-index -f -a &&
+       git read-tree --reset $tree_A &&
+       test_must_fail git update-index --refresh -q &&
+       git diff-files >.test-a &&
+       cmp_diff_files_output .test-a .test-recursive-AB
+'
 
 ################################################################
 # Now we have established the baseline, we do not have to
 # rely on individual object ID values that much.
 
-test_expect_success \
-    'diff-tree O A == diff-tree -R A O' \
-    'git diff-tree $tree_O $tree_A >.test-a &&
-    git diff-tree -R $tree_A $tree_O >.test-b &&
-    cmp -s .test-a .test-b'
-
-test_expect_success \
-    'diff-tree -r O A == diff-tree -r -R A O' \
-    'git diff-tree -r $tree_O $tree_A >.test-a &&
-    git diff-tree -r -R $tree_A $tree_O >.test-b &&
-    cmp -s .test-a .test-b'
-
-test_expect_success \
-    'diff-tree B A == diff-tree -R A B' \
-    'git diff-tree $tree_B $tree_A >.test-a &&
-    git diff-tree -R $tree_A $tree_B >.test-b &&
-    cmp -s .test-a .test-b'
-
-test_expect_success \
-    'diff-tree -r B A == diff-tree -r -R A B' \
-    'git diff-tree -r $tree_B $tree_A >.test-a &&
-    git diff-tree -r -R $tree_A $tree_B >.test-b &&
-    cmp -s .test-a .test-b'
-
-test_expect_success \
-    'diff can read from stdin' \
-    'test_must_fail git diff --no-index -- MN - < NN |
-        grep -v "^index" | sed "s#/-#/NN#" >.test-a &&
-    test_must_fail git diff --no-index -- MN NN |
-        grep -v "^index" >.test-b &&
-    test_cmp .test-a .test-b'
+test_expect_success 'diff-tree O A == diff-tree -R A O' '
+       git diff-tree $tree_O $tree_A >.test-a &&
+       git diff-tree -R $tree_A $tree_O >.test-b &&
+       cmp -s .test-a .test-b
+'
+
+test_expect_success 'diff-tree -r O A == diff-tree -r -R A O' '
+       git diff-tree -r $tree_O $tree_A >.test-a &&
+       git diff-tree -r -R $tree_A $tree_O >.test-b &&
+       cmp -s .test-a .test-b
+'
+
+test_expect_success 'diff-tree B A == diff-tree -R A B' '
+       git diff-tree $tree_B $tree_A >.test-a &&
+       git diff-tree -R $tree_A $tree_B >.test-b &&
+       cmp -s .test-a .test-b
+'
+
+test_expect_success 'diff-tree -r B A == diff-tree -r -R A B' '
+       git diff-tree -r $tree_B $tree_A >.test-a &&
+       git diff-tree -r -R $tree_A $tree_B >.test-b &&
+       cmp -s .test-a .test-b'
+
+test_expect_success 'diff can read from stdin' '
+       test_must_fail git diff --no-index -- MN - < NN |
+               grep -v "^index" | sed "s#/-#/NN#" >.test-a &&
+       test_must_fail git diff --no-index -- MN NN |
+               grep -v "^index" >.test-b &&
+       test_cmp .test-a .test-b
+'
 
 test_done
index 181e9683a7955e18fcd149cd179c58c9f28d940a..ebe091828c878eb2d3ea3ab6f0f2e371e4d34329 100755 (executable)
@@ -11,20 +11,20 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash
 
-test_expect_success \
-    'prepare reference tree' \
-    'COPYING_test_data >COPYING &&
-     echo frotz >rezrov &&
-    git update-index --add COPYING rezrov &&
-    tree=$(git write-tree) &&
-    echo $tree'
-
-test_expect_success \
-    'prepare work tree' \
-    'sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
-    sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
-    rm -f COPYING &&
-    git update-index --add --remove COPYING COPYING.?'
+test_expect_success 'prepare reference tree' '
+       COPYING_test_data >COPYING &&
+       echo frotz >rezrov &&
+       git update-index --add COPYING rezrov &&
+       tree=$(git write-tree) &&
+       echo $tree
+'
+
+test_expect_success 'prepare work tree' '
+       sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
+       sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
+       rm -f COPYING &&
+       git update-index --add --remove COPYING COPYING.?
+'
 
 # tree has COPYING and rezrov.  work tree has COPYING.1 and COPYING.2,
 # both are slightly edited, and unchanged rezrov.  So we say you
@@ -57,14 +57,14 @@ rename to COPYING.2
 +      This file is licensed under the G.P.L v2, or a later version
 EOF
 
-test_expect_success \
-    'validate output from rename/copy detection (#1)' \
-    'compare_diff_patch current expected'
+test_expect_success 'validate output from rename/copy detection (#1)' '
+       compare_diff_patch current expected
+'
 
-test_expect_success \
-    'prepare work tree again' \
-    'mv COPYING.2 COPYING &&
-     git update-index --add --remove COPYING COPYING.1 COPYING.2'
+test_expect_success 'prepare work tree again' '
+       mv COPYING.2 COPYING &&
+       git update-index --add --remove COPYING COPYING.1 COPYING.2
+'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
 # both are slightly edited, and unchanged rezrov.  So we say you
@@ -95,14 +95,14 @@ copy to COPYING.1
 + However, in order to allow a migration to GPLv3 if that seems like
 EOF
 
-test_expect_success \
-    'validate output from rename/copy detection (#2)' \
-    'compare_diff_patch current expected'
+test_expect_success 'validate output from rename/copy detection (#2)' '
+       compare_diff_patch current expected
+'
 
-test_expect_success \
-    'prepare work tree once again' \
-    'COPYING_test_data >COPYING &&
-     git update-index --add --remove COPYING COPYING.1'
+test_expect_success 'prepare work tree once again' '
+       COPYING_test_data >COPYING &&
+       git update-index --add --remove COPYING COPYING.1
+'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
 # but COPYING is not edited.  We say you copy-and-edit COPYING.1; this
@@ -123,8 +123,8 @@ copy to COPYING.1
 + However, in order to allow a migration to GPLv3 if that seems like
 EOF
 
-test_expect_success \
-    'validate output from rename/copy detection (#3)' \
-    'compare_diff_patch current expected'
+test_expect_success 'validate output from rename/copy detection (#3)' '
+       compare_diff_patch current expected
+'
 
 test_done
index 8def4d4aee9d2f2b39469fd550020fedab1d0ee7..1d70d4d221b7536c430852e9014c9372743a4a2a 100755 (executable)
@@ -14,21 +14,21 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
-test_expect_success SYMLINKS \
-    'prepare reference tree' \
-    'echo xyzzy | tr -d '\\\\'012 >yomin &&
-     ln -s xyzzy frotz &&
-    git update-index --add frotz yomin &&
-    tree=$(git write-tree) &&
-    echo $tree'
+test_expect_success SYMLINKS 'prepare reference tree' '
+       echo xyzzy | tr -d '\\\\'012 >yomin &&
+       ln -s xyzzy frotz &&
+       git update-index --add frotz yomin &&
+       tree=$(git write-tree) &&
+       echo $tree
+'
 
-test_expect_success SYMLINKS \
-    'prepare work tree' \
-    'mv frotz rezrov &&
-     rm -f yomin &&
-     ln -s xyzzy nitfol &&
-     ln -s xzzzy bozbar &&
-    git update-index --add --remove frotz rezrov nitfol bozbar yomin'
+test_expect_success SYMLINKS 'prepare work tree' '
+       mv frotz rezrov &&
+       rm -f yomin &&
+       ln -s xyzzy nitfol &&
+       ln -s xzzzy bozbar &&
+       git update-index --add --remove frotz rezrov nitfol bozbar yomin
+'
 
 # tree has frotz pointing at xyzzy, and yomin that contains xyzzy to
 # confuse things.  work tree has rezrov (xyzzy) nitfol (xyzzy) and
@@ -36,9 +36,9 @@ test_expect_success SYMLINKS \
 # rezrov and nitfol are rename/copy of frotz and bozbar should be
 # a new creation.
 
-test_expect_success SYMLINKS 'setup diff output' "
-    GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current &&
-    cat >expected <<\EOF
+test_expect_success SYMLINKS 'setup diff output' '
+       GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current &&
+       cat >expected <<\EOF
 diff --git a/bozbar b/bozbar
 new file mode 120000
 --- /dev/null
@@ -62,10 +62,10 @@ deleted file mode 100644
 -xyzzy
 \ No newline at end of file
 EOF
-"
+'
 
-test_expect_success SYMLINKS \
-    'validate diff output' \
-    'compare_diff_patch current expected'
+test_expect_success SYMLINKS 'validate diff output' '
+       compare_diff_patch current expected
+'
 
 test_done
index 5de1d190759f958f8c3c0319f7b4cca34f39d83c..4b474808311e3e654258445128acaacb7b988240 100755 (executable)
@@ -473,6 +473,14 @@ test_expect_success 'log --diff-merges=on matches --diff-merges=separate' '
        test_cmp expected actual
 '
 
+test_expect_success 'log --dd matches --diff-merges=1 -p' '
+       git log --diff-merges=1 -p master >result &&
+       process_diffs result >expected &&
+       git log --dd master >result &&
+       process_diffs result >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'deny wrong log.diffMerges config' '
        test_config log.diffMerges wrong-value &&
        test_expect_code 128 git log
index 3cf2b7a7fb70ec272d9f12294a26e2a1685c5999..0a4ab36c3aff97bc4fac0a38df9f6222ad50a0ce 100755 (executable)
@@ -1373,7 +1373,27 @@ test_expect_success '--rfc' '
        Subject: [RFC PATCH 1/1] header with . in it
        EOF
        git format-patch -n -1 --stdout --rfc >patch &&
-       grep ^Subject: patch >actual &&
+       grep "^Subject:" patch >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--rfc does not overwrite prefix' '
+       cat >expect <<-\EOF &&
+       Subject: [RFC PATCH foobar 1/1] header with . in it
+       EOF
+       git -c format.subjectPrefix="PATCH foobar" \
+               format-patch -n -1 --stdout --rfc >patch &&
+       grep "^Subject:" patch >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--rfc is argument order independent' '
+       cat >expect <<-\EOF &&
+       Subject: [RFC PATCH foobar 1/1] header with . in it
+       EOF
+       git format-patch -n -1 --stdout --rfc \
+               --subject-prefix="PATCH foobar" >patch &&
+       grep "^Subject:" patch >actual &&
        test_cmp expect actual
 '
 
@@ -1991,6 +2011,20 @@ test_expect_success 'cover letter using branch description (6)' '
        grep hello actual
 '
 
+test_expect_success 'cover letter with --description-file' '
+       test_when_finished "rm -f description.txt" &&
+       cat >description.txt <<-\EOF &&
+       subject from file
+
+       body from file
+       EOF
+       git checkout rebuild-1 &&
+       git format-patch --stdout --cover-letter --cover-from-description auto \
+               --description-file description.txt main >actual &&
+       grep "^Subject: \[PATCH 0/2\] subject from file$" actual &&
+       grep "^body from file$" actual
+'
+
 test_expect_success 'cover letter with nothing' '
        git format-patch --stdout --cover-letter >actual &&
        test_line_count = 0 actual
index b298f220e01fe6de17a5dfe608550a5a57dcf9c6..fcd2473e5290dc5a25d643e6af139378fe7ebdc5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # Copyright (c) 2006 Johannes E. Schindelin
-#
+# Copyright (c) 2023 Google LLC
 
 test_description='Test special whitespace in diff engine.
 
@@ -11,6 +11,43 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \
+              --raw! --name-only! --name-status!
+do
+       opts=${opt_res%!} expect_failure=
+       test "$opts" = "$opt_res" ||
+               expect_failure="test_expect_code 1"
+
+       test_expect_success "status with $opts (different)" '
+               echo foo >x &&
+               git add x &&
+               echo bar >x &&
+               test_expect_code 1 git diff -w $opts --exit-code x
+       '
+
+       test_expect_success POSIXPERM "status with $opts (mode differs)" '
+               test_when_finished "git update-index --chmod=-x x" &&
+               echo foo >x &&
+               git add x &&
+               git update-index --chmod=+x x &&
+               test_expect_code 1 git diff -w $opts --exit-code x
+       '
+
+       test_expect_success "status with $opts (removing an empty file)" '
+               : >x &&
+               git add x &&
+               rm x &&
+               test_expect_code 1 git diff -w $opts --exit-code -- x
+       '
+
+       test_expect_success "status with $opts (different but equivalent)" '
+               echo foo >x &&
+               git add x &&
+               echo " foo" >x &&
+               $expect_failure git diff -w $opts --exit-code x
+       '
+done
+
 test_expect_success "Ray Lehtiniemi's example" '
        cat <<-\EOF >x &&
        do {
index 5bc28ad9f042a0476d94d9e90e5b58073cc17f99..f439f469bd2bfd3942a61e104fd290d8e3461e19 100755 (executable)
@@ -138,4 +138,9 @@ test_expect_success 'check honors conflict marker length' '
        git reset --hard
 '
 
+test_expect_success 'option errors are not confused by --exit-code' '
+       test_must_fail git diff --exit-code --nonsense 2>err &&
+       grep '^usage:' err
+'
+
 test_done
index e70e020ae9349c378b4b922933668932e95acc8d..eec3d73dc2b475be7185d9d1dc8733bf391a868b 100755 (executable)
@@ -28,8 +28,7 @@ test_expect_success 'diff-tree --exit-code' '
 
 test_expect_success 'diff-tree -b --exit-code' '
        git diff -b --exit-code HEAD^ HEAD &&
-       git diff-tree -b -p --exit-code HEAD^ HEAD &&
-       git diff-tree -b --exit-code HEAD^ HEAD
+       git diff-tree -b -p --exit-code HEAD^ HEAD
 '
 
 test_expect_success 'diff-index --cached --exit-code' '
index 3ee27e277dca1cd95484ec9ef3b1251e38b22dde..7badd72488d664ff776e1004f620df1fbc774cdc 100755 (executable)
@@ -12,7 +12,7 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-# 120 character name
+# 120-character name
 name=aaaaaaaaaa
 name=$name$name$name$name$name$name$name$name$name$name$name$name
 test_expect_success 'preparation' '
@@ -49,12 +49,41 @@ log -1 --stat
 EOF
 
 cat >expect.60 <<-'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
 EOF
 cat >expect.6030 <<-'EOF'
  ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
 EOF
-cat >expect2.60 <<-'EOF'
+while read verb expect cmd args
+do
+       # No width limit applied when statNameWidth is ignored
+       case "$expect" in expect72|expect.6030)
+               test_expect_success "$cmd $verb diff.statNameWidth with long name" '
+                       git -c diff.statNameWidth=30 $cmd $args >output &&
+                       grep " | " output >actual &&
+                       test_cmp $expect actual
+               ';;
+       esac
+       # Maximum width limit still applied when statNameWidth is ignored
+       case "$expect" in expect.60|expect.6030)
+               test_expect_success "$cmd --stat=width $verb diff.statNameWidth with long name" '
+                       git -c diff.statNameWidth=30 $cmd $args --stat=60 >output &&
+                       grep " | " output >actual &&
+                       test_cmp $expect actual
+               ';;
+       esac
+done <<\EOF
+ignores expect72 format-patch -1 --stdout
+ignores expect.60 format-patch -1 --stdout
+respects expect.6030 diff HEAD^ HEAD --stat
+respects expect.6030 show --stat
+respects expect.6030 log -1 --stat
+EOF
+
+cat >expect.40 <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+EOF
+cat >expect2.40 <<-'EOF'
  ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
  ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
 EOF
@@ -67,22 +96,22 @@ do
        test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" '
                git $cmd $args --stat=40 >output &&
                grep " | " output >actual &&
-               test_cmp $expect.60 actual
+               test_cmp $expect.40 actual
        '
 
        test_expect_success "$cmd --stat-width=width with long name" '
                git $cmd $args --stat-width=40 >output &&
                grep " | " output >actual &&
-               test_cmp $expect.60 actual
+               test_cmp $expect.40 actual
        '
 
-       test_expect_success "$cmd --stat=...,name-width with long name" '
+       test_expect_success "$cmd --stat=width,name-width with long name" '
                git $cmd $args --stat=60,30 >output &&
                grep " | " output >actual &&
                test_cmp $expect.6030 actual
        '
 
-       test_expect_success "$cmd --stat-name-width with long name" '
+       test_expect_success "$cmd --stat-name-width=width with long name" '
                git $cmd $args --stat-name-width=30 >output &&
                grep " | " output >actual &&
                test_cmp $expect.6030 actual
@@ -94,8 +123,7 @@ expect show --stat
 expect log -1 --stat
 EOF
 
-
-test_expect_success 'preparation for big change tests' '
+test_expect_success 'preparation for big-change tests' '
        >abcd &&
        git add abcd &&
        git commit -m message &&
@@ -111,7 +139,7 @@ cat >expect72 <<'EOF'
  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 EOF
-test_expect_success "format-patch --cover-letter ignores COLUMNS (big change)" '
+test_expect_success "format-patch --cover-letter ignores COLUMNS with big change" '
        COLUMNS=200 git format-patch -1 --stdout --cover-letter >output &&
        grep " | " output >actual &&
        test_cmp expect72 actual
@@ -131,7 +159,7 @@ cat >expect200-graph <<'EOF'
 EOF
 while read verb expect cmd args
 do
-       test_expect_success "$cmd $verb COLUMNS (big change)" '
+       test_expect_success "$cmd $verb COLUMNS with big change" '
                COLUMNS=200 git $cmd $args >output &&
                grep " | " output >actual &&
                test_cmp "$expect" actual
@@ -139,7 +167,7 @@ do
 
        case "$cmd" in diff|show) continue;; esac
 
-       test_expect_success "$cmd --graph $verb COLUMNS (big change)" '
+       test_expect_success "$cmd --graph $verb COLUMNS with big change" '
                COLUMNS=200 git $cmd $args --graph >output &&
                grep " | " output >actual &&
                test_cmp "$expect-graph" actual
@@ -159,7 +187,7 @@ cat >expect40-graph <<'EOF'
 EOF
 while read verb expect cmd args
 do
-       test_expect_success "$cmd $verb not enough COLUMNS (big change)" '
+       test_expect_success "$cmd $verb not enough COLUMNS with big change" '
                COLUMNS=40 git $cmd $args >output &&
                grep " | " output >actual &&
                test_cmp "$expect" actual
@@ -167,7 +195,7 @@ do
 
        case "$cmd" in diff|show) continue;; esac
 
-       test_expect_success "$cmd --graph $verb not enough COLUMNS (big change)" '
+       test_expect_success "$cmd --graph $verb not enough COLUMNS with big change" '
                COLUMNS=40 git $cmd $args --graph >output &&
                grep " | " output >actual &&
                test_cmp "$expect-graph" actual
@@ -187,7 +215,7 @@ cat >expect40-graph <<'EOF'
 EOF
 while read verb expect cmd args
 do
-       test_expect_success "$cmd $verb statGraphWidth config" '
+       test_expect_success "$cmd $verb diff.statGraphWidth" '
                git -c diff.statGraphWidth=26 $cmd $args >output &&
                grep " | " output >actual &&
                test_cmp "$expect" actual
@@ -195,7 +223,7 @@ do
 
        case "$cmd" in diff|show) continue;; esac
 
-       test_expect_success "$cmd --graph $verb statGraphWidth config" '
+       test_expect_success "$cmd --graph $verb diff.statGraphWidth" '
                git -c diff.statGraphWidth=26 $cmd $args --graph >output &&
                grep " | " output >actual &&
                test_cmp "$expect-graph" actual
@@ -207,7 +235,6 @@ respects expect40 show --stat
 respects expect40 log -1 --stat
 EOF
 
-
 cat >expect <<'EOF'
  abcd | 1000 ++++++++++++++++++++++++++
 EOF
@@ -228,7 +255,7 @@ do
                test_cmp expect actual
        '
 
-       test_expect_success "$cmd --stat-graph-width with big change" '
+       test_expect_success "$cmd --stat-graph-width=width with big change" '
                git $cmd $args --stat-graph-width=26 >output &&
                grep " | " output >actual &&
                test_cmp expect actual
@@ -242,7 +269,7 @@ do
                test_cmp expect-graph actual
        '
 
-       test_expect_success "$cmd --stat-graph-width --graph with big change" '
+       test_expect_success "$cmd --stat-graph-width=width --graph with big change" '
                git $cmd $args --stat-graph-width=26 --graph >output &&
                grep " | " output >actual &&
                test_cmp expect-graph actual
@@ -254,7 +281,7 @@ show --stat
 log -1 --stat
 EOF
 
-test_expect_success 'preparation for long filename tests' '
+test_expect_success 'preparation for long-name tests' '
        cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
        git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
        git commit -m message
@@ -302,7 +329,7 @@ cat >expect200-graph <<'EOF'
 EOF
 while read verb expect cmd args
 do
-       test_expect_success "$cmd $verb COLUMNS (long filename)" '
+       test_expect_success "$cmd $verb COLUMNS with long name" '
                COLUMNS=200 git $cmd $args >output &&
                grep " | " output >actual &&
                test_cmp "$expect" actual
@@ -310,7 +337,7 @@ do
 
        case "$cmd" in diff|show) continue;; esac
 
-       test_expect_success "$cmd --graph $verb COLUMNS (long filename)" '
+       test_expect_success "$cmd --graph $verb COLUMNS with long name" '
                COLUMNS=200 git $cmd $args --graph >output &&
                grep " | " output >actual &&
                test_cmp "$expect-graph" actual
@@ -331,7 +358,7 @@ EOF
 while read verb expect cmd args
 do
        test_expect_success COLUMNS_CAN_BE_1 \
-               "$cmd $verb prefix greater than COLUMNS (big change)" '
+               "$cmd $verb prefix greater than COLUMNS with big change" '
                COLUMNS=1 git $cmd $args >output &&
                grep " | " output >actual &&
                test_cmp "$expect" actual
@@ -340,7 +367,7 @@ do
        case "$cmd" in diff|show) continue;; esac
 
        test_expect_success COLUMNS_CAN_BE_1 \
-               "$cmd --graph $verb prefix greater than COLUMNS (big change)" '
+               "$cmd --graph $verb prefix greater than COLUMNS with big change" '
                COLUMNS=1 git $cmd $args --graph >output &&
                grep " | " output >actual &&
                test_cmp "$expect-graph" actual
@@ -355,8 +382,14 @@ EOF
 cat >expect <<'EOF'
  abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 EOF
-test_expect_success 'merge --stat respects COLUMNS (big change)' '
-       git checkout -b branch HEAD^^ &&
+test_expect_success 'merge --stat respects diff.statGraphWidth with big change' '
+       git checkout -b branch1 HEAD^^ &&
+       git -c diff.statGraphWidth=26 merge --stat --no-ff main^ >output &&
+       grep " | " output >actual &&
+       test_cmp expect40 actual
+'
+test_expect_success 'merge --stat respects COLUMNS with big change' '
+       git checkout -b branch2 HEAD^^ &&
        COLUMNS=100 git merge --stat --no-ff main^ >output &&
        grep " | " output >actual &&
        test_cmp expect actual
@@ -365,7 +398,17 @@ test_expect_success 'merge --stat respects COLUMNS (big change)' '
 cat >expect <<'EOF'
  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++
 EOF
-test_expect_success 'merge --stat respects COLUMNS (long filename)' '
+cat >expect.30 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++++++++++++++++++++++
+EOF
+test_expect_success 'merge --stat respects diff.statNameWidth with long name' '
+       git switch branch1 &&
+       git -c diff.statNameWidth=30 merge --stat --no-ff main >output &&
+       grep " | " output >actual &&
+       test_cmp expect.30 actual
+'
+test_expect_success 'merge --stat respects COLUMNS with long name' '
+       git switch branch2 &&
        COLUMNS=100 git merge --stat --no-ff main >output &&
        grep " | " output >actual &&
        test_cmp expect actual
index 4e9fa0403d3631fdeafd0e90e3ae80894930c2e9..5f059f65fced87fd0c25400cec0ed1a50b24edb4 100755 (executable)
@@ -205,4 +205,83 @@ test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not lik
        test_cmp expected actual
 '
 
+test_expect_success "diff --no-index treats '-' as stdin" '
+       cat >expect <<-EOF &&
+       diff --git a/- b/a/1
+       index $ZERO_OID..$(git hash-object --stdin <a/1) 100644
+       --- a/-
+       +++ b/a/1
+       @@ -1 +1 @@
+       -x
+       +1
+       EOF
+
+       test_write_lines x | test_expect_code 1 \
+               git -c core.abbrev=no diff --no-index -- - a/1 >actual &&
+       test_cmp expect actual &&
+
+       test_write_lines 1 | git diff --no-index -- a/1 - >actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success "diff --no-index -R treats '-' as stdin" '
+       cat >expect <<-EOF &&
+       diff --git b/a/1 a/-
+       index $(git hash-object --stdin <a/1)..$ZERO_OID 100644
+       --- b/a/1
+       +++ a/-
+       @@ -1 +1 @@
+       -1
+       +x
+       EOF
+
+       test_write_lines x | test_expect_code 1 \
+               git -c core.abbrev=no diff --no-index -R -- - a/1 >actual &&
+       test_cmp expect actual &&
+
+       test_write_lines 1 | git diff --no-index -R -- a/1 - >actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success 'diff --no-index refuses to diff stdin and a directory' '
+       test_must_fail git diff --no-index -- - a </dev/null 2>err &&
+       grep "fatal: cannot compare stdin to a directory" err
+'
+
+test_expect_success PIPE 'diff --no-index refuses to diff a named pipe and a directory' '
+       test_when_finished "rm -f pipe" &&
+       mkfifo pipe &&
+       test_must_fail git diff --no-index -- pipe a 2>err &&
+       grep "fatal: cannot compare a named pipe to a directory" err
+'
+
+test_expect_success PIPE,SYMLINKS 'diff --no-index reads from pipes' '
+       test_when_finished "rm -f old new new-link" &&
+       mkfifo old &&
+       mkfifo new &&
+       ln -s new new-link &&
+       {
+               (test_write_lines a b c >old) &
+       } &&
+       test_when_finished "kill $! || :" &&
+       {
+               (test_write_lines a x c >new) &
+       } &&
+       test_when_finished "kill $! || :" &&
+
+       cat >expect <<-EOF &&
+       diff --git a/old b/new-link
+       --- a/old
+       +++ b/new-link
+       @@ -1,3 +1,3 @@
+        a
+       -b
+       +x
+        c
+       EOF
+
+       test_expect_code 1 git diff --no-index old new-link >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 2d650d8f1032ca7c113fa0f48c72719fb08ab245..541642650f533816ae8ea6490141893cbc111ce4 100755 (executable)
@@ -34,7 +34,7 @@ test_expect_success setup '
        echo c >c &&
        git add c &&
        git commit -m C &&
-       git tag commit-C &&
+       git tag -m commit-C commit-C &&
        git merge -m D main &&
        git tag commit-D &&
        git checkout main &&
@@ -109,6 +109,13 @@ do
                test_cmp expect actual
        '
 
+       test_expect_success "$cmd --merge-base with annotated tag" '
+               git checkout main &&
+               git $cmd commit-C >expect &&
+               git $cmd --merge-base commit-C >actual &&
+               test_cmp expect actual
+       '
+
        test_expect_success "$cmd --merge-base with one commit and unstaged changes" '
                git checkout main &&
                test_when_finished git reset --hard &&
@@ -143,7 +150,7 @@ do
        test_expect_success "$cmd --merge-base with non-commit" '
                git checkout main &&
                test_must_fail git $cmd --merge-base main^{tree} 2>err &&
-               test_i18ngrep "fatal: --merge-base only works with commits" err
+               test_i18ngrep "is a tree, not a commit" err
        '
 
        test_expect_success "$cmd --merge-base with no merge bases and one commit" '
@@ -169,7 +176,7 @@ do
 
        test_expect_success "$cmd --merge-base commit and non-commit" '
                test_must_fail git $cmd --merge-base br2 main^{tree} 2>err &&
-               test_i18ngrep "fatal: --merge-base only works with commits" err
+               test_i18ngrep "is a tree, not a commit" err
        '
 
        test_expect_success "$cmd --merge-base with no merge bases and two commits" '
index 58742d4fc5d5208808004cc17eb566abbf385461..20cc1209f6259c703fc3ed3e9c193be24b429a3f 100755 (executable)
@@ -17,7 +17,7 @@ test_expect_success EXPENSIVE 'git apply rejects patches that are too large' '
                EOF
                test-tool genzeros
        } | test_copy_bytes $sz | test_must_fail git apply 2>err &&
-       grep "git apply: failed to read" err
+       grep "patch too large" err
 '
 
 test_done
index ae73aef922f950f9a289085a5417c84654bbcd8f..af4a123cd223ef5a3cdff9c97cf6af35abe53854 100755 (executable)
@@ -187,6 +187,21 @@ test_expect_success 'git config log.follow does not die with no paths' '
        git log --
 '
 
+test_expect_success 'git log --follow rejects unsupported pathspec magic' '
+       test_must_fail git log --follow ":(top,glob,icase)ichi" 2>stderr &&
+       # check full error message; we want to be sure we mention both
+       # of the rejected types (glob,icase), but not the allowed one (top)
+       echo "fatal: pathspec magic not supported by --follow: ${SQ}glob${SQ}, ${SQ}icase${SQ}" >expect &&
+       test_cmp expect stderr
+'
+
+test_expect_success 'log.follow disabled with unsupported pathspec magic' '
+       test_config log.follow true &&
+       git log --format=%s ":(glob,icase)ichi" >actual &&
+       echo third >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git config log.follow is overridden by --no-follow' '
        test_config log.follow true &&
        git log --no-follow --pretty="format:%s" ichi >actual &&
@@ -2343,10 +2358,10 @@ test_expect_success 'log --decorate does not include things outside filter' '
 '
 
 test_expect_success 'log --end-of-options' '
-       git update-ref refs/heads/--source HEAD &&
-       git log --end-of-options --source >actual &&
-       git log >expect &&
-       test_cmp expect actual
+       git update-ref refs/heads/--source HEAD &&
+       git log --end-of-options --source >actual &&
+       git log >expect &&
+       test_cmp expect actual
 '
 
 test_expect_success 'set up commits with different authors' '
index fa7f987284b117607fa051c91dd439749da546d4..2016132f5161743018a09a663224806a93496730 100755 (executable)
@@ -466,7 +466,7 @@ test_expect_success 'gitmailmap(5) example output: example #1' '
        Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@laptop.(none)>
        Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
 
-       Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)>
+       Author Jane D. <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)>
        Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
        EOF
        git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
@@ -494,7 +494,7 @@ test_expect_success 'gitmailmap(5) example output: example #2' '
        Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@example.com>
        Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
 
-       Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@example.com>
+       Author Jane D. <jane@desktop.(none)> maps to Jane Doe <jane@example.com>
        Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
        EOF
        git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
index 4cf8a7766768bfed03c7016ffdf70c10802c0708..e3d655e6b8b5565d619298b16da010ee671667a2 100755 (executable)
@@ -576,6 +576,38 @@ test_expect_success 'clean log decoration' '
        test_cmp expected actual1
 '
 
+test_expect_success 'pretty format %decorate' '
+       git checkout -b foo &&
+       git commit --allow-empty -m "new commit" &&
+       git tag bar &&
+       git branch qux &&
+
+       echo " (HEAD -> foo, tag: bar, qux)" >expect1 &&
+       git log --format="%(decorate)" -1 >actual1 &&
+       test_cmp expect1 actual1 &&
+
+       echo "HEAD -> foo, tag: bar, qux" >expect2 &&
+       git log --format="%(decorate:prefix=,suffix=)" -1 >actual2 &&
+       test_cmp expect2 actual2 &&
+
+       echo "[ bar; qux; foo ]" >expect3 &&
+       git log --format="%(decorate:prefix=[ ,suffix= ],separator=%x3B ,tag=)" \
+               --decorate-refs=refs/ -1 >actual3 &&
+       test_cmp expect3 actual3 &&
+
+       # Try with a typo (in "separator"), in which case the placeholder should
+       # not be replaced.
+       echo "%(decorate:prefix=[ ,suffix= ],separater=; )" >expect4 &&
+       git log --format="%(decorate:prefix=[ ,suffix= ],separater=%x3B )" \
+               -1 >actual4 &&
+       test_cmp expect4 actual4 &&
+
+       echo "HEAD->foo bar qux" >expect5 &&
+       git log --format="%(decorate:prefix=,suffix=,separator= ,tag=,pointer=->)" \
+               -1 >actual5 &&
+       test_cmp expect5 actual5
+'
+
 cat >trailers <<EOF
 Signed-off-by: A U Thor <author@example.com>
 Acked-by: A U Thor <author@example.com>
@@ -924,6 +956,36 @@ test_expect_success '%S in git log --format works with other placeholders (part
        test_cmp expect actual
 '
 
+test_expect_success 'setup more commits for %S with --bisect' '
+       test_commit four &&
+       test_commit five &&
+
+       head1=$(git rev-parse --verify HEAD~0) &&
+       head2=$(git rev-parse --verify HEAD~1) &&
+       head3=$(git rev-parse --verify HEAD~2) &&
+       head4=$(git rev-parse --verify HEAD~3)
+'
+
+test_expect_success '%S with --bisect labels commits with refs/bisect/bad ref' '
+       git update-ref refs/bisect/bad-$head1 $head1 &&
+       git update-ref refs/bisect/go $head1 &&
+       git update-ref refs/bisect/bad-$head2 $head2 &&
+       git update-ref refs/bisect/b $head3 &&
+       git update-ref refs/bisect/bad-$head4 $head4 &&
+       git update-ref refs/bisect/good-$head4 $head4 &&
+
+       # We expect to see the range of commits betwee refs/bisect/good-$head4
+       # and refs/bisect/bad-$head1. The "source" ref is the nearest bisect ref
+       # from which the commit is reachable.
+       cat >expect <<-EOF &&
+       $head1 refs/bisect/bad-$head1
+       $head2 refs/bisect/bad-$head2
+       $head3 refs/bisect/bad-$head2
+       EOF
+       git log --bisect --format="%H %S" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'log --pretty=reference' '
        git log --pretty="tformat:%h (%s, %as)" >expect &&
        git log --pretty=reference >actual &&
@@ -1012,10 +1074,25 @@ test_expect_success '%(describe:tags) vs git describe --tags' '
 
 test_expect_success '%(describe:abbrev=...) vs git describe --abbrev=...' '
        test_when_finished "git tag -d tagname" &&
+
+       # Case 1: We have commits between HEAD and the most recent tag
+       #         reachable from it
+       test_commit --no-tag file &&
+       git describe --abbrev=15 >expect &&
+       git log -1 --format="%(describe:abbrev=15)" >actual &&
+       test_cmp expect actual &&
+
+       # Make sure the hash used is at least 15 digits long
+       sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
+       test 16 -le $(wc -c <hexpart) &&
+
+       # Case 2: We have a tag at HEAD, describe directly gives the
+       #         name of the tag
        git tag -a -m tagged tagname &&
        git describe --abbrev=15 >expect &&
        git log -1 --format="%(describe:abbrev=15)" >actual &&
-       test_cmp expect actual
+       test_cmp expect actual &&
+       test tagname = $(cat actual)
 '
 
 test_expect_success 'log --pretty with space stealing' '
index 33ecf82c7f98d3b9fb59422e614eb47cfe54fecb..9167b0351f221205cf2700a318b8041513e34248 100755 (executable)
@@ -16,29 +16,29 @@ Line 2
 Line 3
 '
 
-test_expect_success \
-    'add a file path0 and commit.' \
-    'git add path0 &&
-     git commit -m "Add path0"'
+test_expect_success 'add a file path0 and commit.' '
+       git add path0 &&
+       git commit -m "Add path0"
+'
 
 echo >path0 'New line 1
 New line 2
 New line 3
 '
-test_expect_success \
-    'Change path0.' \
-    'git add path0 &&
-     git commit -m "Change path0"'
+test_expect_success 'Change path0.' '
+       git add path0 &&
+       git commit -m "Change path0"
+'
 
 cat <path0 >path1
-test_expect_success \
-    'copy path0 to path1.' \
-    'git add path1 &&
-     git commit -m "Copy path1 from path0"'
+test_expect_success 'copy path0 to path1.' '
+       git add path1 &&
+       git commit -m "Copy path1 from path0"
+'
 
-test_expect_success \
-    'find the copy path0 -> path1 harder' \
-    'git log --follow --name-status --pretty="format:%s"  path1 > current'
+test_expect_success 'find the copy path0 -> path1 harder' '
+       git log --follow --name-status --pretty="format:%s"  path1 > current
+'
 
 cat >expected <<\EOF
 Copy path1 from path0
@@ -51,8 +51,8 @@ Add path0
 A      path0
 EOF
 
-test_expect_success \
-    'validate the output.' \
-    'compare_diff_patch current expected'
+test_expect_success 'validate the output.' '
+       compare_diff_patch current expected
+'
 
 test_done
index ded33a82e2c94cd4f44c1df4c9fe93ce9bf5f148..21986a866df65c9ed9025f7ab48dc596e6df81ca 100755 (executable)
@@ -53,15 +53,17 @@ cmp_filtered_decorations () {
 # to this test since it does not contain any decoration, hence --first-parent
 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_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\
+${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_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
+       ${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: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
        EOF
 
        git log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&
@@ -76,12 +78,14 @@ test_expect_success 'test coloring with replace-objects' '
        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_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\
+${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_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
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
 EOF
 
        git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
@@ -100,13 +104,15 @@ test_expect_success 'test coloring with grafted commit' '
        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_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\
+${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_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
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
+       ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
        EOF
 
        git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
index f70c46bbbfa2c8fc9cc5ca1b620c9a80f29e382e..79055978690962fc3b58cd754a9383a88148f0f9 100755 (executable)
@@ -5,6 +5,7 @@ test_description='git log --graph of skewed left octopus merge.'
 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-log-graph.sh
 
index 28d0779a8c599ee9eab9b0b31afe1a57bb558c28..b877ac723516dc710fd42c17b65877d795d874ff 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git log --graph of skewed merges'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-log-graph.sh
 
index fa9d32facfb0ddca6c001d78c1011cf0b3568f19..2ba0324a693731412242cf9603826736a3c9279a 100755 (executable)
@@ -5,6 +5,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
 
 GIT_TEST_COMMIT_GRAPH=0
 GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
@@ -404,4 +405,53 @@ test_expect_success 'Bloom generation backfills empty commits' '
        )
 '
 
+corrupt_graph () {
+       graph=.git/objects/info/commit-graph &&
+       test_when_finished "rm -rf $graph" &&
+       git commit-graph write --reachable --changed-paths &&
+       corrupt_chunk_file $graph "$@"
+}
+
+check_corrupt_graph () {
+       corrupt_graph "$@" &&
+       git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
+       git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
+       test_cmp expect.out out
+}
+
+test_expect_success 'Bloom reader notices too-small data chunk' '
+       check_corrupt_graph BDAT clear 00000000 &&
+       echo "warning: ignoring too-small changed-path chunk" \
+               "(4 < 12) in commit-graph file" >expect.err &&
+       test_cmp expect.err err
+'
+
+test_expect_success 'Bloom reader notices out-of-bounds filter offsets' '
+       check_corrupt_graph BIDX 12 FFFFFFFF &&
+       # use grep to avoid depending on exact chunk size
+       grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
+'
+
+test_expect_success 'Bloom reader notices too-small index chunk' '
+       # replace the index with a single entry, making most
+       # lookups out-of-bounds
+       check_corrupt_graph BIDX clear 00000000 &&
+       echo "warning: commit-graph changed-path index chunk" \
+               "is too small" >expect.err &&
+       test_cmp expect.err err
+'
+
+test_expect_success 'Bloom reader notices out-of-order index offsets' '
+       # we do not know any real offsets, but we can pick
+       # something plausible; we should not get to the point of
+       # actually reading from the bogus offsets anyway.
+       corrupt_graph BIDX 4 0000000c00000005 &&
+       echo "warning: ignoring decreasing changed-path index offsets" \
+               "(12 > 5) for positions 1 and 2 of .git/objects/info/commit-graph" >expect.err &&
+       git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
+       git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
+       test_cmp expect.out out &&
+       test_cmp expect.err err
+'
+
 test_done
index 6e01e2629c1b158464ab29e4086fb4eeea16bbaa..613f0710e90511c6419e843eec3cb4d11aafc437 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git log with filter options limiting the output'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup test' '
index 57c4f26e4613a97644ad5822b1f6a0c4572a33a4..9c197260d5bbf54d3ad578c27f54e278d88ab97b 100755 (executable)
@@ -86,6 +86,33 @@ EXPECTED
        test_cmp expected actual
 '
 
+test_expect_success '3-way merge with --attr-source' '
+       test_when_finished rm -rf 3-way &&
+       git init 3-way &&
+       (
+               cd 3-way &&
+               test_commit initial file1 foo &&
+               base=$(git rev-parse HEAD) &&
+               git checkout -b brancha &&
+               echo bar >>file1 &&
+               git commit -am "adding bar" &&
+               source=$(git rev-parse HEAD) &&
+               git checkout @{-1} &&
+               git checkout -b branchb &&
+               echo baz >>file1 &&
+               git commit -am "adding baz" &&
+               merge=$(git rev-parse HEAD) &&
+               git checkout -b gitattributes &&
+               test_commit "gitattributes" .gitattributes "file1 merge=union" &&
+               git checkout @{-1} &&
+               tree=$(git --attr-source=gitattributes merge-tree --write-tree \
+               --merge-base "$base" --end-of-options "$source" "$merge") &&
+               test_write_lines foo bar baz >expect &&
+               git cat-file -p "$tree:file1" >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_expect_success 'file change A, B (same)' '
        git reset --hard initial &&
        test_commit "change-a-b-same-A" "initial-file" "AAA" &&
index 250f721795b5bd2ecba3090b7e181c50673540aa..b2c8a43fce311570e358d77a3b062228adcbbf68 100755 (executable)
@@ -22,6 +22,7 @@ test_expect_success setup '
        git branch side1 &&
        git branch side2 &&
        git branch side3 &&
+       git branch side4 &&
 
        git checkout side1 &&
        test_write_lines 1 2 3 4 5 6 >numbers &&
@@ -46,6 +47,13 @@ test_expect_success setup '
        test_tick &&
        git commit -m rename-numbers &&
 
+       git checkout side4 &&
+       test_write_lines 0 1 2 3 4 5 >numbers &&
+       echo yo >greeting &&
+       git add numbers greeting &&
+       test_tick &&
+       git commit -m other-content-modifications &&
+
        git switch --orphan unrelated &&
        >something-else &&
        git add something-else &&
@@ -97,6 +105,21 @@ test_expect_success 'Content merge and a few conflicts' '
        test_cmp expect actual
 '
 
+test_expect_success 'Auto resolve conflicts by "ours" strategy option' '
+       git checkout side1^0 &&
+
+       # make sure merge conflict exists
+       test_must_fail git merge side4 &&
+       git merge --abort &&
+
+       git merge -X ours side4 &&
+       git rev-parse HEAD^{tree} >expected &&
+
+       git merge-tree -X ours side1 side4 >actual &&
+
+       test_cmp expected 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 &&
index 0ff47a239db905eb5c3e65de53994b0ac81cbd86..eaf959d8f63f158651609a7c5b0c2eb6592b4926 100755 (executable)
@@ -138,7 +138,7 @@ test_expect_success 'git archive with worktree attributes, bare' '
 '
 
 test_expect_missing    bare-worktree/ignored
-test_expect_exists     bare-worktree/ignored-by-tree
+test_expect_missing    bare-worktree/ignored-by-tree
 test_expect_exists     bare-worktree/ignored-by-worktree
 
 test_expect_success 'export-subst' '
index d2ce236d612e9a52c022526762ffe7e491b0bdd1..745089479ca3a87e36239e196466aadb0b886848 100755 (executable)
@@ -208,7 +208,7 @@ test_expect_success 'unpack with OFS_DELTA' '
 '
 
 test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' '
-       check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION"
+       check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION"
 '
 
 test_expect_success 'compare delta flavors' '
@@ -263,97 +263,97 @@ test_expect_success 'survive missing objects/pack directory' '
        )
 '
 
-test_expect_success \
-    'verify pack' \
-    'git verify-pack   test-1-${packname_1}.idx \
-                       test-2-${packname_2}.idx \
-                       test-3-${packname_3}.idx'
-
-test_expect_success \
-    'verify pack -v' \
-    'git verify-pack -v        test-1-${packname_1}.idx \
-                       test-2-${packname_2}.idx \
-                       test-3-${packname_3}.idx'
-
-test_expect_success \
-    'verify-pack catches mismatched .idx and .pack files' \
-    'cat test-1-${packname_1}.idx >test-3.idx &&
-     cat test-2-${packname_2}.pack >test-3.pack &&
-     if git verify-pack test-3.idx
-     then false
-     else :;
-     fi'
-
-test_expect_success \
-    'verify-pack catches a corrupted pack signature' \
-    'cat test-1-${packname_1}.pack >test-3.pack &&
-     echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=2 &&
-     if git verify-pack test-3.idx
-     then false
-     else :;
-     fi'
-
-test_expect_success \
-    'verify-pack catches a corrupted pack version' \
-    'cat test-1-${packname_1}.pack >test-3.pack &&
-     echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=7 &&
-     if git verify-pack test-3.idx
-     then false
-     else :;
-     fi'
-
-test_expect_success \
-    'verify-pack catches a corrupted type/size of the 1st packed object data' \
-    'cat test-1-${packname_1}.pack >test-3.pack &&
-     echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=12 &&
-     if git verify-pack test-3.idx
-     then false
-     else :;
-     fi'
-
-test_expect_success \
-    'verify-pack catches a corrupted sum of the index file itself' \
-    'l=$(wc -c <test-3.idx) &&
-     l=$(expr $l - 20) &&
-     cat test-1-${packname_1}.pack >test-3.pack &&
-     printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l &&
-     if git verify-pack test-3.pack
-     then false
-     else :;
-     fi'
-
-test_expect_success \
-    'build pack index for an existing pack' \
-    'cat test-1-${packname_1}.pack >test-3.pack &&
-     git index-pack -o tmp.idx test-3.pack &&
-     cmp tmp.idx test-1-${packname_1}.idx &&
-
-     git index-pack --promisor=message test-3.pack &&
-     cmp test-3.idx test-1-${packname_1}.idx &&
-     echo message >expect &&
-     test_cmp expect test-3.promisor &&
-
-     cat test-2-${packname_2}.pack >test-3.pack &&
-     git index-pack -o tmp.idx test-2-${packname_2}.pack &&
-     cmp tmp.idx test-2-${packname_2}.idx &&
-
-     git index-pack test-3.pack &&
-     cmp test-3.idx test-2-${packname_2}.idx &&
-
-     cat test-3-${packname_3}.pack >test-3.pack &&
-     git index-pack -o tmp.idx test-3-${packname_3}.pack &&
-     cmp tmp.idx test-3-${packname_3}.idx &&
-
-     git index-pack test-3.pack &&
-     cmp test-3.idx test-3-${packname_3}.idx &&
-
-     cat test-1-${packname_1}.pack >test-4.pack &&
-     rm -f test-4.keep &&
-     git index-pack --keep=why test-4.pack &&
-     cmp test-1-${packname_1}.idx test-4.idx &&
-     test -f test-4.keep &&
-
-     :'
+test_expect_success 'verify pack' '
+       git verify-pack test-1-${packname_1}.idx \
+               test-2-${packname_2}.idx \
+               test-3-${packname_3}.idx
+'
+
+test_expect_success 'verify pack -v' '
+       git verify-pack -v test-1-${packname_1}.idx \
+               test-2-${packname_2}.idx \
+               test-3-${packname_3}.idx
+'
+
+test_expect_success 'verify-pack catches mismatched .idx and .pack files' '
+       cat test-1-${packname_1}.idx >test-3.idx &&
+       cat test-2-${packname_2}.pack >test-3.pack &&
+       if git verify-pack test-3.idx
+       then false
+       else :;
+       fi
+'
+
+test_expect_success 'verify-pack catches a corrupted pack signature' '
+       cat test-1-${packname_1}.pack >test-3.pack &&
+       echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=2 &&
+       if git verify-pack test-3.idx
+       then false
+       else :;
+       fi
+'
+
+test_expect_success 'verify-pack catches a corrupted pack version' '
+       cat test-1-${packname_1}.pack >test-3.pack &&
+       echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=7 &&
+       if git verify-pack test-3.idx
+       then false
+       else :;
+       fi
+'
+
+test_expect_success 'verify-pack catches a corrupted type/size of the 1st packed object data' '
+       cat test-1-${packname_1}.pack >test-3.pack &&
+       echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=12 &&
+       if git verify-pack test-3.idx
+       then false
+       else :;
+       fi
+'
+
+test_expect_success 'verify-pack catches a corrupted sum of the index file itself' '
+       l=$(wc -c <test-3.idx) &&
+       l=$(expr $l - 20) &&
+       cat test-1-${packname_1}.pack >test-3.pack &&
+       printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l &&
+       if git verify-pack test-3.pack
+       then false
+       else :;
+       fi
+'
+
+test_expect_success 'build pack index for an existing pack' '
+       cat test-1-${packname_1}.pack >test-3.pack &&
+       git index-pack -o tmp.idx test-3.pack &&
+       cmp tmp.idx test-1-${packname_1}.idx &&
+
+       git index-pack --promisor=message test-3.pack &&
+       cmp test-3.idx test-1-${packname_1}.idx &&
+       echo message >expect &&
+       test_cmp expect test-3.promisor &&
+
+       cat test-2-${packname_2}.pack >test-3.pack &&
+       git index-pack -o tmp.idx test-2-${packname_2}.pack &&
+       cmp tmp.idx test-2-${packname_2}.idx &&
+
+       git index-pack test-3.pack &&
+       cmp test-3.idx test-2-${packname_2}.idx &&
+
+       cat test-3-${packname_3}.pack >test-3.pack &&
+       git index-pack -o tmp.idx test-3-${packname_3}.pack &&
+       cmp tmp.idx test-3-${packname_3}.idx &&
+
+       git index-pack test-3.pack &&
+       cmp test-3.idx test-3-${packname_3}.idx &&
+
+       cat test-1-${packname_1}.pack >test-4.pack &&
+       rm -f test-4.keep &&
+       git index-pack --keep=why test-4.pack &&
+       cmp test-1-${packname_1}.idx test-4.idx &&
+       test -f test-4.keep &&
+
+       :
+'
 
 test_expect_success 'unpacking with --strict' '
 
index 3ccaaeb397774da8978c5406840ec307ffe7564d..226490d60df3a61b6b9831118562c4a88bae1cc9 100755 (executable)
@@ -8,55 +8,55 @@ test_description='mmap sliding window tests'
 TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
-test_expect_success \
-    'setup' \
-    'rm -f .git/index* &&
-     for i in a b c
-     do
-         echo $i >$i &&
-        test-tool genrandom "$i" 32768 >>$i &&
-         git update-index --add $i || return 1
-     done &&
-     echo d >d && cat c >>d && git update-index --add d &&
-     tree=$(git write-tree) &&
-     commit1=$(git commit-tree $tree </dev/null) &&
-     git update-ref HEAD $commit1 &&
-     git repack -a -d &&
-     test "$(git count-objects)" = "0 objects, 0 kilobytes" &&
-     pack1=$(ls .git/objects/pack/*.pack) &&
-     test -f "$pack1"'
-
-test_expect_success \
-    'verify-pack -v, defaults' \
-    'git verify-pack -v "$pack1"'
-
-test_expect_success \
-    'verify-pack -v, packedGitWindowSize == 1 page' \
-    'git config core.packedGitWindowSize 512 &&
-     git verify-pack -v "$pack1"'
-
-test_expect_success \
-    'verify-pack -v, packedGit{WindowSize,Limit} == 1 page' \
-    'git config core.packedGitWindowSize 512 &&
-     git config core.packedGitLimit 512 &&
-     git verify-pack -v "$pack1"'
-
-test_expect_success \
-    'repack -a -d, packedGit{WindowSize,Limit} == 1 page' \
-    'git config core.packedGitWindowSize 512 &&
-     git config core.packedGitLimit 512 &&
-     commit2=$(git commit-tree $tree -p $commit1 </dev/null) &&
-     git update-ref HEAD $commit2 &&
-     git repack -a -d &&
-     test "$(git count-objects)" = "0 objects, 0 kilobytes" &&
-     pack2=$(ls .git/objects/pack/*.pack) &&
-     test -f "$pack2" &&
-     test "$pack1" \!= "$pack2"'
-
-test_expect_success \
-    'verify-pack -v, defaults' \
-    'git config --unset core.packedGitWindowSize &&
-     git config --unset core.packedGitLimit &&
-     git verify-pack -v "$pack2"'
+test_expect_success 'setup' '
+       rm -f .git/index* &&
+       for i in a b c
+       do
+       echo $i >$i &&
+       test-tool genrandom "$i" 32768 >>$i &&
+       git update-index --add $i || return 1
+       done &&
+       echo d >d && cat c >>d && git update-index --add d &&
+       tree=$(git write-tree) &&
+       commit1=$(git commit-tree $tree </dev/null) &&
+       git update-ref HEAD $commit1 &&
+       git repack -a -d &&
+       test "$(git count-objects)" = "0 objects, 0 kilobytes" &&
+       pack1=$(ls .git/objects/pack/*.pack) &&
+       test -f "$pack1"
+'
+
+test_expect_success 'verify-pack -v, defaults' '
+       git verify-pack -v "$pack1"
+'
+
+test_expect_success 'verify-pack -v, packedGitWindowSize == 1 page' '
+       git config core.packedGitWindowSize 512 &&
+       git verify-pack -v "$pack1"
+'
+
+test_expect_success 'verify-pack -v, packedGit{WindowSize,Limit} == 1 page' '
+       git config core.packedGitWindowSize 512 &&
+       git config core.packedGitLimit 512 &&
+       git verify-pack -v "$pack1"
+'
+
+test_expect_success 'repack -a -d, packedGit{WindowSize,Limit} == 1 page' '
+       git config core.packedGitWindowSize 512 &&
+       git config core.packedGitLimit 512 &&
+       commit2=$(git commit-tree $tree -p $commit1 </dev/null) &&
+       git update-ref HEAD $commit2 &&
+       git repack -a -d &&
+       test "$(git count-objects)" = "0 objects, 0 kilobytes" &&
+       pack2=$(ls .git/objects/pack/*.pack) &&
+       test -f "$pack2" &&
+       test "$pack1" \!= "$pack2"
+'
+
+test_expect_success 'verify-pack -v, defaults' '
+       git config --unset core.packedGitWindowSize &&
+       git config --unset core.packedGitLimit &&
+       git verify-pack -v "$pack2"
+'
 
 test_done
index 2926e8dfc41223cc0030685beec8f6612db25a4d..61469ef4a681200044f45f0a98f54f39dec2a4c2 100755 (executable)
@@ -59,304 +59,304 @@ do_corrupt_object() {
 
 printf '\0' > zero
 
-test_expect_success \
-    'initial setup validation' \
-    'create_test_files &&
-     create_new_pack &&
-     git prune-packed &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'create corruption in header of first object' \
-    'do_corrupt_object $blob_1 0 < zero &&
-     test_must_fail git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_1 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and loose copy of first delta allows for partial recovery' \
-    'git prune-packed &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     test_must_fail git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'create corruption in data of first object' \
-    'create_new_pack &&
-     git prune-packed &&
-     chmod +w ${pack}.pack &&
-     perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
-     test_must_fail git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_1 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and loose copy of second object allows for partial recovery' \
-    'git prune-packed &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     test_must_fail git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'create corruption in header of first delta' \
-    'create_new_pack &&
-     git prune-packed &&
-     do_corrupt_object $blob_2 0 < zero &&
-     git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and then a repack "clears" the corruption' \
-    'do_repack &&
-     git prune-packed &&
-     git verify-pack ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'create corruption in data of first delta' \
-    'create_new_pack &&
-     git prune-packed &&
-     chmod +w ${pack}.pack &&
-     perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and then a repack "clears" the corruption' \
-    'do_repack &&
-     git prune-packed &&
-     git verify-pack ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \
-    'create_new_pack &&
-     git prune-packed &&
-     do_corrupt_object $blob_2 2 < zero &&
-     git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and then a repack "clears" the corruption' \
-    'do_repack &&
-     git prune-packed &&
-     git verify-pack ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \
-    'create_new_pack --delta-base-offset &&
-     git prune-packed &&
-     do_corrupt_object $blob_2 2 < zero &&
-     git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and then a repack "clears" the corruption' \
-    'do_repack --delta-base-offset &&
-     git prune-packed &&
-     git verify-pack ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' \
-    'create_new_pack --delta-base-offset &&
-     git prune-packed &&
-     printf "\001" | do_corrupt_object $blob_2 2 &&
-     git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_2 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and then a repack "clears" the corruption' \
-    'do_repack --delta-base-offset &&
-     git prune-packed &&
-     git verify-pack ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and a redundant pack allows for full recovery too' \
-    'do_corrupt_object $blob_2 2 < zero &&
-     git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null &&
-     mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_1 &&
-     git hash-object -t blob -w file_2 &&
-     printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack &&
-     git prune-packed &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'corruption of delta base reference pointing to wrong object' \
-    'create_new_pack --delta-base-offset &&
-     git prune-packed &&
-     printf "\220\033" | do_corrupt_object $blob_3 2 &&
-     git cat-file blob $blob_1 >/dev/null &&
-     git cat-file blob $blob_2 >/dev/null &&
-     test_must_fail git cat-file blob $blob_3 >/dev/null'
-
-test_expect_success \
-    '... but having a loose copy allows for full recovery' \
-    'mv ${pack}.idx tmp &&
-     git hash-object -t blob -w file_3 &&
-     mv tmp ${pack}.idx &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    '... and then a repack "clears" the corruption' \
-    'do_repack --delta-base-offset --no-reuse-delta &&
-     git prune-packed &&
-     git verify-pack ${pack}.pack &&
-     git cat-file blob $blob_1 > /dev/null &&
-     git cat-file blob $blob_2 > /dev/null &&
-     git cat-file blob $blob_3 > /dev/null'
-
-test_expect_success \
-    'corrupting header to have too small output buffer fails unpack' \
-    'create_new_pack &&
-     git prune-packed &&
-     printf "\262\001" | do_corrupt_object $blob_1 0 &&
-     test_must_fail git cat-file blob $blob_1 > /dev/null &&
-     test_must_fail git cat-file blob $blob_2 > /dev/null &&
-     test_must_fail git cat-file blob $blob_3 > /dev/null'
+test_expect_success 'initial setup validation' '
+       create_test_files &&
+       create_new_pack &&
+       git prune-packed &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'create corruption in header of first object' '
+       do_corrupt_object $blob_1 0 < zero &&
+       test_must_fail git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_1 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and loose copy of first delta allows for partial recovery' '
+       git prune-packed &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       test_must_fail git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'create corruption in data of first object' '
+       create_new_pack &&
+       git prune-packed &&
+       chmod +w ${pack}.pack &&
+       perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack &&
+       test_must_fail git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_1 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and loose copy of second object allows for partial recovery' '
+       git prune-packed &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       test_must_fail git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'create corruption in header of first delta' '
+       create_new_pack &&
+       git prune-packed &&
+       do_corrupt_object $blob_2 0 < zero &&
+       git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and then a repack "clears" the corruption' '
+       do_repack &&
+       git prune-packed &&
+       git verify-pack ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'create corruption in data of first delta' '
+       create_new_pack &&
+       git prune-packed &&
+       chmod +w ${pack}.pack &&
+       perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and then a repack "clears" the corruption' '
+       do_repack &&
+       git prune-packed &&
+       git verify-pack ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' '
+       create_new_pack &&
+       git prune-packed &&
+       do_corrupt_object $blob_2 2 < zero &&
+       git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and then a repack "clears" the corruption' '
+       do_repack &&
+       git prune-packed &&
+       git verify-pack ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' '
+       create_new_pack --delta-base-offset &&
+       git prune-packed &&
+       do_corrupt_object $blob_2 2 < zero &&
+       git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and then a repack "clears" the corruption' '
+       do_repack --delta-base-offset &&
+       git prune-packed &&
+       git verify-pack ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' '
+       create_new_pack --delta-base-offset &&
+       git prune-packed &&
+       printf "\001" | do_corrupt_object $blob_2 2 &&
+       git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_2 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and then a repack "clears" the corruption' '
+       do_repack --delta-base-offset &&
+       git prune-packed &&
+       git verify-pack ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and a redundant pack allows for full recovery too' '
+       do_corrupt_object $blob_2 2 < zero &&
+       git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null &&
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_1 &&
+       git hash-object -t blob -w file_2 &&
+       printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack &&
+       git prune-packed &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'corruption of delta base reference pointing to wrong object' '
+       create_new_pack --delta-base-offset &&
+       git prune-packed &&
+       printf "\220\033" | do_corrupt_object $blob_3 2 &&
+       git cat-file blob $blob_1 >/dev/null &&
+       git cat-file blob $blob_2 >/dev/null &&
+       test_must_fail git cat-file blob $blob_3 >/dev/null
+'
+
+test_expect_success '... but having a loose copy allows for full recovery' '
+       mv ${pack}.idx tmp &&
+       git hash-object -t blob -w file_3 &&
+       mv tmp ${pack}.idx &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success '... and then a repack "clears" the corruption' '
+       do_repack --delta-base-offset --no-reuse-delta &&
+       git prune-packed &&
+       git verify-pack ${pack}.pack &&
+       git cat-file blob $blob_1 > /dev/null &&
+       git cat-file blob $blob_2 > /dev/null &&
+       git cat-file blob $blob_3 > /dev/null
+'
+
+test_expect_success 'corrupting header to have too small output buffer fails unpack' '
+       create_new_pack &&
+       git prune-packed &&
+       printf "\262\001" | do_corrupt_object $blob_1 0 &&
+       test_must_fail git cat-file blob $blob_1 > /dev/null &&
+       test_must_fail git cat-file blob $blob_2 > /dev/null &&
+       test_must_fail git cat-file blob $blob_3 > /dev/null
+'
 
 # \0 - empty base
 # \1 - one byte in result
 # \1 - one literal byte (X)
-test_expect_success \
-    'apply good minimal delta' \
-    'printf "\0\1\1X" > minimal_delta &&
-     test-tool delta -p /dev/null minimal_delta /dev/null'
+test_expect_success 'apply good minimal delta' '
+       printf "\0\1\1X" > minimal_delta &&
+       test-tool delta -p /dev/null minimal_delta /dev/null
+'
 
 # \0 - empty base
 # \1 - 1 byte in result
 # \2 - two literal bytes (one too many)
-test_expect_success \
-    'apply delta with too many literal bytes' \
-    'printf "\0\1\2XX" > too_big_literal &&
-     test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null'
+test_expect_success 'apply delta with too many literal bytes' '
+       printf "\0\1\2XX" > too_big_literal &&
+       test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null
+'
 
 # \4 - four bytes in base
 # \1 - one byte in result
 # \221 - copy, one byte offset, one byte size
 #   \0 - copy from offset 0
 #   \2 - copy two bytes (one too many)
-test_expect_success \
-    'apply delta with too many copied bytes' \
-    'printf "\4\1\221\0\2" > too_big_copy &&
-     printf base >base &&
-     test_must_fail test-tool delta -p base too_big_copy /dev/null'
+test_expect_success 'apply delta with too many copied bytes' '
+       printf "\4\1\221\0\2" > too_big_copy &&
+       printf base >base &&
+       test_must_fail test-tool delta -p base too_big_copy /dev/null
+'
 
 # \0 - empty base
 # \2 - two bytes in result
 # \2 - two literal bytes (we are short one)
-test_expect_success \
-    'apply delta with too few literal bytes' \
-    'printf "\0\2\2X" > truncated_delta &&
-     test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null'
+test_expect_success 'apply delta with too few literal bytes' '
+       printf "\0\2\2X" > truncated_delta &&
+       test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null
+'
 
 # \0 - empty base
 # \1 - one byte in result
 # \221 - copy, one byte offset, one byte size
 #   \0 - copy from offset 0
 #   \1 - copy one byte (we are short one)
-test_expect_success \
-    'apply delta with too few bytes in base' \
-    'printf "\0\1\221\0\1" > truncated_base &&
-     test_must_fail test-tool delta -p /dev/null truncated_base /dev/null'
+test_expect_success 'apply delta with too few bytes in base' '
+       printf "\0\1\221\0\1" > truncated_base &&
+       test_must_fail test-tool delta -p /dev/null truncated_base /dev/null
+'
 
 # \4 - four bytes in base
 # \2 - two bytes in result
@@ -366,20 +366,20 @@ test_expect_success \
 #
 # Note that the literal byte is necessary to get past the uninteresting minimum
 # delta size check.
-test_expect_success \
-    'apply delta with truncated copy parameters' \
-    'printf "\4\2\1X\221" > truncated_copy_delta &&
-     printf base >base &&
-     test_must_fail test-tool delta -p base truncated_copy_delta /dev/null'
+test_expect_success 'apply delta with truncated copy parameters' '
+       printf "\4\2\1X\221" > truncated_copy_delta &&
+       printf base >base &&
+       test_must_fail test-tool delta -p base truncated_copy_delta /dev/null
+'
 
 # \0 - empty base
 # \1 - one byte in result
 # \1 - one literal byte (X)
 # \1 - trailing garbage command
-test_expect_success \
-    'apply delta with trailing garbage literal' \
-    'printf "\0\1\1X\1" > tail_garbage_literal &&
-     test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null'
+test_expect_success 'apply delta with trailing garbage literal' '
+       printf "\0\1\1X\1" > tail_garbage_literal &&
+       test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null
+'
 
 # \4 - four bytes in base
 # \1 - one byte in result
@@ -387,19 +387,19 @@ test_expect_success \
 # \221 - copy, one byte offset, one byte size
 #   \0 - copy from offset 0
 #   \1 - copy 1 byte
-test_expect_success \
-    'apply delta with trailing garbage copy' \
-    'printf "\4\1\1X\221\0\1" > tail_garbage_copy &&
-     printf base >base &&
-     test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null'
+test_expect_success 'apply delta with trailing garbage copy' '
+       printf "\4\1\1X\221\0\1" > tail_garbage_copy &&
+       printf base >base &&
+       test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null
+'
 
 # \0 - empty base
 # \1 - one byte in result
 # \1 - one literal byte (X)
 # \0 - bogus opcode
-test_expect_success \
-    'apply delta with trailing garbage opcode' \
-    'printf "\0\1\1X\0" > tail_garbage_opcode &&
-     test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null'
+test_expect_success 'apply delta with trailing garbage opcode' '
+       printf "\0\1\1X\0" > tail_garbage_opcode &&
+       test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null
+'
 
 test_done
index f3673274418cd7bf6cb395601241c4f2152f8af6..b4df545e5ab602a869cfde5d13090e40c6d003a5 100755 (executable)
@@ -350,4 +350,18 @@ test_expect_success 'old reachable-from-recent retained with bitmaps' '
        test_must_fail git cat-file -e $to_drop
 '
 
+test_expect_success 'gc.recentObjectsHook' '
+       add_blob &&
+       test-tool chmtime =-86500 $BLOB_FILE &&
+
+       write_script precious-objects <<-EOF &&
+       echo $BLOB
+       EOF
+       test_config gc.recentObjectsHook ./precious-objects &&
+
+       git prune --expire=now &&
+
+       git cat-file -p $BLOB
+'
+
 test_done
index 846c5ca7d341ccb1705e4bded2c910c430337f3f..0d50c6b4bca4c0a005ad05f262e4dfc91eb73d53 100755 (executable)
@@ -12,18 +12,17 @@ TEST_PASSES_SANITIZE_LEAK=true
 
 # Create A-B chain
 #
-test_expect_success \
-    'setup base' \
-    'test_write_lines a b c d e f g h i >text &&
-     echo side >side &&
-     git update-index --add text side &&
-     A=$(echo A | git commit-tree $(git write-tree)) &&
+test_expect_success 'setup base' '
+       test_write_lines a b c d e f g h i >text &&
+       echo side >side &&
+       git update-index --add text side &&
+       A=$(echo A | git commit-tree $(git write-tree)) &&
 
-     echo m >>text &&
-     git update-index text &&
-     B=$(echo B | git commit-tree $(git write-tree) -p $A) &&
-     git update-ref HEAD $B
-    '
+       echo m >>text &&
+       git update-index text &&
+       B=$(echo B | git commit-tree $(git write-tree) -p $A) &&
+       git update-ref HEAD $B
+'
 
 # Create repository with C whose parent is B.
 # Repository contains C, C^{tree}, C:text, B, B^{tree}.
@@ -31,52 +30,49 @@ test_expect_success \
 # Repository is missing A (parent of B).
 # Repository is missing A:side.
 #
-test_expect_success \
-    'setup patch_clone' \
-    'base_objects=$(pwd)/.git/objects &&
-     (mkdir patch_clone &&
-      cd patch_clone &&
-      git init &&
-      echo "$base_objects" >.git/objects/info/alternates &&
-      echo q >>text &&
-      git read-tree $B &&
-      git update-index text &&
-      git update-ref HEAD $(echo C | git commit-tree $(git write-tree) -p $B) &&
-      rm .git/objects/info/alternates &&
+test_expect_success 'setup patch_clone' '
+       base_objects=$(pwd)/.git/objects &&
+       (mkdir patch_clone &&
+       cd patch_clone &&
+       git init &&
+       echo "$base_objects" >.git/objects/info/alternates &&
+       echo q >>text &&
+       git read-tree $B &&
+       git update-index text &&
+       git update-ref HEAD $(echo C | git commit-tree $(git write-tree) -p $B) &&
+       rm .git/objects/info/alternates &&
 
-      git --git-dir=../.git cat-file commit $B |
-      git hash-object -t commit -w --stdin &&
+       git --git-dir=../.git cat-file commit $B |
+       git hash-object -t commit -w --stdin &&
 
-      git --git-dir=../.git cat-file tree "$B^{tree}" |
-      git hash-object -t tree -w --stdin
-     ) &&
-     C=$(git --git-dir=patch_clone/.git rev-parse HEAD)
-    '
+       git --git-dir=../.git cat-file tree "$B^{tree}" |
+       git hash-object -t tree -w --stdin
+       ) &&
+       C=$(git --git-dir=patch_clone/.git rev-parse HEAD)
+'
 
 # Clone patch_clone indirectly by cloning base and fetching.
 #
-test_expect_success \
-    'indirectly clone patch_clone' \
-    '(mkdir user_clone &&
-      cd user_clone &&
-      git init &&
-      git pull ../.git &&
-      test $(git rev-parse HEAD) = $B &&
+test_expect_success 'indirectly clone patch_clone' '
+       (mkdir user_clone &&
+        cd user_clone &&
+        git init &&
+        git pull ../.git &&
+        test $(git rev-parse HEAD) = $B &&
 
-      git pull ../patch_clone/.git &&
-      test $(git rev-parse HEAD) = $C
-     )
-    '
+        git pull ../patch_clone/.git &&
+        test $(git rev-parse HEAD) = $C
+       )
+'
 
 # Cloning the patch_clone directly should fail.
 #
-test_expect_success \
-    'clone of patch_clone is incomplete' \
-    '(mkdir user_direct &&
-      cd user_direct &&
-      git init &&
-      test_must_fail git fetch ../patch_clone/.git
-     )
-    '
+test_expect_success 'clone of patch_clone is incomplete' '
+       (mkdir user_direct &&
+        cd user_direct &&
+        git init &&
+        test_must_fail git fetch ../patch_clone/.git
+       )
+'
 
 test_done
index 526a5a506eb5b6f1cc46a2ade9118447505c3aa3..78c1c6c923d62d1047b654e680d61a2ddf4f2269 100755 (executable)
@@ -9,6 +9,10 @@ test_description='exercise basic bitmap functionality'
 # their place.
 GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
 
+# Likewise, allow individual tests to control whether or not they use
+# the boundary-based traversal.
+sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
+
 objpath () {
        echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')"
 }
@@ -457,6 +461,13 @@ test_bitmap_cases () {
 
 test_bitmap_cases
 
+GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=1
+export GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
+
+test_bitmap_cases
+
+sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
+
 test_expect_success 'incremental repack fails when bitmaps are requested' '
        test_commit more-1 &&
        test_must_fail git repack -d 2>err &&
@@ -468,6 +479,33 @@ test_expect_success 'incremental repack can disable bitmaps' '
        git repack -d --no-write-bitmap-index
 '
 
+test_expect_success 'boundary-based traversal is used when requested' '
+       git repack -a -d --write-bitmap-index &&
+
+       for argv in \
+               "git -c pack.useBitmapBoundaryTraversal=true" \
+               "git -c feature.experimental=true" \
+               "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=1 git"
+       do
+               eval "GIT_TRACE2_EVENT=1 $argv rev-list --objects \
+                       --use-bitmap-index second..other 2>perf" &&
+               grep "\"region_enter\".*\"label\":\"haves/boundary\"" perf ||
+                       return 1
+       done &&
+
+       for argv in \
+               "git -c pack.useBitmapBoundaryTraversal=false" \
+               "git -c feature.experimental=true -c pack.useBitmapBoundaryTraversal=false" \
+               "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=0 git -c pack.useBitmapBoundaryTraversal=true" \
+               "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=0 git -c feature.experimental=true"
+       do
+               eval "GIT_TRACE2_EVENT=1 $argv rev-list --objects \
+                       --use-bitmap-index second..other 2>perf" &&
+               grep "\"region_enter\".*\"label\":\"haves/classic\"" perf ||
+                       return 1
+       done
+'
+
 test_bitmap_cases "pack.writeBitmapLookupTable"
 
 test_expect_success 'verify writing bitmap lookup table when enabled' '
index b26d476c646fdb63a9569d98bc9d2792dd6f3426..2ff3eef9a3b8cad7f95253c79283d3ac542802fd 100755 (executable)
@@ -53,6 +53,14 @@ test_expect_success 'verify blob:none packfile has no blobs' '
        ! grep blob verify_result
 '
 
+test_expect_success 'verify blob:none packfile without --stdout' '
+       git -C r1 pack-objects --revs --filter=blob:none mypackname >packhash <<-EOF &&
+       HEAD
+       EOF
+       git -C r1 verify-pack -v "mypackname-$(cat packhash).pack" >verify_result &&
+       ! grep blob verify_result
+'
+
 test_expect_success 'verify normal and blob:none packfiles have same commits/trees' '
        git -C r1 verify-pack -v ../all.pack >verify_result &&
        grep -E "commit|tree" verify_result |
index b6e12115786fda5b3b89ad63f2761192593c7f1b..6505ff595a389afa7d79fe31305d214046c376f2 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='commit graph'
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
 
 GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
 
@@ -24,12 +25,10 @@ test_expect_success 'usage shown with an error on unknown sub-command' '
        test_cmp expect actual
 '
 
+objdir=".git/objects"
+
 test_expect_success 'setup full repo' '
-       mkdir full &&
-       cd "$TRASH_DIRECTORY/full" &&
-       git init &&
-       git config core.commitGraph true &&
-       objdir=".git/objects"
+       git init full
 '
 
 test_expect_success POSIXPERM 'tweak umask for modebit tests' '
@@ -37,31 +36,28 @@ test_expect_success POSIXPERM 'tweak umask for modebit tests' '
 '
 
 test_expect_success 'verify graph with no graph file' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph verify
+       git -C full commit-graph verify
 '
 
 test_expect_success 'write graph with no packs' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write --object-dir $objdir &&
-       test_path_is_missing $objdir/info/commit-graph
+       git -C full commit-graph write --object-dir $objdir &&
+       test_path_is_missing full/$objdir/info/commit-graph
 '
 
 test_expect_success 'exit with correct error on bad input to --stdin-packs' '
-       cd "$TRASH_DIRECTORY/full" &&
        echo doesnotexist >in &&
-       test_expect_code 1 git commit-graph write --stdin-packs <in 2>stderr &&
+       test_expect_code 1 git -C full commit-graph write --stdin-packs \
+               <in 2>stderr &&
        test_i18ngrep "error adding pack" stderr
 '
 
 test_expect_success 'create commits and repack' '
-       cd "$TRASH_DIRECTORY/full" &&
        for i in $(test_seq 3)
        do
-               test_commit $i &&
-               git branch commits/$i || return 1
+               test_commit -C full $i &&
+               git -C full branch commits/$i || return 1
        done &&
-       git repack
+       git -C full repack
 '
 
 . "$TEST_DIRECTORY"/lib-commit-graph.sh
@@ -69,117 +65,106 @@ test_expect_success 'create commits and repack' '
 graph_git_behavior 'no graph' full commits/3 commits/1
 
 test_expect_success 'exit with correct error on bad input to --stdin-commits' '
-       cd "$TRASH_DIRECTORY/full" &&
        # invalid, non-hex OID
-       echo HEAD >in &&
-       test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr &&
+       echo HEAD | test_expect_code 1 git -C full commit-graph write \
+               --stdin-commits 2>stderr &&
        test_i18ngrep "unexpected non-hex object ID: HEAD" stderr &&
        # non-existent OID
-       echo $ZERO_OID >in &&
-       test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr &&
+       echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \
+               --stdin-commits 2>stderr &&
        test_i18ngrep "invalid object" stderr &&
        # valid commit and tree OID
-       git rev-parse HEAD HEAD^{tree} >in &&
-       git commit-graph write --stdin-commits <in &&
-       graph_read_expect 3 generation_data
+       git -C full rev-parse HEAD HEAD^{tree} >in &&
+       git -C full commit-graph write --stdin-commits <in &&
+       graph_read_expect -C full 3 generation_data
 '
 
 test_expect_success 'write graph' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "3" generation_data
+       git -C full commit-graph write &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 3 generation_data
 '
 
 test_expect_success POSIXPERM 'write graph has correct permissions' '
-       test_path_is_file $objdir/info/commit-graph &&
+       test_path_is_file full/$objdir/info/commit-graph &&
        echo "-r--r--r--" >expect &&
-       test_modebits $objdir/info/commit-graph >actual &&
+       test_modebits full/$objdir/info/commit-graph >actual &&
        test_cmp expect actual
 '
 
 graph_git_behavior 'graph exists' full commits/3 commits/1
 
 test_expect_success 'Add more commits' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git reset --hard commits/1 &&
+       git -C full reset --hard commits/1 &&
        for i in $(test_seq 4 5)
        do
-               test_commit $i &&
-               git branch commits/$i || return 1
+               test_commit -C full $i &&
+               git -C full branch commits/$i || return 1
        done &&
-       git reset --hard commits/2 &&
+       git -C full reset --hard commits/2 &&
        for i in $(test_seq 6 7)
        do
-               test_commit $i &&
-               git branch commits/$i || return 1
+               test_commit -C full $i &&
+               git -C full branch commits/$i || return 1
        done &&
-       git reset --hard commits/2 &&
-       git merge commits/4 &&
-       git branch merge/1 &&
-       git reset --hard commits/4 &&
-       git merge commits/6 &&
-       git branch merge/2 &&
-       git reset --hard commits/3 &&
-       git merge commits/5 commits/7 &&
-       git branch merge/3 &&
-       git repack
+       git -C full reset --hard commits/2 &&
+       git -C full merge commits/4 &&
+       git -C full branch merge/1 &&
+       git -C full reset --hard commits/4 &&
+       git -C full merge commits/6 &&
+       git -C full branch merge/2 &&
+       git -C full reset --hard commits/3 &&
+       git -C full merge commits/5 commits/7 &&
+       git -C full branch merge/3 &&
+       git -C full repack
 '
 
 test_expect_success 'commit-graph write progress off for redirected stderr' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write 2>err &&
+       git -C full commit-graph write 2>err &&
        test_must_be_empty err
 '
 
 test_expect_success 'commit-graph write force progress on for stderr' '
-       cd "$TRASH_DIRECTORY/full" &&
-       GIT_PROGRESS_DELAY=0 git commit-graph write --progress 2>err &&
+       GIT_PROGRESS_DELAY=0 git -C full commit-graph write --progress 2>err &&
        test_file_not_empty err
 '
 
 test_expect_success 'commit-graph write with the --no-progress option' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write --no-progress 2>err &&
+       git -C full commit-graph write --no-progress 2>err &&
        test_must_be_empty err
 '
 
 test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git rev-parse commits/5 >in &&
-       git commit-graph write --stdin-commits <in 2>err &&
+       git -C full rev-parse commits/5 >in &&
+       git -C full commit-graph write --stdin-commits <in 2>err &&
        test_must_be_empty err
 '
 
 test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git rev-parse commits/5 >in &&
-       GIT_PROGRESS_DELAY=0 git commit-graph write --stdin-commits --progress <in 2>err &&
+       git -C full rev-parse commits/5 >in &&
+       GIT_PROGRESS_DELAY=0 git -C full commit-graph write --stdin-commits \
+               --progress <in 2>err &&
        test_i18ngrep "Collecting commits from input" err
 '
 
 test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git rev-parse commits/5 >in &&
-       git commit-graph write --stdin-commits --no-progress <in 2>err &&
+       git -C full rev-parse commits/5 >in &&
+       git -C full commit-graph write --stdin-commits --no-progress <in 2>err &&
        test_must_be_empty err
 '
 
 test_expect_success 'commit-graph verify progress off for redirected stderr' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph verify 2>err &&
+       git -C full commit-graph verify 2>err &&
        test_must_be_empty err
 '
 
 test_expect_success 'commit-graph verify force progress on for stderr' '
-       cd "$TRASH_DIRECTORY/full" &&
-       GIT_PROGRESS_DELAY=0 git commit-graph verify --progress 2>err &&
+       GIT_PROGRESS_DELAY=0 git -C full commit-graph verify --progress 2>err &&
        test_file_not_empty err
 '
 
 test_expect_success 'commit-graph verify with the --no-progress option' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph verify --no-progress 2>err &&
+       git -C full commit-graph verify --no-progress 2>err &&
        test_must_be_empty err
 '
 
@@ -194,10 +179,9 @@ test_expect_success 'commit-graph verify with the --no-progress option' '
 # 1
 
 test_expect_success 'write graph with merges' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "10" "generation_data extra_edges"
+       git -C full commit-graph write &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 10 "generation_data extra_edges"
 '
 
 graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2
@@ -205,12 +189,11 @@ graph_git_behavior 'merge 1 vs 3' full merge/1 merge/3
 graph_git_behavior 'merge 2 vs 3' full merge/2 merge/3
 
 test_expect_success 'Add one more commit' '
-       cd "$TRASH_DIRECTORY/full" &&
-       test_commit 8 &&
-       git branch commits/8 &&
-       ls $objdir/pack | grep idx >existing-idx &&
-       git repack &&
-       ls $objdir/pack| grep idx | grep -v -f existing-idx >new-idx
+       test_commit -C full 8 &&
+       git -C full branch commits/8 &&
+       ls full/$objdir/pack | grep idx >existing-idx &&
+       git -C full repack &&
+       ls full/$objdir/pack| grep idx | grep -v -f existing-idx >new-idx
 '
 
 # Current graph structure:
@@ -229,114 +212,101 @@ graph_git_behavior 'mixed mode, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'mixed mode, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'write graph with new commit' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "11" "generation_data extra_edges"
+       git -C full commit-graph write &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 11 "generation_data extra_edges"
 '
 
 graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'full graph, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'write graph with nothing new' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "11" "generation_data extra_edges"
+       git -C full commit-graph write &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 11 "generation_data extra_edges"
 '
 
 graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'build graph from latest pack with closure' '
-       cd "$TRASH_DIRECTORY/full" &&
-       cat new-idx | git commit-graph write --stdin-packs &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "9" "generation_data extra_edges"
+       git -C full commit-graph write --stdin-packs <new-idx &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 9 "generation_data extra_edges"
 '
 
 graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'build graph from commits with closure' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git tag -a -m "merge" tag/merge merge/2 &&
-       git rev-parse tag/merge >commits-in &&
-       git rev-parse merge/1 >>commits-in &&
-       cat commits-in | git commit-graph write --stdin-commits &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "6" "generation_data"
+       git -C full tag -a -m "merge" tag/merge merge/2 &&
+       git -C full rev-parse tag/merge >commits-in &&
+       git -C full rev-parse merge/1 >>commits-in &&
+       git -C full commit-graph write --stdin-commits <commits-in &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 6 "generation_data"
 '
 
 graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'build graph from commits with append' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git rev-parse merge/3 | git commit-graph write --stdin-commits --append &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "10" "generation_data extra_edges"
+       git -C full rev-parse merge/3 >in &&
+       git -C full commit-graph write --stdin-commits --append <in &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 10 "generation_data extra_edges"
 '
 
 graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'build graph using --reachable' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit-graph write --reachable &&
-       test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "11" "generation_data extra_edges"
+       git -C full commit-graph write --reachable &&
+       test_path_is_file full/$objdir/info/commit-graph &&
+       graph_read_expect -C full 11 "generation_data extra_edges"
 '
 
 graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1
 graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2
 
 test_expect_success 'setup bare repo' '
-       cd "$TRASH_DIRECTORY" &&
-       git clone --bare --no-local full bare &&
-       cd bare &&
-       git config core.commitGraph true &&
-       baredir="./objects"
+       git clone --bare --no-local full bare
 '
 
 graph_git_behavior 'bare repo, commit 8 vs merge 1' bare commits/8 merge/1
 graph_git_behavior 'bare repo, commit 8 vs merge 2' bare commits/8 merge/2
 
 test_expect_success 'write graph in bare repo' '
-       cd "$TRASH_DIRECTORY/bare" &&
-       git commit-graph write &&
-       test_path_is_file $baredir/info/commit-graph &&
-       graph_read_expect "11" "generation_data extra_edges"
+       git -C bare commit-graph write &&
+       test_path_is_file bare/objects/info/commit-graph &&
+       graph_read_expect -C bare 11 "generation_data extra_edges"
 '
 
 graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1
 graph_git_behavior 'bare repo with graph, commit 8 vs merge 2' bare commits/8 merge/2
 
 test_expect_success 'perform fast-forward merge in full repo' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git checkout -b merge-5-to-8 commits/5 &&
-       git merge commits/8 &&
-       git show-ref -s merge-5-to-8 >output &&
-       git show-ref -s commits/8 >expect &&
+       git -C full checkout -b merge-5-to-8 commits/5 &&
+       git -C full merge commits/8 &&
+       git -C full show-ref -s merge-5-to-8 >output &&
+       git -C full show-ref -s commits/8 >expect &&
        test_cmp expect output
 '
 
 test_expect_success 'check that gc computes commit-graph' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git commit --allow-empty -m "blank" &&
-       git commit-graph write --reachable &&
-       cp $objdir/info/commit-graph commit-graph-before-gc &&
-       git reset --hard HEAD~1 &&
-       git config gc.writeCommitGraph true &&
-       git gc &&
-       cp $objdir/info/commit-graph commit-graph-after-gc &&
+       test_commit -C full --no-tag blank &&
+       git -C full commit-graph write --reachable &&
+       cp full/$objdir/info/commit-graph commit-graph-before-gc &&
+       git -C full reset --hard HEAD~1 &&
+       test_config -C full gc.writeCommitGraph true &&
+       git -C full gc &&
+       cp full/$objdir/info/commit-graph commit-graph-after-gc &&
        ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc &&
-       git commit-graph write --reachable &&
-       test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph
+       git -C full commit-graph write --reachable &&
+       test_cmp_bin commit-graph-after-gc full/$objdir/info/commit-graph
 '
 
 test_expect_success 'replace-objects invalidates commit-graph' '
-       cd "$TRASH_DIRECTORY" &&
        test_when_finished rm -rf replace &&
        git clone full replace &&
        (
@@ -359,7 +329,6 @@ 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 --template= full graft &&
        (
@@ -384,7 +353,6 @@ test_expect_success 'commit grafts invalidate commit-graph' '
 '
 
 test_expect_success 'replace-objects invalidates commit-graph' '
-       cd "$TRASH_DIRECTORY" &&
        test_when_finished rm -rf shallow &&
        git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow &&
        (
@@ -427,24 +395,25 @@ test_expect_success 'warn on improper hash version' '
 '
 
 test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' '
-       cd "$TRASH_DIRECTORY/full" &&
        UNIX_EPOCH_ZERO="@0 +0000" &&
        FUTURE_DATE="@4147483646 +0000" &&
-       rm -f .git/objects/info/commit-graph &&
-       test_commit --date "$FUTURE_DATE" future-1 &&
-       test_commit --date "$UNIX_EPOCH_ZERO" old-1 &&
-       git commit-graph write --reachable &&
-       test_commit --date "$FUTURE_DATE" future-2 &&
-       test_commit --date "$UNIX_EPOCH_ZERO" old-2 &&
-       git commit-graph write --reachable --split=no-merge &&
-       test_commit extra &&
-       git commit-graph write --reachable --split=no-merge &&
-       git commit-graph write --reachable &&
-       graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
-       mv .git/objects/info/commit-graph commit-graph-upgraded &&
-       git commit-graph write --reachable &&
-       graph_read_expect 16 "generation_data generation_data_overflow extra_edges" &&
-       test_cmp .git/objects/info/commit-graph commit-graph-upgraded
+       rm -f full/.git/objects/info/commit-graph &&
+       test_commit -C full --date "$FUTURE_DATE" future-1 &&
+       test_commit -C full --date "$UNIX_EPOCH_ZERO" old-1 &&
+       git -C full commit-graph write --reachable &&
+       test_commit -C full --date "$FUTURE_DATE" future-2 &&
+       test_commit -C full --date "$UNIX_EPOCH_ZERO" old-2 &&
+       git -C full commit-graph write --reachable --split=no-merge &&
+       test_commit -C full extra &&
+       git -C full commit-graph write --reachable --split=no-merge &&
+       git -C full commit-graph write --reachable &&
+       graph_read_expect -C full 16 \
+               "generation_data generation_data_overflow extra_edges" &&
+       mv full/.git/objects/info/commit-graph commit-graph-upgraded &&
+       git -C full commit-graph write --reachable &&
+       graph_read_expect -C full 16 \
+               "generation_data generation_data_overflow extra_edges" &&
+       test_cmp full/.git/objects/info/commit-graph commit-graph-upgraded
 '
 
 # the verify tests below expect the commit-graph to contain
@@ -454,10 +423,11 @@ test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow ch
 # and the tests will likely break.
 
 test_expect_success 'git commit-graph verify' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git rev-parse commits/8 | git -c commitGraph.generationVersion=1 commit-graph write --stdin-commits &&
-       git commit-graph verify >output &&
-       graph_read_expect 9 extra_edges 1
+       git -C full rev-parse commits/8 >in &&
+       git -C full -c commitGraph.generationVersion=1 commit-graph write \
+               --stdin-commits <in &&
+       git -C full commit-graph verify >output &&
+       graph_read_expect -C full 9 extra_edges 1
 '
 
 NUM_COMMITS=9
@@ -481,39 +451,39 @@ GRAPH_BYTE_FANOUT2=$(($GRAPH_FANOUT_OFFSET + 4 * 255))
 GRAPH_OID_LOOKUP_OFFSET=$(($GRAPH_FANOUT_OFFSET + 4 * 256))
 GRAPH_BYTE_OID_LOOKUP_ORDER=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 8))
 GRAPH_BYTE_OID_LOOKUP_MISSING=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 4 + 10))
+GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16))
 GRAPH_COMMIT_DATA_OFFSET=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * $NUM_COMMITS))
 GRAPH_BYTE_COMMIT_TREE=$GRAPH_COMMIT_DATA_OFFSET
 GRAPH_BYTE_COMMIT_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN))
 GRAPH_BYTE_COMMIT_EXTRA_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 4))
 GRAPH_BYTE_COMMIT_WRONG_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 3))
 GRAPH_BYTE_COMMIT_GENERATION=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 11))
+GRAPH_BYTE_COMMIT_GENERATION_LAST=$(($GRAPH_BYTE_COMMIT_GENERATION + $(($NUM_COMMITS - 1)) * $GRAPH_COMMIT_DATA_WIDTH))
 GRAPH_BYTE_COMMIT_DATE=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 12))
-GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16))
 GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \
                             $GRAPH_COMMIT_DATA_WIDTH * $NUM_COMMITS))
 GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4))
 GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
 
 corrupt_graph_setup() {
-       cd "$TRASH_DIRECTORY/full" &&
-       test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
-       cp $objdir/info/commit-graph commit-graph-backup &&
-       chmod u+w $objdir/info/commit-graph
+       test_when_finished mv commit-graph-backup full/$objdir/info/commit-graph &&
+       cp full/$objdir/info/commit-graph commit-graph-backup &&
+       chmod u+w full/$objdir/info/commit-graph
 }
 
 corrupt_graph_verify() {
        grepstr=$1
-       test_must_fail git commit-graph verify 2>test_err &&
+       test_must_fail git -C full commit-graph verify 2>test_err &&
        grep -v "^+" test_err >err &&
        test_i18ngrep "$grepstr" err &&
        if test "$2" != "no-copy"
        then
-               cp $objdir/info/commit-graph commit-graph-pre-write-test
+               cp full/$objdir/info/commit-graph commit-graph-pre-write-test
        fi &&
-       git status --short &&
-       GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git commit-graph write &&
-       chmod u+w $objdir/info/commit-graph &&
-       git commit-graph verify
+       git -C full status --short &&
+       GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git -C full commit-graph write &&
+       chmod u+w full/$objdir/info/commit-graph &&
+       git -C full commit-graph verify
 }
 
 # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>]
@@ -527,24 +497,24 @@ corrupt_graph_and_verify() {
        data="${2:-\0}"
        grepstr=$3
        corrupt_graph_setup &&
-       orig_size=$(wc -c < $objdir/info/commit-graph) &&
+       orig_size=$(wc -c <full/$objdir/info/commit-graph) &&
        zero_pos=${4:-${orig_size}} &&
-       printf "$data" | dd of="$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc &&
-       dd of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null &&
-       test-tool genzeros $(($orig_size - $zero_pos)) >>"$objdir/info/commit-graph" &&
+       printf "$data" | dd of="full/$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc &&
+       dd of="full/$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null &&
+       test-tool genzeros $(($orig_size - $zero_pos)) >>"full/$objdir/info/commit-graph" &&
        corrupt_graph_verify "$grepstr"
 
 }
 
 test_expect_success POSIXPERM,SANITY 'detect permission problem' '
        corrupt_graph_setup &&
-       chmod 000 $objdir/info/commit-graph &&
+       chmod 000 full/$objdir/info/commit-graph &&
        corrupt_graph_verify "Could not open" "no-copy"
 '
 
 test_expect_success 'detect too small' '
        corrupt_graph_setup &&
-       echo "a small graph" >$objdir/info/commit-graph &&
+       echo "a small graph" >full/$objdir/info/commit-graph &&
        corrupt_graph_verify "too small"
 '
 
@@ -590,7 +560,7 @@ test_expect_success 'detect incorrect fanout' '
 
 test_expect_success 'detect incorrect fanout final value' '
        corrupt_graph_and_verify $GRAPH_BYTE_FANOUT2 "\01" \
-               "fanout value"
+               "oid table and fanout disagree on size"
 '
 
 test_expect_success 'detect incorrect OID order' '
@@ -628,11 +598,6 @@ test_expect_success 'detect incorrect generation number' '
                "generation for commit"
 '
 
-test_expect_success 'detect incorrect generation number' '
-       corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\01" \
-               "commit-graph generation for commit"
-'
-
 test_expect_success 'detect incorrect commit date' '
        corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATE "\01" \
                "commit date"
@@ -654,34 +619,51 @@ test_expect_success 'detect incorrect chunk count' '
                $GRAPH_CHUNK_LOOKUP_OFFSET
 '
 
+test_expect_success 'detect mixed generation numbers (non-zero to zero)' '
+       corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION_LAST "\0\0\0\0" \
+               "both zero and non-zero generations"
+'
+
+test_expect_success 'detect mixed generation numbers (zero to non-zero)' '
+       corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\0\0\0\0" \
+               "both zero and non-zero generations"
+'
+
 test_expect_success 'git fsck (checks commit-graph when config set to true)' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git fsck &&
+       git -C full fsck &&
        corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
                "incorrect checksum" &&
-       cp commit-graph-pre-write-test $objdir/info/commit-graph &&
-       test_must_fail git -c core.commitGraph=true fsck
+       cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
+       test_must_fail git -C full -c core.commitGraph=true fsck
 '
 
 test_expect_success 'git fsck (ignores commit-graph when config set to false)' '
-       cd "$TRASH_DIRECTORY/full" &&
-       git fsck &&
+       git -C full fsck &&
        corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
                "incorrect checksum" &&
-       cp commit-graph-pre-write-test $objdir/info/commit-graph &&
-       git -c core.commitGraph=false fsck
+       cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
+       git -C full -c core.commitGraph=false fsck
 '
 
 test_expect_success 'git fsck (checks commit-graph when config unset)' '
-       cd "$TRASH_DIRECTORY/full" &&
-       test_when_finished "git config core.commitGraph true" &&
+       test_when_finished "git -C full config core.commitGraph true" &&
 
-       git fsck &&
+       git -C full fsck &&
        corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \
                "incorrect checksum" &&
-       test_unconfig core.commitGraph &&
-       cp commit-graph-pre-write-test $objdir/info/commit-graph &&
-       test_must_fail git fsck
+       test_unconfig -C full core.commitGraph &&
+       cp commit-graph-pre-write-test full/$objdir/info/commit-graph &&
+       test_must_fail git -C full fsck
+'
+
+test_expect_success 'git fsck shows commit-graph output with --progress' '
+       git -C "$TRASH_DIRECTORY/full" fsck --progress 2>err &&
+       grep "Verifying commits in commit graph" err
+'
+
+test_expect_success 'git fsck suppresses commit-graph output with --no-progress' '
+       git -C "$TRASH_DIRECTORY/full" fsck --no-progress 2>err &&
+       ! grep "Verifying commits in commit graph" err
 '
 
 test_expect_success 'setup non-the_repository tests' '
@@ -782,32 +764,33 @@ test_expect_success 'corrupt commit-graph write (missing tree)' '
 #
 
 test_expect_success 'set up and verify repo with generation data overflow chunk' '
-       objdir=".git/objects" &&
        UNIX_EPOCH_ZERO="@0 +0000" &&
        FUTURE_DATE="@2147483646 +0000" &&
-       cd "$TRASH_DIRECTORY" &&
-       mkdir repo &&
-       cd repo &&
-       git init &&
-       test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
-       test_commit 2 &&
-       test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
-       git commit-graph write --reachable &&
-       graph_read_expect 3 generation_data &&
-       test_commit --date "$FUTURE_DATE" 4 &&
-       test_commit 5 &&
-       test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
-       git branch left &&
-       git reset --hard 3 &&
-       test_commit 7 &&
-       test_commit --date "$FUTURE_DATE" 8 &&
-       test_commit 9 &&
-       git branch right &&
-       git reset --hard 3 &&
-       test_merge M left right &&
-       git commit-graph write --reachable &&
-       graph_read_expect 10 "generation_data generation_data_overflow" &&
-       git commit-graph verify
+
+       git init repo &&
+       (
+               cd repo &&
+
+               test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
+               test_commit 2 &&
+               test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
+               git commit-graph write --reachable &&
+               graph_read_expect 3 generation_data &&
+               test_commit --date "$FUTURE_DATE" 4 &&
+               test_commit 5 &&
+               test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
+               git branch left &&
+               git reset --hard 3 &&
+               test_commit 7 &&
+               test_commit --date "$FUTURE_DATE" 8 &&
+               test_commit 9 &&
+               git branch right &&
+               git reset --hard 3 &&
+               test_merge M left right &&
+               git commit-graph write --reachable &&
+               graph_read_expect 10 "generation_data generation_data_overflow" &&
+               git commit-graph verify
+       )
 '
 
 graph_git_behavior 'generation data overflow chunk repo' repo left right
@@ -839,4 +822,77 @@ test_expect_success 'overflow during generation version upgrade' '
        )
 '
 
+corrupt_chunk () {
+       graph=full/.git/objects/info/commit-graph &&
+       test_when_finished "rm -rf $graph" &&
+       git -C full commit-graph write --reachable &&
+       corrupt_chunk_file $graph "$@"
+}
+
+check_corrupt_chunk () {
+       corrupt_chunk "$@" &&
+       git -C full -c core.commitGraph=false log >expect.out &&
+       git -C full -c core.commitGraph=true log >out 2>err &&
+       test_cmp expect.out out
+}
+
+test_expect_success 'reader notices too-small oid fanout chunk' '
+       # make it big enough that the graph file is plausible,
+       # otherwise we hit an earlier check
+       check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
+       cat >expect.err <<-\EOF &&
+       error: commit-graph oid fanout chunk is wrong size
+       error: commit-graph is missing the OID Fanout chunk
+       EOF
+       test_cmp expect.err err
+'
+
+test_expect_success 'reader notices fanout/lookup table mismatch' '
+       check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
+       cat >expect.err <<-\EOF &&
+       error: commit-graph oid table and fanout disagree on size
+       EOF
+       test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds fanout' '
+       # Rather than try to corrupt a specific hash, we will just
+       # wreck them all. But we cannot just set them all to 0xFFFFFFFF or
+       # similar, as they are used for hi/lo starts in a binary search (so if
+       # they are identical, that indicates that the search should abort
+       # immediately). Instead, we will give them high values that differ by
+       # 2^24, ensuring that any that are used would cause an out-of-bounds
+       # read.
+       check_corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) &&
+       cat >expect.err <<-\EOF &&
+       error: commit-graph fanout values out of order
+       EOF
+       test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small commit data chunk' '
+       check_corrupt_chunk CDAT clear 00000000 &&
+       cat >expect.err <<-\EOF &&
+       error: commit-graph commit data chunk is wrong size
+       error: commit-graph is missing the Commit Data chunk
+       EOF
+       test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds extra edge' '
+       check_corrupt_chunk EDGE clear &&
+       cat >expect.err <<-\EOF &&
+       error: commit-graph extra-edges pointer out of bounds
+       EOF
+       test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small generations chunk' '
+       check_corrupt_chunk GDA2 clear 00000000 &&
+       cat >expect.err <<-\EOF &&
+       error: commit-graph generations chunk is wrong size
+       EOF
+       test_cmp expect.err err
+'
+
 test_done
index 0883c7c6bd965d5506ca45a10c2c406a2700707a..d3c9e97feb12b7d80a1c74189a0da04c438152c5 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='multi-pack-indexes'
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
 
 GIT_TEST_MULTI_PACK_INDEX=0
 objdir=.git/objects
@@ -438,7 +439,7 @@ test_expect_success 'verify extended chunk count' '
 
 test_expect_success 'verify missing required chunk' '
        corrupt_midx_and_verify $MIDX_BYTE_CHUNK_ID "\01" $objdir \
-               "missing required"
+               "required pack-name chunk missing"
 '
 
 test_expect_success 'verify invalid chunk offset' '
@@ -485,6 +486,18 @@ test_expect_success 'git-fsck incorrect offset' '
        git -c core.multiPackIndex=false fsck
 '
 
+test_expect_success 'git fsck shows MIDX output with --progress' '
+       git fsck --progress 2>err &&
+       grep "Verifying OID order in multi-pack-index" err &&
+       grep "Verifying object offsets" err
+'
+
+test_expect_success 'git fsck suppresses MIDX output with --no-progress' '
+       git fsck --no-progress 2>err &&
+       ! grep "Verifying OID order in multi-pack-index" err &&
+       ! grep "Verifying object offsets" err
+'
+
 test_expect_success 'corrupt MIDX is not reused' '
        corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \
                "incorrect object offset" &&
@@ -1043,4 +1056,105 @@ test_expect_success 'repack with delta islands' '
        )
 '
 
+corrupt_chunk () {
+       midx=.git/objects/pack/multi-pack-index &&
+       test_when_finished "rm -rf $midx" &&
+       git repack -ad --write-midx &&
+       corrupt_chunk_file $midx "$@"
+}
+
+test_expect_success 'reader notices too-small oid fanout chunk' '
+       corrupt_chunk OIDF clear 00000000 &&
+       test_must_fail git log 2>err &&
+       cat >expect <<-\EOF &&
+       error: multi-pack-index OID fanout is of the wrong size
+       fatal: multi-pack-index required OID fanout chunk missing or corrupted
+       EOF
+       test_cmp expect err
+'
+
+test_expect_success 'reader notices too-small oid lookup chunk' '
+       corrupt_chunk OIDL clear 00000000 &&
+       test_must_fail git log 2>err &&
+       cat >expect <<-\EOF &&
+       error: multi-pack-index OID lookup chunk is the wrong size
+       fatal: multi-pack-index required OID lookup chunk missing or corrupted
+       EOF
+       test_cmp expect err
+'
+
+test_expect_success 'reader notices too-small pack names chunk' '
+       # There is no NUL to terminate the name here, so the
+       # chunk is too short.
+       corrupt_chunk PNAM clear 70656666 &&
+       test_must_fail git log 2>err &&
+       cat >expect <<-\EOF &&
+       fatal: multi-pack-index pack-name chunk is too short
+       EOF
+       test_cmp expect err
+'
+
+test_expect_success 'reader handles unaligned chunks' '
+       # A 9-byte PNAM means all of the subsequent chunks
+       # will no longer be 4-byte aligned, but it is still
+       # a valid one-pack chunk on its own (it is "foo.pack\0").
+       corrupt_chunk PNAM clear 666f6f2e7061636b00 &&
+       git -c core.multipackindex=false log >expect.out &&
+       git -c core.multipackindex=true log >out 2>err &&
+       test_cmp expect.out out &&
+       cat >expect.err <<-\EOF &&
+       error: chunk id 4f494446 not 4-byte aligned
+       EOF
+       test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small object offset chunk' '
+       corrupt_chunk OOFF clear 00000000 &&
+       test_must_fail git log 2>err &&
+       cat >expect <<-\EOF &&
+       error: multi-pack-index object offset chunk is the wrong size
+       fatal: multi-pack-index required object offsets chunk missing or corrupted
+       EOF
+       test_cmp expect err
+'
+
+test_expect_success 'reader bounds-checks large offset table' '
+       # re-use the objects64 dir here to cheaply get access to a midx
+       # with large offsets.
+       git init repo &&
+       test_when_finished "rm -rf repo" &&
+       (
+               cd repo &&
+               (cd ../objects64 && pwd) >.git/objects/info/alternates &&
+               git multi-pack-index --object-dir=../objects64 write &&
+               midx=../objects64/pack/multi-pack-index &&
+               corrupt_chunk_file $midx LOFF clear &&
+               # using only %(objectsize) is important here; see the commit
+               # message for more details
+               test_must_fail git cat-file --batch-all-objects \
+                       --batch-check="%(objectsize)" 2>err &&
+               cat >expect <<-\EOF &&
+               fatal: multi-pack-index large offset out of bounds
+               EOF
+               test_cmp expect err
+       )
+'
+
+test_expect_success 'reader notices too-small revindex chunk' '
+       # We only get a revindex with bitmaps (and likewise only
+       # load it when they are asked for).
+       test_config repack.writeBitmaps true &&
+       corrupt_chunk RIDX clear 00000000 &&
+       git -c core.multipackIndex=false rev-list \
+               --all --use-bitmap-index >expect.out &&
+       git -c core.multipackIndex=true rev-list \
+               --all --use-bitmap-index >out 2>err &&
+       test_cmp expect.out out &&
+       cat >expect.err <<-\EOF &&
+       error: multi-pack-index reverse-index chunk is the wrong size
+       warning: multi-pack bitmap is missing required reverse index
+       EOF
+       test_cmp expect.err err
+'
+
 test_done
index 669ddc645faccfc402b04044ed75676592e64356..97eb6d2e72bac5c3936965c269ff9bfa56d87568 100755 (executable)
@@ -1,7 +1,10 @@
 #!/bin/sh
 
 test_description='split commit graph'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-chunk.sh
 
 GIT_TEST_COMMIT_GRAPH=0
 GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
@@ -285,13 +288,39 @@ test_expect_success 'verify hashes along chain, even in shallow' '
        )
 '
 
+test_expect_success 'verify notices chain slice which is bogus (base)' '
+       git clone --no-hardlinks . verify-chain-bogus-base &&
+       (
+               cd verify-chain-bogus-base &&
+               git commit-graph verify &&
+               base_file=$graphdir/graph-$(sed -n 1p $graphdir/commit-graph-chain).graph &&
+               echo "garbage" >$base_file &&
+               test_must_fail git commit-graph verify 2>test_err &&
+               grep -v "^+" test_err >err &&
+               grep "commit-graph file is too small" err
+       )
+'
+
+test_expect_success 'verify notices chain slice which is bogus (tip)' '
+       git clone --no-hardlinks . verify-chain-bogus-tip &&
+       (
+               cd verify-chain-bogus-tip &&
+               git commit-graph verify &&
+               tip_file=$graphdir/graph-$(sed -n 2p $graphdir/commit-graph-chain).graph &&
+               echo "garbage" >$tip_file &&
+               test_must_fail git commit-graph verify 2>test_err &&
+               grep -v "^+" test_err >err &&
+               grep "commit-graph file is too small" err
+       )
+'
+
 test_expect_success 'verify --shallow does not check base contents' '
        git clone --no-hardlinks . verify-shallow &&
        (
                cd verify-shallow &&
                git commit-graph verify &&
                base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph &&
-               corrupt_file "$base_file" 1000 "\01" &&
+               corrupt_file "$base_file" 1500 "\01" &&
                git commit-graph verify --shallow &&
                test_must_fail git commit-graph verify 2>test_err &&
                grep -v "^+" test_err >err &&
@@ -306,27 +335,54 @@ test_expect_success 'warn on base graph chunk incorrect' '
                git commit-graph verify &&
                base_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
                corrupt_file "$base_file" $(test_oid base) "\01" &&
-               git commit-graph verify --shallow 2>test_err &&
+               test_must_fail git commit-graph verify --shallow 2>test_err &&
                grep -v "^+" test_err >err &&
                test_i18ngrep "commit-graph chain does not match" err
        )
 '
 
-test_expect_success 'verify after commit-graph-chain corruption' '
-       git clone --no-hardlinks . verify-chain &&
+test_expect_success 'verify after commit-graph-chain corruption (base)' '
+       git clone --no-hardlinks . verify-chain-base &&
        (
-               cd verify-chain &&
-               corrupt_file "$graphdir/commit-graph-chain" 60 "G" &&
-               git commit-graph verify 2>test_err &&
+               cd verify-chain-base &&
+               corrupt_file "$graphdir/commit-graph-chain" 30 "G" &&
+               test_must_fail git commit-graph verify 2>test_err &&
                grep -v "^+" test_err >err &&
                test_i18ngrep "invalid commit-graph chain" err &&
-               corrupt_file "$graphdir/commit-graph-chain" 60 "A" &&
-               git commit-graph verify 2>test_err &&
+               corrupt_file "$graphdir/commit-graph-chain" 30 "A" &&
+               test_must_fail git commit-graph verify 2>test_err &&
                grep -v "^+" test_err >err &&
                test_i18ngrep "unable to find all commit-graph files" err
        )
 '
 
+test_expect_success 'verify after commit-graph-chain corruption (tip)' '
+       git clone --no-hardlinks . verify-chain-tip &&
+       (
+               cd verify-chain-tip &&
+               corrupt_file "$graphdir/commit-graph-chain" 70 "G" &&
+               test_must_fail git commit-graph verify 2>test_err &&
+               grep -v "^+" test_err >err &&
+               test_i18ngrep "invalid commit-graph chain" err &&
+               corrupt_file "$graphdir/commit-graph-chain" 70 "A" &&
+               test_must_fail git commit-graph verify 2>test_err &&
+               grep -v "^+" test_err >err &&
+               test_i18ngrep "unable to find all commit-graph files" err
+       )
+'
+
+test_expect_success 'verify notices too-short chain file' '
+       git clone --no-hardlinks . verify-chain-short &&
+       (
+               cd verify-chain-short &&
+               git commit-graph verify &&
+               echo "garbage" >$graphdir/commit-graph-chain &&
+               test_must_fail git commit-graph verify 2>test_err &&
+               grep -v "^+" test_err >err &&
+               grep "commit-graph chain file too small" err
+       )
+'
+
 test_expect_success 'verify across alternates' '
        git clone --no-hardlinks . verify-alt &&
        (
@@ -338,10 +394,23 @@ test_expect_success 'verify across alternates' '
                test_commit extra &&
                git commit-graph write --reachable --split &&
                tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
-               corrupt_file "$tip_file" 100 "\01" &&
+               corrupt_file "$tip_file" 1500 "\01" &&
                test_must_fail git commit-graph verify --shallow 2>test_err &&
                grep -v "^+" test_err >err &&
-               test_i18ngrep "commit-graph has incorrect fanout value" err
+               test_i18ngrep "incorrect checksum" err
+       )
+'
+
+test_expect_success 'reader bounds-checks base-graph chunk' '
+       git clone --no-hardlinks . corrupt-base-chunk &&
+       (
+               cd corrupt-base-chunk &&
+               tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
+               corrupt_chunk_file "$tip_file" BASE clear 01020304 &&
+               git -c core.commitGraph=false log >expect.out &&
+               git -c core.commitGraph=true log >out 2>err &&
+               test_cmp expect.out out &&
+               grep "commit-graph base graphs chunk is too small" err
        )
 '
 
@@ -351,7 +420,8 @@ test_expect_success 'add octopus merge' '
        git branch merge/octopus &&
        git commit-graph write --reachable --split &&
        git commit-graph verify --progress 2>err &&
-       test_line_count = 3 err &&
+       test_line_count = 1 err &&
+       grep "Verifying commits in commit graph: 100% (18/18)" err &&
        test_i18ngrep ! warning err &&
        test_line_count = 3 $graphdir/commit-graph-chain
 '
index f771c442d41f52b10e750f95e1b332c72033d9e7..70d1b58709a91199bf6d589e141897ca96204547 100755 (executable)
@@ -478,4 +478,39 @@ test_expect_success 'git fsck correctly identifies good and bad bitmaps' '
        grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err
 '
 
+test_expect_success 'corrupt MIDX with bitmap causes fallback' '
+       git init corrupt-midx-bitmap &&
+       (
+               cd corrupt-midx-bitmap &&
+
+               test_commit first &&
+               git repack -d &&
+               test_commit second &&
+               git repack -d &&
+
+               git multi-pack-index write --bitmap &&
+               checksum=$(midx_checksum $objdir) &&
+               for f in $midx $midx-$checksum.bitmap
+               do
+                       mv $f $f.bak || return 1
+               done &&
+
+               # pack everything together, invalidating the MIDX
+               git repack -ad &&
+               # then restore the now-stale MIDX
+               for f in $midx $midx-$checksum.bitmap
+               do
+                       mv $f.bak $f || return 1
+               done &&
+
+               git rev-list --count --objects --use-bitmap-index HEAD >out 2>err &&
+               # should attempt opening the broken pack twice (once
+               # from the attempt to load it via the stale bitmap, and
+               # again when attempting to load it from the stale MIDX)
+               # before falling back to the non-MIDX case
+               test 2 -eq $(grep -c "could not open pack" err) &&
+               test 6 -eq $(cat out)
+       )
+'
+
 test_done
index 57e4d9c6998c2b690881984f5809fba6525bd4cc..fc6a242b56d88686036ff019003352ee806ef8ce 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='commit graph with 64-bit timestamps'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 if ! test_have_prereq TIME_IS_64BIT || ! test_have_prereq TIME_T_IS_64BIT
@@ -10,6 +12,7 @@ then
 fi
 
 . "$TEST_DIRECTORY"/lib-commit-graph.sh
+. "$TEST_DIRECTORY/lib-chunk.sh"
 
 UNIX_EPOCH_ZERO="@0 +0000"
 FUTURE_DATE="@4147483646 +0000"
@@ -37,39 +40,48 @@ test_expect_success 'lower layers have overflow chunk' '
 graph_git_behavior 'overflow' '' HEAD~2 HEAD
 
 test_expect_success 'set up and verify repo with generation data overflow chunk' '
-       mkdir repo &&
-       cd repo &&
-       git init &&
-       test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
-       test_commit 2 &&
-       test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
-       git commit-graph write --reachable &&
-       graph_read_expect 3 generation_data &&
-       test_commit --date "$FUTURE_DATE" 4 &&
-       test_commit 5 &&
-       test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
-       git branch left &&
-       git reset --hard 3 &&
-       test_commit 7 &&
-       test_commit --date "$FUTURE_DATE" 8 &&
-       test_commit 9 &&
-       git branch right &&
-       git reset --hard 3 &&
-       test_merge M left right &&
-       git commit-graph write --reachable &&
-       graph_read_expect 10 "generation_data generation_data_overflow" &&
-       git commit-graph verify
+       git init repo &&
+       (
+               cd repo &&
+               test_commit --date "$UNIX_EPOCH_ZERO" 1 &&
+               test_commit 2 &&
+               test_commit --date "$UNIX_EPOCH_ZERO" 3 &&
+               git commit-graph write --reachable &&
+               graph_read_expect 3 generation_data &&
+               test_commit --date "$FUTURE_DATE" 4 &&
+               test_commit 5 &&
+               test_commit --date "$UNIX_EPOCH_ZERO" 6 &&
+               git branch left &&
+               git reset --hard 3 &&
+               test_commit 7 &&
+               test_commit --date "$FUTURE_DATE" 8 &&
+               test_commit 9 &&
+               git branch right &&
+               git reset --hard 3 &&
+               test_merge M left right &&
+               git commit-graph write --reachable &&
+               graph_read_expect 10 "generation_data generation_data_overflow" &&
+               git commit-graph verify
+       )
 '
 
 graph_git_behavior 'overflow 2' repo left right
 
 test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
        git init repo-uint32-max &&
-       cd repo-uint32-max &&
-       test_commit --date "@4294967297 +0000" 1 &&
+       test_commit -C repo-uint32-max --date "@4294967297 +0000" 1 &&
+       git -C repo-uint32-max commit-graph write --reachable &&
+       graph_read_expect -C repo-uint32-max 1 "generation_data" &&
+       git -C repo-uint32-max commit-graph verify
+'
+
+test_expect_success 'reader notices out-of-bounds generation overflow' '
+       graph=.git/objects/info/commit-graph &&
+       test_when_finished "rm -rf $graph" &&
        git commit-graph write --reachable &&
-       graph_read_expect 1 "generation_data" &&
-       git commit-graph verify
+       corrupt_chunk_file $graph GDO2 clear &&
+       test_must_fail git log 2>err &&
+       grep "commit-graph overflow generation data is too small" err
 '
 
 test_done
index 303f7a5d842d36edb191bb05ec61df9a6af8d7c9..fc5fedbe9b0c4dd5b59a429a4a877c422f46e602 100755 (executable)
@@ -573,23 +573,54 @@ test_expect_success 'cruft repack with no reachable objects' '
        )
 '
 
-test_expect_success 'cruft repack ignores --max-pack-size' '
+write_blob () {
+       test-tool genrandom "$@" >in &&
+       git hash-object -w -t blob in
+}
+
+find_pack () {
+       for idx in $(ls $packdir/pack-*.idx)
+       do
+               git show-index <$idx >out &&
+               if grep -q "$1" out
+               then
+                       echo $idx
+               fi || return 1
+       done
+}
+
+test_expect_success 'cruft repack with --max-pack-size' '
        git init max-pack-size &&
        (
                cd max-pack-size &&
                test_commit base &&
+
                # two cruft objects which exceed the maximum pack size
-               test-tool genrandom foo 1048576 | git hash-object --stdin -w &&
-               test-tool genrandom bar 1048576 | git hash-object --stdin -w &&
+               foo=$(write_blob foo 1048576) &&
+               bar=$(write_blob bar 1048576) &&
+               test-tool chmtime --get -1000 \
+                       "$objdir/$(test_oid_to_path $foo)" >foo.mtime &&
+               test-tool chmtime --get -2000 \
+                       "$objdir/$(test_oid_to_path $bar)" >bar.mtime &&
                git repack --cruft --max-pack-size=1M &&
                find $packdir -name "*.mtimes" >cruft &&
-               test_line_count = 1 cruft &&
-               test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects &&
-               test_line_count = 2 objects
+               test_line_count = 2 cruft &&
+
+               foo_mtimes="$(basename $(find_pack $foo) .idx).mtimes" &&
+               bar_mtimes="$(basename $(find_pack $bar) .idx).mtimes" &&
+               test-tool pack-mtimes $foo_mtimes >foo.actual &&
+               test-tool pack-mtimes $bar_mtimes >bar.actual &&
+
+               echo "$foo $(cat foo.mtime)" >foo.expect &&
+               echo "$bar $(cat bar.mtime)" >bar.expect &&
+
+               test_cmp foo.expect foo.actual &&
+               test_cmp bar.expect bar.actual &&
+               test "$foo_mtimes" != "$bar_mtimes"
        )
 '
 
-test_expect_success 'cruft repack ignores pack.packSizeLimit' '
+test_expect_success 'cruft repack with pack.packSizeLimit' '
        (
                cd max-pack-size &&
                # repack everything back together to remove the existing cruft
@@ -599,9 +630,12 @@ test_expect_success 'cruft repack ignores pack.packSizeLimit' '
                # ensure the same post condition is met when --max-pack-size
                # would otherwise be inferred from the configuration
                find $packdir -name "*.mtimes" >cruft &&
-               test_line_count = 1 cruft &&
-               test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects &&
-               test_line_count = 2 objects
+               test_line_count = 2 cruft &&
+               for pack in $(cat cruft)
+               do
+                       test-tool pack-mtimes "$(basename $pack)" >objects &&
+                       test_line_count = 1 objects || return 1
+               done
        )
 '
 
@@ -739,4 +773,175 @@ test_expect_success 'cruft objects are freshend via loose' '
        )
 '
 
+test_expect_success 'gc.recentObjectsHook' '
+       git init repo &&
+       test_when_finished "rm -fr repo" &&
+       (
+               cd repo &&
+
+               # Create a handful of objects.
+               #
+               #   - one reachable commit, "base", designated for the reachable
+               #     pack
+               #   - one unreachable commit, "cruft.discard", which is marked
+               #     for deletion
+               #   - one unreachable commit, "cruft.old", which would be marked
+               #     for deletion, but is rescued as an extra cruft tip
+               #   - one unreachable commit, "cruft.new", which is not marked
+               #     for deletion
+               test_commit base &&
+               git branch -M main &&
+
+               git checkout --orphan discard &&
+               git rm -fr . &&
+               test_commit --no-tag cruft.discard &&
+
+               git checkout --orphan old &&
+               git rm -fr . &&
+               test_commit --no-tag cruft.old &&
+               cruft_old="$(git rev-parse HEAD)" &&
+
+               git checkout --orphan new &&
+               git rm -fr . &&
+               test_commit --no-tag cruft.new &&
+               cruft_new="$(git rev-parse HEAD)" &&
+
+               git checkout main &&
+               git branch -D discard old new &&
+               git reflog expire --all --expire=all &&
+
+               # mark cruft.old with an mtime that is many minutes
+               # older than the expiration period, and mark cruft.new
+               # with an mtime that is in the future (and thus not
+               # eligible for pruning).
+               test-tool chmtime -2000 "$objdir/$(test_oid_to_path $cruft_old)" &&
+               test-tool chmtime +1000 "$objdir/$(test_oid_to_path $cruft_new)" &&
+
+               # Write the list of cruft objects we expect to
+               # accumulate, which is comprised of everything reachable
+               # from cruft.old and cruft.new, but not cruft.discard.
+               git rev-list --objects --no-object-names \
+                       $cruft_old $cruft_new >cruft.raw &&
+               sort cruft.raw >cruft.expect &&
+
+               # Write the script to list extra tips, which are limited
+               # to cruft.old, in this case.
+               write_script extra-tips <<-EOF &&
+               echo $cruft_old
+               EOF
+               git config gc.recentObjectsHook ./extra-tips &&
+
+               git repack --cruft --cruft-expiration=now -d &&
+
+               mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+               git show-index <${mtimes%.mtimes}.idx >cruft &&
+               cut -d" " -f2 cruft | sort >cruft.actual &&
+               test_cmp cruft.expect cruft.actual &&
+
+               # Ensure that the "old" objects are removed after
+               # dropping the gc.recentObjectsHook hook.
+               git config --unset gc.recentObjectsHook &&
+               git repack --cruft --cruft-expiration=now -d &&
+
+               mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+               git show-index <${mtimes%.mtimes}.idx >cruft &&
+               cut -d" " -f2 cruft | sort >cruft.actual &&
+
+               git rev-list --objects --no-object-names $cruft_new >cruft.raw &&
+               cp cruft.expect cruft.old &&
+               sort cruft.raw >cruft.expect &&
+               test_cmp cruft.expect cruft.actual &&
+
+               # ensure objects which are no longer in the cruft pack were
+               # removed from the repository
+               for object in $(comm -13 cruft.expect cruft.old)
+               do
+                       test_must_fail git cat-file -t $object || return 1
+               done
+       )
+'
+
+test_expect_success 'multi-valued gc.recentObjectsHook' '
+       git init repo &&
+       test_when_finished "rm -fr repo" &&
+       (
+               cd repo &&
+
+               test_commit base &&
+               git branch -M main &&
+
+               git checkout --orphan cruft.a &&
+               git rm -fr . &&
+               test_commit --no-tag cruft.a &&
+               cruft_a="$(git rev-parse HEAD)" &&
+
+               git checkout --orphan cruft.b &&
+               git rm -fr . &&
+               test_commit --no-tag cruft.b &&
+               cruft_b="$(git rev-parse HEAD)" &&
+
+               git checkout main &&
+               git branch -D cruft.a cruft.b &&
+               git reflog expire --all --expire=all &&
+
+               echo "echo $cruft_a" | write_script extra-tips.a &&
+               echo "echo $cruft_b" | write_script extra-tips.b &&
+               echo "false" | write_script extra-tips.c &&
+
+               git rev-list --objects --no-object-names $cruft_a $cruft_b \
+                       >cruft.raw &&
+               sort cruft.raw >cruft.expect &&
+
+               # ensure that each extra cruft tip is saved by its
+               # respective hook
+               git config --add gc.recentObjectsHook ./extra-tips.a &&
+               git config --add gc.recentObjectsHook ./extra-tips.b &&
+               git repack --cruft --cruft-expiration=now -d &&
+
+               mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+               git show-index <${mtimes%.mtimes}.idx >cruft &&
+               cut -d" " -f2 cruft | sort >cruft.actual &&
+               test_cmp cruft.expect cruft.actual &&
+
+               # ensure that a dirty exit halts cruft pack generation
+               git config --add gc.recentObjectsHook ./extra-tips.c &&
+               test_must_fail git repack --cruft --cruft-expiration=now -d 2>err &&
+               grep "unable to enumerate additional recent objects" err &&
+
+               # and that the existing cruft pack is left alone
+               test_path_is_file "$mtimes"
+       )
+'
+
+test_expect_success 'additional cruft blobs via gc.recentObjectsHook' '
+       git init repo &&
+       test_when_finished "rm -fr repo" &&
+       (
+               cd repo &&
+
+               test_commit base &&
+
+               blob=$(echo "unreachable" | git hash-object -w --stdin) &&
+
+               # mark the unreachable blob we wrote above as having
+               # aged out of the retention period
+               test-tool chmtime -2000 "$objdir/$(test_oid_to_path $blob)" &&
+
+               # Write the script to list extra tips, which is just the
+               # extra blob as above.
+               write_script extra-tips <<-EOF &&
+               echo $blob
+               EOF
+               git config gc.recentObjectsHook ./extra-tips &&
+
+               git repack --cruft --cruft-expiration=now -d &&
+
+               mtimes="$(ls .git/objects/pack/pack-*.mtimes)" &&
+               git show-index <${mtimes%.mtimes}.idx >cruft &&
+               cut -d" " -f2 cruft >actual &&
+               echo $blob >expect &&
+               test_cmp expect actual
+       )
+'
+
 test_done
index 8c8af99b844be1ad571f55364891db10fc172d98..43cbcd5d497ecaef33c97032e7c5a8729fb4c01c 100755 (executable)
@@ -55,7 +55,7 @@ check_fsync_events () {
 
        cat >expect &&
        sed -n \
-               -e '/^{"event":"data",.*"category":"fsync",/ {
+               -e '/^{"event":"counter",.*"category":"fsync",/ {
                        s/.*"category":"fsync",//;
                        s/}$//;
                        p;
@@ -78,8 +78,8 @@ test_expect_success 'unpack big object in stream (core.fsyncmethod=batch)' '
                flush_count=1
        fi &&
        check_fsync_events trace2.txt <<-EOF &&
-       "key":"fsync/writeout-only","value":"6"
-       "key":"fsync/hardware-flush","value":"$flush_count"
+       "name":"writeout-only","count":6
+       "name":"hardware-flush","count":$flush_count
        EOF
 
        test_dir_is_empty dest.git/objects/pack &&
index cc078896673ae221754a5b65102b559b872dcfd9..51737eeafeeefa0c1b1f075081f4c5c4b95de64e 100755 (executable)
@@ -5,6 +5,7 @@ test_description='tracking branch update checks for git push'
 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 5f3ff051ca2fa3bba8beabbcb1491d5e69262f34..ad7f8c6f00202c5ec844108b14a2c1301c185223 100755 (executable)
@@ -17,6 +17,12 @@ test_expect_success 'setup' '
        git checkout A^0 &&
        test_commit E bar E &&
        test_commit F foo F &&
+       git checkout B &&
+       git merge E &&
+       git tag merge-E &&
+       test_commit G G &&
+       test_commit H H &&
+       test_commit I I &&
        git checkout main &&
 
        test_hook --setup post-rewrite <<-EOF
@@ -173,6 +179,48 @@ test_fail_interactive_rebase () {
        )
 }
 
+test_expect_success 'git rebase with failed pick' '
+       clear_hook_input &&
+       cat >todo <<-\EOF &&
+       exec >bar
+       merge -C merge-E E
+       exec >G
+       pick G
+       exec >H 2>I
+       pick H
+       fixup I
+       EOF
+
+       (
+               set_replace_editor todo &&
+               test_must_fail git rebase -i D D 2>err
+       ) &&
+       grep "would be overwritten" err &&
+       rm bar &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "would be overwritten" err &&
+       rm G &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "would be overwritten" err &&
+       rm H &&
+
+       test_must_fail git rebase --continue 2>err &&
+       grep "would be overwritten" err &&
+       rm I &&
+
+       git rebase --continue &&
+       echo rebase >expected.args &&
+       cat >expected.data <<-EOF &&
+       $(git rev-parse merge-E) $(git rev-parse HEAD~2)
+       $(git rev-parse G) $(git rev-parse HEAD~1)
+       $(git rev-parse H) $(git rev-parse HEAD)
+       $(git rev-parse I) $(git rev-parse HEAD)
+       EOF
+       verify_hook_input
+'
+
 test_expect_success 'git rebase -i (unchanged)' '
        git reset --hard D &&
        clear_hook_input &&
index 4f289063ced85dc2beabde28788c191a20bf9634..19c36b57f4b2d5363599625ea71ee5a9a87509b0 100755 (executable)
@@ -1127,6 +1127,52 @@ do
        '
 done
 
+test_expect_success 'prepare source branch' '
+       echo one >onebranch &&
+       git checkout --orphan onebranch &&
+       git rm --cached -r . &&
+       git add onebranch &&
+       git commit -m onebranch &&
+       git rev-list --objects onebranch -- >actual &&
+       # 3 objects should be created, at least ...
+       test 3 -le $(wc -l <actual)
+'
+
+validate_store_type () {
+       git -C dest count-objects -v >actual &&
+       case "$store_type" in
+       packed)
+               grep "^count: 0$" actual ;;
+       loose)
+               grep "^packs: 0$" actual ;;
+       esac || {
+               echo "store_type is $store_type"
+               cat actual
+               false
+       }
+}
+
+test_unpack_limit () {
+       store_type=$1
+
+       case "$store_type" in
+       packed) fetch_limit=1 transfer_limit=10000 ;;
+       loose) fetch_limit=10000 transfer_limit=1 ;;
+       esac
+
+       test_expect_success "fetch trumps transfer limit" '
+               rm -fr dest &&
+               git --bare init dest &&
+               git -C dest config fetch.unpacklimit $fetch_limit &&
+               git -C dest config transfer.unpacklimit $transfer_limit &&
+               git -C dest fetch .. onebranch &&
+               validate_store_type
+       '
+}
+
+test_unpack_limit packed
+test_unpack_limit loose
+
 setup_negotiation_tip () {
        SERVER="$1"
        URL="$2"
index 19ebefa5aceb1afd3916f903971013e985836329..87163d77456e5c2738c48dcdde282e2ea7b65a4d 100755 (executable)
@@ -120,6 +120,17 @@ test_expect_success setup '
 
 '
 
+for cmd in push fetch
+do
+       for opt in ipv4 ipv6
+       do
+               test_expect_success "reject 'git $cmd --no-$opt'" '
+                       test_must_fail git $cmd --no-$opt 2>err &&
+                       grep "unknown option .no-$opt" err
+               '
+       done
+done
+
 test_expect_success 'fetch without wildcard' '
        mk_empty testrepo &&
        (
index a448e169bd029f21ec77cd89dc087c8e637578f8..6d4944a72826401d3e698ad4c1b6982c4a233eae 100755 (executable)
@@ -5,6 +5,7 @@ test_description='pushing to a mirror repository'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 D=$(pwd)
index 264de29c35c11cbe09d31d57629aabaae0423b35..079b2f2536e6974c90b152226d8ea2189016a6f6 100755 (executable)
@@ -5,6 +5,7 @@ test_description='pull options'
 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 45815f737850b61684f648af9d984ac16ea0944e..3a28f1ded5fdcce6b2a55aa6122e27489d942265 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='tagopt variable affects "git fetch" and is overridden by commandline.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 setup_clone () {
index eed3c9d81abaffa8886b44f26224111b369735ce..9fc9ba552f1db320a595dcf7b5b23c31b5c855b1 100755 (executable)
@@ -9,10 +9,26 @@ TEST_PASSES_SANITIZE_LEAK=true
 # When the limit is 1, `git receive-pack` will call `git index-pack`.
 # When the limit is 10000, `git receive-pack` will call `git unpack-objects`.
 
+validate_store_type () {
+       git -C dest count-objects -v >actual &&
+       case "$store_type" in
+       index)
+               grep "^count: 0$" actual ;;
+       unpack)
+               grep "^packs: 0$" actual ;;
+       esac || {
+               echo "store_type is $store_type"
+               cat actual
+               false;
+       }
+}
+
 test_pack_input_limit () {
-       case "$1" in
-       index) unpack_limit=1 ;;
-       unpack) unpack_limit=10000 ;;
+       store_type=$1
+
+       case "$store_type" in
+       index) unpack_limit=1 other_limit=10000 ;;
+       unpack) unpack_limit=10000 other_limit=1 ;;
        esac
 
        test_expect_success 'prepare destination repository' '
@@ -43,6 +59,19 @@ test_pack_input_limit () {
                git --git-dir=dest config receive.maxInputSize 0 &&
                git push dest HEAD
        '
+
+       test_expect_success 'prepare destination repository (once more)' '
+               rm -fr dest &&
+               git --bare init dest
+       '
+
+       test_expect_success 'receive trumps transfer' '
+               git --git-dir=dest config receive.unpacklimit "$unpack_limit" &&
+               git --git-dir=dest config transfer.unpacklimit "$other_limit" &&
+               git push dest HEAD &&
+               validate_store_type
+       '
+
 }
 
 test_expect_success "create known-size (1024 bytes) commit" '
index a11b20e378223ea30242e70d5befcfeed889a2ed..448134c4bf72bd5f3a4c2287e59f6f2a1f3f074b 100755 (executable)
@@ -4,6 +4,7 @@ test_description='check pre-push 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 'setup' '
index e7e1b6dab66fb31d065c4dc7611c824a7bc1bf5b..320f49c753f41376ad757aedf134a76bd6206a68 100755 (executable)
@@ -5,6 +5,7 @@ test_description='check the consisitency of behavior of --all and --branches'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 delete_refs() {
index 27f9f7763895ec98761800d2a3e4ad2adf33aeb9..5890319b97b8269ee2957315a3670a7c0cfa8caf 100755 (executable)
@@ -120,6 +120,16 @@ test_expect_success 'prefers -c config over --template config' '
 
 '
 
+test_expect_failure 'prefers --template config even for core.bare' '
+
+       template="$TRASH_DIRECTORY/template-with-bare-config" &&
+       mkdir "$template" &&
+       git config --file "$template/config" core.bare true &&
+       git clone "--template=$template" parent clone-bare-config &&
+       test "$(git -C clone-bare-config config --local core.bare)" = "true" &&
+       test_path_is_file clone-bare-config/HEAD
+'
+
 test_expect_success 'prefers config "clone.defaultRemoteName" over default' '
 
        test_config_global clone.defaultRemoteName from_config &&
index f519d2a87a7d84e482284998cbca338a0dfba419..8759fc285337e2bbc43fc746aa7c97bdc91a5b91 100755 (executable)
@@ -257,8 +257,8 @@ test_expect_success 'partial clone with transfer.fsckobjects=1 works with submod
        test_commit -C submodule mycommit &&
 
        test_create_repo src_with_sub &&
-       test_config -C src_with_sub uploadpack.allowfilter 1 &&
-       test_config -C src_with_sub uploadpack.allowanysha1inwant 1 &&
+       git -C src_with_sub config uploadpack.allowfilter 1 &&
+       git -C src_with_sub config uploadpack.allowanysha1inwant 1 &&
 
        test_config_global protocol.file.allow always &&
 
@@ -270,6 +270,12 @@ test_expect_success 'partial clone with transfer.fsckobjects=1 works with submod
        test_when_finished rm -rf dst
 '
 
+test_expect_success 'lazily fetched .gitmodules works' '
+       git clone --filter="blob:none" --no-checkout "file://$(pwd)/src_with_sub" dst &&
+       git -C dst fetch &&
+       test_when_finished rm -rf dst
+'
+
 test_expect_success 'partial clone with transfer.fsckobjects=1 uses index-pack --fsck-objects' '
        git init src &&
        test_commit -C src x &&
index 8ac6b2a1d0a286cac120c751e5e3038e465dc074..ed773e7432694b7ccc05a4d09084f238c9ff4b42 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='test disabling of git-over-tcp in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY/lib-proto-disable.sh"
 . "$TEST_DIRECTORY/lib-git-daemon.sh"
index 5a67bbc760fdc8c2b53dc7721a144e033bf8e934..ced40157ed68c077c17cb4758d1ebbc529e67d9c 100755 (executable)
@@ -5,6 +5,7 @@ test_description='ancestor culling and limiting by parent number'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_revlist () {
index 05162512a09d422a9592a112a1d613d34be4f5ed..4821b90e7479ad8f4878ab4432ce0e9d2ce47de5 100755 (executable)
@@ -48,7 +48,9 @@ test_expect_success setup '
                        git add file-$i &&
                        test_tick &&
                        git commit -m side-$i || exit
-               done
+               done &&
+
+               git update-ref refs/heads/-dashed-branch HEAD
        )
 '
 
@@ -60,6 +62,13 @@ check side-1 ^side-7 -- file-2
 check side-3 ^side-4 -- file-3
 check side-3 ^side-2
 check side-3 ^side-2 -- file-1
+check --all
+check --all --not --branches
+check --glob=refs/heads
+check --glob=refs/heads --
+check --glob=refs/heads -- file-1
+check --end-of-options -dashed-branch
+check --all --not refs/heads/main
 
 test_expect_success 'not only --stdin' '
        cat >expect <<-EOF &&
@@ -78,4 +87,65 @@ test_expect_success 'not only --stdin' '
        test_cmp expect actual
 '
 
+test_expect_success 'pseudo-opt with missing value' '
+       cat >input <<-EOF &&
+       --glob
+       refs/heads
+       EOF
+
+       cat >expect <<-EOF &&
+       fatal: Option ${SQ}--glob${SQ} requires a value
+       EOF
+
+       test_must_fail git rev-list --stdin <input 2>error &&
+       test_cmp expect error
+'
+
+test_expect_success 'pseudo-opt with invalid value' '
+       cat >input <<-EOF &&
+       --no-walk=garbage
+       EOF
+
+       cat >expect <<-EOF &&
+       error: invalid argument to --no-walk
+       fatal: invalid option ${SQ}--no-walk=garbage${SQ} in --stdin mode
+       EOF
+
+       test_must_fail git rev-list --stdin <input 2>error &&
+       test_cmp expect error
+'
+
+test_expect_success 'unknown option without --end-of-options' '
+       cat >input <<-EOF &&
+       -dashed-branch
+       EOF
+
+       cat >expect <<-EOF &&
+       fatal: invalid option ${SQ}-dashed-branch${SQ} in --stdin mode
+       EOF
+
+       test_must_fail git rev-list --stdin <input 2>error &&
+       test_cmp expect error
+'
+
+test_expect_success '--not on command line does not influence revisions read via --stdin' '
+       cat >input <<-EOF &&
+       refs/heads/main
+       EOF
+       git rev-list refs/heads/main >expect &&
+
+       git rev-list refs/heads/main --not --stdin <input >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--not via stdin does not influence revisions from command line' '
+       cat >input <<-EOF &&
+       --not
+       EOF
+       git rev-list refs/heads/main >expect &&
+
+       git rev-list refs/heads/main --stdin refs/heads/main <input >actual &&
+       test_cmp expect actual
+'
+
 test_done
index dface8bcfe2641ee07ee36309d1c333224879283..3e6bcbf30cdaf0e623ae73858a4f98838e03255c 100755 (executable)
@@ -619,6 +619,12 @@ test_expect_success TTY 'create --quiet disables all bundle progress' '
        test_must_be_empty err
 '
 
+test_expect_success 'bundle progress with --no-quiet' '
+       GIT_PROGRESS_DELAY=0 \
+               git bundle create --no-quiet out.bundle --all 2>err &&
+       grep "%" err
+'
+
 test_expect_success 'read bundle over stdin' '
        git bundle create some.bundle HEAD &&
 
index a313849406ddb4b7f104ee06eabc9068d5551425..7ddbd96e58e71d0ef5cae0334b0ff005c7a5cb25 100755 (executable)
@@ -5,6 +5,7 @@ test_description='remote tracking stats'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 advance () {
index 2500acc2ef80f9679105adfa73a805d06e14180c..c9925edf20e7b82ed286b97b9d7247f884c20a62 100755 (executable)
@@ -62,59 +62,59 @@ HASH6=
 HASH7=
 
 test_expect_success 'set up buggy branch' '
-     echo "line 1" >>hello &&
-     echo "line 2" >>hello &&
-     echo "line 3" >>hello &&
-     echo "line 4" >>hello &&
-     add_and_commit_file hello "4 lines" &&
-     HASH1=$(git rev-parse --verify HEAD) &&
-     echo "line BUG" >>hello &&
-     echo "line 6" >>hello &&
-     echo "line 7" >>hello &&
-     echo "line 8" >>hello &&
-     add_and_commit_file hello "4 more lines with a BUG" &&
-     HASH2=$(git rev-parse --verify HEAD) &&
-     echo "line 9" >>hello &&
-     echo "line 10" >>hello &&
-     add_and_commit_file hello "2 more lines" &&
-     HASH3=$(git rev-parse --verify HEAD) &&
-     echo "line 11" >>hello &&
-     add_and_commit_file hello "1 more line" &&
-     HASH4=$(git rev-parse --verify HEAD) &&
-     sed -e "s/BUG/5/" hello >hello.new &&
-     mv hello.new hello &&
-     add_and_commit_file hello "BUG fixed" &&
-     HASH5=$(git rev-parse --verify HEAD) &&
-     echo "line 12" >>hello &&
-     echo "line 13" >>hello &&
-     add_and_commit_file hello "2 more lines" &&
-     HASH6=$(git rev-parse --verify HEAD) &&
-     echo "line 14" >>hello &&
-     echo "line 15" >>hello &&
-     echo "line 16" >>hello &&
-     add_and_commit_file hello "again 3 more lines" &&
-     HASH7=$(git rev-parse --verify HEAD)
+       echo "line 1" >>hello &&
+       echo "line 2" >>hello &&
+       echo "line 3" >>hello &&
+       echo "line 4" >>hello &&
+       add_and_commit_file hello "4 lines" &&
+       HASH1=$(git rev-parse --verify HEAD) &&
+       echo "line BUG" >>hello &&
+       echo "line 6" >>hello &&
+       echo "line 7" >>hello &&
+       echo "line 8" >>hello &&
+       add_and_commit_file hello "4 more lines with a BUG" &&
+       HASH2=$(git rev-parse --verify HEAD) &&
+       echo "line 9" >>hello &&
+       echo "line 10" >>hello &&
+       add_and_commit_file hello "2 more lines" &&
+       HASH3=$(git rev-parse --verify HEAD) &&
+       echo "line 11" >>hello &&
+       add_and_commit_file hello "1 more line" &&
+       HASH4=$(git rev-parse --verify HEAD) &&
+       sed -e "s/BUG/5/" hello >hello.new &&
+       mv hello.new hello &&
+       add_and_commit_file hello "BUG fixed" &&
+       HASH5=$(git rev-parse --verify HEAD) &&
+       echo "line 12" >>hello &&
+       echo "line 13" >>hello &&
+       add_and_commit_file hello "2 more lines" &&
+       HASH6=$(git rev-parse --verify HEAD) &&
+       echo "line 14" >>hello &&
+       echo "line 15" >>hello &&
+       echo "line 16" >>hello &&
+       add_and_commit_file hello "again 3 more lines" &&
+       HASH7=$(git rev-parse --verify HEAD)
 '
 
 test_expect_success 'replace the author' '
-     git cat-file commit $HASH2 | grep "author A U Thor" &&
-     R=$(git cat-file commit $HASH2 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) &&
-     git cat-file commit $R | grep "author O Thor" &&
-     git update-ref refs/replace/$HASH2 $R &&
-     git show HEAD~5 | grep "O Thor" &&
-     git show $HASH2 | grep "O Thor"
+       git cat-file commit $HASH2 | grep "author A U Thor" &&
+       R=$(git cat-file commit $HASH2 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) &&
+       git cat-file commit $R | grep "author O Thor" &&
+       git update-ref refs/replace/$HASH2 $R &&
+       git show HEAD~5 | grep "O Thor" &&
+       git show $HASH2 | grep "O Thor"
 '
 
 test_expect_success 'test --no-replace-objects option' '
-     git cat-file commit $HASH2 | grep "author O Thor" &&
-     git --no-replace-objects cat-file commit $HASH2 | grep "author A U Thor" &&
-     git show $HASH2 | grep "O Thor" &&
-     git --no-replace-objects show $HASH2 | grep "A U Thor"
+       git cat-file commit $HASH2 | grep "author O Thor" &&
+       git --no-replace-objects cat-file commit $HASH2 | grep "author A U Thor" &&
+       git show $HASH2 | grep "O Thor" &&
+       git --no-replace-objects show $HASH2 | grep "A U Thor"
 '
 
 test_expect_success 'test GIT_NO_REPLACE_OBJECTS env variable' '
-     GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 | grep "author A U Thor" &&
-     GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 | grep "A U Thor"
+       GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 | grep "author A U Thor" &&
+       GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 | grep "A U Thor"
 '
 
 test_expect_success 'test core.usereplacerefs config option' '
@@ -132,64 +132,64 @@ tagger T A Gger <> 0 +0000
 EOF
 
 test_expect_success 'tag replaced commit' '
-     git update-ref refs/tags/mytag $(git mktag <tag.sig)
+       git update-ref refs/tags/mytag $(git mktag <tag.sig)
 '
 
 test_expect_success '"git fsck" works' '
-     git fsck main >fsck_main.out &&
-     test_i18ngrep "dangling commit $R" fsck_main.out &&
-     test_i18ngrep "dangling tag $(git show-ref -s refs/tags/mytag)" fsck_main.out &&
-     test -z "$(git fsck)"
+       git fsck main >fsck_main.out &&
+       test_i18ngrep "dangling commit $R" fsck_main.out &&
+       test_i18ngrep "dangling tag $(git show-ref -s refs/tags/mytag)" fsck_main.out &&
+       test -z "$(git fsck)"
 '
 
 test_expect_success 'repack, clone and fetch work' '
-     git repack -a -d &&
-     git clone --no-hardlinks . clone_dir &&
-     (
-         cd clone_dir &&
-         git show HEAD~5 | grep "A U Thor" &&
-         git show $HASH2 | grep "A U Thor" &&
-         git cat-file commit $R &&
-         git repack -a -d &&
-         test_must_fail git cat-file commit $R &&
-         git fetch ../ "refs/replace/*:refs/replace/*" &&
-         git show HEAD~5 | grep "O Thor" &&
-         git show $HASH2 | grep "O Thor" &&
-         git cat-file commit $R
-     )
+       git repack -a -d &&
+       git clone --no-hardlinks . clone_dir &&
+       (
+               cd clone_dir &&
+               git show HEAD~5 | grep "A U Thor" &&
+               git show $HASH2 | grep "A U Thor" &&
+               git cat-file commit $R &&
+               git repack -a -d &&
+               test_must_fail git cat-file commit $R &&
+               git fetch ../ "refs/replace/*:refs/replace/*" &&
+               git show HEAD~5 | grep "O Thor" &&
+               git show $HASH2 | grep "O Thor" &&
+               git cat-file commit $R
+       )
 '
 
 test_expect_success '"git replace" listing and deleting' '
-     test "$HASH2" = "$(git replace -l)" &&
-     test "$HASH2" = "$(git replace)" &&
-     aa=${HASH2%??????????????????????????????????????} &&
-     test "$HASH2" = "$(git replace --list "$aa*")" &&
-     test_must_fail git replace -d $R &&
-     test_must_fail git replace --delete &&
-     test_must_fail git replace -l -d $HASH2 &&
-     git replace -d $HASH2 &&
-     git show $HASH2 | grep "A U Thor" &&
-     test -z "$(git replace -l)"
+       test "$HASH2" = "$(git replace -l)" &&
+       test "$HASH2" = "$(git replace)" &&
+       aa=${HASH2%??????????????????????????????????????} &&
+       test "$HASH2" = "$(git replace --list "$aa*")" &&
+       test_must_fail git replace -d $R &&
+       test_must_fail git replace --delete &&
+       test_must_fail git replace -l -d $HASH2 &&
+       git replace -d $HASH2 &&
+       git show $HASH2 | grep "A U Thor" &&
+       test -z "$(git replace -l)"
 '
 
 test_expect_success '"git replace" replacing' '
-     git replace $HASH2 $R &&
-     git show $HASH2 | grep "O Thor" &&
-     test_must_fail git replace $HASH2 $R &&
-     git replace -f $HASH2 $R &&
-     test_must_fail git replace -f &&
-     test "$HASH2" = "$(git replace)"
+       git replace $HASH2 $R &&
+       git show $HASH2 | grep "O Thor" &&
+       test_must_fail git replace $HASH2 $R &&
+       git replace -f $HASH2 $R &&
+       test_must_fail git replace -f &&
+       test "$HASH2" = "$(git replace)"
 '
 
 test_expect_success '"git replace" resolves sha1' '
-     SHORTHASH2=$(git rev-parse --short=8 $HASH2) &&
-     git replace -d $SHORTHASH2 &&
-     git replace $SHORTHASH2 $R &&
-     git show $HASH2 | grep "O Thor" &&
-     test_must_fail git replace $HASH2 $R &&
-     git replace -f $HASH2 $R &&
-     test_must_fail git replace --force &&
-     test "$HASH2" = "$(git replace)"
+       SHORTHASH2=$(git rev-parse --short=8 $HASH2) &&
+       git replace -d $SHORTHASH2 &&
+       git replace $SHORTHASH2 $R &&
+       git show $HASH2 | grep "O Thor" &&
+       test_must_fail git replace $HASH2 $R &&
+       git replace -f $HASH2 $R &&
+       test_must_fail git replace --force &&
+       test "$HASH2" = "$(git replace)"
 '
 
 # This creates a side branch where the bug in H2
@@ -207,79 +207,79 @@ test_expect_success '"git replace" resolves sha1' '
 # Then we replace H6 with P6.
 #
 test_expect_success 'create parallel branch without the bug' '
-     git replace -d $HASH2 &&
-     git show $HASH2 | grep "A U Thor" &&
-     git checkout $HASH1 &&
-     git cherry-pick $HASH2 &&
-     git show $HASH5 | git apply &&
-     git commit --amend -m "hello: 4 more lines WITHOUT the bug" hello &&
-     PARA2=$(git rev-parse --verify HEAD) &&
-     git cherry-pick $HASH3 &&
-     PARA3=$(git rev-parse --verify HEAD) &&
-     git cherry-pick $HASH4 &&
-     PARA4=$(git rev-parse --verify HEAD) &&
-     git cherry-pick $HASH6 &&
-     PARA6=$(git rev-parse --verify HEAD) &&
-     git replace $HASH6 $PARA6 &&
-     git checkout main &&
-     cur=$(git rev-parse --verify HEAD) &&
-     test "$cur" = "$HASH7" &&
-     git log --pretty=oneline | grep $PARA2 &&
-     git remote add cloned ./clone_dir
+       git replace -d $HASH2 &&
+       git show $HASH2 | grep "A U Thor" &&
+       git checkout $HASH1 &&
+       git cherry-pick $HASH2 &&
+       git show $HASH5 | git apply &&
+       git commit --amend -m "hello: 4 more lines WITHOUT the bug" hello &&
+       PARA2=$(git rev-parse --verify HEAD) &&
+       git cherry-pick $HASH3 &&
+       PARA3=$(git rev-parse --verify HEAD) &&
+       git cherry-pick $HASH4 &&
+       PARA4=$(git rev-parse --verify HEAD) &&
+       git cherry-pick $HASH6 &&
+       PARA6=$(git rev-parse --verify HEAD) &&
+       git replace $HASH6 $PARA6 &&
+       git checkout main &&
+       cur=$(git rev-parse --verify HEAD) &&
+       test "$cur" = "$HASH7" &&
+       git log --pretty=oneline | grep $PARA2 &&
+       git remote add cloned ./clone_dir
 '
 
 test_expect_success 'push to cloned repo' '
-     git push cloned $HASH6^:refs/heads/parallel &&
-     (
-         cd clone_dir &&
-         git checkout parallel &&
-         git log --pretty=oneline | grep $PARA2
-     )
+       git push cloned $HASH6^:refs/heads/parallel &&
+       (
+               cd clone_dir &&
+               git checkout parallel &&
+               git log --pretty=oneline | grep $PARA2
+       )
 '
 
 test_expect_success 'push branch with replacement' '
-     git cat-file commit $PARA3 | grep "author A U Thor" &&
-     S=$(git cat-file commit $PARA3 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) &&
-     git cat-file commit $S | grep "author O Thor" &&
-     git replace $PARA3 $S &&
-     git show $HASH6~2 | grep "O Thor" &&
-     git show $PARA3 | grep "O Thor" &&
-     git push cloned $HASH6^:refs/heads/parallel2 &&
-     (
-         cd clone_dir &&
-         git checkout parallel2 &&
-         git log --pretty=oneline | grep $PARA3 &&
-         git show $PARA3 | grep "A U Thor"
-     )
+       git cat-file commit $PARA3 | grep "author A U Thor" &&
+       S=$(git cat-file commit $PARA3 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) &&
+       git cat-file commit $S | grep "author O Thor" &&
+       git replace $PARA3 $S &&
+       git show $HASH6~2 | grep "O Thor" &&
+       git show $PARA3 | grep "O Thor" &&
+       git push cloned $HASH6^:refs/heads/parallel2 &&
+       (
+               cd clone_dir &&
+               git checkout parallel2 &&
+               git log --pretty=oneline | grep $PARA3 &&
+               git show $PARA3 | grep "A U Thor"
+       )
 '
 
 test_expect_success 'fetch branch with replacement' '
-     git branch tofetch $HASH6 &&
-     (
-         cd clone_dir &&
-         git fetch origin refs/heads/tofetch:refs/heads/parallel3 &&
-         git log --pretty=oneline parallel3 >output.txt &&
-         ! grep $PARA3 output.txt &&
-         git show $PARA3 >para3.txt &&
-         grep "A U Thor" para3.txt &&
-         git fetch origin "refs/replace/*:refs/replace/*" &&
-         git log --pretty=oneline parallel3 >output.txt &&
-         grep $PARA3 output.txt &&
-         git show $PARA3 >para3.txt &&
-         grep "O Thor" para3.txt
-     )
+       git branch tofetch $HASH6 &&
+       (
+               cd clone_dir &&
+               git fetch origin refs/heads/tofetch:refs/heads/parallel3 &&
+               git log --pretty=oneline parallel3 >output.txt &&
+               ! grep $PARA3 output.txt &&
+               git show $PARA3 >para3.txt &&
+               grep "A U Thor" para3.txt &&
+               git fetch origin "refs/replace/*:refs/replace/*" &&
+               git log --pretty=oneline parallel3 >output.txt &&
+               grep $PARA3 output.txt &&
+               git show $PARA3 >para3.txt &&
+               grep "O Thor" para3.txt
+       )
 '
 
 test_expect_success 'bisect and replacements' '
-     git bisect start $HASH7 $HASH1 &&
-     test "$PARA3" = "$(git rev-parse --verify HEAD)" &&
-     git bisect reset &&
-     GIT_NO_REPLACE_OBJECTS=1 git bisect start $HASH7 $HASH1 &&
-     test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
-     git bisect reset &&
-     git --no-replace-objects bisect start $HASH7 $HASH1 &&
-     test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
-     git bisect reset
+       git bisect start $HASH7 $HASH1 &&
+       test "$PARA3" = "$(git rev-parse --verify HEAD)" &&
+       git bisect reset &&
+       GIT_NO_REPLACE_OBJECTS=1 git bisect start $HASH7 $HASH1 &&
+       test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
+       git bisect reset &&
+       git --no-replace-objects bisect start $HASH7 $HASH1 &&
+       test "$HASH4" = "$(git rev-parse --verify HEAD)" &&
+       git bisect reset
 '
 
 test_expect_success 'index-pack and replacements' '
index c9afcef2018b052a81600487c33846e2917c982f..0a5c4875407e5ec504831cdcb5d2c6e438d622f1 100755 (executable)
@@ -85,6 +85,7 @@ check_describe e-1-gHASH --tags HEAD^^
 check_describe c-2-gHASH --tags HEAD^^2
 check_describe B --tags HEAD^^2^
 check_describe e --tags HEAD^^^
+check_describe e --tags --exact-match HEAD^^^
 
 check_describe heads/main --all HEAD
 check_describe tags/c-6-gHASH --all HEAD^
@@ -96,6 +97,13 @@ check_describe A-3-gHASH --long HEAD^^2
 check_describe c-7-gHASH --tags
 check_describe e-3-gHASH --first-parent --tags
 
+check_describe c-7-gHASH --tags --no-exact-match HEAD
+check_describe e-3-gHASH --first-parent --tags --no-exact-match HEAD
+
+test_expect_success '--exact-match failure' '
+       test_must_fail git describe --exact-match HEAD 2>err
+'
+
 test_expect_success 'describe --contains defaults to HEAD without commit-ish' '
        echo "A^0" >expect &&
        git checkout A &&
index 457cc167c774a0e4551cfc98c4f9aec6a17e1416..f70c395e75f556d72936c78dbd9bfa9a2554a58f 100755 (executable)
@@ -65,7 +65,8 @@ test_expect_success 'setup .gitattributes' '
        fileValue label=foo
        fileWrongLabel label☺
        EOF
-       git add .gitattributes &&
+       echo fileSetLabel label1 >sub/.gitattributes &&
+       git add .gitattributes sub/.gitattributes &&
        git commit -m "add attributes"
 '
 
@@ -78,7 +79,17 @@ test_expect_success 'check specific set attr' '
        test_cmp expect actual
 '
 
-test_expect_success 'check specific set attr (2)' '
+test_expect_success 'check set attr with pathspec pattern' '
+       echo sub/fileSetLabel >expect &&
+
+       git ls-files ":(attr:label)sub" >actual &&
+       test_cmp expect actual &&
+
+       git ls-files ":(attr:label)sub/" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'check specific set attr in tree-ish' '
        cat <<-\EOF >expect &&
        HEAD:fileSetLabel
        HEAD:sub/fileSetLabel
@@ -87,6 +98,16 @@ test_expect_success 'check specific set attr (2)' '
        test_cmp expect actual
 '
 
+test_expect_success 'check specific set attr with pathspec pattern in tree-ish' '
+       echo HEAD:sub/fileSetLabel >expect &&
+
+       git grep -l content HEAD ":(attr:label)sub" >actual &&
+       test_cmp expect actual &&
+
+       git grep -l content HEAD ":(attr:label)sub/" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'check specific unset attr' '
        cat <<-\EOF >expect &&
        fileUnsetLabel
@@ -137,6 +158,7 @@ test_expect_success 'check unspecified attr' '
        fileC
        fileNoLabel
        fileWrongLabel
+       sub/.gitattributes
        sub/fileA
        sub/fileAB
        sub/fileAC
@@ -161,6 +183,7 @@ test_expect_success 'check unspecified attr (2)' '
        HEAD:fileC
        HEAD:fileNoLabel
        HEAD:fileWrongLabel
+       HEAD:sub/.gitattributes
        HEAD:sub/fileA
        HEAD:sub/fileAB
        HEAD:sub/fileAC
@@ -180,6 +203,7 @@ test_expect_success 'check multiple unspecified attr' '
        fileC
        fileNoLabel
        fileWrongLabel
+       sub/.gitattributes
        sub/fileC
        sub/fileNoLabel
        sub/fileWrongLabel
@@ -253,4 +277,22 @@ test_expect_success 'backslash cannot be used as a value' '
        test_i18ngrep "for value matching" actual
 '
 
+test_expect_success 'reading from .gitattributes in a subdirectory (1)' '
+       git ls-files ":(attr:label1)" >actual &&
+       test_write_lines "sub/fileSetLabel" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'reading from .gitattributes in a subdirectory (2)' '
+       git ls-files ":(attr:label1)sub" >actual &&
+       test_write_lines "sub/fileSetLabel" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'reading from .gitattributes in a subdirectory (3)' '
+       git ls-files ":(attr:label1)sub/" >actual &&
+       test_write_lines "sub/fileSetLabel" >expect &&
+       test_cmp expect actual
+'
+
 test_done
index 5c00607608a847525650db93807d72bb235abd5f..00a060df0b5e81cc1c47758240a7c790384b758e 100755 (executable)
@@ -6,6 +6,7 @@
 test_description='for-each-ref test'
 
 . ./test-lib.sh
+GNUPGHOME_NOT_USED=$GNUPGHOME
 . "$TEST_DIRECTORY"/lib-gpg.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
@@ -24,6 +25,13 @@ test_expect_success setup '
        disklen sha1:138
        disklen sha256:154
        EOF
+
+       # setup .mailmap
+       cat >.mailmap <<-EOF &&
+       A Thor <athor@example.com> A U Thor <author@example.com>
+       C Mitter <cmitter@example.com> C O Mitter <committer@example.com>
+       EOF
+
        setdate_and_increment &&
        echo "Using $datestamp" > one &&
        git add one &&
@@ -40,25 +48,29 @@ test_expect_success setup '
        git config push.default current
 '
 
-test_atom() {
+test_atom () {
        case "$1" in
                head) ref=refs/heads/main ;;
                 tag) ref=refs/tags/testtag ;;
                 sym) ref=refs/heads/sym ;;
                   *) ref=$1 ;;
        esac
+       format=$2
+       test_do=test_expect_${4:-success}
+
        printf '%s\n' "$3" >expected
-       test_expect_${4:-success} $PREREQ "basic atom: $1 $2" "
-               git for-each-ref --format='%($2)' $ref >actual &&
+       $test_do $PREREQ "basic atom: $ref $format" '
+               git for-each-ref --format="%($format)" "$ref" >actual &&
                sanitize_pgp <actual >actual.clean &&
                test_cmp expected actual.clean
-       "
+       '
+
        # Automatically test "contents:size" atom after testing "contents"
-       if test "$2" = "contents"
+       if test "$format" = "contents"
        then
                # for commit leg, $3 is changed there
                expect=$(printf '%s' "$3" | wc -c)
-               test_expect_${4:-success} $PREREQ "basic atom: $1 contents:size" '
+               $test_do $PREREQ "basic atom: $ref contents:size" '
                        type=$(git cat-file -t "$ref") &&
                        case $type in
                        tag)
@@ -140,15 +152,31 @@ test_atom head '*objectname' ''
 test_atom head '*objecttype' ''
 test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
 test_atom head authorname 'A U Thor'
+test_atom head authorname:mailmap 'A Thor'
 test_atom head authoremail '<author@example.com>'
 test_atom head authoremail:trim 'author@example.com'
 test_atom head authoremail:localpart 'author'
+test_atom head authoremail:trim,localpart 'author'
+test_atom head authoremail:mailmap '<athor@example.com>'
+test_atom head authoremail:mailmap,trim 'athor@example.com'
+test_atom head authoremail:trim,mailmap 'athor@example.com'
+test_atom head authoremail:mailmap,localpart 'athor'
+test_atom head authoremail:localpart,mailmap 'athor'
+test_atom head authoremail:mailmap,trim,localpart,mailmap,trim 'athor'
 test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'
 test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'
 test_atom head committername 'C O Mitter'
+test_atom head committername:mailmap 'C Mitter'
 test_atom head committeremail '<committer@example.com>'
 test_atom head committeremail:trim 'committer@example.com'
 test_atom head committeremail:localpart 'committer'
+test_atom head committeremail:localpart,trim 'committer'
+test_atom head committeremail:mailmap '<cmitter@example.com>'
+test_atom head committeremail:mailmap,trim 'cmitter@example.com'
+test_atom head committeremail:trim,mailmap 'cmitter@example.com'
+test_atom head committeremail:mailmap,localpart 'cmitter'
+test_atom head committeremail:localpart,mailmap 'cmitter'
+test_atom head committeremail:trim,mailmap,trim,trim,localpart 'cmitter'
 test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'
 test_atom head tag ''
 test_atom head tagger ''
@@ -198,22 +226,46 @@ test_atom tag '*objectname' $(git rev-parse refs/tags/testtag^{})
 test_atom tag '*objecttype' 'commit'
 test_atom tag author ''
 test_atom tag authorname ''
+test_atom tag authorname:mailmap ''
 test_atom tag authoremail ''
 test_atom tag authoremail:trim ''
 test_atom tag authoremail:localpart ''
+test_atom tag authoremail:trim,localpart ''
+test_atom tag authoremail:mailmap ''
+test_atom tag authoremail:mailmap,trim ''
+test_atom tag authoremail:trim,mailmap ''
+test_atom tag authoremail:mailmap,localpart ''
+test_atom tag authoremail:localpart,mailmap ''
+test_atom tag authoremail:mailmap,trim,localpart,mailmap,trim ''
 test_atom tag authordate ''
 test_atom tag committer ''
 test_atom tag committername ''
+test_atom tag committername:mailmap ''
 test_atom tag committeremail ''
 test_atom tag committeremail:trim ''
 test_atom tag committeremail:localpart ''
+test_atom tag committeremail:localpart,trim ''
+test_atom tag committeremail:mailmap ''
+test_atom tag committeremail:mailmap,trim ''
+test_atom tag committeremail:trim,mailmap ''
+test_atom tag committeremail:mailmap,localpart ''
+test_atom tag committeremail:localpart,mailmap ''
+test_atom tag committeremail:trim,mailmap,trim,trim,localpart ''
 test_atom tag committerdate ''
 test_atom tag tag 'testtag'
 test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'
 test_atom tag taggername 'C O Mitter'
+test_atom tag taggername:mailmap 'C Mitter'
 test_atom tag taggeremail '<committer@example.com>'
 test_atom tag taggeremail:trim 'committer@example.com'
 test_atom tag taggeremail:localpart 'committer'
+test_atom tag taggeremail:trim,localpart 'committer'
+test_atom tag taggeremail:mailmap '<cmitter@example.com>'
+test_atom tag taggeremail:mailmap,trim 'cmitter@example.com'
+test_atom tag taggeremail:trim,mailmap 'cmitter@example.com'
+test_atom tag taggeremail:mailmap,localpart 'cmitter'
+test_atom tag taggeremail:localpart,mailmap 'cmitter'
+test_atom tag taggeremail:trim,mailmap,trim,localpart,localpart 'cmitter'
 test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'
 test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'
 test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'
@@ -266,6 +318,66 @@ test_expect_success 'arguments to %(objectname:short=) must be positive integers
        test_must_fail git for-each-ref --format="%(objectname:short=foo)"
 '
 
+test_bad_atom () {
+       case "$1" in
+       head) ref=refs/heads/main ;;
+        tag) ref=refs/tags/testtag ;;
+        sym) ref=refs/heads/sym ;;
+          *) ref=$1 ;;
+       esac
+       format=$2
+       test_do=test_expect_${4:-success}
+
+       printf '%s\n' "$3" >expect
+       $test_do $PREREQ "err basic atom: $ref $format" '
+               test_must_fail git for-each-ref \
+                       --format="%($format)" "$ref" 2>error &&
+               test_cmp expect error
+       '
+}
+
+test_bad_atom head 'authoremail:foo' \
+       'fatal: unrecognized %(authoremail) argument: foo'
+
+test_bad_atom head 'authoremail:mailmap,trim,bar' \
+       'fatal: unrecognized %(authoremail) argument: bar'
+
+test_bad_atom head 'authoremail:trim,' \
+       'fatal: unrecognized %(authoremail) argument: '
+
+test_bad_atom head 'authoremail:mailmaptrim' \
+       'fatal: unrecognized %(authoremail) argument: trim'
+
+test_bad_atom head 'committeremail: ' \
+       'fatal: unrecognized %(committeremail) argument:  '
+
+test_bad_atom head 'committeremail: trim,foo' \
+       'fatal: unrecognized %(committeremail) argument:  trim,foo'
+
+test_bad_atom head 'committeremail:mailmap,localpart ' \
+       'fatal: unrecognized %(committeremail) argument:  '
+
+test_bad_atom head 'committeremail:trim_localpart' \
+       'fatal: unrecognized %(committeremail) argument: _localpart'
+
+test_bad_atom head 'committeremail:localpart,,,trim' \
+       'fatal: unrecognized %(committeremail) argument: ,,trim'
+
+test_bad_atom tag 'taggeremail:mailmap,trim, foo ' \
+       'fatal: unrecognized %(taggeremail) argument:  foo '
+
+test_bad_atom tag 'taggeremail:trim,localpart,' \
+       'fatal: unrecognized %(taggeremail) argument: '
+
+test_bad_atom tag 'taggeremail:mailmap;localpart trim' \
+       'fatal: unrecognized %(taggeremail) argument: ;localpart trim'
+
+test_bad_atom tag 'taggeremail:localpart trim' \
+       'fatal: unrecognized %(taggeremail) argument:  trim'
+
+test_bad_atom tag 'taggeremail:mailmap,mailmap,trim,qux,localpart,trim' \
+       'fatal: unrecognized %(taggeremail) argument: qux,localpart,trim'
+
 test_date () {
        f=$1 &&
        committer_date=$2 &&
@@ -447,6 +559,41 @@ test_expect_success 'exercise glob patterns with prefixes' '
        test_cmp expected actual
 '
 
+cat >expected <<\EOF
+refs/tags/bar
+refs/tags/baz
+refs/tags/testtag
+EOF
+
+test_expect_success 'exercise patterns with prefix exclusions' '
+       for tag in foo/one foo/two foo/three bar baz
+       do
+               git tag "$tag" || return 1
+       done &&
+       test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
+       git for-each-ref --format="%(refname)" \
+               refs/tags/ --exclude=refs/tags/foo >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/tags/bar
+refs/tags/baz
+refs/tags/foo/one
+refs/tags/testtag
+EOF
+
+test_expect_success 'exercise patterns with pattern exclusions' '
+       for tag in foo/one foo/two foo/three bar baz
+       do
+               git tag "$tag" || return 1
+       done &&
+       test_when_finished "git tag -d foo/one foo/two foo/three bar baz" &&
+       git for-each-ref --format="%(refname)" \
+               refs/tags/ --exclude="refs/tags/foo/t*" >actual &&
+       test_cmp expected actual
+'
+
 cat >expected <<\EOF
 'refs/heads/main'
 'refs/remotes/origin/main'
@@ -561,6 +708,144 @@ test_expect_success 'color.ui=always does not override tty check' '
        test_cmp expected.bare actual
 '
 
+test_expect_success 'setup for describe atom tests' '
+       git init -b master describe-repo &&
+       (
+               cd describe-repo &&
+
+               test_commit --no-tag one &&
+               git tag tagone &&
+
+               test_commit --no-tag two &&
+               git tag -a -m "tag two" tagtwo
+       )
+'
+
+test_expect_success 'describe atom vs git describe' '
+       (
+               cd describe-repo &&
+
+               git for-each-ref --format="%(objectname)" \
+                       refs/tags/ >obj &&
+               while read hash
+               do
+                       if desc=$(git describe $hash)
+                       then
+                               : >expect-contains-good
+                       else
+                               : >expect-contains-bad
+                       fi &&
+                       echo "$hash $desc" || return 1
+               done <obj >expect &&
+               test_path_exists expect-contains-good &&
+               test_path_exists expect-contains-bad &&
+
+               git for-each-ref --format="%(objectname) %(describe)" \
+                       refs/tags/ >actual 2>err &&
+               test_cmp expect actual &&
+               test_must_be_empty err
+       )
+'
+
+test_expect_success 'describe:tags vs describe --tags' '
+       (
+               cd describe-repo &&
+               git describe --tags >expect &&
+               git for-each-ref --format="%(describe:tags)" \
+                               refs/heads/master >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'describe:abbrev=... vs describe --abbrev=...' '
+       (
+               cd describe-repo &&
+
+               # Case 1: We have commits between HEAD and the most
+               #         recent tag reachable from it
+               test_commit --no-tag file &&
+               git describe --abbrev=14 >expect &&
+               git for-each-ref --format="%(describe:abbrev=14)" \
+                       refs/heads/master >actual &&
+               test_cmp expect actual &&
+
+               # Make sure the hash used is atleast 14 digits long
+               sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
+               test 15 -le $(wc -c <hexpart) &&
+
+               # Case 2: We have a tag at HEAD, describe directly gives
+               #         the name of the tag
+               git tag -a -m tagged tagname &&
+               git describe --abbrev=14 >expect &&
+               git for-each-ref --format="%(describe:abbrev=14)" \
+                       refs/heads/master >actual &&
+               test_cmp expect actual &&
+               test tagname = $(cat actual)
+       )
+'
+
+test_expect_success 'describe:match=... vs describe --match ...' '
+       (
+               cd describe-repo &&
+               git tag -a -m "tag foo" tag-foo &&
+               git describe --match "*-foo" >expect &&
+               git for-each-ref --format="%(describe:match="*-foo")" \
+                       refs/heads/master >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'describe:exclude:... vs describe --exclude ...' '
+       (
+               cd describe-repo &&
+               git tag -a -m "tag bar" tag-bar &&
+               git describe --exclude "*-bar" >expect &&
+               git for-each-ref --format="%(describe:exclude="*-bar")" \
+                       refs/heads/master >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'deref with describe atom' '
+       (
+               cd describe-repo &&
+               cat >expect <<-\EOF &&
+
+               tagname
+               tagname
+               tagname
+
+               tagtwo
+               EOF
+               git for-each-ref --format="%(*describe)" >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'err on bad describe atom arg' '
+       (
+               cd describe-repo &&
+
+               # The bad arg is the only arg passed to describe atom
+               cat >expect <<-\EOF &&
+               fatal: unrecognized %(describe) argument: baz
+               EOF
+               test_must_fail git for-each-ref --format="%(describe:baz)" \
+                       refs/heads/master 2>actual &&
+               test_cmp expect actual &&
+
+               # The bad arg is in the middle of the option string
+               # passed to the describe atom
+               cat >expect <<-\EOF &&
+               fatal: unrecognized %(describe) argument: qux=1,abbrev=14
+               EOF
+               test_must_fail git for-each-ref \
+                       --format="%(describe:tags,qux=1,abbrev=14)" \
+                       ref/heads/master 2>actual &&
+               test_cmp expect actual
+       )
+'
+
 cat >expected <<\EOF
 heads/main
 tags/main
@@ -843,16 +1128,16 @@ test_expect_success 'Verify sorts with raw' '
 test_expect_success 'Verify sorts with raw:size' '
        cat >expected <<-EOF &&
        refs/myblobs/blob8
-       refs/myblobs/first
        refs/myblobs/blob7
-       refs/heads/main
        refs/myblobs/blob4
        refs/myblobs/blob1
        refs/myblobs/blob2
        refs/myblobs/blob3
        refs/myblobs/blob5
        refs/myblobs/blob6
+       refs/myblobs/first
        refs/mytrees/first
+       refs/heads/main
        EOF
        git for-each-ref --format="%(refname)" --sort=raw:size \
                refs/heads/main refs/myblobs/ refs/mytrees/first >actual &&
@@ -964,6 +1249,17 @@ test_expect_success 'for-each-ref --format compare with cat-file --batch' '
        test_cmp expected actual
 '
 
+test_expect_success 'verify sorts with contents:size' '
+       cat >expect <<-\EOF &&
+       refs/heads/main
+       refs/heads/newtag
+       refs/heads/ambiguous
+       EOF
+       git for-each-ref --format="%(refname)" \
+               --sort=contents:size refs/heads/ >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'set up multiple-sort tags' '
        for when in 100000 200000
        do
@@ -1522,4 +1818,192 @@ test_expect_success 'git for-each-ref with non-existing refs' '
        test_must_be_empty actual
 '
 
+GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
+TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
+
+test_expect_success GPG 'setup for signature atom using gpg' '
+       git checkout -b signed &&
+
+       test_when_finished "test_unconfig commit.gpgSign" &&
+
+       echo "1" >file &&
+       git add file &&
+       test_tick &&
+       git commit -S -m "file: 1" &&
+       git tag first-signed &&
+
+       echo "2" >file &&
+       test_tick &&
+       git commit -a -m "file: 2" &&
+       git tag second-unsigned &&
+
+       git config commit.gpgSign 1 &&
+       echo "3" >file &&
+       test_tick &&
+       git commit -a --no-gpg-sign -m "file: 3" &&
+       git tag third-unsigned &&
+
+       test_tick &&
+       git rebase -f HEAD^^ && git tag second-signed HEAD^ &&
+       git tag third-signed &&
+
+       echo "4" >file &&
+       test_tick &&
+       git commit -a -SB7227189 -m "file: 4" &&
+       git tag fourth-signed &&
+
+       echo "5" >file &&
+       test_tick &&
+       git commit -a --no-gpg-sign -m "file: 5" &&
+       git tag fifth-unsigned &&
+
+       echo "6" >file &&
+       test_tick &&
+       git commit -a --no-gpg-sign -m "file: 6" &&
+
+       test_tick &&
+       git rebase -f HEAD^^ &&
+       git tag fifth-signed HEAD^ &&
+       git tag sixth-signed &&
+
+       echo "7" >file &&
+       test_tick &&
+       git commit -a --no-gpg-sign -m "file: 7" &&
+       git tag seventh-unsigned
+'
+
+test_expect_success GPGSSH 'setup for signature atom using ssh' '
+       test_when_finished "test_unconfig gpg.format user.signingkey" &&
+
+       test_config gpg.format ssh &&
+       test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
+       echo "8" >file &&
+       test_tick &&
+       git add file &&
+       git commit -S -m "file: 8" &&
+       git tag eighth-signed-ssh
+'
+
+test_expect_success GPG2 'bare signature atom' '
+       git verify-commit first-signed 2>expect &&
+       echo  >>expect &&
+       git for-each-ref refs/tags/first-signed \
+               --format="%(signature)" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show good signature with custom format' '
+       git verify-commit first-signed &&
+       cat >expect <<-\EOF &&
+       G
+       13B6F51ECDDE430D
+       C O Mitter <committer@example.com>
+       73D758744BE721698EC54E8713B6F51ECDDE430D
+       73D758744BE721698EC54E8713B6F51ECDDE430D
+       EOF
+       git for-each-ref refs/tags/first-signed \
+               --format="$GRADE_FORMAT" >actual &&
+       test_cmp expect actual
+'
+test_expect_success GPGSSH 'show good signature with custom format
+                           with ssh' '
+       test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+       FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") &&
+       cat >expect.tmpl <<-\EOF &&
+       G
+       FINGERPRINT
+       principal with number 1
+       FINGERPRINT
+
+       EOF
+       sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect &&
+       git for-each-ref refs/tags/eighth-signed-ssh \
+               --format="$GRADE_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'signature atom with grade option and bad signature' '
+       git cat-file commit third-signed >raw &&
+       sed -e "s/^file: 3/file: 3 forged/" raw >forged1 &&
+       FORGED1=$(git hash-object -w -t commit forged1) &&
+       git update-ref refs/tags/third-signed "$FORGED1" &&
+       test_must_fail git verify-commit "$FORGED1" &&
+
+       cat >expect <<-\EOF &&
+       B
+       13B6F51ECDDE430D
+       C O Mitter <committer@example.com>
+
+
+       EOF
+       git for-each-ref refs/tags/third-signed \
+               --format="$GRADE_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show untrusted signature with custom format' '
+       cat >expect <<-\EOF &&
+       U
+       65A0EEA02E30CAD7
+       Eris Discordia <discord@example.net>
+       F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
+       D4BE22311AD3131E5EDA29A461092E85B7227189
+       EOF
+       git for-each-ref refs/tags/fourth-signed \
+               --format="$GRADE_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show untrusted signature with undefined trust level' '
+       cat >expect <<-\EOF &&
+       undefined
+       65A0EEA02E30CAD7
+       Eris Discordia <discord@example.net>
+       F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
+       D4BE22311AD3131E5EDA29A461092E85B7227189
+       EOF
+       git for-each-ref refs/tags/fourth-signed \
+               --format="$TRUSTLEVEL_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show untrusted signature with ultimate trust level' '
+       cat >expect <<-\EOF &&
+       ultimate
+       13B6F51ECDDE430D
+       C O Mitter <committer@example.com>
+       73D758744BE721698EC54E8713B6F51ECDDE430D
+       73D758744BE721698EC54E8713B6F51ECDDE430D
+       EOF
+       git for-each-ref refs/tags/sixth-signed \
+               --format="$TRUSTLEVEL_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show unknown signature with custom format' '
+       cat >expect <<-\EOF &&
+       E
+       13B6F51ECDDE430D
+
+
+
+       EOF
+       GNUPGHOME="$GNUPGHOME_NOT_USED" git for-each-ref \
+               refs/tags/sixth-signed --format="$GRADE_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show lack of signature with custom format' '
+       cat >expect <<-\EOF &&
+       N
+
+
+
+
+       EOF
+       git for-each-ref refs/tags/seventh-unsigned \
+               --format="$GRADE_FORMAT" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 1ce5f490e99d374e039d29e708ee98dfb8988eab..af223e44d679571b3148d265ebb09049275cef3a 100755 (executable)
@@ -45,6 +45,8 @@ test_expect_success 'check signed tags with --points-at' '
        sed -e "s/Z$//" >expect <<-\EOF &&
        refs/heads/side Z
        refs/tags/annotated-tag four
+       refs/tags/doubly-annotated-tag An annotated tag
+       refs/tags/doubly-signed-tag A signed tag
        refs/tags/four Z
        refs/tags/signed-tag four
        EOF
index 5e4e4dd6d9e6b967f8c1d94fe7ce1a79c787a177..72f8c1722ff76d332529450b4115d7afb39ed5ec 100755 (executable)
@@ -56,6 +56,12 @@ test_expect_success setup '
        ) >"$ours+"
        cat "$ours+" >"$ours"
        rm -f "$ours+"
+
+       if test -f ./please-abort
+       then
+               echo >>./please-abort killing myself
+               kill -9 $$
+       fi
        exit "$exit"
        EOF
        chmod +x ./custom-merge
@@ -162,6 +168,24 @@ test_expect_success 'custom merge backend' '
        rm -f $o $a $b
 '
 
+test_expect_success !WINDOWS 'custom merge driver that is killed with a signal' '
+       test_when_finished "rm -f output please-abort" &&
+
+       git reset --hard anchor &&
+       git config --replace-all \
+       merge.custom.driver "./custom-merge %O %A %B 0 %P" &&
+       git config --replace-all \
+       merge.custom.name "custom merge driver for testing" &&
+
+       >./please-abort &&
+       echo "* merge=custom" >.gitattributes &&
+       test_must_fail git merge main 2>err &&
+       grep "^error: failed to execute internal merge" err &&
+       git ls-files -u >output &&
+       git diff --name-only HEAD >>output &&
+       test_must_be_empty output
+'
+
 test_expect_success 'up-to-date merge without common ancestor' '
        git init repo1 &&
        git init repo2 &&
index 17b54d625d0e468047377c378faae25c50633c9b..5f414abc89267d3f3729366d67f8b7d6aec52c37 100755 (executable)
@@ -5,6 +5,7 @@ test_description='recursive merge corner cases involving criss-cross merges'
 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
 
index b16031465f34b20600cadd51c2f620ec64ae0e54..2b42f095dcba5b228a60cb6ce2ea5678e611c893 100755 (executable)
@@ -5,6 +5,7 @@ test_description='"git merge" top-level frontend'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 t3033_reset () {
index c9a86f2e947e4a2943438cc5adcaaeab39a465d9..daa507862c65ea73d39c555ed2c316503094be49 100755 (executable)
@@ -8,6 +8,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-merge.sh
 
index 69509d0c11db655a12fc6ed20215ed25976c46eb..04acf22d930421cf206556c54b1acf0a22b644d4 100755 (executable)
@@ -202,6 +202,30 @@ test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "e
        grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out
 '
 
+test_expect_success 'gc.repackFilter launches repack with a filter' '
+       git clone --no-local --bare . bare.git &&
+
+       git -C bare.git -c gc.cruftPacks=false gc &&
+       test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+
+       GIT_TRACE=$(pwd)/trace.out git -C bare.git -c gc.repackFilter=blob:none \
+               -c repack.writeBitmaps=false -c gc.cruftPacks=false gc &&
+       test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack &&
+       grep -E "^trace: (built-in|exec|run_command): git repack .* --filter=blob:none ?.*" trace.out
+'
+
+test_expect_success 'gc.repackFilterTo store filtered out objects' '
+       test_when_finished "rm -rf bare.git filtered.git" &&
+
+       git init --bare filtered.git &&
+       git -C bare.git -c gc.repackFilter=blob:none \
+               -c gc.repackFilterTo=../filtered.git/objects/pack/pack \
+               -c repack.writeBitmaps=false -c gc.cruftPacks=false gc &&
+
+       test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+       test_stdout_line_count = 1 ls filtered.git/objects/pack/*.pack
+'
+
 prepare_cruft_history () {
        test_commit base &&
 
@@ -303,6 +327,33 @@ test_expect_success 'gc.bigPackThreshold ignores cruft packs' '
        )
 '
 
+cruft_max_size_opts="git repack -d -l --cruft --cruft-expiration=2.weeks.ago"
+
+test_expect_success 'setup for --max-cruft-size tests' '
+       git init cruft--max-size &&
+       (
+               cd cruft--max-size &&
+               prepare_cruft_history
+       )
+'
+
+test_expect_success '--max-cruft-size sets appropriate repack options' '
+       GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size \
+               gc --cruft --max-cruft-size=1M &&
+       test_subcommand $cruft_max_size_opts --max-cruft-size=1048576 <trace2.txt
+'
+
+test_expect_success 'gc.maxCruftSize sets appropriate repack options' '
+       GIT_TRACE2_EVENT=$(pwd)/trace2.txt \
+               git -C cruft--max-size -c gc.maxCruftSize=2M gc --cruft &&
+       test_subcommand $cruft_max_size_opts --max-cruft-size=2097152 <trace2.txt &&
+
+       GIT_TRACE2_EVENT=$(pwd)/trace2.txt \
+               git -C cruft--max-size -c gc.maxCruftSize=2M gc --cruft \
+               --max-cruft-size=3M &&
+       test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt
+'
+
 run_and_wait_for_auto_gc () {
        # We read stdout from gc for the side effect of waiting until the
        # background gc process exits, closing its fd 9.  Furthermore, the
diff --git a/t/t6700-tree-depth.sh b/t/t6700-tree-depth.sh
new file mode 100755 (executable)
index 0000000..9e70a7c
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='handling of deep trees in various commands'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+# We'll test against two depths here: a small one that will let us check the
+# behavior of the config setting easily, and a large one that should be
+# forbidden by default. Testing the default depth will let us know whether our
+# default is enough to prevent segfaults on systems that run the tests.
+small_depth=50
+big_depth=4100
+
+small_ok="-c core.maxtreedepth=$small_depth"
+small_no="-c core.maxtreedepth=$((small_depth-1))"
+
+# usage: mkdeep <name> <depth>
+#   Create a tag <name> containing a file whose path has depth <depth>.
+#
+# We'll use fast-import here for two reasons:
+#
+#   1. It's faster than creating $big_depth tree objects.
+#
+#   2. As we tighten tree limits, it's more likely to allow large sizes
+#      than trying to stuff a deep path into the index.
+mkdeep () {
+       {
+               echo "commit refs/tags/$1" &&
+               echo "committer foo <foo@example.com> 1234 -0000" &&
+               echo "data <<EOF" &&
+               echo "the commit message" &&
+               echo "EOF" &&
+
+               printf 'M 100644 inline ' &&
+               i=0 &&
+               while test $i -lt $2
+               do
+                       printf 'a/'
+                       i=$((i+1))
+               done &&
+               echo "file" &&
+
+               echo "data <<EOF" &&
+               echo "the file contents" &&
+               echo "EOF" &&
+               echo
+       } | git fast-import
+}
+
+test_expect_success 'create small tree' '
+       mkdeep small $small_depth
+'
+
+test_expect_success 'create big tree' '
+       mkdeep big $big_depth
+'
+
+test_expect_success 'limit recursion of git-archive' '
+       git $small_ok archive small >/dev/null &&
+       test_must_fail git $small_no archive small >/dev/null
+'
+
+test_expect_success 'default limit for git-archive fails gracefully' '
+       test_must_fail git archive big >/dev/null
+'
+
+test_expect_success 'limit recursion of ls-tree -r' '
+       git $small_ok ls-tree -r small &&
+       test_must_fail git $small_no ls-tree -r small
+'
+
+test_expect_success 'default limit for ls-tree fails gracefully' '
+       test_must_fail git ls-tree -r big >/dev/null
+'
+
+test_expect_success 'limit recursion of rev-list --objects' '
+       git $small_ok rev-list --objects small >/dev/null &&
+       test_must_fail git $small_no rev-list --objects small >/dev/null
+'
+
+test_expect_success 'default limit for rev-list fails gracefully' '
+       test_must_fail git rev-list --objects big >/dev/null
+'
+
+test_expect_success 'limit recursion of diff-tree -r' '
+       git $small_ok diff-tree -r $EMPTY_TREE small &&
+       test_must_fail git $small_no diff-tree -r $EMPTY_TREE small
+'
+
+test_expect_success 'default limit for diff-tree fails gracefully' '
+       test_must_fail git diff-tree -r $EMPTY_TREE big
+'
+
+test_done
index 898a92053282d762b10fc2b53b76f84fbd2892e6..f136ea76f7f8a04c7b2b9c5dbf38ca1a50260819 100755 (executable)
@@ -174,6 +174,13 @@ test_expect_success 'do not move directory over existing directory' '
        test_must_fail git mv path2 path0
 '
 
+test_expect_success 'rename directory to non-existing directory' '
+       mkdir dir-a &&
+       >dir-a/f &&
+       git add dir-a &&
+       git mv dir-a non-existing-dir
+'
+
 test_expect_success 'move into "."' '
        git mv path1/path2/ .
 '
index 0fe6ba93a29f996e7f473fe2fa708956a46d059b..e689db429292e60162d4f8f89905cc8489d7a3e0 100755 (executable)
@@ -2188,4 +2188,23 @@ test_expect_success 'Does --[no-]contains stop at commits? Yes!' '
        test_cmp expected actual
 '
 
+test_expect_success 'If tag is created then tag message file is unlinked' '
+       test_when_finished "git tag -d foo" &&
+       write_script fakeeditor <<-\EOF &&
+       echo Message >.git/TAG_EDITMSG
+       EOF
+       GIT_EDITOR=./fakeeditor git tag -a foo &&
+       test_path_is_missing .git/TAG_EDITMSG
+'
+
+test_expect_success 'If tag cannot be created then tag message file is not unlinked' '
+       test_when_finished "git tag -d foo/bar && rm .git/TAG_EDITMSG" &&
+       write_script fakeeditor <<-\EOF &&
+       echo Message >.git/TAG_EDITMSG
+       EOF
+       git tag foo/bar &&
+       test_must_fail env GIT_EDITOR=./fakeeditor git tag -a foo &&
+       test_path_exists .git/TAG_EDITMSG
+'
+
 test_done
index 638bb04e217600387fdf3f46fb8ba1caacba0f94..89cf98b30c8f96335180bccfe7fe07b7156febc9 100755 (executable)
@@ -10,57 +10,57 @@ TEST_PASSES_SANITIZE_LEAK=true
 . "$TEST_DIRECTORY"/lib-diff-data.sh
 
 test_expect_success 'creating initial files' '
-     mkdir path0 &&
-     COPYING_test_data >path0/COPYING &&
-     git add path0/COPYING &&
-     git commit -m add -a
+       mkdir path0 &&
+       COPYING_test_data >path0/COPYING &&
+       git add path0/COPYING &&
+       git commit -m add -a
 '
 
 test_expect_success 'creating second files' '
-     mkdir path1 &&
-     mkdir path1/path2 &&
-     COPYING_test_data >path1/path2/COPYING &&
-     COPYING_test_data >path1/COPYING &&
-     COPYING_test_data >COPYING &&
-     COPYING_test_data >path0/COPYING-TOO &&
-     git add path1/path2/COPYING &&
-     git add path1/COPYING &&
-     git add COPYING &&
-     git add path0/COPYING-TOO &&
-     git commit -m change -a
+       mkdir path1 &&
+       mkdir path1/path2 &&
+       COPYING_test_data >path1/path2/COPYING &&
+       COPYING_test_data >path1/COPYING &&
+       COPYING_test_data >COPYING &&
+       COPYING_test_data >path0/COPYING-TOO &&
+       git add path1/path2/COPYING &&
+       git add path1/COPYING &&
+       git add COPYING &&
+       git add path0/COPYING-TOO &&
+       git commit -m change -a
 '
 
 test_expect_success 'resetting tree HEAD^' '
-     git reset --hard HEAD^
+       git reset --hard HEAD^
 '
 
 test_expect_success 'checking initial files exist after rewind' '
-     test -d path0 &&
-     test -f path0/COPYING
+       test -d path0 &&
+       test -f path0/COPYING
 '
 
 test_expect_success 'checking lack of path1/path2/COPYING' '
-    ! test -f path1/path2/COPYING
+       ! test -f path1/path2/COPYING
 '
 
 test_expect_success 'checking lack of path1/COPYING' '
-    ! test -f path1/COPYING
+       ! test -f path1/COPYING
 '
 
 test_expect_success 'checking lack of COPYING' '
-     ! test -f COPYING
+       ! test -f COPYING
 '
 
 test_expect_success 'checking checking lack of path1/COPYING-TOO' '
-     ! test -f path0/COPYING-TOO
+       ! test -f path0/COPYING-TOO
 '
 
 test_expect_success 'checking lack of path1/path2' '
-     ! test -d path1/path2
+       ! test -d path1/path2
 '
 
 test_expect_success 'checking lack of path1' '
-     ! test -d path1
+       ! test -d path1
 '
 
 test_done
index 22477f3a312e4a44b0c3f99ee356d29487ed5399..4287863ae6cab9a67564c9328effd68d2c186ab6 100755 (executable)
@@ -71,6 +71,16 @@ check_changes () {
        done | test_cmp .cat_expect -
 }
 
+# no negated form for various type of resets
+for opt in soft mixed hard merge keep
+do
+       test_expect_success "no 'git reset --no-$opt'" '
+               test_when_finished "rm -f err" &&
+               test_must_fail git reset --no-$opt 2>err &&
+               grep "error: unknown option .no-$opt." err
+       '
+done
+
 test_expect_success 'reset --hard message' '
        hex=$(git log -1 --format="%h") &&
        git reset --hard >.actual &&
index eb881be95b615f53867dbe8f56c6b0f9cc7a9d3c..772480a345ffa0703432e070e5e85ec56a322c00 100755 (executable)
@@ -9,17 +9,17 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success setup '
-    printf "line %d\n" 1 2 3 >file1 &&
-    cat file1 >file2 &&
-    git add file1 file2 &&
-    test_tick &&
-    git commit -m "Initial commit" &&
-    git tag initial &&
-    echo line 4 >>file1 &&
-    cat file1 >file2 &&
-    test_tick &&
-    git commit -m "add line 4 to file1" file1 &&
-    git tag second
+       printf "line %d\n" 1 2 3 >file1 &&
+       cat file1 >file2 &&
+       git add file1 file2 &&
+       test_tick &&
+       git commit -m "Initial commit" &&
+       git tag initial &&
+       echo line 4 >>file1 &&
+       cat file1 >file2 &&
+       test_tick &&
+       git commit -m "add line 4 to file1" file1 &&
+       git tag second
 '
 
 # The next test will test the following:
@@ -29,19 +29,19 @@ test_expect_success setup '
 # file1:     C       C     C    D     --merge  D       D     D
 # file2:     C       D     D    D     --merge  C       D     D
 test_expect_success 'reset --merge is ok with changes in file it does not touch' '
-    git reset --merge HEAD^ &&
-    ! grep 4 file1 &&
-    grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
-    test -z "$(git diff --cached)"
+       git reset --merge HEAD^ &&
+       ! grep 4 file1 &&
+       grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
+       test -z "$(git diff --cached)"
 '
 
 test_expect_success 'reset --merge is ok when switching back' '
-    git reset --merge second &&
-    grep 4 file1 &&
-    grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
-    test -z "$(git diff --cached)"
+       git reset --merge second &&
+       grep 4 file1 &&
+       grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+       test -z "$(git diff --cached)"
 '
 
 # The next test will test the following:
@@ -51,21 +51,21 @@ test_expect_success 'reset --merge is ok when switching back' '
 # file1:     C       C     C    D     --keep   D       D     D
 # file2:     C       D     D    D     --keep   C       D     D
 test_expect_success 'reset --keep is ok with changes in file it does not touch' '
-    git reset --hard second &&
-    cat file1 >file2 &&
-    git reset --keep HEAD^ &&
-    ! grep 4 file1 &&
-    grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
-    test -z "$(git diff --cached)"
+       git reset --hard second &&
+       cat file1 >file2 &&
+       git reset --keep HEAD^ &&
+       ! grep 4 file1 &&
+       grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
+       test -z "$(git diff --cached)"
 '
 
 test_expect_success 'reset --keep is ok when switching back' '
-    git reset --keep second &&
-    grep 4 file1 &&
-    grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
-    test -z "$(git diff --cached)"
+       git reset --keep second &&
+       grep 4 file1 &&
+       grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+       test -z "$(git diff --cached)"
 '
 
 # The next test will test the following:
@@ -75,28 +75,28 @@ test_expect_success 'reset --keep is ok when switching back' '
 # file1:     B       B     C    D     --merge  D       D     D
 # file2:     C       D     D    D     --merge  C       D     D
 test_expect_success 'reset --merge discards changes added to index (1)' '
-    git reset --hard second &&
-    cat file1 >file2 &&
-    echo "line 5" >> file1 &&
-    git add file1 &&
-    git reset --merge HEAD^ &&
-    ! grep 4 file1 &&
-    ! grep 5 file1 &&
-    grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
-    test -z "$(git diff --cached)"
+       git reset --hard second &&
+       cat file1 >file2 &&
+       echo "line 5" >> file1 &&
+       git add file1 &&
+       git reset --merge HEAD^ &&
+       ! grep 4 file1 &&
+       ! grep 5 file1 &&
+       grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
+       test -z "$(git diff --cached)"
 '
 
 test_expect_success 'reset --merge is ok again when switching back (1)' '
-    git reset --hard initial &&
-    echo "line 5" >> file2 &&
-    git add file2 &&
-    git reset --merge second &&
-    ! grep 4 file2 &&
-    ! grep 5 file1 &&
-    grep 4 file1 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
-    test -z "$(git diff --cached)"
+       git reset --hard initial &&
+       echo "line 5" >> file2 &&
+       git add file2 &&
+       git reset --merge second &&
+       ! grep 4 file2 &&
+       ! grep 5 file1 &&
+       grep 4 file1 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+       test -z "$(git diff --cached)"
 '
 
 # The next test will test the following:
@@ -105,10 +105,10 @@ test_expect_success 'reset --merge is ok again when switching back (1)' '
 #           ----------------------------------------------------
 # file1:     B       B     C    D     --keep   (disallowed)
 test_expect_success 'reset --keep fails with changes in index in files it touches' '
-    git reset --hard second &&
-    echo "line 5" >> file1 &&
-    git add file1 &&
-    test_must_fail git reset --keep HEAD^
+       git reset --hard second &&
+       echo "line 5" >> file1 &&
+       git add file1 &&
+       test_must_fail git reset --keep HEAD^
 '
 
 # The next test will test the following:
@@ -118,23 +118,23 @@ test_expect_success 'reset --keep fails with changes in index in files it touche
 # file1:     C       C     C    D     --merge  D       D     D
 # file2:     C       C     D    D     --merge  D       D     D
 test_expect_success 'reset --merge discards changes added to index (2)' '
-    git reset --hard second &&
-    echo "line 4" >> file2 &&
-    git add file2 &&
-    git reset --merge HEAD^ &&
-    ! grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
-    test -z "$(git diff)" &&
-    test -z "$(git diff --cached)"
+       git reset --hard second &&
+       echo "line 4" >> file2 &&
+       git add file2 &&
+       git reset --merge HEAD^ &&
+       ! grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
+       test -z "$(git diff)" &&
+       test -z "$(git diff --cached)"
 '
 
 test_expect_success 'reset --merge is ok again when switching back (2)' '
-    git reset --hard initial &&
-    git reset --merge second &&
-    ! grep 4 file2 &&
-    grep 4 file1 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
-    test -z "$(git diff --cached)"
+       git reset --hard initial &&
+       git reset --merge second &&
+       ! grep 4 file2 &&
+       grep 4 file1 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+       test -z "$(git diff --cached)"
 '
 
 # The next test will test the following:
@@ -144,21 +144,21 @@ test_expect_success 'reset --merge is ok again when switching back (2)' '
 # file1:     C       C     C    D     --keep   D       D     D
 # file2:     C       C     D    D     --keep   C       D     D
 test_expect_success 'reset --keep keeps changes it does not touch' '
-    git reset --hard second &&
-    echo "line 4" >> file2 &&
-    git add file2 &&
-    git reset --keep HEAD^ &&
-    grep 4 file2 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
-    test -z "$(git diff --cached)"
+       git reset --hard second &&
+       echo "line 4" >> file2 &&
+       git add file2 &&
+       git reset --keep HEAD^ &&
+       grep 4 file2 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" &&
+       test -z "$(git diff --cached)"
 '
 
 test_expect_success 'reset --keep keeps changes when switching back' '
-    git reset --keep second &&
-    grep 4 file2 &&
-    grep 4 file1 &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
-    test -z "$(git diff --cached)"
+       git reset --keep second &&
+       grep 4 file2 &&
+       grep 4 file1 &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+       test -z "$(git diff --cached)"
 '
 
 # The next test will test the following:
@@ -167,14 +167,14 @@ test_expect_success 'reset --keep keeps changes when switching back' '
 #           ----------------------------------------------------
 # file1:     A       B     B    C     --merge  (disallowed)
 test_expect_success 'reset --merge fails with changes in file it touches' '
-    git reset --hard second &&
-    echo "line 5" >> file1 &&
-    test_tick &&
-    git commit -m "add line 5" file1 &&
-    sed -e "s/line 1/changed line 1/" <file1 >file3 &&
-    mv file3 file1 &&
-    test_must_fail git reset --merge HEAD^ 2>err.log &&
-    grep file1 err.log | grep "not uptodate"
+       git reset --hard second &&
+       echo "line 5" >> file1 &&
+       test_tick &&
+       git commit -m "add line 5" file1 &&
+       sed -e "s/line 1/changed line 1/" <file1 >file3 &&
+       mv file3 file1 &&
+       test_must_fail git reset --merge HEAD^ 2>err.log &&
+       grep file1 err.log | grep "not uptodate"
 '
 
 # The next test will test the following:
@@ -183,36 +183,36 @@ test_expect_success 'reset --merge fails with changes in file it touches' '
 #           ----------------------------------------------------
 # file1:     A       B     B    C     --keep   (disallowed)
 test_expect_success 'reset --keep fails with changes in file it touches' '
-    git reset --hard second &&
-    echo "line 5" >> file1 &&
-    test_tick &&
-    git commit -m "add line 5" file1 &&
-    sed -e "s/line 1/changed line 1/" <file1 >file3 &&
-    mv file3 file1 &&
-    test_must_fail git reset --keep HEAD^ 2>err.log &&
-    grep file1 err.log | grep "not uptodate"
+       git reset --hard second &&
+       echo "line 5" >> file1 &&
+       test_tick &&
+       git commit -m "add line 5" file1 &&
+       sed -e "s/line 1/changed line 1/" <file1 >file3 &&
+       mv file3 file1 &&
+       test_must_fail git reset --keep HEAD^ 2>err.log &&
+       grep file1 err.log | grep "not uptodate"
 '
 
 test_expect_success 'setup 3 different branches' '
-    git reset --hard second &&
-    git branch branch1 &&
-    git branch branch2 &&
-    git branch branch3 &&
-    git checkout branch1 &&
-    echo "line 5 in branch1" >> file1 &&
-    test_tick &&
-    git commit -a -m "change in branch1" &&
-    git checkout branch2 &&
-    echo "line 5 in branch2" >> file1 &&
-    test_tick &&
-    git commit -a -m "change in branch2" &&
-    git tag third &&
-    git checkout branch3 &&
-    echo a new file >file3 &&
-    rm -f file1 &&
-    git add file3 &&
-    test_tick &&
-    git commit -a -m "change in branch3"
+       git reset --hard second &&
+       git branch branch1 &&
+       git branch branch2 &&
+       git branch branch3 &&
+       git checkout branch1 &&
+       echo "line 5 in branch1" >> file1 &&
+       test_tick &&
+       git commit -a -m "change in branch1" &&
+       git checkout branch2 &&
+       echo "line 5 in branch2" >> file1 &&
+       test_tick &&
+       git commit -a -m "change in branch2" &&
+       git tag third &&
+       git checkout branch3 &&
+       echo a new file >file3 &&
+       rm -f file1 &&
+       git add file3 &&
+       test_tick &&
+       git commit -a -m "change in branch3"
 '
 
 # The next test will test the following:
@@ -221,12 +221,12 @@ test_expect_success 'setup 3 different branches' '
 #           ----------------------------------------------------
 # file1:     X       U     B    C     --merge  C       C     C
 test_expect_success '"reset --merge HEAD^" is ok with pending merge' '
-    git checkout third &&
-    test_must_fail git merge branch1 &&
-    git reset --merge HEAD^ &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
-    test -z "$(git diff --cached)" &&
-    test -z "$(git diff)"
+       git checkout third &&
+       test_must_fail git merge branch1 &&
+       git reset --merge HEAD^ &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+       test -z "$(git diff --cached)" &&
+       test -z "$(git diff)"
 '
 
 # The next test will test the following:
@@ -235,10 +235,10 @@ test_expect_success '"reset --merge HEAD^" is ok with pending merge' '
 #           ----------------------------------------------------
 # file1:     X       U     B    C     --keep   (disallowed)
 test_expect_success '"reset --keep HEAD^" fails with pending merge' '
-    git reset --hard third &&
-    test_must_fail git merge branch1 &&
-    test_must_fail git reset --keep HEAD^ 2>err.log &&
-    test_i18ngrep "middle of a merge" err.log
+       git reset --hard third &&
+       test_must_fail git merge branch1 &&
+       test_must_fail git reset --keep HEAD^ 2>err.log &&
+       test_i18ngrep "middle of a merge" err.log
 '
 
 # The next test will test the following:
@@ -247,12 +247,12 @@ test_expect_success '"reset --keep HEAD^" fails with pending merge' '
 #           ----------------------------------------------------
 # file1:     X       U     B    B     --merge  B       B     B
 test_expect_success '"reset --merge HEAD" is ok with pending merge' '
-    git reset --hard third &&
-    test_must_fail git merge branch1 &&
-    git reset --merge HEAD &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse third)" &&
-    test -z "$(git diff --cached)" &&
-    test -z "$(git diff)"
+       git reset --hard third &&
+       test_must_fail git merge branch1 &&
+       git reset --merge HEAD &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse third)" &&
+       test -z "$(git diff --cached)" &&
+       test -z "$(git diff)"
 '
 
 # The next test will test the following:
@@ -261,36 +261,36 @@ test_expect_success '"reset --merge HEAD" is ok with pending merge' '
 #           ----------------------------------------------------
 # file1:     X       U     B    B     --keep   (disallowed)
 test_expect_success '"reset --keep HEAD" fails with pending merge' '
-    git reset --hard third &&
-    test_must_fail git merge branch1 &&
-    test_must_fail git reset --keep HEAD 2>err.log &&
-    test_i18ngrep "middle of a merge" err.log
+       git reset --hard third &&
+       test_must_fail git merge branch1 &&
+       test_must_fail git reset --keep HEAD 2>err.log &&
+       test_i18ngrep "middle of a merge" err.log
 '
 
 test_expect_success '--merge is ok with added/deleted merge' '
-    git reset --hard third &&
-    rm -f file2 &&
-    test_must_fail git merge branch3 &&
-    ! test -f file2 &&
-    test -f file3 &&
-    git diff --exit-code file3 &&
-    git diff --exit-code branch3 file3 &&
-    git reset --merge HEAD &&
-    ! test -f file3 &&
-    ! test -f file2 &&
-    git diff --exit-code --cached
+       git reset --hard third &&
+       rm -f file2 &&
+       test_must_fail git merge branch3 &&
+       ! test -f file2 &&
+       test -f file3 &&
+       git diff --exit-code file3 &&
+       git diff --exit-code branch3 file3 &&
+       git reset --merge HEAD &&
+       ! test -f file3 &&
+       ! test -f file2 &&
+       git diff --exit-code --cached
 '
 
 test_expect_success '--keep fails with added/deleted merge' '
-    git reset --hard third &&
-    rm -f file2 &&
-    test_must_fail git merge branch3 &&
-    ! test -f file2 &&
-    test -f file3 &&
-    git diff --exit-code file3 &&
-    git diff --exit-code branch3 file3 &&
-    test_must_fail git reset --keep HEAD 2>err.log &&
-    test_i18ngrep "middle of a merge" err.log
+       git reset --hard third &&
+       rm -f file2 &&
+       test_must_fail git merge branch3 &&
+       ! test -f file2 &&
+       test -f file3 &&
+       git diff --exit-code file3 &&
+       git diff --exit-code branch3 file3 &&
+       test_must_fail git reset --keep HEAD 2>err.log &&
+       test_i18ngrep "middle of a merge" err.log
 '
 
 test_done
index 78f25c1c7ead9820ed647711e4749d7e9d444c52..01b7c3503ca882cd292f2eef252a977ac5dcc183 100755 (executable)
@@ -10,9 +10,9 @@ TEST_PASSES_SANITIZE_LEAK=true
 
 
 test_expect_success 'creating initial commits' '
-    test_commit E file1 &&
-    test_commit D file1 &&
-    test_commit C file1
+       test_commit E file1 &&
+       test_commit D file1 &&
+       test_commit C file1
 '
 
 while read W1 I1 H1 T opt W2 I2 H2
@@ -74,13 +74,13 @@ B C C C keep   B C C
 EOF
 
 test_expect_success 'setting up branches to test with unmerged entries' '
-    git reset --hard C &&
-    git branch branch1 &&
-    git branch branch2 &&
-    git checkout branch1 &&
-    test_commit B1 file1 &&
-    git checkout branch2 &&
-    test_commit B file1
+       git reset --hard C &&
+       git branch branch1 &&
+       git branch branch2 &&
+       git checkout branch1 &&
+       test_commit B1 file1 &&
+       git checkout branch2 &&
+       test_commit B file1
 '
 
 while read W1 I1 H1 T opt W2 I2 H2
index 61ad47b0c18d231c60327acda04348895947809c..ebf273e84380c4c97054d6f2c38319cf3de17453 100755 (executable)
@@ -372,75 +372,75 @@ test_expect_success 'checkout specific path while in subdirectory' '
 '
 
 test_expect_success 'checkout w/--track sets up tracking' '
-    git config branch.autosetupmerge false &&
-    git checkout main &&
-    git checkout --track -b track1 &&
-    test "$(git config branch.track1.remote)" &&
-    test "$(git config branch.track1.merge)"
+       git config branch.autosetupmerge false &&
+       git checkout main &&
+       git checkout --track -b track1 &&
+       test "$(git config branch.track1.remote)" &&
+       test "$(git config branch.track1.merge)"
 '
 
 test_expect_success 'checkout w/autosetupmerge=always sets up tracking' '
-    test_when_finished git config branch.autosetupmerge false &&
-    git config branch.autosetupmerge always &&
-    git checkout main &&
-    git checkout -b track2 &&
-    test "$(git config branch.track2.remote)" &&
-    test "$(git config branch.track2.merge)"
+       test_when_finished git config branch.autosetupmerge false &&
+       git config branch.autosetupmerge always &&
+       git checkout main &&
+       git checkout -b track2 &&
+       test "$(git config branch.track2.remote)" &&
+       test "$(git config branch.track2.merge)"
 '
 
 test_expect_success 'checkout w/--track from non-branch HEAD fails' '
-    git checkout main^0 &&
-    test_must_fail git symbolic-ref HEAD &&
-    test_must_fail git checkout --track -b track &&
-    test_must_fail git rev-parse --verify track &&
-    test_must_fail git symbolic-ref HEAD &&
-    test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
+       git checkout main^0 &&
+       test_must_fail git symbolic-ref HEAD &&
+       test_must_fail git checkout --track -b track &&
+       test_must_fail git rev-parse --verify track &&
+       test_must_fail git symbolic-ref HEAD &&
+       test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
 '
 
 test_expect_success 'checkout w/--track from tag fails' '
-    git checkout main^0 &&
-    test_must_fail git symbolic-ref HEAD &&
-    test_must_fail git checkout --track -b track frotz &&
-    test_must_fail git rev-parse --verify track &&
-    test_must_fail git symbolic-ref HEAD &&
-    test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
+       git checkout main^0 &&
+       test_must_fail git symbolic-ref HEAD &&
+       test_must_fail git checkout --track -b track frotz &&
+       test_must_fail git rev-parse --verify track &&
+       test_must_fail git symbolic-ref HEAD &&
+       test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
 '
 
 test_expect_success 'detach a symbolic link HEAD' '
-    git checkout main &&
-    git config --bool core.prefersymlinkrefs yes &&
-    git checkout side &&
-    git checkout main &&
-    it=$(git symbolic-ref HEAD) &&
-    test "z$it" = zrefs/heads/main &&
-    here=$(git rev-parse --verify refs/heads/main) &&
-    git checkout side^ &&
-    test "z$(git rev-parse --verify refs/heads/main)" = "z$here"
+       git checkout main &&
+       git config --bool core.prefersymlinkrefs yes &&
+       git checkout side &&
+       git checkout main &&
+       it=$(git symbolic-ref HEAD) &&
+       test "z$it" = zrefs/heads/main &&
+       here=$(git rev-parse --verify refs/heads/main) &&
+       git checkout side^ &&
+       test "z$(git rev-parse --verify refs/heads/main)" = "z$here"
 '
 
 test_expect_success 'checkout with --track fakes a sensible -b <name>' '
-    git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
-    git update-ref refs/remotes/origin/koala/bear renamer &&
+       git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
+       git update-ref refs/remotes/origin/koala/bear renamer &&
 
-    git checkout --track origin/koala/bear &&
-    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
+       git checkout --track origin/koala/bear &&
+       test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 
-    git checkout main && git branch -D koala/bear &&
+       git checkout main && git branch -D koala/bear &&
 
-    git checkout --track refs/remotes/origin/koala/bear &&
-    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
+       git checkout --track refs/remotes/origin/koala/bear &&
+       test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 
-    git checkout main && git branch -D koala/bear &&
+       git checkout main && git branch -D koala/bear &&
 
-    git checkout --track remotes/origin/koala/bear &&
-    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
+       git checkout --track remotes/origin/koala/bear &&
+       test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
+       test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
 '
 
 test_expect_success 'checkout with --track, but without -b, fails with too short tracked name' '
-    test_must_fail git checkout --track renamer
+       test_must_fail git checkout --track renamer
 '
 
 setup_conflicting_index () {
@@ -497,6 +497,11 @@ test_expect_success 'checkout unmerged stage' '
        test ztheirside = "z$(cat file)"
 '
 
+test_expect_success 'checkout path with --merge from tree-ish is a no-no' '
+       setup_conflicting_index &&
+       test_must_fail git checkout -m HEAD -- file
+'
+
 test_expect_success 'checkout with --merge' '
        setup_conflicting_index &&
        echo "none of the above" >sample &&
@@ -517,6 +522,48 @@ test_expect_success 'checkout with --merge' '
        test_cmp merged file
 '
 
+test_expect_success 'checkout -m works after (mistaken) resolution' '
+       setup_conflicting_index &&
+       echo "none of the above" >sample &&
+       cat sample >fild &&
+       cat sample >file &&
+       cat sample >filf &&
+       # resolve to something
+       git add file &&
+       git checkout --merge -- fild file filf &&
+       {
+               echo "<<<<<<< ours" &&
+               echo ourside &&
+               echo "=======" &&
+               echo theirside &&
+               echo ">>>>>>> theirs"
+       } >merged &&
+       test_cmp expect fild &&
+       test_cmp expect filf &&
+       test_cmp merged file
+'
+
+test_expect_success 'checkout -m works after (mistaken) resolution to remove' '
+       setup_conflicting_index &&
+       echo "none of the above" >sample &&
+       cat sample >fild &&
+       cat sample >file &&
+       cat sample >filf &&
+       # resolve to remove
+       git rm file &&
+       git checkout --merge -- fild file filf &&
+       {
+               echo "<<<<<<< ours" &&
+               echo ourside &&
+               echo "=======" &&
+               echo theirside &&
+               echo ">>>>>>> theirs"
+       } >merged &&
+       test_cmp expect fild &&
+       test_cmp expect filf &&
+       test_cmp merged file
+'
+
 test_expect_success 'checkout with --merge, in diff3 -m style' '
        git config merge.conflictstyle diff3 &&
        setup_conflicting_index &&
index eae6a46ef3d89f2563d5ec69f83dfd2ad6e7829f..d9fbabb2b9d810d0c39cd504d105bcb8ba3e568c 100755 (executable)
@@ -1351,6 +1351,22 @@ test_expect_success 'clone active submodule without submodule url set' '
        )
 '
 
+test_expect_success 'update submodules without url set in .gitconfig' '
+       test_when_finished "rm -rf multisuper_clone" &&
+       git clone file://"$pwd"/multisuper multisuper_clone &&
+
+       git -C multisuper_clone submodule init &&
+       for s in sub0 sub1 sub2 sub3
+       do
+               key=submodule.$s.url &&
+               git -C multisuper_clone config --local --unset $key &&
+               git -C multisuper_clone config --file .gitmodules --unset $key || return 1
+       done &&
+
+       test_must_fail git -C multisuper_clone submodule update 2>err &&
+       grep "cannot clone submodule .sub[0-3]. without a URL" err
+'
+
 test_expect_success 'clone --recurse-submodules with a pathspec works' '
        test_when_finished "rm -rf multisuper_clone" &&
        cat >expected <<-\EOF &&
index f094e3d7f3642de61a69b3d9131e31707654539c..00651c25cb4089a4d7334ad00f6ebc8e51bafb0f 100755 (executable)
@@ -1179,4 +1179,27 @@ test_expect_success 'submodule update --recursive skip submodules with strategy=
        test_cmp expect.err actual.err
 '
 
+add_submodule_commit_and_validate () {
+       HASH=$(git rev-parse HEAD) &&
+       git update-index --add --cacheinfo 160000,$HASH,sub &&
+       git commit -m "create submodule" &&
+       echo "160000 commit $HASH       sub" >expect &&
+       git ls-tree HEAD -- sub >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'commit with staged submodule change' '
+       add_submodule_commit_and_validate
+'
+
+test_expect_success 'commit with staged submodule change with ignoreSubmodules dirty' '
+       test_config diff.ignoreSubmodules dirty &&
+       add_submodule_commit_and_validate
+'
+
+test_expect_success 'commit with staged submodule change with ignoreSubmodules all' '
+       test_config diff.ignoreSubmodules all &&
+       add_submodule_commit_and_validate
+'
+
 test_done
index 232065504cbfdcba60d3f5f69ffb4536b5ae99e8..a5d1bc5c54ae095f79bf9b3ee420ba004bb18a88 100755 (executable)
@@ -11,6 +11,10 @@ as expected.
 
 TEST_PASSES_SANITIZE_LEAK=true
 TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
 . ./test-lib.sh
 
 test_expect_success 'setup' '
@@ -27,26 +31,28 @@ test_expect_success 'submodule config cache setup' '
                git checkout -b topic &&
                echo b >a &&
                git add . &&
-               git commit -mb
+               git commit -mb &&
+               git checkout main
        ) &&
        mkdir super &&
        (cd super &&
                git init &&
                git submodule add ../submodule &&
-               git commit -m "add submodule"
+               git submodule add --name thename ../submodule thepath &&
+               git commit -m "add submodules"
        )
 '
 
 test_expect_success 'ensure submodule branch is unset' '
        (cd super &&
-               ! grep branch .gitmodules
+               test_cmp_config "" -f .gitmodules --default "" submodule.submodule.branch
        )
 '
 
 test_expect_success 'test submodule set-branch --branch' '
        (cd super &&
                git submodule set-branch --branch topic submodule &&
-               grep "branch = topic" .gitmodules &&
+               test_cmp_config topic -f .gitmodules submodule.submodule.branch &&
                git submodule update --remote &&
                cat <<-\EOF >expect &&
                b
@@ -57,13 +63,12 @@ test_expect_success 'test submodule set-branch --branch' '
 '
 
 test_expect_success 'test submodule set-branch --default' '
-       test_commit -C submodule c &&
        (cd super &&
                git submodule set-branch --default submodule &&
-               ! grep branch .gitmodules &&
+               test_cmp_config "" -f .gitmodules --default "" submodule.submodule.branch &&
                git submodule update --remote &&
                cat <<-\EOF >expect &&
-               c
+               a
                EOF
                git -C submodule show -s --pretty=%s >actual &&
                test_cmp expect actual
@@ -71,10 +76,9 @@ test_expect_success 'test submodule set-branch --default' '
 '
 
 test_expect_success 'test submodule set-branch -b' '
-       test_commit -C submodule b &&
        (cd super &&
                git submodule set-branch -b topic submodule &&
-               grep "branch = topic" .gitmodules &&
+               test_cmp_config topic -f .gitmodules submodule.submodule.branch &&
                git submodule update --remote &&
                cat <<-\EOF >expect &&
                b
@@ -85,17 +89,43 @@ test_expect_success 'test submodule set-branch -b' '
 '
 
 test_expect_success 'test submodule set-branch -d' '
-       test_commit -C submodule d &&
        (cd super &&
                git submodule set-branch -d submodule &&
-               ! grep branch .gitmodules &&
+               test_cmp_config "" -f .gitmodules --default "" submodule.submodule.branch &&
                git submodule update --remote &&
                cat <<-\EOF >expect &&
-               d
+               a
                EOF
                git -C submodule show -s --pretty=%s >actual &&
                test_cmp expect actual
        )
 '
 
+test_expect_success 'test submodule set-branch --branch with named submodule' '
+       (cd super &&
+               git submodule set-branch --branch topic thepath &&
+               test_cmp_config topic -f .gitmodules submodule.thename.branch &&
+               test_cmp_config "" -f .gitmodules --default "" submodule.thepath.branch &&
+               git submodule update --remote &&
+               cat <<-\EOF >expect &&
+               b
+               EOF
+               git -C thepath show -s --pretty=%s >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'test submodule set-branch --default with named submodule' '
+       (cd super &&
+               git submodule set-branch --default thepath &&
+               test_cmp_config "" -f .gitmodules --default "" submodule.thename.branch &&
+               git submodule update --remote &&
+               cat <<-\EOF >expect &&
+               a
+               EOF
+               git -C thepath show -s --pretty=%s >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done
index d6bf62b3ac670fc0be8167150cdf79cbd9000a45..bf7f15ee7973958970dfe0d1b34cea9d25e635a9 100755 (executable)
@@ -25,17 +25,26 @@ test_expect_success 'submodule config cache setup' '
                git add file &&
                git commit -ma
        ) &&
+       mkdir namedsubmodule &&
+       (
+               cd namedsubmodule &&
+               git init &&
+               echo 1 >file &&
+               git add file &&
+               git commit -m1
+       ) &&
        mkdir super &&
        (
                cd super &&
                git init &&
                git submodule add ../submodule &&
-               git commit -m "add submodule"
+               git submodule add --name thename ../namedsubmodule thepath &&
+               git commit -m "add submodules"
        )
 '
 
 test_expect_success 'test submodule set-url' '
-       # add a commit and move the submodule (change the url)
+       # add commits and move the submodules (change the urls)
        (
                cd submodule &&
                echo b >>file &&
@@ -44,15 +53,28 @@ test_expect_success 'test submodule set-url' '
        ) &&
        mv submodule newsubmodule &&
 
+       (
+               cd namedsubmodule &&
+               echo 2 >>file &&
+               git add file &&
+               git commit -m2
+       ) &&
+       mv namedsubmodule newnamedsubmodule &&
+
        git -C newsubmodule show >expect &&
+       git -C newnamedsubmodule show >>expect &&
        (
                cd super &&
                test_must_fail git submodule update --remote &&
                git submodule set-url submodule ../newsubmodule &&
-               grep -F "url = ../newsubmodule" .gitmodules &&
+               test_cmp_config ../newsubmodule -f .gitmodules submodule.submodule.url &&
+               git submodule set-url thepath ../newnamedsubmodule &&
+               test_cmp_config ../newnamedsubmodule -f .gitmodules submodule.thename.url &&
+               test_cmp_config "" -f .gitmodules --default "" submodule.thepath.url &&
                git submodule update --remote
        ) &&
        git -C super/submodule show >actual &&
+       git -C super/thepath show >>actual &&
        test_cmp expect actual
 '
 
index 38a532d81ccd060d7c42e1a3f413bdfeccf4715b..b5bf7de7cd66c781657173bac3074cacb1107bf1 100755 (executable)
@@ -466,6 +466,25 @@ test_expect_success 'commit --trailer with -c and command' '
        test_cmp expected actual
 '
 
+test_expect_success 'commit --trailer not confused by --- separator' '
+       cat >msg <<-\EOF &&
+       subject
+
+       body with dashes
+       ---
+       in it
+       EOF
+       git commit --allow-empty --trailer="my-trailer: value" -F msg &&
+       {
+               cat msg &&
+               echo &&
+               echo "my-trailer: value"
+       } >expected &&
+       git cat-file commit HEAD >commit.msg &&
+       sed -e "1,/^\$/d" commit.msg >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'multiple -m' '
 
        >negative &&
index aed07c5b622e9a244313e781ceba0e6898024d21..6c46648e1128ccc7182c8618f89ac3d7c15b988c 100755 (executable)
@@ -5,6 +5,7 @@
 
 test_description='git status'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
@@ -91,7 +92,7 @@ test_expect_success 'status --column' '
 # On branch main
 # Your branch and '\''upstream'\'' have diverged,
 # and have 1 and 2 different commits each, respectively.
-#   (use "git pull" to merge the remote branch into yours)
+#   (use "git pull" if you want to integrate the remote branch with yours)
 #
 # Changes to be committed:
 #   (use "git restore --staged <file>..." to unstage)
@@ -122,7 +123,7 @@ cat >expect <<\EOF
 # On branch main
 # Your branch and 'upstream' have diverged,
 # and have 1 and 2 different commits each, respectively.
-#   (use "git pull" to merge the remote branch into yours)
+#   (use "git pull" if you want to integrate the remote branch with yours)
 #
 # Changes to be committed:
 #   (use "git restore --staged <file>..." to unstage)
@@ -269,7 +270,7 @@ test_expect_success 'status with gitignore' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -334,7 +335,7 @@ test_expect_success 'status with gitignore (nothing untracked)' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -404,7 +405,7 @@ test_expect_success 'status -uno' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -466,7 +467,7 @@ test_expect_success 'status -unormal' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -521,7 +522,7 @@ test_expect_success 'status -uall' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -581,7 +582,7 @@ test_expect_success 'status with relative paths' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -649,7 +650,7 @@ test_expect_success TTY 'status with color.ui' '
 On branch <GREEN>main<RESET>
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -772,7 +773,7 @@ test_expect_success 'status without relative paths' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -846,7 +847,6 @@ test_expect_success 'dry-run of partial commit excluding new file in index' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -900,7 +900,7 @@ test_expect_success 'status submodule summary is disabled by default' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -957,7 +957,7 @@ test_expect_success 'status submodule summary' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 1 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -1012,11 +1012,11 @@ test_expect_success 'status -s submodule summary' '
 '
 
 test_expect_success 'status submodule summary (clean submodule): commit' '
-       cat >expect <<EOF &&
+       cat >expect-status <<EOF &&
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes not staged for commit:
   (use "git add <file>..." to update what will be committed)
@@ -1032,12 +1032,13 @@ Untracked files:
 
 no changes added to commit (use "git add" and/or "git commit -a")
 EOF
+       sed "/git pull/d" expect-status > expect-commit &&
        git commit -m "commit submodule" &&
        git config status.submodulesummary 10 &&
        test_must_fail git commit --dry-run >output &&
-       test_cmp expect output &&
+       test_cmp expect-commit output &&
        git status >output &&
-       test_cmp expect output
+       test_cmp expect-status output
 '
 
 cat >expect <<EOF
@@ -1064,7 +1065,6 @@ test_expect_success 'commit --dry-run submodule summary (--amend)' '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
   (use "git restore --source=HEAD^1 --staged <file>..." to unstage)
@@ -1116,7 +1116,7 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -1225,7 +1225,7 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -1282,7 +1282,7 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -1363,7 +1363,7 @@ cat > expect << EOF
 ; On branch main
 ; Your branch and 'upstream' have diverged,
 ; and have 2 and 2 different commits each, respectively.
-;   (use "git pull" to merge the remote branch into yours)
+;   (use "git pull" if you want to integrate the remote branch with yours)
 ;
 ; Changes to be committed:
 ;   (use "git restore --staged <file>..." to unstage)
@@ -1411,7 +1411,7 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" '
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes not staged for commit:
   (use "git add <file>..." to update what will be committed)
@@ -1437,7 +1437,7 @@ test_expect_success '.gitmodules ignore=all suppresses unstaged submodule summar
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
+  (use "git pull" if you want to integrate the remote branch with yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -1519,8 +1519,8 @@ test_expect_success '"status.branch=true" weaker than "--no-branch"' '
 '
 
 test_expect_success '"status.branch=true" weaker than "--porcelain"' '
-       git -c status.branch=true status --porcelain >actual &&
-       test_cmp expected_nobranch actual
+       git -c status.branch=true status --porcelain >actual &&
+       test_cmp expected_nobranch actual
 '
 
 test_expect_success '"status.branch=false" same as "--no-branch"' '
@@ -1557,7 +1557,6 @@ test_expect_success 'git commit --dry-run will show a staged but ignored submodu
 On branch main
 Your branch and '\''upstream'\'' have diverged,
 and have 2 and 2 different commits each, respectively.
-  (use "git pull" to merge the remote branch into yours)
 
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
@@ -1746,4 +1745,20 @@ test_expect_success 'slow status advice when core.untrackedCache true, and fsmon
        )
 '
 
+test_expect_success EXPENSIVE 'status does not re-read unchanged 4 or 8 GiB file' '
+       (
+               mkdir large-file &&
+               cd large-file &&
+               # Files are 2 GiB, 4 GiB, and 8 GiB sparse files.
+               test-tool truncate file-a 0x080000000 &&
+               test-tool truncate file-b 0x100000000 &&
+               test-tool truncate file-c 0x200000000 &&
+               # This will be slow.
+               git add file-a file-b file-c &&
+               git commit -m "add large files" &&
+               git diff-index HEAD file-a file-b file-c >actual &&
+               test_must_be_empty actual
+       )
+'
+
 test_done
index ccbc416402894aeda02a70b9c248f5ed8ed4d825..0d2dd29fe6a12c20ffbbe169afabd4c31bc6545c 100755 (executable)
@@ -218,6 +218,13 @@ test_expect_success GPG 'amending already signed commit' '
        ! grep "BAD signature from" actual
 '
 
+test_expect_success GPG2 'bare signature' '
+       git verify-commit fifth-signed 2>expect &&
+       echo >>expect &&
+       git log -1 --format="%GG" fifth-signed >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success GPG 'show good signature with custom format' '
        cat >expect <<-\EOF &&
        G
index 2f16d5787edfb16956312a3be70fb9da1ffadc46..c2ab8a444a832513b9365a2a6eca11535e2ec8fe 100755 (executable)
@@ -774,6 +774,28 @@ EOF
        test_cmp expected actual
 '
 
+test_expect_success 'status when cherry-picking multiple commits' '
+       git reset --hard cherry_branch &&
+       test_when_finished "git cherry-pick --abort" &&
+       test_must_fail git cherry-pick cherry_branch_second one_cherry &&
+       TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) &&
+       cat >expected <<EOF &&
+On branch cherry_branch
+You are currently cherry-picking commit $TO_CHERRY_PICK.
+  (fix conflicts and run "git cherry-pick --continue")
+  (use "git cherry-pick --skip" to skip this patch)
+  (use "git cherry-pick --abort" to cancel the cherry-pick operation)
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+       both modified:   main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+       git status --untracked-files=no >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'status when cherry-picking after committing conflict resolution' '
        git reset --hard cherry_branch &&
        test_when_finished "git cherry-pick --abort" &&
index 97f10905d23fd3077aa9dd253fa079eb9c5be73d..832aff0616736025cb78d2b35e3823594b543b1d 100755 (executable)
@@ -489,7 +489,7 @@ test_expect_success 'multiline field treated as atomic for neighbor check' '
 '
 
 test_expect_success 'with config setup' '
-       git config trailer.ack.key "Acked-by: " &&
+       test_config trailer.ack.key "Acked-by: " &&
        cat >expected <<-\EOF &&
 
                Acked-by: Peff
@@ -503,8 +503,8 @@ test_expect_success 'with config setup' '
 '
 
 test_expect_success 'with config setup and ":=" as separators' '
-       git config trailer.separators ":=" &&
-       git config trailer.ack.key "Acked-by= " &&
+       test_config trailer.separators ":=" &&
+       test_config trailer.ack.key "Acked-by= " &&
        cat >expected <<-\EOF &&
 
                Acked-by= Peff
@@ -518,7 +518,7 @@ test_expect_success 'with config setup and ":=" as separators' '
 '
 
 test_expect_success 'with config setup and "%" as separators' '
-       git config trailer.separators "%" &&
+       test_config trailer.separators "%" &&
        cat >expected <<-\EOF &&
 
                bug% 42
@@ -532,6 +532,7 @@ test_expect_success 'with config setup and "%" as separators' '
 '
 
 test_expect_success 'with "%" as separators and a message with trailers' '
+       test_config trailer.separators "%" &&
        cat >special_message <<-\EOF &&
                Special Message
 
@@ -553,8 +554,8 @@ test_expect_success 'with "%" as separators and a message with trailers' '
 '
 
 test_expect_success 'with config setup and ":=#" as separators' '
-       git config trailer.separators ":=#" &&
-       git config trailer.bug.key "Bug #" &&
+       test_config trailer.separators ":=#" &&
+       test_config trailer.bug.key "Bug #" &&
        cat >expected <<-\EOF &&
 
                Bug #42
@@ -581,6 +582,8 @@ test_expect_success 'with basic patch' '
 '
 
 test_expect_success 'with commit complex message as argument' '
+       test_config trailer.separators ":=" &&
+       test_config trailer.ack.key "Acked-by= " &&
        cat complex_message_body complex_message_trailers >complex_message &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
@@ -594,6 +597,8 @@ test_expect_success 'with commit complex message as argument' '
 '
 
 test_expect_success 'with 2 files arguments' '
+       test_config trailer.separators ":=" &&
+       test_config trailer.ack.key "Acked-by= " &&
        cat basic_message >>expected &&
        echo >>expected &&
        cat basic_patch >>expected &&
@@ -677,6 +682,9 @@ test_expect_success 'with message that has an old style conflict block' '
 '
 
 test_expect_success 'with commit complex message and trailer args' '
+       test_config trailer.separators ":=#" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.bug.key "Bug #" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -692,6 +700,9 @@ test_expect_success 'with commit complex message and trailer args' '
 '
 
 test_expect_success 'with complex patch, args and --trim-empty' '
+       test_config trailer.separators ":=#" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.bug.key "Bug #" &&
        cat complex_message >complex_patch &&
        cat basic_patch >>complex_patch &&
        cat complex_message_body >expected &&
@@ -746,7 +757,10 @@ test_expect_success POSIXPERM,SANITY "in-place editing doesn't clobber original
 '
 
 test_expect_success 'using "where = before"' '
-       git config trailer.bug.where "before" &&
+       test_config trailer.separators ":=#" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -762,7 +776,9 @@ test_expect_success 'using "where = before"' '
 '
 
 test_expect_success 'overriding configuration with "--where after"' '
-       git config trailer.ack.where "before" &&
+       test_config trailer.separators ":=" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "before" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -776,7 +792,12 @@ test_expect_success 'overriding configuration with "--where after"' '
        test_cmp expected actual
 '
 
-test_expect_success 'using "where = before" with "--no-where"' '
+test_expect_success 'using "--where after" with "--no-where"' '
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "before" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -791,8 +812,59 @@ test_expect_success 'using "where = before" with "--no-where"' '
        test_cmp expected actual
 '
 
+# Check whether using "--no-where" clears out only the "--where after", such
+# that we still use the configuration in trailer.where (which is different from
+# the hardcoded default (in WHERE_END) assuming the absence of .gitconfig).
+# Here, the "start" setting of trailer.where is respected, so the new "Acked-by"
+# and "Bug" trailers are placed at the beginning, and not at the end which is
+# the harcoded default.
+test_expect_success 'using "--where after" with "--no-where" defaults to configuration' '
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.separators ":=#" &&
+       test_config trailer.where "start" &&
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+               Bug #42
+               Acked-by= Peff
+               Fixes: Z
+               Acked-by= Z
+               Reviewed-by: Z
+               Signed-off-by: Z
+       EOF
+       git interpret-trailers --where after --no-where --trailer "ack: Peff" \
+               --trailer "bug: 42" complex_message >actual &&
+       test_cmp expected actual
+'
+
+# The "--where after" will only get respected for the trailer that came
+# immediately after it. For the next trailer (Bug #42), we default to using the
+# hardcoded WHERE_END because we don't have any "trailer.where" or
+# "trailer.bug.where" configured.
+test_expect_success 'using "--no-where" defaults to harcoded default if nothing configured' '
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.separators ":=#" &&
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+               Fixes: Z
+               Acked-by= Z
+               Acked-by= Peff
+               Reviewed-by: Z
+               Signed-off-by: Z
+               Bug #42
+       EOF
+       git interpret-trailers --where after --trailer "ack: Peff" --no-where \
+               --trailer "bug: 42" complex_message >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'using "where = after"' '
-       git config trailer.ack.where "after" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -808,8 +880,11 @@ test_expect_success 'using "where = after"' '
 '
 
 test_expect_success 'using "where = end"' '
-       git config trailer.review.key "Reviewed-by" &&
-       git config trailer.review.where "end" &&
+       test_config trailer.review.key "Reviewed-by" &&
+       test_config trailer.review.where "end" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -827,8 +902,11 @@ test_expect_success 'using "where = end"' '
 '
 
 test_expect_success 'using "where = start"' '
-       git config trailer.review.key "Reviewed-by" &&
-       git config trailer.review.where "start" &&
+       test_config trailer.review.key "Reviewed-by" &&
+       test_config trailer.review.where "start" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Reviewed-by: Johannes
@@ -846,8 +924,13 @@ test_expect_success 'using "where = start"' '
 '
 
 test_expect_success 'using "where = before" for a token in the middle of the message' '
-       git config trailer.review.key "Reviewed-by:" &&
-       git config trailer.review.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.review.where "before" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -864,6 +947,12 @@ test_expect_success 'using "where = before" for a token in the middle of the mes
 '
 
 test_expect_success 'using "where = before" and --trim-empty' '
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        cat >>expected <<-\EOF &&
                Bug #46
@@ -878,6 +967,13 @@ test_expect_success 'using "where = before" and --trim-empty' '
 '
 
 test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' '
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.review.where "before" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -896,7 +992,13 @@ test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' '
 '
 
 test_expect_success 'default "ifExists" is now "addIfDifferent"' '
-       git config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -914,8 +1016,14 @@ test_expect_success 'default "ifExists" is now "addIfDifferent"' '
 '
 
 test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' '
-       git config trailer.ack.ifExists "addIfDifferent" &&
-       git config trailer.ack.where "end" &&
+       test_config trailer.ack.ifExists "addIfDifferent" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "end" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -932,8 +1040,14 @@ test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' '
 '
 
 test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' '
-       git config trailer.ack.ifExists "addIfDifferent" &&
-       git config trailer.ack.where "before" &&
+       test_config trailer.ack.ifExists "addIfDifferent" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "before" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -950,8 +1064,14 @@ test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' '
 '
 
 test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end"' '
-       git config trailer.ack.ifExists "addIfDifferentNeighbor" &&
-       git config trailer.ack.where "end" &&
+       test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "end" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -973,8 +1093,14 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end
 '
 
 test_expect_success 'using "ifExists = addIfDifferentNeighbor"  with "where = after"' '
-       git config trailer.ack.ifExists "addIfDifferentNeighbor" &&
-       git config trailer.ack.where "after" &&
+       test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -995,7 +1121,11 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor"  with "where = af
 '
 
 test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty' '
-       git config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+       test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        cat >>expected <<-\EOF &&
                Bug #42
@@ -1011,8 +1141,14 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty'
 '
 
 test_expect_success 'using "ifExists = add" with "where = end"' '
-       git config trailer.ack.ifExists "add" &&
-       git config trailer.ack.where "end" &&
+       test_config trailer.ack.ifExists "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "end" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1036,8 +1172,14 @@ test_expect_success 'using "ifExists = add" with "where = end"' '
 '
 
 test_expect_success 'using "ifExists = add" with "where = after"' '
-       git config trailer.ack.ifExists "add" &&
-       git config trailer.ack.where "after" &&
+       test_config trailer.ack.ifExists "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1058,8 +1200,15 @@ test_expect_success 'using "ifExists = add" with "where = after"' '
 '
 
 test_expect_success 'overriding configuration with "--if-exists replace"' '
-       git config trailer.fix.key "Fixes: " &&
-       git config trailer.fix.ifExists "add" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.review.where "before" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1074,9 +1223,66 @@ test_expect_success 'overriding configuration with "--if-exists replace"' '
        test_cmp expected actual
 '
 
+# "trailer.ifexists" is set to "doNothing", so using "--no-if-exists" defaults
+# to this "doNothing" behavior. So the "Fixes: 53" trailer does not get added.
+test_expect_success 'using "--if-exists replace" with "--no-if-exists" defaults to configuration' '
+       test_config trailer.ifexists "doNothing" &&
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+               Fixes: Z
+               Acked-by: Z
+               Reviewed-by: Z
+               Signed-off-by: Z
+       EOF
+       git interpret-trailers --if-exists replace --no-if-exists --trailer "Fixes: 53" \
+               <complex_message >actual &&
+       test_cmp expected actual
+'
+
+# No "ifexists" configuration is set, so using "--no-if-exists" makes it default
+# to addIfDifferentNeighbor. Because we do have a different neighbor "Fixes: 53"
+# (because it got added by overriding with "--if-exists replace" earlier in the
+# arguments list), we add "Signed-off-by: addme".
+test_expect_success 'using "--no-if-exists" defaults to hardcoded default if nothing configured' '
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+               Acked-by: Z
+               Reviewed-by: Z
+               Signed-off-by: Z
+               Fixes: 53
+               Signed-off-by: addme
+       EOF
+       git interpret-trailers --if-exists replace --trailer "Fixes: 53" --no-if-exists \
+               --trailer "Signed-off-by: addme" <complex_message >actual &&
+       test_cmp expected actual
+'
+
+# The second "Fixes: 53" trailer is discarded, because the "--no-if-exists" here
+# makes us default to addIfDifferentNeighbor, and we already added the "Fixes:
+# 53" trailer earlier in the argument list.
+test_expect_success 'using "--no-if-exists" defaults to hardcoded default if nothing configured (no addition)' '
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+               Acked-by: Z
+               Reviewed-by: Z
+               Signed-off-by: Z
+               Fixes: 53
+       EOF
+       git interpret-trailers --if-exists replace --trailer "Fixes: 53" --no-if-exists \
+               --trailer "Fixes: 53" <complex_message >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'using "ifExists = replace"' '
-       git config trailer.fix.key "Fixes: " &&
-       git config trailer.fix.ifExists "replace" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "replace" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1095,7 +1301,16 @@ test_expect_success 'using "ifExists = replace"' '
 '
 
 test_expect_success 'using "ifExists = replace" with "where = after"' '
-       git config trailer.fix.where "after" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "replace" &&
+       test_config trailer.fix.where "after" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1114,7 +1329,15 @@ test_expect_success 'using "ifExists = replace" with "where = after"' '
 '
 
 test_expect_success 'using "ifExists = doNothing"' '
-       git config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1133,8 +1356,17 @@ test_expect_success 'using "ifExists = doNothing"' '
 '
 
 test_expect_success 'the default is "ifMissing = add"' '
-       git config trailer.cc.key "Cc: " &&
-       git config trailer.cc.where "before" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.cc.key "Cc: " &&
+       test_config trailer.cc.where "before" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1154,7 +1386,14 @@ test_expect_success 'the default is "ifMissing = add"' '
 '
 
 test_expect_success 'overriding configuration with "--if-missing doNothing"' '
-       git config trailer.ifmissing "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.ifmissing "add" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -1173,7 +1412,13 @@ test_expect_success 'overriding configuration with "--if-missing doNothing"' '
 '
 
 test_expect_success 'when default "ifMissing" is "doNothing"' '
-       git config trailer.ifmissing "doNothing" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.ifmissing "doNothing" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -1187,14 +1432,21 @@ test_expect_success 'when default "ifMissing" is "doNothing"' '
                --trailer "cc=Linus" --trailer "ack: Junio" \
                --trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \
                <complex_message >actual &&
-       test_cmp expected actual &&
-       git config trailer.ifmissing "add"
+       test_cmp expected actual
 '
 
 test_expect_success 'using "ifMissing = add" with "where = end"' '
-       git config trailer.cc.key "Cc: " &&
-       git config trailer.cc.where "end" &&
-       git config trailer.cc.ifMissing "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.cc.key "Cc: " &&
+       test_config trailer.cc.ifMissing "add" &&
+       test_config trailer.cc.where "end" &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1214,9 +1466,17 @@ test_expect_success 'using "ifMissing = add" with "where = end"' '
 '
 
 test_expect_success 'using "ifMissing = add" with "where = before"' '
-       git config trailer.cc.key "Cc: " &&
-       git config trailer.cc.where "before" &&
-       git config trailer.cc.ifMissing "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.cc.key "Cc: " &&
+       test_config trailer.cc.ifMissing "add" &&
+       test_config trailer.cc.where "before" &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Cc: Linus
@@ -1236,7 +1496,15 @@ test_expect_success 'using "ifMissing = add" with "where = before"' '
 '
 
 test_expect_success 'using "ifMissing = doNothing"' '
-       git config trailer.cc.ifMissing "doNothing" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.cc.ifMissing "doNothing" &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1254,9 +1522,50 @@ test_expect_success 'using "ifMissing = doNothing"' '
        test_cmp expected actual
 '
 
+# Ignore the "IgnoredTrailer" because of "--if-missing doNothing", but also
+# ignore the "StillIgnoredTrailer" because we set "trailer.ifMissing" to
+# "doNothing" in configuration.
+test_expect_success 'using "--no-if-missing" defaults to configuration' '
+       test_config trailer.ifMissing "doNothing" &&
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+                       Fixes: Z
+                       Acked-by: Z
+                       Reviewed-by: Z
+                       Signed-off-by: Z
+       EOF
+       git interpret-trailers --if-missing doNothing --trailer "IgnoredTrailer: ignoreme" --no-if-missing \
+                       --trailer "StillIgnoredTrailer: ignoreme" <complex_message >actual &&
+       test_cmp expected actual
+'
+
+# Add the "AddedTrailer" because the "--no-if-missing" clears the "--if-missing
+# doNothing" from earlier in the argument list.
+test_expect_success 'using "--no-if-missing" defaults to hardcoded default if nothing configured' '
+       cat complex_message_body >expected &&
+       sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
+                       Fixes: Z
+                       Acked-by: Z
+                       Reviewed-by: Z
+                       Signed-off-by: Z
+                       AddedTrailer: addme
+       EOF
+       git interpret-trailers --if-missing doNothing --trailer "IgnoredTrailer: ignoreme" --no-if-missing \
+                       --trailer "AddedTrailer: addme" <complex_message >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'default "where" is now "after"' '
        git config trailer.where "after" &&
-       git config --unset trailer.ack.where &&
+       test_config trailer.ack.ifExists "add" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.ack.where "after" &&
+       test_config trailer.bug.key "Bug #" &&
+       test_config trailer.bug.where "before" &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=#" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Bug #42
@@ -1280,10 +1589,15 @@ test_expect_success 'default "where" is now "after"' '
 '
 
 test_expect_success 'with simple command' '
-       git config trailer.sign.key "Signed-off-by: " &&
-       git config trailer.sign.where "after" &&
-       git config trailer.sign.ifExists "addIfDifferentNeighbor" &&
-       git config trailer.sign.command "echo \"A U Thor <author@example.com>\"" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.sign.command "echo \"A U Thor <author@example.com>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.sign.ifExists "addIfDifferentNeighbor" &&
+       test_config trailer.sign.where "after" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -1298,8 +1612,14 @@ test_expect_success 'with simple command' '
 '
 
 test_expect_success 'with command using committer information' '
-       git config trailer.sign.ifExists "addIfDifferent" &&
-       git config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.sign.ifExists "addIfDifferent" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -1314,10 +1634,15 @@ test_expect_success 'with command using committer information' '
 '
 
 test_expect_success 'with command using author information' '
-       git config trailer.sign.key "Signed-off-by: " &&
-       git config trailer.sign.where "after" &&
-       git config trailer.sign.ifExists "addIfDifferentNeighbor" &&
-       git config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.fix.ifExists "doNothing" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.sign.ifExists "addIfDifferentNeighbor" &&
+       test_config trailer.sign.where "after" &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
                Fixes: Z
@@ -1338,12 +1663,19 @@ test_expect_success 'setup a commit' '
 '
 
 test_expect_success 'cmd takes precedence over command' '
-       test_when_finished "git config --unset trailer.fix.cmd" &&
-       git config trailer.fix.ifExists "replace" &&
-       git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
-       --abbrev-commit --abbrev=14 \"\$1\" || true" &&
-       git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
                --abbrev-commit --abbrev=14 \$ARG" &&
+       test_config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
+       --abbrev-commit --abbrev=14 \"\$1\" || true" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "replace" &&
+       test_config trailer.fix.where "after" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=" &&
        FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
        cat complex_message_body >expected2 &&
        sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
@@ -1359,8 +1691,16 @@ test_expect_success 'cmd takes precedence over command' '
 '
 
 test_expect_success 'with command using $ARG' '
-       git config trailer.fix.ifExists "replace" &&
-       git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "replace" &&
+       test_config trailer.fix.where "after" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=" &&
        FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-EOF &&
@@ -1376,8 +1716,16 @@ test_expect_success 'with command using $ARG' '
 '
 
 test_expect_success 'with failing command using $ARG' '
-       git config trailer.fix.ifExists "replace" &&
-       git config trailer.fix.command "false \$ARG" &&
+       test_config trailer.ack.key "Acked-by= " &&
+       test_config trailer.fix.command "false \$ARG" &&
+       test_config trailer.fix.key "Fixes: " &&
+       test_config trailer.fix.ifExists "replace" &&
+       test_config trailer.fix.where "after" &&
+       test_config trailer.review.key "Reviewed-by:" &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.ifexists "addIfDifferent" &&
+       test_config trailer.separators ":=" &&
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-EOF &&
                Fixes: Z
@@ -1392,7 +1740,9 @@ test_expect_success 'with failing command using $ARG' '
 '
 
 test_expect_success 'with empty tokens' '
-       git config --unset trailer.fix.command &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.sign.key "Signed-off-by: " &&
+       test_config trailer.ifexists "addIfDifferent" &&
        cat >expected <<-EOF &&
 
                Signed-off-by: A U Thor <author@example.com>
@@ -1403,7 +1753,8 @@ test_expect_success 'with empty tokens' '
 '
 
 test_expect_success 'with command but no key' '
-       git config --unset trailer.sign.key &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.ifexists "addIfDifferent" &&
        cat >expected <<-EOF &&
 
                sign: A U Thor <author@example.com>
@@ -1414,7 +1765,9 @@ test_expect_success 'with command but no key' '
 '
 
 test_expect_success 'with no command and no key' '
-       git config --unset trailer.review.key &&
+       test_config trailer.review.where "before" &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
+       test_config trailer.ifexists "addIfDifferent" &&
        cat >expected <<-EOF &&
 
                review: Junio
@@ -1426,6 +1779,8 @@ test_expect_success 'with no command and no key' '
 '
 
 test_expect_success 'with cut line' '
+       test_config trailer.review.where "before" &&
+       test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
        cat >expected <<-\EOF &&
                my subject
 
@@ -1443,7 +1798,8 @@ test_expect_success 'with cut line' '
 '
 
 test_expect_success 'only trailers' '
-       git config trailer.sign.command "echo config-value" &&
+       test_config trailer.sign.command "echo config-value" &&
+       test_config trailer.ifexists "addIfDifferent" &&
        cat >expected <<-\EOF &&
                existing: existing-value
                sign: config-value
@@ -1462,7 +1818,7 @@ test_expect_success 'only trailers' '
 '
 
 test_expect_success 'only-trailers omits non-trailer in middle of block' '
-       git config trailer.sign.command "echo config-value" &&
+       test_config trailer.sign.command "echo config-value" &&
        cat >expected <<-\EOF &&
                Signed-off-by: nobody <nobody@nowhere>
                Signed-off-by: somebody <somebody@somewhere>
@@ -1482,7 +1838,7 @@ test_expect_success 'only-trailers omits non-trailer in middle of block' '
 '
 
 test_expect_success 'only input' '
-       git config trailer.sign.command "echo config-value" &&
+       test_config trailer.sign.command "echo config-value" &&
        cat >expected <<-\EOF &&
                existing: existing-value
        EOF
index 2d38a16480e82c0441075e0e54ffe8454b413cb2..bb95f09810b704b552352d90b6ec2a046c7d0fc1 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='git commit races'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'race to create orphan commit' '
index fffdb6ff2e751d2441e8f805c475a044bfdd0920..9ab2ae2f3b23807b4ee1eb3fcfaf62d9c1fe7bc3 100755 (executable)
@@ -20,10 +20,19 @@ test_expect_success 'empty name and missing email' '
 '
 
 test_expect_success 'commit rejects all-crud name' '
-       test_must_fail env GIT_AUTHOR_NAME=" .;<>" \
+       test_must_fail env GIT_AUTHOR_NAME=" ,;<>" \
                git commit --allow-empty -m foo
 '
 
+test_expect_success 'commit does not strip trailing dot' '
+       author_name="Pat Doe Jr." &&
+       env GIT_AUTHOR_NAME="$author_name" \
+               git commit --allow-empty -m foo &&
+       git log -1 --format=%an >actual &&
+       echo "$author_name" >expected &&
+       test_cmp actual expected
+'
+
 # We must test the actual error message here, as an unwanted
 # auto-detection could fail for other reasons.
 test_expect_success 'empty configured name does not auto-detect' '
index 0c241d6c148d7b5ebc9a9b3aaf44723fb1028e8b..78503158fd699d2df75e8fbbbaf164a129f2578b 100755 (executable)
@@ -809,6 +809,11 @@ my_match_and_clean () {
                status --porcelain=v2 >actual.without &&
        test_cmp actual.with actual.without &&
 
+       git -C super --no-optional-locks diff-index --name-status HEAD >actual.with &&
+       git -C super --no-optional-locks -c core.fsmonitor=false \
+               diff-index --name-status HEAD >actual.without &&
+       test_cmp actual.with actual.without &&
+
        git -C super/dir_1/dir_2/sub reset --hard &&
        git -C super/dir_1/dir_2/sub clean -d -f
 }
index 060e145957f3ad94933b37ebe6148ffbdf168d37..fdc607277c2fca64a573959b2f3ea7f35a8beaae 100755 (executable)
@@ -639,41 +639,41 @@ test_expect_success 'merge log message' '
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c0, c2, c0, and c1' '
-       git reset --hard c1 &&
-       test_tick &&
-       git merge c0 c2 c0 c1 &&
-       verify_merge file result.1-5 &&
-       verify_parents $c1 $c2
+       git reset --hard c1 &&
+       test_tick &&
+       git merge c0 c2 c0 c1 &&
+       verify_merge file result.1-5 &&
+       verify_parents $c1 $c2
 '
 
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c0, c2, c0, and c1' '
-       git reset --hard c1 &&
-       test_tick &&
-       git merge c0 c2 c0 c1 &&
-       verify_merge file result.1-5 &&
-       verify_parents $c1 $c2
+       git reset --hard c1 &&
+       test_tick &&
+       git merge c0 c2 c0 c1 &&
+       verify_merge file result.1-5 &&
+       verify_parents $c1 $c2
 '
 
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c1 with c1 and c2' '
-       git reset --hard c1 &&
-       test_tick &&
-       git merge c1 c2 &&
-       verify_merge file result.1-5 &&
-       verify_parents $c1 $c2
+       git reset --hard c1 &&
+       test_tick &&
+       git merge c1 c2 &&
+       verify_merge file result.1-5 &&
+       verify_parents $c1 $c2
 '
 
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge fast-forward in a dirty tree' '
-       git reset --hard c0 &&
-       mv file file1 &&
-       cat file1 >file &&
-       rm -f file1 &&
-       git merge c2
+       git reset --hard c0 &&
+       mv file file1 &&
+       cat file1 >file &&
+       rm -f file1 &&
+       git merge c2
 '
 
 test_debug 'git log --graph --decorate --oneline --all'
index bd238d89b0cb07ed6a92707dcfd80ac277b75524..e08767df66e452e9cbbd0e6ccc1f35ce56ff1f98 100755 (executable)
@@ -349,13 +349,13 @@ test_expect_success 'Cannot rebase with multiple heads' '
 
 test_expect_success 'merge c1 with c2' '
        git reset --hard c1 &&
-       test -f c0.c &&
-       test -f c1.c &&
-       test ! -f c2.c &&
-       test ! -f c3.c &&
+       test_path_is_file c0.c &&
+       test_path_is_file c1.c &&
+       test_path_is_missing c2.c &&
+       test_path_is_missing c3.c &&
        git merge c2 &&
-       test -f c1.c &&
-       test -f c2.c
+       test_path_is_file c1.c &&
+       test_path_is_file c2.c
 '
 
 test_expect_success 'fast-forward pull succeeds with "true" in pull.ff' '
@@ -411,8 +411,8 @@ test_expect_success 'merge c1 with c2 (ours in pull.twohead)' '
        git reset --hard c1 &&
        git config pull.twohead ours &&
        git merge c2 &&
-       test -f c1.c &&
-       ! test -f c2.c
+       test_path_is_file c1.c &&
+       test_path_is_missing c2.c
 '
 
 test_expect_success 'merge c1 with c2 and c3 (recursive in pull.octopus)' '
@@ -431,10 +431,10 @@ test_expect_success 'merge c1 with c2 and c3 (recursive and octopus in pull.octo
        test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" &&
        test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" &&
        git diff --exit-code &&
-       test -f c0.c &&
-       test -f c1.c &&
-       test -f c2.c &&
-       test -f c3.c
+       test_path_is_file c0.c &&
+       test_path_is_file c1.c &&
+       test_path_is_file c2.c &&
+       test_path_is_file c3.c
 '
 
 conflict_count()
index ff085b086cc38f36a180e22ab02bbea12a29cc0c..3669d33bd5a15fc19fbfd2cbea14507c8e273642 100755 (executable)
@@ -4,6 +4,7 @@ test_description='git merge
 
 Testing octopus merge with more than 25 refs.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup' '
index 4887ca705b330e8cbf6f25595cbcadfdfd67f9f2..0e85b21ec82cc64e7d1e519c269a9bdcb189e01b 100755 (executable)
@@ -4,6 +4,7 @@ test_description='git merge
 
 Testing octopus merge when reducing parents to independent branches.'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # 0 - 1
index 89a62ac53b3d6012d13b3b1ce0dfa97d494060f2..9001674f2ea2201836613e4909d9442062f609f4 100755 (executable)
@@ -4,6 +4,7 @@ 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_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'Ensure we restore original state if no merge strategy handles it' '
index 0b908ab2e7128052a0513e740b54ba308b9feadc..2179938c437e47552eccb7af85fa3e4669ccc1bf 100755 (executable)
@@ -4,6 +4,7 @@ test_description='test auto-generated merge messages'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 check_oneline() {
index faa739eeb91f020976a92656e0a06bf3f06a64cc..d2975e6c93a07480e8da4e89bb1bd48faf397cba 100755 (executable)
@@ -10,6 +10,10 @@ test_description='git repack works correctly'
 commit_and_pack () {
        test_commit "$@" 1>&2 &&
        incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) &&
+       # Remove any loose object(s) created by test_commit, since they have
+       # already been packed. Leaving these around can create subtly different
+       # packs with `pack-objects`'s `--unpacked` option.
+       git prune-packed 1>&2 &&
        echo pack-${incrpackid}.pack
 }
 
@@ -209,6 +213,8 @@ test_expect_success 'repack --keep-pack' '
        test_create_repo keep-pack &&
        (
                cd keep-pack &&
+               # avoid producing different packs due to delta/base choices
+               git config pack.window 0 &&
                P1=$(commit_and_pack 1) &&
                P2=$(commit_and_pack 2) &&
                P3=$(commit_and_pack 3) &&
@@ -220,10 +226,61 @@ test_expect_success 'repack --keep-pack' '
                grep -q $P1 new-counts &&
                grep -q $P4 new-counts &&
                test_line_count = 3 new-counts &&
+               git fsck &&
+
+               P5=$(commit_and_pack --no-tag 5) &&
+               git reset --hard HEAD^ &&
+               git reflog expire --all --expire=all &&
+               rm -f ".git/objects/pack/${P5%.pack}.idx" &&
+               rm -f ".git/objects/info/commit-graph" &&
+               for from in $(find .git/objects/pack -type f -name "${P5%.pack}.*")
+               do
+                       to="$(dirname "$from")/.tmp-1234-$(basename "$from")" &&
+                       mv "$from" "$to" || return 1
+               done &&
+
+               # A .idx file without a .pack should not stop us from
+               # repacking what we can.
+               touch .git/objects/pack/pack-does-not-exist.idx &&
+
+               git repack --cruft -d --keep-pack $P1 --keep-pack $P4 &&
+
+               ls .git/objects/pack/*.pack >newer-counts &&
+               test_cmp new-counts newer-counts &&
                git fsck
        )
 '
 
+test_expect_success 'repacking fails when missing .pack actually means missing objects' '
+       test_create_repo idx-without-pack &&
+       (
+               cd idx-without-pack &&
+
+               # Avoid producing different packs due to delta/base choices
+               git config pack.window 0 &&
+               P1=$(commit_and_pack 1) &&
+               P2=$(commit_and_pack 2) &&
+               P3=$(commit_and_pack 3) &&
+               P4=$(commit_and_pack 4) &&
+               ls .git/objects/pack/*.pack >old-counts &&
+               test_line_count = 4 old-counts &&
+
+               # Remove one .pack file
+               rm .git/objects/pack/$P2 &&
+
+               ls .git/objects/pack/*.pack >before-pack-dir &&
+
+               test_must_fail git fsck &&
+               test_must_fail git repack --cruft -d 2>err &&
+               grep "bad object" err &&
+
+               # Before failing, the repack did not modify the
+               # pack directory.
+               ls .git/objects/pack/*.pack >after-pack-dir &&
+               test_cmp before-pack-dir after-pack-dir
+       )
+'
+
 test_expect_success 'bitmaps are created by default in bare repos' '
        git clone --bare .git bare.git &&
        rm -f bare.git/objects/pack/*.bitmap &&
@@ -270,6 +327,203 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' '
        test_must_be_empty actual
 '
 
+test_expect_success 'repacking with a filter works' '
+       git -C bare.git repack -a -d &&
+       test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+       git -C bare.git -c repack.writebitmaps=false repack -a -d --filter=blob:none &&
+       test_stdout_line_count = 2 ls bare.git/objects/pack/*.pack &&
+       commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) &&
+       blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) &&
+       test "$commit_pack" != "$blob_pack" &&
+       tree_pack=$(test-tool -C bare.git find-pack -c 1 HEAD^{tree}) &&
+       test "$tree_pack" = "$commit_pack" &&
+       blob_pack2=$(test-tool -C bare.git find-pack -c 1 HEAD:file2) &&
+       test "$blob_pack2" = "$blob_pack"
+'
+
+test_expect_success '--filter fails with --write-bitmap-index' '
+       test_must_fail \
+               env GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
+               git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
+'
+
+test_expect_success 'repacking with two filters works' '
+       git init two-filters &&
+       (
+               cd two-filters &&
+               mkdir subdir &&
+               test_commit foo &&
+               test_commit subdir_bar subdir/bar &&
+               test_commit subdir_baz subdir/baz
+       ) &&
+       git clone --no-local --bare two-filters two-filters.git &&
+       (
+               cd two-filters.git &&
+               test_stdout_line_count = 1 ls objects/pack/*.pack &&
+               git -c repack.writebitmaps=false repack -a -d \
+                       --filter=blob:none --filter=tree:1 &&
+               test_stdout_line_count = 2 ls objects/pack/*.pack &&
+               commit_pack=$(test-tool find-pack -c 1 HEAD) &&
+               blob_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+               root_tree_pack=$(test-tool find-pack -c 1 HEAD^{tree}) &&
+               subdir_tree_hash=$(git ls-tree --object-only HEAD -- subdir) &&
+               subdir_tree_pack=$(test-tool find-pack -c 1 "$subdir_tree_hash") &&
+
+               # Root tree and subdir tree are not in the same packfiles
+               test "$commit_pack" != "$blob_pack" &&
+               test "$commit_pack" = "$root_tree_pack" &&
+               test "$blob_pack" = "$subdir_tree_pack"
+       )
+'
+
+prepare_for_keep_packs () {
+       git init keep-packs &&
+       (
+               cd keep-packs &&
+               test_commit foo &&
+               test_commit bar
+       ) &&
+       git clone --no-local --bare keep-packs keep-packs.git &&
+       (
+               cd keep-packs.git &&
+
+               # Create two packs
+               # The first pack will contain all of the objects except one blob
+               git rev-list --objects --all >objs &&
+               grep -v "bar.t" objs | git pack-objects pack &&
+               # The second pack will contain the excluded object and be kept
+               packid=$(grep "bar.t" objs | git pack-objects pack) &&
+               >pack-$packid.keep &&
+
+               # Replace the existing pack with the 2 new ones
+               rm -f objects/pack/pack* &&
+               mv pack-* objects/pack/
+       )
+}
+
+test_expect_success '--filter works with .keep packs' '
+       prepare_for_keep_packs &&
+       (
+               cd keep-packs.git &&
+
+               foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+               bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) &&
+               head_pack=$(test-tool find-pack -c 1 HEAD) &&
+
+               test "$foo_pack" != "$bar_pack" &&
+               test "$foo_pack" = "$head_pack" &&
+
+               git -c repack.writebitmaps=false repack -a -d --filter=blob:none &&
+
+               foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+               bar_pack_1=$(test-tool find-pack -c 1 HEAD:bar.t) &&
+               head_pack_1=$(test-tool find-pack -c 1 HEAD) &&
+
+               # Object bar is still only in the old .keep pack
+               test "$foo_pack_1" != "$foo_pack" &&
+               test "$bar_pack_1" = "$bar_pack" &&
+               test "$head_pack_1" != "$head_pack" &&
+
+               test "$foo_pack_1" != "$bar_pack_1" &&
+               test "$foo_pack_1" != "$head_pack_1" &&
+               test "$bar_pack_1" != "$head_pack_1"
+       )
+'
+
+test_expect_success '--filter works with --pack-kept-objects and .keep packs' '
+       rm -rf keep-packs keep-packs.git &&
+       prepare_for_keep_packs &&
+       (
+               cd keep-packs.git &&
+
+               foo_pack=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+               bar_pack=$(test-tool find-pack -c 1 HEAD:bar.t) &&
+               head_pack=$(test-tool find-pack -c 1 HEAD) &&
+
+               test "$foo_pack" != "$bar_pack" &&
+               test "$foo_pack" = "$head_pack" &&
+
+               git -c repack.writebitmaps=false repack -a -d --filter=blob:none \
+                       --pack-kept-objects &&
+
+               foo_pack_1=$(test-tool find-pack -c 1 HEAD:foo.t) &&
+               test-tool find-pack -c 2 HEAD:bar.t >bar_pack_1 &&
+               head_pack_1=$(test-tool find-pack -c 1 HEAD) &&
+
+               test "$foo_pack_1" != "$foo_pack" &&
+               test "$foo_pack_1" != "$bar_pack" &&
+               test "$head_pack_1" != "$head_pack" &&
+
+               # Object bar is in both the old .keep pack and the new
+               # pack that contained the filtered out objects
+               grep "$bar_pack" bar_pack_1 &&
+               grep "$foo_pack_1" bar_pack_1 &&
+               test "$foo_pack_1" != "$head_pack_1"
+       )
+'
+
+test_expect_success '--filter-to stores filtered out objects' '
+       git -C bare.git repack -a -d &&
+       test_stdout_line_count = 1 ls bare.git/objects/pack/*.pack &&
+
+       git init --bare filtered.git &&
+       git -C bare.git -c repack.writebitmaps=false repack -a -d \
+               --filter=blob:none \
+               --filter-to=../filtered.git/objects/pack/pack &&
+       test_stdout_line_count = 1 ls bare.git/objects/pack/pack-*.pack &&
+       test_stdout_line_count = 1 ls filtered.git/objects/pack/pack-*.pack &&
+
+       commit_pack=$(test-tool -C bare.git find-pack -c 1 HEAD) &&
+       blob_pack=$(test-tool -C bare.git find-pack -c 0 HEAD:file1) &&
+       blob_hash=$(git -C bare.git rev-parse HEAD:file1) &&
+       test -n "$blob_hash" &&
+       blob_pack=$(test-tool -C filtered.git find-pack -c 1 $blob_hash) &&
+
+       echo $(pwd)/filtered.git/objects >bare.git/objects/info/alternates &&
+       blob_pack=$(test-tool -C bare.git find-pack -c 1 HEAD:file1) &&
+       blob_content=$(git -C bare.git show $blob_hash) &&
+       test "$blob_content" = "content1"
+'
+
+test_expect_success '--filter works with --max-pack-size' '
+       rm -rf filtered.git &&
+       git init --bare filtered.git &&
+       git init max-pack-size &&
+       (
+               cd max-pack-size &&
+               test_commit base &&
+               # two blobs which exceed the maximum pack size
+               test-tool genrandom foo 1048576 >foo &&
+               git hash-object -w foo &&
+               test-tool genrandom bar 1048576 >bar &&
+               git hash-object -w bar &&
+               git add foo bar &&
+               git commit -m "adding foo and bar"
+       ) &&
+       git clone --no-local --bare max-pack-size max-pack-size.git &&
+       (
+               cd max-pack-size.git &&
+               git -c repack.writebitmaps=false repack -a -d --filter=blob:none \
+                       --max-pack-size=1M \
+                       --filter-to=../filtered.git/objects/pack/pack &&
+               echo $(cd .. && pwd)/filtered.git/objects >objects/info/alternates &&
+
+               # Check that the 3 blobs are in different packfiles in filtered.git
+               test_stdout_line_count = 3 ls ../filtered.git/objects/pack/pack-*.pack &&
+               test_stdout_line_count = 1 ls objects/pack/pack-*.pack &&
+               foo_pack=$(test-tool find-pack -c 1 HEAD:foo) &&
+               bar_pack=$(test-tool find-pack -c 1 HEAD:bar) &&
+               base_pack=$(test-tool find-pack -c 1 HEAD:base.t) &&
+               test "$foo_pack" != "$bar_pack" &&
+               test "$foo_pack" != "$base_pack" &&
+               test "$bar_pack" != "$base_pack" &&
+               for pack in "$foo_pack" "$bar_pack" "$base_pack"
+               do
+                       case "$foo_pack" in */filtered.git/objects/pack/*) true ;; *) return 1 ;; esac
+               done
+       )
+'
+
 objdir=.git/objects
 midx=$objdir/pack/multi-pack-index
 
@@ -460,10 +714,10 @@ test_expect_success '--write-midx -b packs non-kept objects' '
 '
 
 test_expect_success '--write-midx removes stale pack-based bitmaps' '
-       rm -fr repo &&
-       git init repo &&
-       test_when_finished "rm -fr repo" &&
-       (
+       rm -fr repo &&
+       git init repo &&
+       test_when_finished "rm -fr repo" &&
+       (
                cd repo &&
                test_commit base &&
                GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab &&
@@ -477,7 +731,7 @@ test_expect_success '--write-midx removes stale pack-based bitmaps' '
                test_path_is_file $midx &&
                test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
                test_path_is_missing $pack_bitmap
-       )
+       )
 '
 
 test_expect_success '--write-midx with --pack-kept-objects' '
@@ -576,125 +830,4 @@ test_expect_success '-n overrides repack.updateServerInfo=true' '
        test_server_info_missing
 '
 
-test_expect_success '--expire-to stores pruned objects (now)' '
-       git init expire-to-now &&
-       (
-               cd expire-to-now &&
-
-               git branch -M main &&
-
-               test_commit base &&
-
-               git checkout -b cruft &&
-               test_commit --no-tag cruft &&
-
-               git rev-list --objects --no-object-names main..cruft >moved.raw &&
-               sort moved.raw >moved.want &&
-
-               git rev-list --all --objects --no-object-names >expect.raw &&
-               sort expect.raw >expect &&
-
-               git checkout main &&
-               git branch -D cruft &&
-               git reflog expire --all --expire=all &&
-
-               git init --bare expired.git &&
-               git repack -d \
-                       --cruft --cruft-expiration="now" \
-                       --expire-to="expired.git/objects/pack/pack" &&
-
-               expired="$(ls expired.git/objects/pack/pack-*.idx)" &&
-               test_path_is_file "${expired%.idx}.mtimes" &&
-
-               # Since the `--cruft-expiration` is "now", the effective
-               # behavior is to move _all_ unreachable objects out to
-               # the location in `--expire-to`.
-               git show-index <$expired >expired.raw &&
-               cut -d" " -f2 expired.raw | sort >expired.objects &&
-               git rev-list --all --objects --no-object-names \
-                       >remaining.objects &&
-
-               # ...in other words, the combined contents of this
-               # repository and expired.git should be the same as the
-               # set of objects we started with.
-               cat expired.objects remaining.objects | sort >actual &&
-               test_cmp expect actual &&
-
-               # The "moved" objects (i.e., those in expired.git)
-               # should be the same as the cruft objects which were
-               # expired in the previous step.
-               test_cmp moved.want expired.objects
-       )
-'
-
-test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' '
-       git init expire-to-5.minutes.ago &&
-       (
-               cd expire-to-5.minutes.ago &&
-
-               git branch -M main &&
-
-               test_commit base &&
-
-               # Create two classes of unreachable objects, one which
-               # is older than 5 minutes (stale), and another which is
-               # newer (recent).
-               for kind in stale recent
-               do
-                       git checkout -b $kind main &&
-                       test_commit --no-tag $kind || return 1
-               done &&
-
-               git rev-list --objects --no-object-names main..stale >in &&
-               stale="$(git pack-objects $objdir/pack/pack <in)" &&
-               mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" &&
-
-               # expect holds the set of objects we expect to find in
-               # this repository after repacking
-               git rev-list --objects --no-object-names recent >expect.raw &&
-               sort expect.raw >expect &&
-
-               # moved.want holds the set of objects we expect to find
-               # in expired.git
-               git rev-list --objects --no-object-names main..stale >out &&
-               sort out >moved.want &&
-
-               git checkout main &&
-               git branch -D stale recent &&
-               git reflog expire --all --expire=all &&
-               git prune-packed &&
-
-               git init --bare expired.git &&
-               git repack -d \
-                       --cruft --cruft-expiration=5.minutes.ago \
-                       --expire-to="expired.git/objects/pack/pack" &&
-
-               # Some of the remaining objects in this repository are
-               # unreachable, so use `cat-file --batch-all-objects`
-               # instead of `rev-list` to get their names
-               git cat-file --batch-all-objects --batch-check="%(objectname)" \
-                       >remaining.objects &&
-               sort remaining.objects >actual &&
-               test_cmp expect actual &&
-
-               (
-                       cd expired.git &&
-
-                       expired="$(ls objects/pack/pack-*.mtimes)" &&
-                       test-tool pack-mtimes $(basename $expired) >out &&
-                       cut -d" " -f1 out | sort >../moved.got &&
-
-                       # Ensure that there are as many objects with the
-                       # expected mtime as were moved to expired.git.
-                       #
-                       # In other words, ensure that the recorded
-                       # mtimes of any moved objects was written
-                       # correctly.
-                       grep " $mtime$" out >matching &&
-                       test_line_count = $(wc -l <../moved.want) matching
-               ) &&
-               test_cmp moved.want moved.got
-       )
-'
-
 test_done
index ebb267855fe06a0cfb3fa9a4d1cc21157f832d1d..fe6c3e77a3c9add78dadc421be9b0b00b0f6bcd9 100755 (executable)
@@ -113,6 +113,48 @@ test_expect_success 'do not bother loosening old objects' '
        test_must_fail git cat-file -p $obj2
 '
 
+test_expect_success 'gc.recentObjectsHook' '
+       obj1=$(echo one | git hash-object -w --stdin) &&
+       obj2=$(echo two | git hash-object -w --stdin) &&
+       obj3=$(echo three | git hash-object -w --stdin) &&
+       pack1=$(echo $obj1 | git pack-objects .git/objects/pack/pack) &&
+       pack2=$(echo $obj2 | git pack-objects .git/objects/pack/pack) &&
+       pack3=$(echo $obj3 | git pack-objects .git/objects/pack/pack) &&
+       git prune-packed &&
+
+       git cat-file -p $obj1 &&
+       git cat-file -p $obj2 &&
+       git cat-file -p $obj3 &&
+
+       # make an unreachable annotated tag object to ensure we rescue objects
+       # which are reachable from non-pruned unreachable objects
+       obj2_tag="$(git mktag <<-EOF
+       object $obj2
+       type blob
+       tag obj2-tag
+       tagger T A Gger <tagger@example.com> 1234567890 -0000
+       EOF
+       )" &&
+
+       obj2_tag_pack="$(echo $obj2_tag | git pack-objects .git/objects/pack/pack)" &&
+       git prune-packed &&
+
+       write_script precious-objects <<-EOF &&
+       echo $obj2_tag
+       EOF
+       git config gc.recentObjectsHook ./precious-objects &&
+
+       test-tool chmtime =-86400 .git/objects/pack/pack-$pack2.pack &&
+       test-tool chmtime =-86400 .git/objects/pack/pack-$pack3.pack &&
+       test-tool chmtime =-86400 .git/objects/pack/pack-$obj2_tag_pack.pack &&
+       git repack -A -d --unpack-unreachable=1.hour.ago &&
+
+       git cat-file -p $obj1 &&
+       git cat-file -p $obj2 &&
+       git cat-file -p $obj2_tag &&
+       test_must_fail git cat-file -p $obj3
+'
+
 test_expect_success 'keep packed objects found only in index' '
        echo my-unique-content >file &&
        git add file &&
diff --git a/t/t7704-repack-cruft.sh b/t/t7704-repack-cruft.sh
new file mode 100755 (executable)
index 0000000..be3735d
--- /dev/null
@@ -0,0 +1,414 @@
+#!/bin/sh
+
+test_description='git repack works correctly'
+
+. ./test-lib.sh
+
+objdir=.git/objects
+packdir=$objdir/pack
+
+test_expect_success '--expire-to stores pruned objects (now)' '
+       git init expire-to-now &&
+       (
+               cd expire-to-now &&
+
+               git branch -M main &&
+
+               test_commit base &&
+
+               git checkout -b cruft &&
+               test_commit --no-tag cruft &&
+
+               git rev-list --objects --no-object-names main..cruft >moved.raw &&
+               sort moved.raw >moved.want &&
+
+               git rev-list --all --objects --no-object-names >expect.raw &&
+               sort expect.raw >expect &&
+
+               git checkout main &&
+               git branch -D cruft &&
+               git reflog expire --all --expire=all &&
+
+               git init --bare expired.git &&
+               git repack -d \
+                       --cruft --cruft-expiration="now" \
+                       --expire-to="expired.git/objects/pack/pack" &&
+
+               expired="$(ls expired.git/objects/pack/pack-*.idx)" &&
+               test_path_is_file "${expired%.idx}.mtimes" &&
+
+               # Since the `--cruft-expiration` is "now", the effective
+               # behavior is to move _all_ unreachable objects out to
+               # the location in `--expire-to`.
+               git show-index <$expired >expired.raw &&
+               cut -d" " -f2 expired.raw | sort >expired.objects &&
+               git rev-list --all --objects --no-object-names \
+                       >remaining.objects &&
+
+               # ...in other words, the combined contents of this
+               # repository and expired.git should be the same as the
+               # set of objects we started with.
+               cat expired.objects remaining.objects | sort >actual &&
+               test_cmp expect actual &&
+
+               # The "moved" objects (i.e., those in expired.git)
+               # should be the same as the cruft objects which were
+               # expired in the previous step.
+               test_cmp moved.want expired.objects
+       )
+'
+
+test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' '
+       git init expire-to-5.minutes.ago &&
+       (
+               cd expire-to-5.minutes.ago &&
+
+               git branch -M main &&
+
+               test_commit base &&
+
+               # Create two classes of unreachable objects, one which
+               # is older than 5 minutes (stale), and another which is
+               # newer (recent).
+               for kind in stale recent
+               do
+                       git checkout -b $kind main &&
+                       test_commit --no-tag $kind || return 1
+               done &&
+
+               git rev-list --objects --no-object-names main..stale >in &&
+               stale="$(git pack-objects $objdir/pack/pack <in)" &&
+               mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" &&
+
+               # expect holds the set of objects we expect to find in
+               # this repository after repacking
+               git rev-list --objects --no-object-names recent >expect.raw &&
+               sort expect.raw >expect &&
+
+               # moved.want holds the set of objects we expect to find
+               # in expired.git
+               git rev-list --objects --no-object-names main..stale >out &&
+               sort out >moved.want &&
+
+               git checkout main &&
+               git branch -D stale recent &&
+               git reflog expire --all --expire=all &&
+               git prune-packed &&
+
+               git init --bare expired.git &&
+               git repack -d \
+                       --cruft --cruft-expiration=5.minutes.ago \
+                       --expire-to="expired.git/objects/pack/pack" &&
+
+               # Some of the remaining objects in this repository are
+               # unreachable, so use `cat-file --batch-all-objects`
+               # instead of `rev-list` to get their names
+               git cat-file --batch-all-objects --batch-check="%(objectname)" \
+                       >remaining.objects &&
+               sort remaining.objects >actual &&
+               test_cmp expect actual &&
+
+               (
+                       cd expired.git &&
+
+                       expired="$(ls objects/pack/pack-*.mtimes)" &&
+                       test-tool pack-mtimes $(basename $expired) >out &&
+                       cut -d" " -f1 out | sort >../moved.got &&
+
+                       # Ensure that there are as many objects with the
+                       # expected mtime as were moved to expired.git.
+                       #
+                       # In other words, ensure that the recorded
+                       # mtimes of any moved objects was written
+                       # correctly.
+                       grep " $mtime$" out >matching &&
+                       test_line_count = $(wc -l <../moved.want) matching
+               ) &&
+               test_cmp moved.want moved.got
+       )
+'
+
+generate_random_blob() {
+       test-tool genrandom "$@" >blob &&
+       git hash-object -w -t blob blob &&
+       rm blob
+}
+
+pack_random_blob () {
+       generate_random_blob "$@" &&
+       git repack -d -q >/dev/null
+}
+
+generate_cruft_pack () {
+       pack_random_blob "$@" >/dev/null &&
+
+       ls $packdir/pack-*.pack | xargs -n 1 basename >in &&
+       pack="$(git pack-objects --cruft $packdir/pack <in)" &&
+       git prune-packed &&
+
+       echo "$packdir/pack-$pack.mtimes"
+}
+
+test_expect_success '--max-cruft-size creates new packs when above threshold' '
+       git init max-cruft-size-large &&
+       (
+               cd max-cruft-size-large &&
+               test_commit base &&
+
+               foo="$(pack_random_blob foo $((1*1024*1024)))" &&
+               git repack --cruft -d &&
+               cruft_foo="$(ls $packdir/pack-*.mtimes)" &&
+
+               bar="$(pack_random_blob bar $((1*1024*1024)))" &&
+               git repack --cruft -d --max-cruft-size=1M &&
+               cruft_bar="$(ls $packdir/pack-*.mtimes | grep -v $cruft_foo)" &&
+
+               test-tool pack-mtimes $(basename "$cruft_foo") >foo.objects &&
+               test-tool pack-mtimes $(basename "$cruft_bar") >bar.objects &&
+
+               grep "^$foo" foo.objects &&
+               test_line_count = 1 foo.objects &&
+               grep "^$bar" bar.objects &&
+               test_line_count = 1 bar.objects
+       )
+'
+
+test_expect_success '--max-cruft-size combines existing packs when below threshold' '
+       git init max-cruft-size-small &&
+       (
+               cd max-cruft-size-small &&
+               test_commit base &&
+
+               foo="$(pack_random_blob foo $((1*1024*1024)))" &&
+               git repack --cruft -d &&
+
+               bar="$(pack_random_blob bar $((1*1024*1024)))" &&
+               git repack --cruft -d --max-cruft-size=10M &&
+
+               cruft=$(ls $packdir/pack-*.mtimes) &&
+               test-tool pack-mtimes $(basename "$cruft") >cruft.objects &&
+
+               grep "^$foo" cruft.objects &&
+               grep "^$bar" cruft.objects &&
+               test_line_count = 2 cruft.objects
+       )
+'
+
+test_expect_success '--max-cruft-size combines smaller packs first' '
+       git init max-cruft-size-consume-small &&
+       (
+               cd max-cruft-size-consume-small &&
+
+               test_commit base &&
+               git repack -ad &&
+
+               cruft_foo="$(generate_cruft_pack foo 524288)" &&    # 0.5 MiB
+               cruft_bar="$(generate_cruft_pack bar 524288)" &&    # 0.5 MiB
+               cruft_baz="$(generate_cruft_pack baz 1048576)" &&   # 1.0 MiB
+               cruft_quux="$(generate_cruft_pack quux 1572864)" && # 1.5 MiB
+
+               test-tool pack-mtimes "$(basename $cruft_foo)" >expect.raw &&
+               test-tool pack-mtimes "$(basename $cruft_bar)" >>expect.raw &&
+               sort expect.raw >expect.objects &&
+
+               # repacking with `--max-cruft-size=2M` should combine
+               # both 0.5 MiB packs together, instead of, say, one of
+               # the 0.5 MiB packs with the 1.0 MiB pack
+               ls $packdir/pack-*.mtimes | sort >cruft.before &&
+               git repack -d --cruft --max-cruft-size=2M &&
+               ls $packdir/pack-*.mtimes | sort >cruft.after &&
+
+               comm -13 cruft.before cruft.after >cruft.new &&
+               comm -23 cruft.before cruft.after >cruft.removed &&
+
+               test_line_count = 1 cruft.new &&
+               test_line_count = 2 cruft.removed &&
+
+               # the two smaller packs should be rolled up first
+               printf "%s\n" $cruft_foo $cruft_bar | sort >expect.removed &&
+               test_cmp expect.removed cruft.removed &&
+
+               # ...and contain the set of objects rolled up
+               test-tool pack-mtimes "$(basename $(cat cruft.new))" >actual.raw &&
+               sort actual.raw >actual.objects &&
+
+               test_cmp expect.objects actual.objects
+       )
+'
+
+test_expect_success 'setup --max-cruft-size with freshened objects' '
+       git init max-cruft-size-freshen &&
+       (
+               cd max-cruft-size-freshen &&
+
+               test_commit base &&
+               git repack -ad &&
+
+               foo="$(generate_random_blob foo 64)" &&
+               test-tool chmtime --get -10000 \
+                       "$objdir/$(test_oid_to_path "$foo")" >foo.mtime &&
+
+               git repack --cruft -d &&
+
+               cruft="$(ls $packdir/pack-*.mtimes)" &&
+               test-tool pack-mtimes "$(basename $cruft)" >actual &&
+               echo "$foo $(cat foo.mtime)" >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '--max-cruft-size with freshened objects (loose)' '
+       (
+               cd max-cruft-size-freshen &&
+
+               # regenerate the object, setting its mtime to be more recent
+               foo="$(generate_random_blob foo 64)" &&
+               test-tool chmtime --get -100 \
+                       "$objdir/$(test_oid_to_path "$foo")" >foo.mtime &&
+
+               git repack --cruft -d &&
+
+               cruft="$(ls $packdir/pack-*.mtimes)" &&
+               test-tool pack-mtimes "$(basename $cruft)" >actual &&
+               echo "$foo $(cat foo.mtime)" >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '--max-cruft-size with freshened objects (packed)' '
+       (
+               cd max-cruft-size-freshen &&
+
+               # regenerate the object and store it in a packfile,
+               # setting its mtime to be more recent
+               #
+               # store it alongside another cruft object so that we
+               # do not create an identical copy of the existing
+               # cruft pack (which contains $foo).
+               foo="$(generate_random_blob foo 64)" &&
+               bar="$(generate_random_blob bar 64)" &&
+               foo_pack="$(printf "%s\n" $foo $bar | git pack-objects $packdir/pack)" &&
+               git prune-packed &&
+
+               test-tool chmtime --get -10 \
+                       "$packdir/pack-$foo_pack.pack" >foo.mtime &&
+
+               git repack --cruft -d &&
+
+               cruft="$(ls $packdir/pack-*.mtimes)" &&
+               test-tool pack-mtimes "$(basename $cruft)" >actual &&
+               echo "$foo $(cat foo.mtime)" >expect.raw &&
+               echo "$bar $(cat foo.mtime)" >>expect.raw &&
+               sort expect.raw >expect &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success '--max-cruft-size with pruning' '
+       git init max-cruft-size-prune &&
+       (
+               cd max-cruft-size-prune &&
+
+               test_commit base &&
+               foo="$(generate_random_blob foo $((1024*1024)))" &&
+               bar="$(generate_random_blob bar $((1024*1024)))" &&
+               baz="$(generate_random_blob baz $((1024*1024)))" &&
+
+               test-tool chmtime -10000 "$objdir/$(test_oid_to_path "$foo")" &&
+
+               git repack -d --cruft --max-cruft-size=1M &&
+
+               # backdate the mtimes of all cruft packs to validate
+               # that they were rewritten as a result of pruning
+               ls $packdir/pack-*.mtimes | sort >cruft.before &&
+               for cruft in $(cat cruft.before)
+               do
+                       mtime="$(test-tool chmtime --get -10000 "$cruft")" &&
+                       echo $cruft $mtime >>mtimes || return 1
+               done &&
+
+               # repack (and prune) with a --max-cruft-size to ensure
+               # that we appropriately split the resulting set of packs
+               git repack -d --cruft --max-cruft-size=1M \
+                       --cruft-expiration=10.seconds.ago &&
+               ls $packdir/pack-*.mtimes | sort >cruft.after &&
+
+               for cruft in $(cat cruft.after)
+               do
+                       old_mtime="$(grep $cruft mtimes | cut -d" " -f2)" &&
+                       new_mtime="$(test-tool chmtime --get $cruft)" &&
+                       test $old_mtime -lt $new_mtime || return 1
+               done &&
+
+               test_line_count = 3 cruft.before &&
+               test_line_count = 2 cruft.after &&
+               test_must_fail git cat-file -e $foo &&
+               git cat-file -e $bar &&
+               git cat-file -e $baz
+       )
+'
+
+test_expect_success '--max-cruft-size ignores non-local packs' '
+       repo="max-cruft-size-non-local" &&
+       git init $repo &&
+       (
+               cd $repo &&
+               test_commit base &&
+               generate_random_blob foo 64 &&
+               git repack --cruft -d
+       ) &&
+
+       git clone --reference=$repo $repo $repo-alt &&
+       (
+               cd $repo-alt &&
+
+               test_commit other &&
+               generate_random_blob bar 64 &&
+
+               # ensure that we do not attempt to pick up packs from
+               # the non-alternated repository, which would result in a
+               # crash
+               git repack --cruft --max-cruft-size=1M -d
+       )
+'
+
+test_expect_success 'reachable packs are preferred over cruft ones' '
+       repo="cruft-preferred-packs" &&
+       git init "$repo" &&
+       (
+               cd "$repo" &&
+
+               # This test needs to exercise careful control over when a MIDX
+               # is and is not written. Unset the corresponding TEST variable
+               # accordingly.
+               sane_unset GIT_TEST_MULTI_PACK_INDEX &&
+
+               test_commit base &&
+               test_commit --no-tag cruft &&
+
+               non_cruft="$(echo base | git pack-objects --revs $packdir/pack)" &&
+               # Write a cruft pack which both (a) sorts ahead of the non-cruft
+               # pack in lexical order, and (b) has an older mtime to appease
+               # the MIDX preferred pack selection routine.
+               cruft="$(echo pack-$non_cruft.pack | git pack-objects --cruft $packdir/pack-A)" &&
+               test-tool chmtime -1000 $packdir/pack-A-$cruft.pack &&
+
+               test_commit other &&
+               git repack -d &&
+
+               git repack --geometric 2 -d --write-midx --write-bitmap-index &&
+
+               # After repacking, there are two packs left: one reachable one
+               # (which is the result of combining both of the existing two
+               # non-cruft packs), and one cruft pack.
+               find .git/objects/pack -type f -name "*.pack" >packs &&
+               test_line_count = 2 packs &&
+
+               # Make sure that the pack we just wrote is marked as preferred,
+               # not the cruft one.
+               pack="$(test-tool read-midx --preferred-pack $objdir)" &&
+               test_path_is_missing "$packdir/$(basename "$pack" ".idx").mtimes"
+       )
+'
+
+test_done
index 39d6d713ecbe05e9638f8f6ee3f79ff49628b2cf..1caaf12430929a2c01e09dad4270947e480ec614 100755 (executable)
@@ -808,6 +808,19 @@ test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
        test_cmp expected actual
 '
 
+test_expect_success 'grep -f, use cwd relative file' '
+       test_when_finished "git rm -f sub/dir/file" &&
+       mkdir -p sub/dir &&
+       echo hit >sub/dir/file &&
+       git add sub/dir/file &&
+       echo hit >sub/dir/pattern &&
+       echo miss >pattern &&
+       (
+               cd sub/dir && git grep -f pattern file
+       ) &&
+       git -C sub/dir grep -f pattern file
+'
+
 cat >expected <<EOF
 y:y yy
 --
@@ -1234,6 +1247,33 @@ test_expect_success 'outside of git repository with fallbackToNoIndex' '
        )
 '
 
+test_expect_success 'no repository with path outside $cwd' '
+       test_when_finished rm -fr non &&
+       rm -fr non &&
+       mkdir -p non/git/sub non/tig &&
+       (
+               GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+               export GIT_CEILING_DIRECTORIES &&
+               cd non/git &&
+               test_expect_code 128 git grep --no-index search .. 2>error &&
+               grep "is outside the directory tree" error
+       ) &&
+       (
+               GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+               export GIT_CEILING_DIRECTORIES &&
+               cd non/git &&
+               test_expect_code 128 git grep --no-index search ../tig 2>error &&
+               grep "is outside the directory tree" error
+       ) &&
+       (
+               GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+               export GIT_CEILING_DIRECTORIES &&
+               cd non/git &&
+               test_expect_code 128 git grep --no-index search ../non 2>error &&
+               grep "no such path in the working tree" error
+       )
+'
+
 test_expect_success 'inside git repository but with --no-index' '
        rm -fr is &&
        mkdir -p is/git/sub &&
index 8143817b19e7962460387b58b7c807e0c995090e..d37c83b4640c31b9f5b4d04251ecafbf08636aa7 100755 (executable)
@@ -594,4 +594,44 @@ test_expect_success 'grep partially-cloned submodule' '
        )
 '
 
+test_expect_success 'check scope of core.useReplaceRefs' '
+       git init base &&
+       git init base/sub &&
+
+       echo A >base/a &&
+       echo B >base/b &&
+       echo C >base/sub/c &&
+       echo D >base/sub/d &&
+
+       git -C base/sub add c d &&
+       git -C base/sub commit -m "Add files" &&
+
+       git -C base submodule add ./sub &&
+       git -C base add a b sub &&
+       git -C base commit -m "Add files and submodule" &&
+
+       A=$(git -C base rev-parse HEAD:a) &&
+       B=$(git -C base rev-parse HEAD:b) &&
+       C=$(git -C base/sub rev-parse HEAD:c) &&
+       D=$(git -C base/sub rev-parse HEAD:d) &&
+
+       git -C base replace $A $B &&
+       git -C base/sub replace $C $D &&
+
+       test_must_fail git -C base grep --cached --recurse-submodules A &&
+       test_must_fail git -C base grep --cached --recurse-submodules C &&
+
+       git -C base config core.useReplaceRefs false &&
+       git -C base grep --recurse-submodules A &&
+       test_must_fail git -C base grep --cached --recurse-submodules C &&
+
+       git -C base/sub config core.useReplaceRefs false &&
+       git -C base grep --cached --recurse-submodules A &&
+       git -C base grep --cached --recurse-submodules C &&
+
+       git -C base config --unset core.useReplaceRefs &&
+       test_must_fail git -C base grep --cached --recurse-submodules A &&
+       git -C base grep --cached --recurse-submodules C
+'
+
 test_done
index 487e326b3fac126fb611e50851465d7d8b963888..e56f5980dc488ef969dad56560003916daf84829 100755 (executable)
@@ -744,7 +744,15 @@ test_expect_success 'start and stop Linux/systemd maintenance' '
        # start registers the repo
        git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
 
-       test_systemd_analyze_verify "systemd/user/git-maintenance@.service" &&
+       for schedule in hourly daily weekly
+       do
+               test_path_is_file "systemd/user/git-maintenance@$schedule.timer" || return 1
+       done &&
+       test_path_is_file "systemd/user/git-maintenance@.service" &&
+
+       test_systemd_analyze_verify "systemd/user/git-maintenance@hourly.service" &&
+       test_systemd_analyze_verify "systemd/user/git-maintenance@daily.service" &&
+       test_systemd_analyze_verify "systemd/user/git-maintenance@weekly.service" &&
 
        printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
        test_cmp expect args &&
@@ -755,7 +763,10 @@ test_expect_success 'start and stop Linux/systemd maintenance' '
        # stop does not unregister the repo
        git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
 
-       test_path_is_missing "systemd/user/git-maintenance@.timer" &&
+       for schedule in hourly daily weekly
+       do
+               test_path_is_missing "systemd/user/git-maintenance@$schedule.timer" || return 1
+       done &&
        test_path_is_missing "systemd/user/git-maintenance@.service" &&
 
        printf -- "--user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
@@ -838,4 +849,17 @@ test_expect_success 'register and unregister bare repo' '
        )
 '
 
+test_expect_success 'failed schedule prevents config change' '
+       git init --bare failcase &&
+
+       for scheduler in crontab launchctl schtasks systemctl
+       do
+               GIT_TEST_MAINT_SCHEDULER="$scheduler:false" &&
+               export GIT_TEST_MAINT_SCHEDULER &&
+               test_must_fail \
+                       git -C failcase maintenance start &&
+               test_must_fail git -C failcase config maintenance.auto || return 1
+       done
+'
+
 test_done
index bdac4c24a15248f402b049350a9cdb32ebaf98c2..dc7785eadb9814894183171d1452f35d2cf2250f 100755 (executable)
@@ -4,7 +4,7 @@ test_description='git send-email'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
-# no longer TEST_PASSES_SANITIZE_LEAK=true - format-patch --thread leaks
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 # May be altered later in the test
@@ -61,8 +61,8 @@ test_no_confirm () {
                --smtp-server="$(pwd)/fake.sendmail" \
                $@ \
                $patches >stdout &&
-               ! grep "Send this email" stdout &&
-               >no_confirm_okay
+       ! grep "Send this email" stdout &&
+       >no_confirm_okay
 }
 
 # Exit immediately to prevent hang if a no-confirm test fails
@@ -337,13 +337,14 @@ test_expect_success $PREREQ 'Show all headers' '
 test_expect_success $PREREQ 'Prompting works' '
        clean_fake_sendmail &&
        (echo "to@example.com" &&
-        echo ""
+        echo "my-message-id@example.com"
        ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches \
                2>errors &&
                grep "^From: A U Thor <author@example.com>\$" msgtxt1 &&
-               grep "^To: to@example.com\$" msgtxt1
+               grep "^To: to@example.com\$" msgtxt1 &&
+               grep "^In-Reply-To: <my-message-id@example.com>" msgtxt1
 '
 
 test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' '
@@ -678,7 +679,6 @@ test_expect_success $PREREQ 'clear message-id before parsing a new message' '
        clean_fake_sendmail &&
        echo true | write_script my-hooks/sendemail-validate &&
        test_config core.hooksPath my-hooks &&
-       GIT_SEND_EMAIL_NOTTY=1 \
        git send-email --validate --to=recipient@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches $threaded_patches &&
@@ -2524,4 +2524,45 @@ test_expect_success $PREREQ 'test forbidSendmailVariables behavior override' '
                HEAD^
 '
 
+test_expect_success $PREREQ '--compose handles lowercase headers' '
+       write_script fake-editor <<-\EOF &&
+       sed "s/^From:.*/from: edited-from@example.com/i" "$1" >"$1.tmp" &&
+       mv "$1.tmp" "$1"
+       EOF
+       clean_fake_sendmail &&
+       git send-email \
+               --compose \
+               --from="Example <from@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               HEAD^ &&
+       grep "From: edited-from@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose handles to headers' '
+       write_script fake-editor <<-\EOF &&
+       sed "s/^To: .*/&, edited-to@example.com/" <"$1" >"$1.tmp" &&
+       echo this is the body >>"$1.tmp" &&
+       mv "$1.tmp" "$1"
+       EOF
+       clean_fake_sendmail &&
+       GIT_SEND_EMAIL_NOTTY=1 \
+       git send-email \
+               --compose \
+               --from="Example <from@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               HEAD^ &&
+       # Check both that the cover letter used our modified "to" line,
+       # but also that it was picked up for the patch.
+       q_to_tab >expect <<-\EOF &&
+       To: nobody@example.com,
+       Qedited-to@example.com
+       EOF
+       grep -A1 "^To:" msgtxt1 >msgtxt1.to &&
+       test_cmp expect msgtxt1.to &&
+       grep -A1 "^To:" msgtxt2 >msgtxt2.to &&
+       test_cmp expect msgtxt2.to
+'
+
 test_done
index 7e8894a4a70648fd12d3ab4425f1beac2c3e4641..590aab0304c679b6559df0e840ddce6dacc684af 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 
 test_description='check that example code compiles and runs'
+
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'decorate' '
index fea41b3c3606df1fc6d8111cdd74522532ca8b0b..af28b01fefa49c647b3ab87a395dd8c2dfb70a5a 100755 (executable)
@@ -21,7 +21,7 @@ test_expect_success 'git svn help works anywhere' '
 '
 
 test_expect_success \
-    'initialize git svn' '
+       'initialize git svn' '
        mkdir import &&
        (
                cd import &&
@@ -38,9 +38,9 @@ test_expect_success \
        rm -rf import &&
        git svn init "$svnrepo"'
 
-test_expect_success \
-    'import an SVN revision into git' \
-    'git svn fetch'
+test_expect_success 'import an SVN revision into git' '
+       git svn fetch
+'
 
 test_expect_success "checkout from svn" 'svn co "$svnrepo" "$SVN_TREE"'
 
@@ -233,27 +233,26 @@ test_expect_success POSIXPERM,SYMLINKS "$name" '
 '
 
 test_expect_success 'exit if remote refs are ambigious' '
-        git config --add svn-remote.svn.fetch \
+       git config --add svn-remote.svn.fetch \
                bar:refs/remotes/git-svn &&
        test_must_fail git svn migrate
 '
 
 test_expect_success 'exit if init-ing a would clobber a URL' '
-        svnadmin create "${PWD}/svnrepo2" &&
-        svn mkdir -m "mkdir bar" "${svnrepo}2/bar" &&
-        git config --unset svn-remote.svn.fetch \
+       svnadmin create "${PWD}/svnrepo2" &&
+       svn mkdir -m "mkdir bar" "${svnrepo}2/bar" &&
+       git config --unset svn-remote.svn.fetch \
                "^bar:refs/remotes/git-svn$" &&
        test_must_fail git svn init "${svnrepo}2/bar"
         '
 
-test_expect_success \
-  'init allows us to connect to another directory in the same repo' '
-        git svn init --minimize-url -i bar "$svnrepo/bar" &&
-        git config --get svn-remote.svn.fetch \
-                              "^bar:refs/remotes/bar$" &&
-        git config --get svn-remote.svn.fetch \
-                             "^:refs/remotes/git-svn$"
-        '
+test_expect_success 'init allows us to connect to another directory in the same repo' '
+       git svn init --minimize-url -i bar "$svnrepo/bar" &&
+       git config --get svn-remote.svn.fetch \
+               "^bar:refs/remotes/bar$" &&
+       git config --get svn-remote.svn.fetch \
+               "^:refs/remotes/git-svn$"
+'
 
 test_expect_success 'dcommit $rev does not clobber current branch' '
        git svn fetch -i bar &&
index 85d735861fc9f500561e9f5fb4baa131657752c0..b5845e28feef8219ac5405e9e0400a40694eec30 100755 (executable)
@@ -41,51 +41,51 @@ test_expect_success 'init and fetch a moved directory' '
        '
 
 test_expect_success 'init and fetch from one svn-remote' '
-        git config svn-remote.svn.url "$svnrepo" &&
-        git config --add svn-remote.svn.fetch \
-          trunk:refs/remotes/svn/trunk &&
-        git config --add svn-remote.svn.fetch \
-          thunk:refs/remotes/svn/thunk &&
-        git svn fetch -i svn/thunk &&
+       git config svn-remote.svn.url "$svnrepo" &&
+       git config --add svn-remote.svn.fetch \
+               trunk:refs/remotes/svn/trunk &&
+       git config --add svn-remote.svn.fetch \
+               thunk:refs/remotes/svn/thunk &&
+       git svn fetch -i svn/thunk &&
        test "$(git rev-parse --verify refs/remotes/svn/trunk)" \
-          = "$(git rev-parse --verify refs/remotes/svn/thunk~1)" &&
+               = "$(git rev-parse --verify refs/remotes/svn/thunk~1)" &&
        git cat-file blob refs/remotes/svn/thunk:readme >actual &&
        test "$(sed -n -e "3p" actual)" = goodbye
-        '
+'
 
 test_expect_success 'follow deleted parent' '
-        (svn_cmd cp -m "resurrecting trunk as junk" \
-               "$svnrepo"/trunk@2 "$svnrepo"/junk ||
-         svn cp -m "resurrecting trunk as junk" \
-               -r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
-        git config --add svn-remote.svn.fetch \
-          junk:refs/remotes/svn/junk &&
-        git svn fetch -i svn/thunk &&
-        git svn fetch -i svn/junk &&
+       (svn_cmd cp -m "resurrecting trunk as junk" \
+               "$svnrepo"/trunk@2 "$svnrepo"/junk ||
+        svn cp -m "resurrecting trunk as junk" \
+               -r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
+       git config --add svn-remote.svn.fetch \
+               junk:refs/remotes/svn/junk &&
+       git svn fetch -i svn/thunk &&
+       git svn fetch -i svn/junk &&
        test -z "$(git diff svn/junk svn/trunk)" &&
        test "$(git merge-base svn/junk svn/trunk)" \
-          = "$(git rev-parse svn/trunk)"
-        '
+               = "$(git rev-parse svn/trunk)"
+'
 
 test_expect_success 'follow larger parent' '
-        mkdir -p import/trunk/thunk/bump/thud &&
-        echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m "import a larger parent" import "$svnrepo"/larger-parent &&
-        svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger &&
-        git svn init --minimize-url -i larger \
-         "$svnrepo"/larger-parent/trunk/thunk/bump/thud &&
-        git svn fetch -i larger &&
+       mkdir -p import/trunk/thunk/bump/thud &&
+       echo hi > import/trunk/thunk/bump/thud/file &&
+       svn import -m "import a larger parent" import "$svnrepo"/larger-parent &&
+       svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger &&
+       git svn init --minimize-url -i larger \
+               "$svnrepo"/larger-parent/trunk/thunk/bump/thud &&
+       git svn fetch -i larger &&
        git svn init --minimize-url -i larger-parent \
-         "$svnrepo"/another-larger/trunk/thunk/bump/thud &&
+               "$svnrepo"/another-larger/trunk/thunk/bump/thud &&
        git svn fetch -i larger-parent &&
-        git rev-parse --verify refs/remotes/larger &&
-        git rev-parse --verify \
-          refs/remotes/larger-parent &&
+       git rev-parse --verify refs/remotes/larger &&
+       git rev-parse --verify \
+               refs/remotes/larger-parent &&
        test "$(git merge-base \
                 refs/remotes/larger-parent \
                 refs/remotes/larger)" = \
-            "$(git rev-parse refs/remotes/larger)"
-        '
+               "$(git rev-parse refs/remotes/larger)"
+'
 
 test_expect_success 'follow higher-level parent' '
        svn mkdir -m "follow higher-level parent" "$svnrepo"/blob &&
index c5946cb0b8a94cfc8c4e2a30284c3343acb8e876..a44eabf0d80fa8db991d77af4da49f58750cf43a 100755 (executable)
@@ -50,56 +50,56 @@ check_entries () {
        fi
 }
 
-test_expect_success \
-    'New file' \
-    'mkdir A B C D E F &&
-     echo hello1 >A/newfile1.txt &&
-     echo hello2 >B/newfile2.txt &&
-     cp "$TEST_DIRECTORY"/test-binary-1.png C/newfile3.png &&
-     cp "$TEST_DIRECTORY"/test-binary-1.png D/newfile4.png &&
-     git add A/newfile1.txt &&
-     git add B/newfile2.txt &&
-     git add C/newfile3.png &&
-     git add D/newfile4.png &&
-     git commit -a -m "Test: New file" &&
-     id=$(git rev-list --max-count=1 HEAD) &&
-     (cd "$CVSWORK" &&
-     git cvsexportcommit -c $id &&
-     check_entries A "newfile1.txt/1.1/" &&
-     check_entries B "newfile2.txt/1.1/" &&
-     check_entries C "newfile3.png/1.1/-kb" &&
-     check_entries D "newfile4.png/1.1/-kb" &&
-     test_cmp A/newfile1.txt ../A/newfile1.txt &&
-     test_cmp B/newfile2.txt ../B/newfile2.txt &&
-     test_cmp C/newfile3.png ../C/newfile3.png &&
-     test_cmp D/newfile4.png ../D/newfile4.png
-     )'
+test_expect_success 'New file' '
+       mkdir A B C D E F &&
+       echo hello1 >A/newfile1.txt &&
+       echo hello2 >B/newfile2.txt &&
+       cp "$TEST_DIRECTORY"/test-binary-1.png C/newfile3.png &&
+       cp "$TEST_DIRECTORY"/test-binary-1.png D/newfile4.png &&
+       git add A/newfile1.txt &&
+       git add B/newfile2.txt &&
+       git add C/newfile3.png &&
+       git add D/newfile4.png &&
+       git commit -a -m "Test: New file" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c $id &&
+       check_entries A "newfile1.txt/1.1/" &&
+       check_entries B "newfile2.txt/1.1/" &&
+       check_entries C "newfile3.png/1.1/-kb" &&
+       check_entries D "newfile4.png/1.1/-kb" &&
+       test_cmp A/newfile1.txt ../A/newfile1.txt &&
+       test_cmp B/newfile2.txt ../B/newfile2.txt &&
+       test_cmp C/newfile3.png ../C/newfile3.png &&
+       test_cmp D/newfile4.png ../D/newfile4.png
+       )
+'
 
-test_expect_success \
-    'Remove two files, add two and update two' \
-    'echo Hello1 >>A/newfile1.txt &&
-     rm -f B/newfile2.txt &&
-     rm -f C/newfile3.png &&
-     echo Hello5  >E/newfile5.txt &&
-     cp "$TEST_DIRECTORY"/test-binary-2.png D/newfile4.png &&
-     cp "$TEST_DIRECTORY"/test-binary-1.png F/newfile6.png &&
-     git add E/newfile5.txt &&
-     git add F/newfile6.png &&
-     git commit -a -m "Test: Remove, add and update" &&
-     id=$(git rev-list --max-count=1 HEAD) &&
-     (cd "$CVSWORK" &&
-     git cvsexportcommit -c $id &&
-     check_entries A "newfile1.txt/1.2/" &&
-     check_entries B "" &&
-     check_entries C "" &&
-     check_entries D "newfile4.png/1.2/-kb" &&
-     check_entries E "newfile5.txt/1.1/" &&
-     check_entries F "newfile6.png/1.1/-kb" &&
-     test_cmp A/newfile1.txt ../A/newfile1.txt &&
-     test_cmp D/newfile4.png ../D/newfile4.png &&
-     test_cmp E/newfile5.txt ../E/newfile5.txt &&
-     test_cmp F/newfile6.png ../F/newfile6.png
-     )'
+test_expect_success 'Remove two files, add two and update two' '
+       echo Hello1 >>A/newfile1.txt &&
+       rm -f B/newfile2.txt &&
+       rm -f C/newfile3.png &&
+       echo Hello5  >E/newfile5.txt &&
+       cp "$TEST_DIRECTORY"/test-binary-2.png D/newfile4.png &&
+       cp "$TEST_DIRECTORY"/test-binary-1.png F/newfile6.png &&
+       git add E/newfile5.txt &&
+       git add F/newfile6.png &&
+       git commit -a -m "Test: Remove, add and update" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c $id &&
+       check_entries A "newfile1.txt/1.2/" &&
+       check_entries B "" &&
+       check_entries C "" &&
+       check_entries D "newfile4.png/1.2/-kb" &&
+       check_entries E "newfile5.txt/1.1/" &&
+       check_entries F "newfile6.png/1.1/-kb" &&
+       test_cmp A/newfile1.txt ../A/newfile1.txt &&
+       test_cmp D/newfile4.png ../D/newfile4.png &&
+       test_cmp E/newfile5.txt ../E/newfile5.txt &&
+       test_cmp F/newfile6.png ../F/newfile6.png
+       )
+'
 
 # Should fail (but only on the git cvsexportcommit stage)
 test_expect_success \
@@ -129,67 +129,67 @@ test_expect_success \
 
 # This test is here because a patch for only binary files will
 # fail with gnu patch, so cvsexportcommit must handle that.
-test_expect_success \
-    'Remove only binary files' \
-    'git reset --hard HEAD^^ &&
-     rm -f D/newfile4.png &&
-     git commit -a -m "test: remove only a binary file" &&
-     id=$(git rev-list --max-count=1 HEAD) &&
-     (cd "$CVSWORK" &&
-     git cvsexportcommit -c $id &&
-     check_entries A "newfile1.txt/1.2/" &&
-     check_entries B "" &&
-     check_entries C "" &&
-     check_entries D "" &&
-     check_entries E "newfile5.txt/1.1/" &&
-     check_entries F "newfile6.png/1.1/-kb" &&
-     test_cmp A/newfile1.txt ../A/newfile1.txt &&
-     test_cmp E/newfile5.txt ../E/newfile5.txt &&
-     test_cmp F/newfile6.png ../F/newfile6.png
-     )'
+test_expect_success 'Remove only binary files' '
+       git reset --hard HEAD^^ &&
+       rm -f D/newfile4.png &&
+       git commit -a -m "test: remove only a binary file" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c $id &&
+       check_entries A "newfile1.txt/1.2/" &&
+       check_entries B "" &&
+       check_entries C "" &&
+       check_entries D "" &&
+       check_entries E "newfile5.txt/1.1/" &&
+       check_entries F "newfile6.png/1.1/-kb" &&
+       test_cmp A/newfile1.txt ../A/newfile1.txt &&
+       test_cmp E/newfile5.txt ../E/newfile5.txt &&
+       test_cmp F/newfile6.png ../F/newfile6.png
+       )
+'
 
-test_expect_success \
-    'Remove only a text file' \
-    'rm -f A/newfile1.txt &&
-     git commit -a -m "test: remove only a binary file" &&
-     id=$(git rev-list --max-count=1 HEAD) &&
-     (cd "$CVSWORK" &&
-     git cvsexportcommit -c $id &&
-     check_entries A "" &&
-     check_entries B "" &&
-     check_entries C "" &&
-     check_entries D "" &&
-     check_entries E "newfile5.txt/1.1/" &&
-     check_entries F "newfile6.png/1.1/-kb" &&
-     test_cmp E/newfile5.txt ../E/newfile5.txt &&
-     test_cmp F/newfile6.png ../F/newfile6.png
-     )'
+test_expect_success 'Remove only a text file' '
+       rm -f A/newfile1.txt &&
+       git commit -a -m "test: remove only a binary file" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c $id &&
+       check_entries A "" &&
+       check_entries B "" &&
+       check_entries C "" &&
+       check_entries D "" &&
+       check_entries E "newfile5.txt/1.1/" &&
+       check_entries F "newfile6.png/1.1/-kb" &&
+       test_cmp E/newfile5.txt ../E/newfile5.txt &&
+       test_cmp F/newfile6.png ../F/newfile6.png
+       )
+'
 
-test_expect_success \
-     'New file with spaces in file name' \
-     'mkdir "G g" &&
-      echo ok then >"G g/with spaces.txt" &&
-      git add "G g/with spaces.txt" && \
-      cp "$TEST_DIRECTORY"/test-binary-1.png "G g/with spaces.png" && \
-      git add "G g/with spaces.png" &&
-      git commit -a -m "With spaces" &&
-      id=$(git rev-list --max-count=1 HEAD) &&
-      (cd "$CVSWORK" &&
-      git cvsexportcommit -c $id &&
-      check_entries "G g" "with spaces.png/1.1/-kb|with spaces.txt/1.1/"
-      )'
+test_expect_success 'New file with spaces in file name' '
+       mkdir "G g" &&
+       echo ok then >"G g/with spaces.txt" &&
+       git add "G g/with spaces.txt" && \
+       cp "$TEST_DIRECTORY"/test-binary-1.png "G g/with spaces.png" && \
+       git add "G g/with spaces.png" &&
+       git commit -a -m "With spaces" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c $id &&
+       check_entries "G g" "with spaces.png/1.1/-kb|with spaces.txt/1.1/"
+       )
+'
 
-test_expect_success \
-     'Update file with spaces in file name' \
-     'echo Ok then >>"G g/with spaces.txt" &&
-      cat "$TEST_DIRECTORY"/test-binary-1.png >>"G g/with spaces.png" && \
-      git add "G g/with spaces.png" &&
-      git commit -a -m "Update with spaces" &&
-      id=$(git rev-list --max-count=1 HEAD) &&
-      (cd "$CVSWORK" &&
-      git cvsexportcommit -c $id &&
-      check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/"
-      )'
+test_expect_success 'Update file with spaces in file name' '
+       echo Ok then >>"G g/with spaces.txt" &&
+       cat "$TEST_DIRECTORY"/test-binary-1.png >>"G g/with spaces.png" && \
+       git add "G g/with spaces.png" &&
+       git commit -a -m "Update with spaces" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c $id &&
+       check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/"
+       )
+'
 
 # Some filesystems mangle pathnames with UTF-8 characters --
 # check and skip
@@ -202,68 +202,68 @@ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" &&
 then
 
 # This test contains UTF-8 characters
-test_expect_success !MINGW \
-     'File with non-ascii file name' \
-     'mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö &&
-      echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
-      git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
-      cp "$TEST_DIRECTORY"/test-binary-1.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
-      git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
-      git commit -a -m "Går det så går det" && \
-      id=$(git rev-list --max-count=1 HEAD) &&
-      (cd "$CVSWORK" &&
-      git cvsexportcommit -v -c $id &&
-      check_entries \
-      "Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" \
-      "gårdetsågårdet.png/1.1/-kb|gårdetsågårdet.txt/1.1/"
-      )'
+test_expect_success !MINGW 'File with non-ascii file name' '
+       mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö &&
+       echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
+       git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
+       cp "$TEST_DIRECTORY"/test-binary-1.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
+       git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png &&
+       git commit -a -m "Går det så går det" && \
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -v -c $id &&
+       check_entries \
+       "Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" \
+       "gårdetsågårdet.png/1.1/-kb|gårdetsågårdet.txt/1.1/"
+       )
+'
 
 fi
 
 rm -fr tst
 
-test_expect_success \
-     'Mismatching patch should fail' \
-     'date >>"E/newfile5.txt" &&
-      git add "E/newfile5.txt" &&
-      git commit -a -m "Update one" &&
-      date >>"E/newfile5.txt" &&
-      git add "E/newfile5.txt" &&
-      git commit -a -m "Update two" &&
-      id=$(git rev-list --max-count=1 HEAD) &&
-      (cd "$CVSWORK" &&
-      test_must_fail git cvsexportcommit -c $id
-      )'
-
-test_expect_success FILEMODE \
-     'Retain execute bit' \
-     'mkdir G &&
-      echo executeon >G/on &&
-      chmod +x G/on &&
-      echo executeoff >G/off &&
-      git add G/on &&
-      git add G/off &&
-      git commit -a -m "Execute test" &&
-      (cd "$CVSWORK" &&
-      git cvsexportcommit -c HEAD &&
-      test -x G/on &&
-      ! test -x G/off
-      )'
+test_expect_success 'Mismatching patch should fail' '
+       date >>"E/newfile5.txt" &&
+       git add "E/newfile5.txt" &&
+       git commit -a -m "Update one" &&
+       date >>"E/newfile5.txt" &&
+       git add "E/newfile5.txt" &&
+       git commit -a -m "Update two" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$CVSWORK" &&
+       test_must_fail git cvsexportcommit -c $id
+       )
+'
+
+test_expect_success FILEMODE 'Retain execute bit' '
+       mkdir G &&
+       echo executeon >G/on &&
+       chmod +x G/on &&
+       echo executeoff >G/off &&
+       git add G/on &&
+       git add G/off &&
+       git commit -a -m "Execute test" &&
+       (cd "$CVSWORK" &&
+       git cvsexportcommit -c HEAD &&
+       test -x G/on &&
+       ! test -x G/off
+       )
+'
 
 test_expect_success '-w option should work with relative GIT_DIR' '
-      mkdir W &&
-      echo foobar >W/file1.txt &&
-      echo bazzle >W/file2.txt &&
-      git add W/file1.txt &&
-      git add W/file2.txt &&
-      git commit -m "More updates" &&
-      id=$(git rev-list --max-count=1 HEAD) &&
-      (cd "$GIT_DIR" &&
-      GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id &&
-      check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" &&
-      test_cmp "$CVSWORK/W/file1.txt" ../W/file1.txt &&
-      test_cmp "$CVSWORK/W/file2.txt" ../W/file2.txt
-      )
+       mkdir W &&
+       echo foobar >W/file1.txt &&
+       echo bazzle >W/file2.txt &&
+       git add W/file1.txt &&
+       git add W/file2.txt &&
+       git commit -m "More updates" &&
+       id=$(git rev-list --max-count=1 HEAD) &&
+       (cd "$GIT_DIR" &&
+       GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id &&
+       check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" &&
+       test_cmp "$CVSWORK/W/file1.txt" ../W/file1.txt &&
+       test_cmp "$CVSWORK/W/file2.txt" ../W/file2.txt
+       )
 '
 
 test_expect_success 'check files before directories' '
@@ -290,21 +290,20 @@ test_expect_success 'check files before directories' '
 '
 
 test_expect_success 're-commit a removed filename which remains in CVS attic' '
-
-    (cd "$CVSWORK" &&
-     echo >attic_gremlin &&
-     cvs -Q add attic_gremlin &&
-     cvs -Q ci -m "added attic_gremlin" &&
-     rm attic_gremlin &&
-     cvs -Q rm attic_gremlin &&
-     cvs -Q ci -m "removed attic_gremlin") &&
-
-    echo > attic_gremlin &&
-    git add attic_gremlin &&
-    git commit -m "Added attic_gremlin" &&
+       (cd "$CVSWORK" &&
+       echo >attic_gremlin &&
+       cvs -Q add attic_gremlin &&
+       cvs -Q ci -m "added attic_gremlin" &&
+       rm attic_gremlin &&
+       cvs -Q rm attic_gremlin &&
+       cvs -Q ci -m "removed attic_gremlin") &&
+
+       echo > attic_gremlin &&
+       git add attic_gremlin &&
+       git commit -m "Added attic_gremlin" &&
        git cvsexportcommit -w "$CVSWORK" -c HEAD &&
-    (cd "$CVSWORK" && cvs -Q update -d) &&
-    test -f "$CVSWORK/attic_gremlin"
+       (cd "$CVSWORK" && cvs -Q update -d) &&
+       test -f "$CVSWORK/attic_gremlin"
 '
 
 # the state of the CVS sandbox may be indeterminate for ' space'
index 872ad1c9c2b156bf25797b2651c69e9749cf391e..7869f45ee646dd511b16e404a8b165200f9c8608 100755 (executable)
@@ -180,4 +180,16 @@ test_expect_success 'scalar clone warns when background maintenance fails' '
        grep "could not turn on maintenance" err
 '
 
+test_expect_success '`scalar clone --no-src`' '
+       scalar clone --src "file://$(pwd)/to-clone" with-src &&
+       scalar clone --no-src "file://$(pwd)/to-clone" without-src &&
+
+       test_path_is_dir with-src/src &&
+       test_path_is_missing without-src/src &&
+
+       (cd with-src/src && ls ?*) >with &&
+       (cd without-src && ls ?*) >without &&
+       test_cmp with without
+'
+
 test_done
index 379b19f2f85157c83e8259b3ae7df52c44665820..003c0b61d0ff45864630782a509a018ff4079116 100755 (executable)
@@ -66,10 +66,11 @@ test_expect_success 'setup' '
 
 # note that cvs doesn't accept absolute pathnames
 # as argument to co -d
-test_expect_success 'basic checkout' \
-  'GIT_CONFIG="$git_config" cvs -Q co -d cvswork main &&
-   test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/" &&
-   test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | sed -ne \$p))" = "secondrootfile/1.1/"'
+test_expect_success 'basic checkout' '
+       GIT_CONFIG="$git_config" cvs -Q co -d cvswork main &&
+       test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/" &&
+       test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | sed -ne \$p))" = "secondrootfile/1.1/"
+'
 
 #------------------------
 # PSERVER AUTHENTICATION
@@ -115,35 +116,40 @@ Ah<Z:yZZ30 e
 END VERIFICATION REQUEST
 EOF
 
-test_expect_success 'pserver authentication' \
-  'cat request-anonymous | git-cvsserver pserver >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'pserver authentication' '
+       cat request-anonymous | git-cvsserver pserver >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
-test_expect_success 'pserver authentication failure (non-anonymous user)' \
-  'if cat request-git | git-cvsserver pserver >log 2>&1
-   then
-       false
-   else
-       true
-   fi &&
-   sed -ne \$p log | grep "^I HATE YOU\$"'
+test_expect_success 'pserver authentication failure (non-anonymous user)' '
+       if cat request-git | git-cvsserver pserver >log 2>&1
+       then
+           false
+       else
+           true
+       fi &&
+       sed -ne \$p log | grep "^I HATE YOU\$"
+'
 
-test_expect_success 'pserver authentication success (non-anonymous user with password)' \
-  'cat login-git-ok | git-cvsserver pserver >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'pserver authentication success (non-anonymous user with password)' '
+       cat login-git-ok | git-cvsserver pserver >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
-test_expect_success 'pserver authentication (login)' \
-  'cat login-anonymous | git-cvsserver pserver >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'pserver authentication (login)' '
+       cat login-anonymous | git-cvsserver pserver >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
-test_expect_success 'pserver authentication failure (login/non-anonymous user)' \
-  'if cat login-git | git-cvsserver pserver >log 2>&1
-   then
-       false
-   else
-       true
-   fi &&
-   sed -ne \$p log | grep "^I HATE YOU\$"'
+test_expect_success 'pserver authentication failure (login/non-anonymous user)' '
+       if cat login-git | git-cvsserver pserver >log 2>&1
+       then
+           false
+       else
+           true
+       fi &&
+       sed -ne \$p log | grep "^I HATE YOU\$"
+'
 
 
 # misuse pserver authentication for testing of req_Root
@@ -165,36 +171,40 @@ END AUTH REQUEST
 Root $WORKDIR
 EOF
 
-test_expect_success 'req_Root failure (relative pathname)' \
-  'if cat request-relative | git-cvsserver pserver >log 2>&1
-   then
-       echo unexpected success
-       false
-   else
-       true
-   fi &&
-   tail log | grep "^error 1 Root must be an absolute pathname$"'
+test_expect_success 'req_Root failure (relative pathname)' '
+       if cat request-relative | git-cvsserver pserver >log 2>&1
+       then
+               echo unexpected success
+               false
+       else
+               true
+       fi &&
+       tail log | grep "^error 1 Root must be an absolute pathname$"
+'
 
-test_expect_success 'req_Root failure (conflicting roots)' \
-  'cat request-conflict | git-cvsserver pserver >log 2>&1 &&
-   tail log | grep "^error 1 Conflicting roots specified$"'
+test_expect_success 'req_Root failure (conflicting roots)' '
+       cat request-conflict | git-cvsserver pserver >log 2>&1 &&
+       tail log | grep "^error 1 Conflicting roots specified$"
+'
 
-test_expect_success 'req_Root (strict paths)' \
-  'cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'req_Root (strict paths)' '
+       cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
 test_expect_success 'req_Root failure (strict-paths)' '
-    ! cat request-anonymous |
-    git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1
+       ! cat request-anonymous |
+       git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1
 '
 
-test_expect_success 'req_Root (w/o strict-paths)' \
-  'cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'req_Root (w/o strict-paths)' '
+       cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
 test_expect_success 'req_Root failure (w/o strict-paths)' '
-    ! cat request-anonymous |
-    git-cvsserver pserver "$WORKDIR/gitcvs" >log 2>&1
+       ! cat request-anonymous |
+       git-cvsserver pserver "$WORKDIR/gitcvs" >log 2>&1
 '
 
 cat >request-base  <<EOF
@@ -206,27 +216,30 @@ END AUTH REQUEST
 Root /gitcvs.git
 EOF
 
-test_expect_success 'req_Root (base-path)' \
-  'cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'req_Root (base-path)' '
+       cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
 test_expect_success 'req_Root failure (base-path)' '
-    ! cat request-anonymous |
-    git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1
+       ! cat request-anonymous |
+       git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1
 '
 
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1
 
-test_expect_success 'req_Root (export-all)' \
-  'cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'req_Root (export-all)' '
+       cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
-test_expect_success 'req_Root failure (export-all w/o directory list)' \
-  '! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)'
+test_expect_success 'req_Root failure (export-all w/o directory list)' '
+       ! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)'
 
-test_expect_success 'req_Root (everything together)' \
-  'cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 &&
-   sed -ne \$p log | grep "^I LOVE YOU\$"'
+test_expect_success 'req_Root (everything together)' '
+       cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 &&
+       sed -ne \$p log | grep "^I LOVE YOU\$"
+'
 
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true || exit 1
 
@@ -247,45 +260,49 @@ test_expect_success 'gitcvs.enabled = false' \
    test ! -d cvswork2'
 
 rm -fr cvswork2
-test_expect_success 'gitcvs.ext.enabled = true' \
-  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
-   GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false &&
-   GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 &&
-   test_cmp cvswork cvswork2'
+test_expect_success 'gitcvs.ext.enabled = true' '
+       GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
+       GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false &&
+       GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 &&
+       test_cmp cvswork cvswork2
+'
 
 rm -fr cvswork2
-test_expect_success 'gitcvs.ext.enabled = false' \
-  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled false &&
-   GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
-   if GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1
-   then
-     echo unexpected cvs success
-     false
-   else
-     true
-   fi &&
-   grep "GITCVS emulation disabled" cvs.log &&
-   test ! -d cvswork2'
+test_expect_success 'gitcvs.ext.enabled = false' '
+       GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled false &&
+       GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
+       if GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1
+       then
+               echo unexpected cvs success
+               false
+       else
+               true
+       fi &&
+       grep "GITCVS emulation disabled" cvs.log &&
+       test ! -d cvswork2
+'
 
 rm -fr cvswork2
-test_expect_success 'gitcvs.dbname' \
-  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
-   GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite &&
-   GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 &&
-   test_cmp cvswork cvswork2 &&
-   test -f "$SERVERDIR/gitcvs.ext.main.sqlite" &&
-   cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs.ext.main.sqlite"'
+test_expect_success 'gitcvs.dbname' '
+       GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
+       GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite &&
+       GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 &&
+       test_cmp cvswork cvswork2 &&
+       test -f "$SERVERDIR/gitcvs.ext.main.sqlite" &&
+       cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs.ext.main.sqlite"
+'
 
 rm -fr cvswork2
-test_expect_success 'gitcvs.ext.dbname' \
-  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
-   GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
-   GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
-   GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 &&
-   test_cmp cvswork cvswork2 &&
-   test -f "$SERVERDIR/gitcvs1.ext.main.sqlite" &&
-   test ! -f "$SERVERDIR/gitcvs2.ext.main.sqlite" &&
-   cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs1.ext.main.sqlite"'
+test_expect_success 'gitcvs.ext.dbname' '
+       GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
+       GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
+       GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
+       GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 &&
+       test_cmp cvswork cvswork2 &&
+       test -f "$SERVERDIR/gitcvs1.ext.main.sqlite" &&
+       test ! -f "$SERVERDIR/gitcvs2.ext.main.sqlite" &&
+       cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs1.ext.main.sqlite"
+'
 
 
 #------------
@@ -299,109 +316,115 @@ GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
 GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
 exit 1
 
-test_expect_success 'cvs update (create new file)' \
-  'echo testfile1 >testfile1 &&
-   git add testfile1 &&
-   git commit -q -m "Add testfile1" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
-   test_cmp testfile1 ../testfile1'
+test_expect_success 'cvs update (create new file)' '
+       echo testfile1 >testfile1 &&
+       git add testfile1 &&
+       git commit -q -m "Add testfile1" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
+       test_cmp testfile1 ../testfile1
+'
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (update existing file)' \
-  'echo line 2 >>testfile1 &&
-   git add testfile1 &&
-   git commit -q -m "Append to testfile1" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" &&
-   test_cmp testfile1 ../testfile1'
+test_expect_success 'cvs update (update existing file)' '
+       echo line 2 >>testfile1 &&
+       git add testfile1 &&
+       git commit -q -m "Append to testfile1" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" &&
+       test_cmp testfile1 ../testfile1
+'
 
 cd "$WORKDIR"
 #TODO: cvsserver doesn't support update w/o -d
 test_expect_failure "cvs update w/o -d doesn't create subdir (TODO)" '
-   mkdir test &&
-   echo >test/empty &&
-   git add test &&
-   git commit -q -m "Single Subdirectory" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test ! -d test
+       mkdir test &&
+       echo >test/empty &&
+       git add test &&
+       git commit -q -m "Single Subdirectory" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test ! -d test
 '
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (subdirectories)' \
-  '(for dir in A A/B A/B/C A/D E; do
-      mkdir $dir &&
-      echo "test file in $dir" >"$dir/file_in_$(echo $dir|sed -e "s#/# #g")"  &&
-      git add $dir || exit 1
-   done) &&
-   git commit -q -m "deep sub directory structure" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update -d &&
-   (for dir in A A/B A/B/C A/D E; do
-      filename="file_in_$(echo $dir|sed -e "s#/# #g")" &&
-      if test "$(echo $(grep -v ^D $dir/CVS/Entries|cut -d/ -f2,3,5))" = "$filename/1.1/" &&
-       test_cmp "$dir/$filename" "../$dir/$filename"; then
-        :
-      else
-       exit 1
-      fi
-    done)'
+test_expect_success 'cvs update (subdirectories)' '
+       (for dir in A A/B A/B/C A/D E; do
+               mkdir $dir &&
+               echo "test file in $dir" >"$dir/file_in_$(echo $dir|sed -e "s#/# #g")"  &&
+               git add $dir || exit 1
+       done) &&
+       git commit -q -m "deep sub directory structure" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update -d &&
+       (for dir in A A/B A/B/C A/D E; do
+               filename="file_in_$(echo $dir|sed -e "s#/# #g")" &&
+               if test "$(echo $(grep -v ^D $dir/CVS/Entries|cut -d/ -f2,3,5))" = "$filename/1.1/" &&
+                       test_cmp "$dir/$filename" "../$dir/$filename"; then
+               :
+               else
+                       exit 1
+               fi
+       done)
+'
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (delete file)' \
-  'git rm testfile1 &&
-   git commit -q -m "Remove testfile1" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test -z "$(grep testfile1 CVS/Entries)" &&
-   test ! -f testfile1'
+test_expect_success 'cvs update (delete file)' '
+       git rm testfile1 &&
+       git commit -q -m "Remove testfile1" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test -z "$(grep testfile1 CVS/Entries)" &&
+       test ! -f testfile1
+'
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (re-add deleted file)' \
-  'echo readded testfile >testfile1 &&
-   git add testfile1 &&
-   git commit -q -m "Re-Add testfile1" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" &&
-   test_cmp testfile1 ../testfile1'
+test_expect_success 'cvs update (re-add deleted file)' '
+       echo readded testfile >testfile1 &&
+       git add testfile1 &&
+       git commit -q -m "Re-Add testfile1" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" &&
+       test_cmp testfile1 ../testfile1
+'
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (merge)' \
-  'echo Line 0 >expected &&
-   for i in 1 2 3 4 5 6 7
-   do
-     echo Line $i >>merge &&
-     echo Line $i >>expected || return 1
-   done &&
-   echo Line 8 >>expected &&
-   git add merge &&
-   git commit -q -m "Merge test (pre-merge)" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" &&
-   test_cmp merge ../merge &&
-   ( echo Line 0 && cat merge ) >merge.tmp &&
-   mv merge.tmp merge &&
-   cd "$WORKDIR" &&
-   echo Line 8 >>merge &&
-   git add merge &&
-   git commit -q -m "Merge test (merge)" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   sleep 1 && touch merge &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test_cmp merge ../expected'
+test_expect_success 'cvs update (merge)' '
+       echo Line 0 >expected &&
+       for i in 1 2 3 4 5 6 7
+       do
+               echo Line $i >>merge &&
+               echo Line $i >>expected || return 1
+       done &&
+       echo Line 8 >>expected &&
+       git add merge &&
+       git commit -q -m "Merge test (pre-merge)" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" &&
+       test_cmp merge ../merge &&
+       ( echo Line 0 && cat merge ) >merge.tmp &&
+       mv merge.tmp merge &&
+       cd "$WORKDIR" &&
+       echo Line 8 >>merge &&
+       git add merge &&
+       git commit -q -m "Merge test (merge)" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       sleep 1 && touch merge &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test_cmp merge ../expected
+'
 
 cd "$WORKDIR"
 
@@ -418,55 +441,58 @@ do
   echo Line $i >>expected.C
 done
 
-test_expect_success 'cvs update (conflict merge)' \
-  '( echo LINE 0 && cat merge ) >merge.tmp &&
-   mv merge.tmp merge &&
-   git add merge &&
-   git commit -q -m "Merge test (conflict)" &&
-   git push gitcvs.git >/dev/null &&
-   cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update &&
-   test_cmp merge ../expected.C'
+test_expect_success 'cvs update (conflict merge)' '
+       ( echo LINE 0 && cat merge ) >merge.tmp &&
+       mv merge.tmp merge &&
+       git add merge &&
+       git commit -q -m "Merge test (conflict)" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test_cmp merge ../expected.C
+'
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (-C)' \
-  'cd cvswork &&
-   GIT_CONFIG="$git_config" cvs -Q update -C &&
-   test_cmp merge ../merge'
+test_expect_success 'cvs update (-C)' '
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs -Q update -C &&
+       test_cmp merge ../merge
+'
 
 cd "$WORKDIR"
-test_expect_success 'cvs update (merge no-op)' \
-   'echo Line 9 >>merge &&
-    cp merge cvswork/merge &&
-    git add merge &&
-    git commit -q -m "Merge test (no-op)" &&
-    git push gitcvs.git >/dev/null &&
-    cd cvswork &&
-    sleep 1 && touch merge &&
-    GIT_CONFIG="$git_config" cvs -Q update &&
-    test_cmp merge ../merge'
+test_expect_success 'cvs update (merge no-op)' '
+       echo Line 9 >>merge &&
+       cp merge cvswork/merge &&
+       git add merge &&
+       git commit -q -m "Merge test (no-op)" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       sleep 1 && touch merge &&
+       GIT_CONFIG="$git_config" cvs -Q update &&
+       test_cmp merge ../merge
+'
 
 cd "$WORKDIR"
 test_expect_success 'cvs update (-p)' '
-    touch really-empty &&
-    echo Line 1 > no-lf &&
-    printf "Line 2" >> no-lf &&
-    git add really-empty no-lf &&
-    git commit -q -m "Update -p test" &&
-    git push gitcvs.git >/dev/null &&
-    cd cvswork &&
-    GIT_CONFIG="$git_config" cvs update &&
-    for i in merge no-lf empty really-empty; do
-       GIT_CONFIG="$git_config" cvs update -p "$i" >$i.out &&
-       test_cmp $i.out ../$i || return 1
-    done
+       touch really-empty &&
+       echo Line 1 > no-lf &&
+       printf "Line 2" >> no-lf &&
+       git add really-empty no-lf &&
+       git commit -q -m "Update -p test" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs update &&
+       for i in merge no-lf empty really-empty; do
+               GIT_CONFIG="$git_config" cvs update -p "$i" >$i.out &&
+               test_cmp $i.out ../$i || return 1
+       done
 '
 
 cd "$WORKDIR"
 test_expect_success 'cvs update (module list supports packed refs)' '
-    GIT_DIR="$SERVERDIR" git pack-refs --all &&
-    GIT_CONFIG="$git_config" cvs -n up -d 2> out &&
-    grep "cvs update: New directory \`main'\''" < out
+       GIT_DIR="$SERVERDIR" git pack-refs --all &&
+       GIT_CONFIG="$git_config" cvs -n up -d 2> out &&
+       grep "cvs update: New directory \`main'\''" < out
 '
 
 #------------
@@ -475,30 +501,30 @@ test_expect_success 'cvs update (module list supports packed refs)' '
 
 cd "$WORKDIR"
 test_expect_success 'cvs status' '
-    mkdir status.dir &&
-    echo Line > status.dir/status.file &&
-    echo Line > status.file &&
-    git add status.dir status.file &&
-    git commit -q -m "Status test" &&
-    git push gitcvs.git >/dev/null &&
-    cd cvswork &&
-    GIT_CONFIG="$git_config" cvs update &&
-    GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out &&
-    test_line_count = 2 ../out
+       mkdir status.dir &&
+       echo Line > status.dir/status.file &&
+       echo Line > status.file &&
+       git add status.dir status.file &&
+       git commit -q -m "Status test" &&
+       git push gitcvs.git >/dev/null &&
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs update &&
+       GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out &&
+       test_line_count = 2 ../out
 '
 
 cd "$WORKDIR"
 test_expect_success 'cvs status (nonrecursive)' '
-    cd cvswork &&
-    GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out &&
-    test_line_count = 1 ../out
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out &&
+       test_line_count = 1 ../out
 '
 
 cd "$WORKDIR"
 test_expect_success 'cvs status (no subdirs in header)' '
-    cd cvswork &&
-    GIT_CONFIG="$git_config" cvs status | grep ^File: >../out &&
-    ! grep / <../out
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs status | grep ^File: >../out &&
+       ! grep / <../out
 '
 
 #------------
@@ -507,9 +533,9 @@ test_expect_success 'cvs status (no subdirs in header)' '
 
 cd "$WORKDIR"
 test_expect_success 'cvs co -c (shows module database)' '
-    GIT_CONFIG="$git_config" cvs co -c > out &&
-    grep "^main[        ][     ]*main$" <out &&
-    ! grep -v "^main[   ][     ]*main$" <out
+       GIT_CONFIG="$git_config" cvs co -c > out &&
+       grep "^main[     ][     ]*main$" <out &&
+       ! grep -v "^main[        ][     ]*main$" <out
 '
 
 #------------
@@ -575,11 +601,11 @@ expectStat="$?"
 
 cd "$WORKDIR"
 test_expect_success 'cvs log' '
-    cd cvswork &&
-    test x"$expectStat" = x"0" &&
-    GIT_CONFIG="$git_config" cvs log merge >../out &&
-    sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual &&
-    test_cmp ../expect ../actual
+       cd cvswork &&
+       test x"$expectStat" = x"0" &&
+       GIT_CONFIG="$git_config" cvs log merge >../out &&
+sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual &&
+       test_cmp ../expect ../actual
 '
 
 #------------
@@ -588,11 +614,11 @@ test_expect_success 'cvs log' '
 
 cd "$WORKDIR"
 test_expect_success 'cvs annotate' '
-    cd cvswork &&
-    GIT_CONFIG="$git_config" cvs annotate merge >../out &&
-    sed -e "s/ .*//" ../out >../actual &&
-    printf "1.%d\n" 3 1 1 1 1 1 1 1 2 4 >../expect &&
-    test_cmp ../expect ../actual
+       cd cvswork &&
+       GIT_CONFIG="$git_config" cvs annotate merge >../out &&
+       sed -e "s/ .*//" ../out >../actual &&
+       printf "1.%d\n" 3 1 1 1 1 1 1 1 2 4 >../expect &&
+       test_cmp ../expect ../actual
 '
 
 #------------
index 8835e16e8110f458885c977d4002685a2fc16662..a7c3b4eb63abfe251dcb9edc4b14b136dcfc91c6 100755 (executable)
@@ -1622,14 +1622,22 @@ test_expect_success 'git checkout - with -d, complete only references' '
 '
 
 test_expect_success 'git switch - with --track, complete only remote branches' '
-       test_completion "git switch --track " <<-\EOF
+       test_completion "git switch --track " <<-\EOF &&
+       other/branch-in-other Z
+       other/main-in-other Z
+       EOF
+       test_completion "git switch -t " <<-\EOF
        other/branch-in-other Z
        other/main-in-other Z
        EOF
 '
 
 test_expect_success 'git checkout - with --track, complete only remote branches' '
-       test_completion "git checkout --track " <<-\EOF
+       test_completion "git checkout --track " <<-\EOF &&
+       other/branch-in-other Z
+       other/main-in-other Z
+       EOF
+       test_completion "git checkout -t " <<-\EOF
        other/branch-in-other Z
        other/main-in-other Z
        EOF
@@ -2456,6 +2464,24 @@ test_expect_success 'completion used <cmd> completion for alias: !f() { : git <c
        EOF
 '
 
+test_expect_success 'completion used <cmd> completion for alias: !f() { : <cmd> ; ... }' '
+       test_config alias.co "!f() { : checkout ; if ... } f" &&
+       test_completion "git co m" <<-\EOF
+       main Z
+       mybranch Z
+       mytag Z
+       EOF
+'
+
+test_expect_success 'completion used <cmd> completion for alias: !f() { : <cmd>; ... }' '
+       test_config alias.co "!f() { : checkout; if ... } f" &&
+       test_completion "git co m" <<-\EOF
+       main Z
+       mybranch Z
+       mytag Z
+       EOF
+'
+
 test_expect_success 'completion without explicit _git_xxx function' '
        test_completion "git version --" <<-\EOF
        --build-options Z
index 6e19ebc922a4166565664995d849bbd248c93ff6..2f8868caa171d2d3ce78f3672e937ab7f8a3db97 100644 (file)
@@ -542,8 +542,17 @@ test_config () {
                config_dir=$1
                shift
        fi
-       test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" &&
-       git ${config_dir:+-C "$config_dir"} config "$@"
+
+       # If --worktree is provided, use it to configure/unconfigure
+       is_worktree=
+       if test "$1" = --worktree
+       then
+               is_worktree=1
+               shift
+       fi
+
+       test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} ${is_worktree:+--worktree} '$1'" &&
+       git ${config_dir:+-C "$config_dir"} config ${is_worktree:+--worktree} "$@"
 }
 
 test_config_global () {
@@ -901,6 +910,15 @@ test_path_is_symlink () {
        fi
 }
 
+test_path_is_executable () {
+       test "$#" -ne 1 && BUG "1 param"
+       if ! test -x "$1"
+       then
+               echo "$1 is not executable"
+               false
+       fi
+}
+
 # Check if the directory exists and is empty as expected, barf otherwise.
 test_dir_is_empty () {
        test "$#" -ne 1 && BUG "1 param"
@@ -1273,6 +1291,39 @@ test_cmp_rev () {
        fi
 }
 
+# Tests that a commit message matches the expected text
+#
+# Usage: test_commit_message <rev> [-m <msg> | <file>]
+#
+# When using "-m" <msg> will have a line feed appended. If the second
+# argument is omitted then the expected message is read from stdin.
+
+test_commit_message () {
+       local msg_file=expect.msg
+
+       case $# in
+       3)
+               if test "$2" = "-m"
+               then
+                       printf "%s\n" "$3" >"$msg_file"
+               else
+                       BUG "Usage: test_commit_message <rev> [-m <message> | <file>]"
+               fi
+               ;;
+       2)
+               msg_file="$2"
+               ;;
+       1)
+               cat >"$msg_file"
+               ;;
+       *)
+               BUG "Usage: test_commit_message <rev> [-m <message> | <file>]"
+               ;;
+       esac
+       git show --no-patch --pretty=format:%B "$1" -- >actual.msg &&
+       test_cmp "$msg_file" actual.msg
+}
+
 # Compare paths respecting core.ignoreCase
 test_cmp_fspath () {
        if test "x$1" = "x$2"
index 293caf0f20e67a366b347064875c60061ecabf89..1656c9eed006bdce115ed6e7673246847319783a 100644 (file)
@@ -89,6 +89,9 @@ prepend_var LSAN_OPTIONS : $GIT_SAN_OPTIONS
 prepend_var LSAN_OPTIONS : fast_unwind_on_malloc=0
 export LSAN_OPTIONS
 
+prepend_var UBSAN_OPTIONS : $GIT_SAN_OPTIONS
+export UBSAN_OPTIONS
+
 if test ! -f "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
 then
        echo >&2 'error: GIT-BUILD-OPTIONS missing (has Git been built?).'
@@ -334,6 +337,7 @@ nr_san_dir_leaks_ () {
        find "$TEST_RESULTS_SAN_DIR" \
                -type f \
                -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null |
+       xargs grep -lv "Unable to get registers from thread" |
        wc -l
 }
 
diff --git a/tag.c b/tag.c
index 96dbd5b2d5501e31b7a7bb75d7630347bfdc24c0..fc3834db467dc4e83ca0a24da61a3f39048f3ec2 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -2,7 +2,7 @@
 #include "environment.h"
 #include "tag.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
 #include "tree.h"
 #include "blob.h"
@@ -10,7 +10,6 @@
 #include "gpg-interface.h"
 #include "hex.h"
 #include "packfile.h"
-#include "wrapper.h"
 
 const char *tag_type = "tag";
 
index 50c377134ce602c3a9f8ed1ec6344bd4da7eb18f..ecdebf1afb0d8465717c18409877fe310f980e46 100644 (file)
  */
 
 #include "git-compat-util.h"
+#include "abspath.h"
 #include "path.h"
 #include "tempfile.h"
 #include "sigchain.h"
-#include "wrapper.h"
 
 static VOLATILE_LIST_HEAD(tempfile_list);
 
index c33a554f921eca089d7535609fe7023614ad1985..5f9074ad1c0b063a0cb906c2dc6182357adcd5ee 100644 (file)
@@ -5,12 +5,13 @@
 #include "dir.h"
 #include "environment.h"
 #include "object-file.h"
+#include "path.h"
 #include "sigchain.h"
 #include "string-list.h"
 #include "strbuf.h"
 #include "strvec.h"
 #include "quote.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 
 struct tmp_objdir {
        struct strbuf path;
diff --git a/trace.c b/trace.c
index 592c141d785a913d45a6910f048b087204ddecdc..971a68abe84bf02656bf9cd5eab584833f3da9f7 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -27,7 +27,6 @@
 #include "quote.h"
 #include "setup.h"
 #include "trace.h"
-#include "wrapper.h"
 
 struct trace_key trace_default_key = { "GIT_TRACE", 0, 0, 0 };
 struct trace_key trace_perf_key = TRACE_KEY_INIT(PERFORMANCE);
index 0efc4e7b958d96bf930d1ca1a1e0f44eb64d1424..6dc74dff4c73205d332a227b0caf2497b71f7538 100644 (file)
--- a/trace2.c
+++ b/trace2.c
@@ -276,7 +276,6 @@ void trace2_cmd_exit_fl(const char *file, int line, int code)
        if (!trace2_enabled)
                return;
 
-       trace_git_fsync_stats();
        trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT);
 
        tr2main_exit_code = code;
@@ -634,7 +633,7 @@ void trace2_thread_exit_fl(const char *file, int line)
 }
 
 void trace2_def_param_fl(const char *file, int line, const char *param,
-                        const char *value)
+                        const char *value, const struct key_value_info *kvi)
 {
        struct tr2_tgt *tgt_j;
        int j;
@@ -644,7 +643,7 @@ void trace2_def_param_fl(const char *file, int line, const char *param,
 
        for_each_wanted_builtin (j, tgt_j)
                if (tgt_j->pfn_param_fl)
-                       tgt_j->pfn_param_fl(file, line, param, value);
+                       tgt_j->pfn_param_fl(file, line, param, value, kvi);
 }
 
 void trace2_def_repo_fl(const char *file, int line, struct repository *repo)
index 4ced30c0db368b640fbaba439ad50049ba9041df..40d8c2e02a5e50ce4f24bc4bd656498773e0853e 100644 (file)
--- a/trace2.h
+++ b/trace2.h
@@ -325,6 +325,7 @@ void trace2_thread_exit_fl(const char *file, int line);
 
 #define trace2_thread_exit() trace2_thread_exit_fl(__FILE__, __LINE__)
 
+struct key_value_info;
 /*
  * Emits a "def_param" message containing a key/value pair.
  *
@@ -334,7 +335,7 @@ void trace2_thread_exit_fl(const char *file, int line);
  * `core.abbrev`, `status.showUntrackedFiles`, or `--no-ahead-behind`.
  */
 void trace2_def_param_fl(const char *file, int line, const char *param,
-                        const char *value);
+                        const char *value, const struct key_value_info *kvi);
 
 #define trace2_def_param(param, value) \
        trace2_def_param_fl(__FILE__, __LINE__, (param), (value))
@@ -540,7 +541,7 @@ void trace2_timer_stop(enum trace2_timer_id tid);
  * elsewhere as array indexes).
  *
  * Any values added to this enum be also be added to the
- * `tr2_counter_metadata[]` in `trace2/tr2_tr2_ctr.c`.
+ * `tr2_counter_metadata[]` in `trace2/tr2_ctr.c`.
  */
 enum trace2_counter_id {
        /*
@@ -551,6 +552,12 @@ enum trace2_counter_id {
        TRACE2_COUNTER_ID_TEST1 = 0, /* emits summary event only */
        TRACE2_COUNTER_ID_TEST2,     /* emits summary and thread events */
 
+       TRACE2_COUNTER_ID_PACKED_REFS_JUMPS, /* counts number of jumps */
+
+       /* counts number of fsyncs */
+       TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY,
+       TRACE2_COUNTER_ID_FSYNC_HARDWARE_FLUSH,
+
        /* Add additional counter definitions before here. */
        TRACE2_NUMBER_OF_COUNTERS
 };
index 78cfc15d52dd5800ea5bd610e5db7b0e73b4f8af..d96d908bb9df6fddb22e4dbecfa07882049bdf78 100644 (file)
@@ -4,6 +4,7 @@
 #include "trace2.h"
 #include "trace2/tr2_cfg.h"
 #include "trace2/tr2_sysenv.h"
+#include "wildmatch.h"
 
 static struct strbuf **tr2_cfg_patterns;
 static int tr2_cfg_count_patterns;
@@ -99,7 +100,8 @@ struct tr2_cfg_data {
 /*
  * See if the given config key matches any of our patterns of interest.
  */
-static int tr2_cfg_cb(const char *key, const char *value, void *d)
+static int tr2_cfg_cb(const char *key, const char *value,
+                     const struct config_context *ctx, void *d)
 {
        struct strbuf **s;
        struct tr2_cfg_data *data = (struct tr2_cfg_data *)d;
@@ -108,7 +110,8 @@ static int tr2_cfg_cb(const char *key, const char *value, void *d)
                struct strbuf *buf = *s;
                int wm = wildmatch(buf->buf, key, WM_CASEFOLD);
                if (wm == WM_MATCH) {
-                       trace2_def_param_fl(data->file, data->line, key, value);
+                       trace2_def_param_fl(data->file, data->line, key, value,
+                                           ctx->kvi);
                        return 0;
                }
        }
@@ -126,8 +129,10 @@ void tr2_cfg_list_config_fl(const char *file, int line)
 
 void tr2_list_env_vars_fl(const char *file, int line)
 {
+       struct key_value_info kvi = KVI_INIT;
        struct strbuf **s;
 
+       kvi_from_param(&kvi);
        if (tr2_load_env_vars() <= 0)
                return;
 
@@ -135,15 +140,19 @@ void tr2_list_env_vars_fl(const char *file, int line)
                struct strbuf *buf = *s;
                const char *val = getenv(buf->buf);
                if (val && *val)
-                       trace2_def_param_fl(file, line, buf->buf, val);
+                       trace2_def_param_fl(file, line, buf->buf, val, &kvi);
        }
 }
 
 void tr2_cfg_set_fl(const char *file, int line, const char *key,
                    const char *value)
 {
+       struct key_value_info kvi = KVI_INIT;
+       struct config_context ctx = {
+               .kvi = &kvi,
+       };
        struct tr2_cfg_data data = { file, line };
 
        if (tr2_cfg_load_patterns() > 0)
-               tr2_cfg_cb(key, value, &data);
+               tr2_cfg_cb(key, value, &ctx, &data);
 }
index b342d3b1a3c033bf539037bb5035ae57af119d6d..87cf9034fba4b91b4d569ea4013e13f9d19b4aa9 100644 (file)
@@ -27,6 +27,21 @@ static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTER
                .name = "test2",
                .want_per_thread_events = 1,
        },
+       [TRACE2_COUNTER_ID_PACKED_REFS_JUMPS] = {
+               .category = "packed-refs",
+               .name = "jumps_made",
+               .want_per_thread_events = 0,
+       },
+       [TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY] = {
+               .category = "fsync",
+               .name = "writeout-only",
+               .want_per_thread_events = 0,
+       },
+       [TRACE2_COUNTER_ID_FSYNC_HARDWARE_FLUSH] = {
+               .category = "fsync",
+               .name = "hardware-flush",
+               .want_per_thread_events = 0,
+       },
 
        /* Add additional metadata before here. */
 };
index 069786cb9274f6ab25324386730962503b834525..d3ecac27728efe8c06dd78f6e394d789d4c1bc7e 100644 (file)
@@ -57,7 +57,9 @@ static struct tr2_sysenv_entry tr2_sysenv_settings[] = {
 };
 /* clang-format on */
 
-static int tr2_sysenv_cb(const char *key, const char *value, void *d)
+static int tr2_sysenv_cb(const char *key, const char *value,
+                        const struct config_context *ctx UNUSED,
+                        void *d UNUSED)
 {
        int k;
 
index bf8745c4f0540cbe0f280e56d3938ec9939413cd..1f626cffea0fc01508beaa65248398faa8c0a8ab 100644 (file)
@@ -69,8 +69,10 @@ typedef void(tr2_tgt_evt_exec_result_fl_t)(const char *file, int line,
                                           uint64_t us_elapsed_absolute,
                                           int exec_id, int code);
 
+struct key_value_info;
 typedef void(tr2_tgt_evt_param_fl_t)(const char *file, int line,
-                                    const char *param, const char *value);
+                                    const char *param, const char *value,
+                                    const struct key_value_info *kvi);
 
 typedef void(tr2_tgt_evt_repo_fl_t)(const char *file, int line,
                                    const struct repository *repo);
index 2af53e5d4de47e012cf22a02ca78a110c7b69a59..59910a1a4f7c0f280fb6839873429d9cc877d3cf 100644 (file)
@@ -335,7 +335,7 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
 }
 
 static void fn_child_start_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute,
+                             uint64_t us_elapsed_absolute UNUSED,
                              const struct child_process *cmd)
 {
        const char *event_name = "child_start";
@@ -367,7 +367,8 @@ static void fn_child_start_fl(const char *file, int line,
 }
 
 static void fn_child_exit_fl(const char *file, int line,
-                            uint64_t us_elapsed_absolute, int cid, int pid,
+                            uint64_t us_elapsed_absolute UNUSED,
+                            int cid, int pid,
                             int code, uint64_t us_elapsed_child)
 {
        const char *event_name = "child_exit";
@@ -388,7 +389,8 @@ static void fn_child_exit_fl(const char *file, int line,
 }
 
 static void fn_child_ready_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute, int cid, int pid,
+                             uint64_t us_elapsed_absolute UNUSED,
+                             int cid, int pid,
                              const char *ready, uint64_t us_elapsed_child)
 {
        const char *event_name = "child_ready";
@@ -409,7 +411,7 @@ static void fn_child_ready_fl(const char *file, int line,
 }
 
 static void fn_thread_start_fl(const char *file, int line,
-                              uint64_t us_elapsed_absolute)
+                              uint64_t us_elapsed_absolute UNUSED)
 {
        const char *event_name = "thread_start";
        struct json_writer jw = JSON_WRITER_INIT;
@@ -423,7 +425,7 @@ static void fn_thread_start_fl(const char *file, int line,
 }
 
 static void fn_thread_exit_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute,
+                             uint64_t us_elapsed_absolute UNUSED,
                              uint64_t us_elapsed_thread)
 {
        const char *event_name = "thread_exit";
@@ -439,7 +441,8 @@ static void fn_thread_exit_fl(const char *file, int line,
        jw_release(&jw);
 }
 
-static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
+static void fn_exec_fl(const char *file, int line,
+                      uint64_t us_elapsed_absolute UNUSED,
                       int exec_id, const char *exe, const char **argv)
 {
        const char *event_name = "exec";
@@ -460,8 +463,8 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
 }
 
 static void fn_exec_result_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute, int exec_id,
-                             int code)
+                             uint64_t us_elapsed_absolute UNUSED,
+                             int exec_id, int code)
 {
        const char *event_name = "exec_result";
        struct json_writer jw = JSON_WRITER_INIT;
@@ -477,11 +480,11 @@ static void fn_exec_result_fl(const char *file, int line,
 }
 
 static void fn_param_fl(const char *file, int line, const char *param,
-                       const char *value)
+                       const char *value, const struct key_value_info *kvi)
 {
        const char *event_name = "def_param";
        struct json_writer jw = JSON_WRITER_INIT;
-       enum config_scope scope = current_config_scope();
+       enum config_scope scope = kvi->scope;
        const char *scope_name = config_scope_name(scope);
 
        jw_object_begin(&jw, 0);
@@ -511,7 +514,7 @@ static void fn_repo_fl(const char *file, int line,
 }
 
 static void fn_region_enter_printf_va_fl(const char *file, int line,
-                                        uint64_t us_elapsed_absolute,
+                                        uint64_t us_elapsed_absolute UNUSED,
                                         const char *category,
                                         const char *label,
                                         const struct repository *repo,
@@ -538,7 +541,7 @@ static void fn_region_enter_printf_va_fl(const char *file, int line,
 }
 
 static void fn_region_leave_printf_va_fl(
-       const char *file, int line, uint64_t us_elapsed_absolute,
+       const char *file, int line, uint64_t us_elapsed_absolute UNUSED,
        uint64_t us_elapsed_region, const char *category, const char *label,
        const struct repository *repo, const char *fmt, va_list ap)
 {
index 1ebfb464d54b0039877933afd640c12722b12458..38d5ebddf65f8061e9d9dbdf18f35c274bc6a31c 100644 (file)
@@ -86,7 +86,7 @@ static void fn_version_fl(const char *file, int line)
 }
 
 static void fn_start_fl(const char *file, int line,
-                       uint64_t us_elapsed_absolute, const char **argv)
+                       uint64_t us_elapsed_absolute UNUSED, const char **argv)
 {
        struct strbuf buf_payload = STRBUF_INIT;
 
@@ -215,7 +215,7 @@ static void fn_alias_fl(const char *file, int line, const char *alias,
 }
 
 static void fn_child_start_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute,
+                             uint64_t us_elapsed_absolute UNUSED,
                              const struct child_process *cmd)
 {
        struct strbuf buf_payload = STRBUF_INIT;
@@ -243,7 +243,8 @@ static void fn_child_start_fl(const char *file, int line,
 }
 
 static void fn_child_exit_fl(const char *file, int line,
-                            uint64_t us_elapsed_absolute, int cid, int pid,
+                            uint64_t us_elapsed_absolute UNUSED,
+                            int cid, int pid,
                             int code, uint64_t us_elapsed_child)
 {
        struct strbuf buf_payload = STRBUF_INIT;
@@ -256,7 +257,8 @@ static void fn_child_exit_fl(const char *file, int line,
 }
 
 static void fn_child_ready_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute, int cid, int pid,
+                             uint64_t us_elapsed_absolute UNUSED,
+                             int cid, int pid,
                              const char *ready, uint64_t us_elapsed_child)
 {
        struct strbuf buf_payload = STRBUF_INIT;
@@ -268,7 +270,8 @@ static void fn_child_ready_fl(const char *file, int line,
        strbuf_release(&buf_payload);
 }
 
-static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
+static void fn_exec_fl(const char *file, int line,
+                      uint64_t us_elapsed_absolute UNUSED,
                       int exec_id, const char *exe, const char **argv)
 {
        struct strbuf buf_payload = STRBUF_INIT;
@@ -284,8 +287,8 @@ static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
 }
 
 static void fn_exec_result_fl(const char *file, int line,
-                             uint64_t us_elapsed_absolute, int exec_id,
-                             int code)
+                             uint64_t us_elapsed_absolute UNUSED,
+                             int exec_id, int code)
 {
        struct strbuf buf_payload = STRBUF_INIT;
 
@@ -297,10 +300,10 @@ static void fn_exec_result_fl(const char *file, int line,
 }
 
 static void fn_param_fl(const char *file, int line, const char *param,
-                       const char *value)
+                       const char *value, const struct key_value_info *kvi)
 {
        struct strbuf buf_payload = STRBUF_INIT;
-       enum config_scope scope = current_config_scope();
+       enum config_scope scope = kvi->scope;
        const char *scope_name = config_scope_name(scope);
 
        strbuf_addf(&buf_payload, "def_param scope:%s %s=%s", scope_name, param,
@@ -321,7 +324,8 @@ static void fn_repo_fl(const char *file, int line,
 }
 
 static void fn_printf_va_fl(const char *file, int line,
-                           uint64_t us_elapsed_absolute, const char *fmt,
+                           uint64_t us_elapsed_absolute UNUSED,
+                           const char *fmt,
                            va_list ap)
 {
        struct strbuf buf_payload = STRBUF_INIT;
index 328e483a05e67c253e8623a9685ab5283970e3fc..a6f9a8a193e058fc164a8e9bd8dc823b7a317a85 100644 (file)
@@ -439,12 +439,12 @@ static void fn_exec_result_fl(const char *file, int line,
 }
 
 static void fn_param_fl(const char *file, int line, const char *param,
-                       const char *value)
+                       const char *value, const struct key_value_info *kvi)
 {
        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();
+       enum config_scope scope = kvi->scope;
        const char *scope_name = config_scope_name(scope);
 
        strbuf_addf(&buf_payload, "%s:%s", param, value);
index 9f46ae12f50f3ac9530db2d53879b03742f769fe..601c9e5036fb27a7f88957559f03821c2fffa4a2 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "thread-utils.h"
 #include "trace.h"
 #include "trace2/tr2_tls.h"
index a2c3ed6f28cc9fedffe50946acdb3594d21f9e7e..b6de5d9cb2dab2c07c26775e62e5bfc40241c9fc 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
@@ -482,6 +481,7 @@ static struct {
 };
 
 static int git_trailer_default_config(const char *conf_key, const char *value,
+                                     const struct config_context *ctx UNUSED,
                                      void *cb UNUSED)
 {
        const char *trailer_item, *variable_name;
@@ -514,6 +514,7 @@ static int git_trailer_default_config(const char *conf_key, const char *value,
 }
 
 static int git_trailer_config(const char *conf_key, const char *value,
+                             const struct config_context *ctx UNUSED,
                              void *cb UNUSED)
 {
        const char *trailer_item, *variable_name;
@@ -710,30 +711,35 @@ static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
        list_add_tail(&new_item->list, arg_head);
 }
 
-static void process_command_line_args(struct list_head *arg_head,
-                                     struct list_head *new_trailer_head)
+static void parse_trailers_from_config(struct list_head *config_head)
 {
        struct arg_item *item;
-       struct strbuf tok = STRBUF_INIT;
-       struct strbuf val = STRBUF_INIT;
-       const struct conf_info *conf;
        struct list_head *pos;
 
-       /*
-        * In command-line arguments, '=' is accepted (in addition to the
-        * separators that are defined).
-        */
-       char *cl_separators = xstrfmt("=%s", separators);
-
        /* Add an arg item for each configured trailer with a command */
        list_for_each(pos, &conf_head) {
                item = list_entry(pos, struct arg_item, list);
                if (item->conf.command)
-                       add_arg_item(arg_head,
+                       add_arg_item(config_head,
                                     xstrdup(token_from_item(item, NULL)),
                                     xstrdup(""),
                                     &item->conf, NULL);
        }
+}
+
+static void parse_trailers_from_command_line_args(struct list_head *arg_head,
+                                                 struct list_head *new_trailer_head)
+{
+       struct strbuf tok = STRBUF_INIT;
+       struct strbuf val = STRBUF_INIT;
+       const struct conf_info *conf;
+       struct list_head *pos;
+
+       /*
+        * In command-line arguments, '=' is accepted (in addition to the
+        * separators that are defined).
+        */
+       char *cl_separators = xstrfmt("=%s", separators);
 
        /* Add an arg item for each trailer on the command line */
        list_for_each(pos, new_trailer_head) {
@@ -960,28 +966,24 @@ static void unfold_value(struct strbuf *val)
        strbuf_release(&out);
 }
 
-static size_t process_input_file(FILE *outfile,
-                                const char *str,
-                                struct list_head *head,
-                                const struct process_trailer_options *opts)
+/*
+ * Parse trailers in "str", populating the trailer info and "head"
+ * linked list structure.
+ */
+static void parse_trailers(struct trailer_info *info,
+                            const char *str,
+                            struct list_head *head,
+                            const struct process_trailer_options *opts)
 {
-       struct trailer_info info;
        struct strbuf tok = STRBUF_INIT;
        struct strbuf val = STRBUF_INIT;
        size_t i;
 
-       trailer_info_get(&info, str, opts);
-
-       /* Print lines before the trailers as is */
-       if (!opts->only_trailers)
-               fwrite(str, 1, info.trailer_start - str, outfile);
+       trailer_info_get(info, str, opts);
 
-       if (!opts->only_trailers && !info.blank_line_before_trailer)
-               fprintf(outfile, "\n");
-
-       for (i = 0; i < info.trailer_nr; i++) {
+       for (i = 0; i < info->trailer_nr; i++) {
                int separator_pos;
-               char *trailer = info.trailers[i];
+               char *trailer = info->trailers[i];
                if (trailer[0] == comment_line_char)
                        continue;
                separator_pos = find_separator(trailer, separators);
@@ -1001,10 +1003,6 @@ static size_t process_input_file(FILE *outfile,
                                         strbuf_detach(&val, NULL));
                }
        }
-
-       trailer_info_release(&info);
-
-       return info.trailer_end - str;
 }
 
 static void free_all(struct list_head *head)
@@ -1053,6 +1051,7 @@ void process_trailers(const char *file,
 {
        LIST_HEAD(head);
        struct strbuf sb = STRBUF_INIT;
+       struct trailer_info info;
        size_t trailer_end;
        FILE *outfile = stdout;
 
@@ -1063,18 +1062,30 @@ void process_trailers(const char *file,
        if (opts->in_place)
                outfile = create_in_place_tempfile(file);
 
+       parse_trailers(&info, sb.buf, &head, opts);
+       trailer_end = info.trailer_end - sb.buf;
+
        /* Print the lines before the trailers */
-       trailer_end = process_input_file(outfile, sb.buf, &head, opts);
+       if (!opts->only_trailers)
+               fwrite(sb.buf, 1, info.trailer_start - sb.buf, outfile);
+
+       if (!opts->only_trailers && !info.blank_line_before_trailer)
+               fprintf(outfile, "\n");
+
 
        if (!opts->only_input) {
+               LIST_HEAD(config_head);
                LIST_HEAD(arg_head);
-               process_command_line_args(&arg_head, new_trailer_head);
+               parse_trailers_from_config(&config_head);
+               parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
+               list_splice(&config_head, &arg_head);
                process_trailers_lists(&head, &arg_head);
        }
 
        print_all(outfile, &head, opts);
 
        free_all(&head);
+       trailer_info_release(&info);
 
        /* Print the lines after the trailers as is */
        if (!opts->only_trailers)
@@ -1219,14 +1230,14 @@ void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
        strbuf_init(&iter->key, 0);
        strbuf_init(&iter->val, 0);
        opts.no_divider = 1;
-       trailer_info_get(&iter->info, msg, &opts);
-       iter->cur = 0;
+       trailer_info_get(&iter->internal.info, msg, &opts);
+       iter->internal.cur = 0;
 }
 
 int trailer_iterator_advance(struct trailer_iterator *iter)
 {
-       while (iter->cur < iter->info.trailer_nr) {
-               char *trailer = iter->info.trailers[iter->cur++];
+       while (iter->internal.cur < iter->internal.info.trailer_nr) {
+               char *trailer = iter->internal.info.trailers[iter->internal.cur++];
                int separator_pos = find_separator(trailer, separators);
 
                if (separator_pos < 1)
@@ -1244,7 +1255,7 @@ int trailer_iterator_advance(struct trailer_iterator *iter)
 
 void trailer_iterator_release(struct trailer_iterator *iter)
 {
-       trailer_info_release(&iter->info);
+       trailer_info_release(&iter->internal.info);
        strbuf_release(&iter->val);
        strbuf_release(&iter->key);
 }
index 795d2fccfd9579500b798ac667feef2ee549f4b4..ab2cd017567b3f782fa9b342ad03e7e93bc17a37 100644 (file)
--- a/trailer.h
+++ b/trailer.h
@@ -119,8 +119,10 @@ struct trailer_iterator {
        struct strbuf val;
 
        /* private */
-       struct trailer_info info;
-       size_t cur;
+       struct {
+               struct trailer_info info;
+               size_t cur;
+       } internal;
 };
 
 /*
index 6b816940dc64d8803c89c866bc2d0acdae849ad6..49811ef176dbc5af5e33fe47cf93cf1f57719f5e 100644 (file)
@@ -8,6 +8,7 @@
 #include "gettext.h"
 #include "hex.h"
 #include "object-name.h"
+#include "repository.h"
 #include "revision.h"
 #include "remote.h"
 #include "string-list.h"
@@ -18,7 +19,6 @@
 #include "refspec.h"
 #include "transport-internal.h"
 #include "protocol.h"
-#include "wrapper.h"
 
 static int debug;
 
index 67afdae57c1c1d0da0d88b1e9823ed6b4fefe4ca..219af8fd50ed57c0fc0f954965e481b51e7aae72 100644 (file)
@@ -1,6 +1,5 @@
 #include "git-compat-util.h"
 #include "advice.h"
-#include "alloc.h"
 #include "config.h"
 #include "environment.h"
 #include "hex.h"
 #include "transport-internal.h"
 #include "protocol.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "color.h"
 #include "bundle-uri.h"
-#include "wrapper.h"
 
 static int transport_use_color = -1;
 static char transport_colors[][COLOR_MAXLEN] = {
index 20bb15f38d9471b9de64fa6bafd620fd18b61901..46107772d178f9b3706f288e6055a34a040db00c 100644 (file)
@@ -4,8 +4,10 @@
 #include "git-compat-util.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "hash.h"
 #include "tree.h"
 #include "tree-walk.h"
+#include "environment.h"
 
 /*
  * Some mode bits are also used internally for computations.
@@ -44,7 +46,8 @@
 static struct combine_diff_path *ll_diff_tree_paths(
        struct combine_diff_path *p, const struct object_id *oid,
        const struct object_id **parents_oid, int nparent,
-       struct strbuf *base, struct diff_options *opt);
+       struct strbuf *base, struct diff_options *opt,
+       int depth);
 static void ll_diff_tree_oid(const struct object_id *old_oid,
                             const struct object_id *new_oid,
                             struct strbuf *base, struct diff_options *opt);
@@ -195,7 +198,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
 static struct combine_diff_path *emit_path(struct combine_diff_path *p,
        struct strbuf *base, struct diff_options *opt, int nparent,
        struct tree_desc *t, struct tree_desc *tp,
-       int imin)
+       int imin, int depth)
 {
        unsigned short mode;
        const char *path;
@@ -301,7 +304,8 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
 
                strbuf_add(base, path, pathlen);
                strbuf_addch(base, '/');
-               p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
+               p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt,
+                                      depth + 1);
                FAST_ARRAY_FREE(parents_oid, nparent);
        }
 
@@ -316,7 +320,7 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
 
        while (t->size) {
                match = tree_entry_interesting(opt->repo->index, &t->entry,
-                                              base, 0, &opt->pathspec);
+                                              base, &opt->pathspec);
                if (match) {
                        if (match == all_entries_not_interesting)
                                t->size = 0;
@@ -422,12 +426,16 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
 static struct combine_diff_path *ll_diff_tree_paths(
        struct combine_diff_path *p, const struct object_id *oid,
        const struct object_id **parents_oid, int nparent,
-       struct strbuf *base, struct diff_options *opt)
+       struct strbuf *base, struct diff_options *opt,
+       int depth)
 {
        struct tree_desc t, *tp;
        void *ttree, **tptree;
        int i;
 
+       if (depth > max_allowed_tree_depth)
+               die("exceeded maximum allowed tree depth");
+
        FAST_ARRAY_ALLOC(tp, nparent);
        FAST_ARRAY_ALLOC(tptree, nparent);
 
@@ -521,7 +529,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
 
                        /* D += {δ(t,pi) if pi=p[imin];  "+a" if pi > p[imin]} */
                        p = emit_path(p, base, opt, nparent,
-                                       &t, tp, imin);
+                                       &t, tp, imin, depth);
 
                skip_emit_t_tp:
                        /* t↓,  ∀ pi=p[imin]  pi↓ */
@@ -533,7 +541,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
                else if (cmp < 0) {
                        /* D += "+t" */
                        p = emit_path(p, base, opt, nparent,
-                                       &t, /*tp=*/NULL, -1);
+                                       &t, /*tp=*/NULL, -1, depth);
 
                        /* t↓ */
                        update_tree_entry(&t);
@@ -549,7 +557,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
                        }
 
                        p = emit_path(p, base, opt, nparent,
-                                       /*t=*/NULL, tp, imin);
+                                       /*t=*/NULL, tp, imin, depth);
 
                skip_emit_tp:
                        /* ∀ pi=p[imin]  pi↓ */
@@ -571,7 +579,7 @@ struct combine_diff_path *diff_tree_paths(
        const struct object_id **parents_oid, int nparent,
        struct strbuf *base, struct diff_options *opt)
 {
-       p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
+       p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt, 0);
 
        /*
         * free pre-allocated last element, if any
index d3c48e06df05b707af9f753fd4a3d4641173c00c..b517792ba23a2104f5f8207519e64cbc5d2daaa4 100644 (file)
@@ -1,15 +1,15 @@
 #include "git-compat-util.h"
 #include "tree-walk.h"
-#include "alloc.h"
 #include "dir.h"
 #include "gettext.h"
 #include "hex.h"
 #include "object-file.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "trace2.h"
 #include "tree.h"
 #include "pathspec.h"
 #include "json-writer.h"
+#include "environment.h"
 
 static const char *get_mode(const char *str, unsigned int *modep)
 {
@@ -435,29 +435,32 @@ static inline int prune_traversal(struct index_state *istate,
        if (still_interesting < 0)
                return still_interesting;
        return tree_entry_interesting(istate, e, base,
-                                     0, info->pathspec);
+                                     info->pathspec);
 }
 
 int traverse_trees(struct index_state *istate,
                   int n, struct tree_desc *t,
                   struct traverse_info *info)
 {
-       int error = 0;
-       struct name_entry entry[MAX_TRAVERSE_TREES];
+       int ret = 0;
+       struct name_entry *entry;
        int i;
-       struct tree_desc_x tx[ARRAY_SIZE(entry)];
+       struct tree_desc_x *tx;
        struct strbuf base = STRBUF_INIT;
        int interesting = 1;
        char *traverse_path;
 
+       if (traverse_trees_cur_depth > max_allowed_tree_depth)
+               return error("exceeded maximum allowed tree depth");
+
        traverse_trees_count++;
        traverse_trees_cur_depth++;
 
        if (traverse_trees_cur_depth > traverse_trees_max_depth)
                traverse_trees_max_depth = traverse_trees_cur_depth;
 
-       if (n >= ARRAY_SIZE(entry))
-               BUG("traverse_trees() called with too many trees (%d)", n);
+       ALLOC_ARRAY(entry, n);
+       ALLOC_ARRAY(tx, n);
 
        for (i = 0; i < n; i++) {
                tx[i].d = t[i];
@@ -540,7 +543,7 @@ int traverse_trees(struct index_state *istate,
                if (interesting) {
                        trees_used = info->fn(n, mask, dirmask, entry, info);
                        if (trees_used < 0) {
-                               error = trees_used;
+                               ret = trees_used;
                                if (!info->show_all_errors)
                                        break;
                        }
@@ -552,12 +555,14 @@ int traverse_trees(struct index_state *istate,
        }
        for (i = 0; i < n; i++)
                free_extended_entry(tx + i);
+       free(tx);
+       free(entry);
        free(traverse_path);
        info->traverse_path = NULL;
        strbuf_release(&base);
 
        traverse_trees_cur_depth--;
-       return error;
+       return ret;
 }
 
 struct dir_state {
@@ -1016,17 +1021,17 @@ static int match_wildcard_base(const struct pathspec_item *item,
 /*
  * Is a tree entry interesting given the pathspec we have?
  *
- * Pre-condition: either baselen == base_offset (i.e. empty path)
+ * Pre-condition: either baselen == 0 (i.e. empty path)
  * or base[baselen-1] == '/' (i.e. with trailing slash).
  */
 static enum interesting do_match(struct index_state *istate,
                                 const struct name_entry *entry,
-                                struct strbuf *base, int base_offset,
+                                struct strbuf *base,
                                 const struct pathspec *ps,
                                 int exclude)
 {
        int i;
-       int pathlen, baselen = base->len - base_offset;
+       int pathlen, baselen = base->len;
        enum interesting never_interesting = ps->has_wildcard ?
                entry_not_interesting : all_entries_not_interesting;
 
@@ -1044,7 +1049,7 @@ static enum interesting do_match(struct index_state *istate,
                    !(ps->magic & PATHSPEC_MAXDEPTH) ||
                    ps->max_depth == -1)
                        return all_entries_interesting;
-               return within_depth(base->buf + base_offset, baselen,
+               return within_depth(base->buf, baselen,
                                    !!S_ISDIR(entry->mode),
                                    ps->max_depth) ?
                        entry_interesting : entry_not_interesting;
@@ -1055,7 +1060,7 @@ static enum interesting do_match(struct index_state *istate,
        for (i = ps->nr - 1; i >= 0; i--) {
                const struct pathspec_item *item = ps->items+i;
                const char *match = item->match;
-               const char *base_str = base->buf + base_offset;
+               const char *base_str = base->buf;
                int matchlen = item->len, matched = 0;
 
                if ((!exclude &&   item->magic & PATHSPEC_EXCLUDE) ||
@@ -1148,9 +1153,9 @@ match_wildcards:
 
                strbuf_add(base, entry->path, pathlen);
 
-               if (!git_fnmatch(item, match, base->buf + base_offset,
+               if (!git_fnmatch(item, match, base->buf,
                                 item->nowildcard_len)) {
-                       strbuf_setlen(base, base_offset + baselen);
+                       strbuf_setlen(base, baselen);
                        goto interesting;
                }
 
@@ -1162,13 +1167,13 @@ match_wildcards:
                 * be performed in the submodule itself.
                 */
                if (ps->recurse_submodules && S_ISGITLINK(entry->mode) &&
-                   !ps_strncmp(item, match, base->buf + base_offset,
+                   !ps_strncmp(item, match, base->buf,
                                item->nowildcard_len)) {
-                       strbuf_setlen(base, base_offset + baselen);
+                       strbuf_setlen(base, baselen);
                        goto interesting;
                }
 
-               strbuf_setlen(base, base_offset + baselen);
+               strbuf_setlen(base, baselen);
 
                /*
                 * Match all directories. We'll try to match files
@@ -1204,9 +1209,9 @@ interesting:
                                return entry_interesting;
 
                        strbuf_add(base, entry->path, pathlen);
-                       ret = match_pathspec_attrs(istate, base->buf + base_offset,
-                                                  base->len - base_offset, item);
-                       strbuf_setlen(base, base_offset + baselen);
+                       ret = match_pathspec_attrs(istate, base->buf,
+                                                  base->len, item);
+                       strbuf_setlen(base, baselen);
                        if (!ret)
                                continue;
                }
@@ -1218,16 +1223,16 @@ interesting:
 /*
  * Is a tree entry interesting given the pathspec we have?
  *
- * Pre-condition: either baselen == base_offset (i.e. empty path)
+ * Pre-condition: either baselen == 0 (i.e. empty path)
  * or base[baselen-1] == '/' (i.e. with trailing slash).
  */
 enum interesting tree_entry_interesting(struct index_state *istate,
                                        const struct name_entry *entry,
-                                       struct strbuf *base, int base_offset,
+                                       struct strbuf *base,
                                        const struct pathspec *ps)
 {
        enum interesting positive, negative;
-       positive = do_match(istate, entry, base, base_offset, ps, 0);
+       positive = do_match(istate, entry, base, ps, 0);
 
        /*
         * case | entry | positive | negative | result
@@ -1264,7 +1269,7 @@ enum interesting tree_entry_interesting(struct index_state *istate,
            positive <= entry_not_interesting) /* #1, #2, #11, #12 */
                return positive;
 
-       negative = do_match(istate, entry, base, base_offset, ps, 1);
+       negative = do_match(istate, entry, base, ps, 1);
 
        /* #8, #18 */
        if (positive == all_entries_interesting &&
index 01a9d8eb4422edbdfa1cf3609623aa2fab66cb4d..a6bfa3da3a826bf5c218132b93582e53ace876be 100644 (file)
@@ -6,8 +6,6 @@
 struct index_state;
 struct repository;
 
-#define MAX_TRAVERSE_TREES 8
-
 /**
  * The tree walking API is used to traverse and inspect trees.
  */
@@ -224,7 +222,7 @@ enum interesting {
 
 enum interesting tree_entry_interesting(struct index_state *istate,
                                        const struct name_entry *,
-                                       struct strbuf *, int,
+                                       struct strbuf *,
                                        const struct pathspec *ps);
 
 #endif
diff --git a/tree.c b/tree.c
index 0dd2029a8a2905338ac7d7cd9062bd9662a2e9f0..990f9c9854e6a1a957ed01f74b20e694af07f278 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -3,18 +3,20 @@
 #include "hex.h"
 #include "tree.h"
 #include "object-name.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "blob.h"
 #include "commit.h"
 #include "tag.h"
 #include "alloc.h"
 #include "tree-walk.h"
 #include "repository.h"
+#include "environment.h"
 
 const char *tree_type = "tree";
 
 int read_tree_at(struct repository *r,
                 struct tree *tree, struct strbuf *base,
+                int depth,
                 const struct pathspec *pathspec,
                 read_tree_fn_t fn, void *context)
 {
@@ -24,6 +26,9 @@ int read_tree_at(struct repository *r,
        int len, oldlen = base->len;
        enum interesting retval = entry_not_interesting;
 
+       if (depth > max_allowed_tree_depth)
+               return error("exceeded maximum allowed tree depth");
+
        if (parse_tree(tree))
                return -1;
 
@@ -32,7 +37,7 @@ int read_tree_at(struct repository *r,
        while (tree_entry(&desc, &entry)) {
                if (retval != all_entries_interesting) {
                        retval = tree_entry_interesting(r->index, &entry,
-                                                       base, 0, pathspec);
+                                                       base, pathspec);
                        if (retval == all_entries_not_interesting)
                                break;
                        if (retval == entry_not_interesting)
@@ -74,7 +79,7 @@ int read_tree_at(struct repository *r,
                strbuf_add(base, entry.path, len);
                strbuf_addch(base, '/');
                retval = read_tree_at(r, lookup_tree(r, &oid),
-                                     base, pathspec,
+                                     base, depth + 1, pathspec,
                                      fn, context);
                strbuf_setlen(base, oldlen);
                if (retval)
@@ -89,7 +94,7 @@ int read_tree(struct repository *r,
              read_tree_fn_t fn, void *context)
 {
        struct strbuf sb = STRBUF_INIT;
-       int ret = read_tree_at(r, tree, &sb, pathspec, fn, context);
+       int ret = read_tree_at(r, tree, &sb, 0, pathspec, fn, context);
        strbuf_release(&sb);
        return ret;
 }
diff --git a/tree.h b/tree.h
index 1b5ecbda6b335b4962ee2150534dfd8c0a73964c..cc6ddf51b3273c2dbeb798b2cb945de29dd28a36 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -44,6 +44,7 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c
 
 int read_tree_at(struct repository *r,
                 struct tree *tree, struct strbuf *base,
+                int depth,
                 const struct pathspec *pathspec,
                 read_tree_fn_t fn, void *context);
 
index e15fb0455bbd9d6b5fa113ec9bb5cea4f6b6d375..be5bf8c4f2ff28827507a70846907aeca731d530 100644 (file)
@@ -396,14 +396,13 @@ static const struct interval double_width[] = {
 { 0x2E80, 0x2E99 },
 { 0x2E9B, 0x2EF3 },
 { 0x2F00, 0x2FD5 },
-{ 0x2FF0, 0x2FFB },
-{ 0x3000, 0x303E },
+{ 0x2FF0, 0x303E },
 { 0x3041, 0x3096 },
 { 0x3099, 0x30FF },
 { 0x3105, 0x312F },
 { 0x3131, 0x318E },
 { 0x3190, 0x31E3 },
-{ 0x31F0, 0x321E },
+{ 0x31EF, 0x321E },
 { 0x3220, 0x3247 },
 { 0x3250, 0x4DBF },
 { 0x4E00, 0xA48C },
index e8c32a40dcba5e8e7cb1dc7f0661953473db350e..c2b20b80d5a448b7b5c76d2de4ac9358fa596b69 100644 (file)
@@ -1,12 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "advice.h"
 #include "strvec.h"
 #include "repository.h"
-#include "config.h"
+#include "parse.h"
 #include "dir.h"
 #include "environment.h"
 #include "gettext.h"
 #include "hex.h"
+#include "name-hash.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "cache-tree.h"
@@ -14,6 +15,7 @@
 #include "progress.h"
 #include "refs.h"
 #include "attr.h"
+#include "read-cache.h"
 #include "split-index.h"
 #include "sparse-index.h"
 #include "submodule.h"
@@ -21,7 +23,7 @@
 #include "symlinks.h"
 #include "trace2.h"
 #include "fsmonitor.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "promisor-remote.h"
 #include "entry.h"
 #include "parallel-checkout.h"
@@ -862,8 +864,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
        struct unpack_trees_options *o = info->data;
        int i, ret, bottom;
        int nr_buf = 0;
-       struct tree_desc t[MAX_UNPACK_TREES];
-       void *buf[MAX_UNPACK_TREES];
+       struct tree_desc *t;
+       void **buf;
        struct traverse_info newinfo;
        struct name_entry *p;
        int nr_entries;
@@ -900,6 +902,9 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
        newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
        newinfo.df_conflicts |= df_conflicts;
 
+       ALLOC_ARRAY(t, n);
+       ALLOC_ARRAY(buf, n);
+
        /*
         * Fetch the tree from the ODB for each peer directory in the
         * n commits.
@@ -935,6 +940,8 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
 
        for (i = 0; i < nr_buf; i++)
                free(buf[i]);
+       free(buf);
+       free(t);
 
        return ret;
 }
index 30622aeebff91f64cd9799412e531bdbb2110bc2..5867e26e17777483f3fc5df0084deb7a4dd135da 100644 (file)
@@ -1,13 +1,13 @@
 #ifndef UNPACK_TREES_H
 #define UNPACK_TREES_H
 
-#include "cache.h"
 #include "convert.h"
+#include "read-cache-ll.h"
 #include "strvec.h"
 #include "string-list.h"
 #include "tree-walk.h"
 
-#define MAX_UNPACK_TREES MAX_TRAVERSE_TREES
+#define MAX_UNPACK_TREES 8
 
 struct cache_entry;
 struct unpack_trees_options;
index d3312006a32bebdc67c4395b6468db328b501c86..83f3d2651ab3feee758178f86394627ffe4f76b0 100644 (file)
@@ -7,7 +7,7 @@
 #include "pkt-line.h"
 #include "sideband.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "oid-array.h"
 #include "tag.h"
 #include "object.h"
@@ -32,7 +32,6 @@
 #include "commit-graph.h"
 #include "commit-reach.h"
 #include "shallow.h"
-#include "wrapper.h"
 #include "write-or-die.h"
 
 /* Remember to update object flag allocation in object.h */
@@ -69,7 +68,7 @@ struct upload_pack_data {
        struct object_array have_obj;
        struct oid_array haves;                                 /* v2 only */
        struct string_list wanted_refs;                         /* v2 only */
-       struct string_list hidden_refs;
+       struct strvec hidden_refs;
 
        struct object_array shallows;
        struct string_list deepen_not;
@@ -127,7 +126,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
 {
        struct string_list symref = STRING_LIST_INIT_DUP;
        struct string_list wanted_refs = STRING_LIST_INIT_DUP;
-       struct string_list hidden_refs = STRING_LIST_INIT_DUP;
+       struct strvec hidden_refs = STRVEC_INIT;
        struct object_array want_obj = OBJECT_ARRAY_INIT;
        struct object_array have_obj = OBJECT_ARRAY_INIT;
        struct oid_array haves = OID_ARRAY_INIT;
@@ -162,7 +161,7 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
 {
        string_list_clear(&data->symref, 1);
        string_list_clear(&data->wanted_refs, 1);
-       string_list_clear(&data->hidden_refs, 0);
+       strvec_clear(&data->hidden_refs);
        object_array_clear(&data->want_obj);
        object_array_clear(&data->have_obj);
        oid_array_clear(&data->haves);
@@ -602,11 +601,36 @@ static int get_common_commits(struct upload_pack_data *data,
        }
 }
 
+static int allow_hidden_refs(enum allow_uor allow_uor)
+{
+       if ((allow_uor & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1)
+               return 1;
+       return !(allow_uor & (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
+}
+
+static void for_each_namespaced_ref_1(each_ref_fn fn,
+                                     struct upload_pack_data *data)
+{
+       const char **excludes = NULL;
+       /*
+        * If `data->allow_uor` allows fetching hidden refs, we need to
+        * mark all references (including hidden ones), to check in
+        * `is_our_ref()` below.
+        *
+        * Otherwise, we only care about whether each reference's object
+        * has the OUR_REF bit set or not, so do not need to visit
+        * hidden references.
+        */
+       if (allow_hidden_refs(data->allow_uor))
+               excludes = hidden_refs_to_excludes(&data->hidden_refs);
+
+       for_each_namespaced_ref(excludes, fn, data);
+}
+
+
 static int is_our_ref(struct object *o, enum allow_uor allow_uor)
 {
-       int allow_hidden_ref = (allow_uor &
-                               (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
-       return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);
+       return o->flags & ((allow_hidden_refs(allow_uor) ? 0 : HIDDEN_REF) | OUR_REF);
 }
 
 /*
@@ -777,11 +801,12 @@ error:
        for (i = 0; i < data->want_obj.nr; i++) {
                struct object *o = data->want_obj.objects[i].item;
                if (!is_our_ref(o, data->allow_uor)) {
+                       error("git upload-pack: not our ref %s",
+                             oid_to_hex(&o->oid));
                        packet_writer_error(&data->writer,
                                            "upload-pack: not our ref %s",
                                            oid_to_hex(&o->oid));
-                       die("git upload-pack: not our ref %s",
-                           oid_to_hex(&o->oid));
+                       exit(128);
                }
        }
 }
@@ -855,7 +880,7 @@ static void deepen(struct upload_pack_data *data, int depth)
                 * marked with OUR_REF.
                 */
                head_ref_namespaced(check_ref, data);
-               for_each_namespaced_ref(check_ref, data);
+               for_each_namespaced_ref_1(check_ref, data);
 
                get_reachable_list(data, &reachable_shallows);
                result = get_shallow_commits(&reachable_shallows,
@@ -1170,7 +1195,7 @@ static void receive_needs(struct upload_pack_data *data,
 
 /* return non-zero if the ref is hidden, otherwise 0 */
 static int mark_our_ref(const char *refname, const char *refname_full,
-                       const struct object_id *oid, const struct string_list *hidden_refs)
+                       const struct object_id *oid, const struct strvec *hidden_refs)
 {
        struct object *o = lookup_unknown_object(the_repository, oid);
 
@@ -1275,7 +1300,8 @@ static int find_symref(const char *refname,
 }
 
 static int parse_object_filter_config(const char *var, const char *value,
-                                      struct upload_pack_data *data)
+                                     const struct key_value_info *kvi,
+                                     struct upload_pack_data *data)
 {
        struct strbuf buf = STRBUF_INIT;
        const char *sub, *key;
@@ -1302,14 +1328,17 @@ static int parse_object_filter_config(const char *var, const char *value,
                }
                string_list_insert(&data->allowed_filters, buf.buf)->util =
                        (void *)(intptr_t)1;
-               data->tree_filter_max_depth = git_config_ulong(var, value);
+               data->tree_filter_max_depth = git_config_ulong(var, value,
+                                                              kvi);
        }
 
        strbuf_release(&buf);
        return 0;
 }
 
-static int upload_pack_config(const char *var, const char *value, void *cb_data)
+static int upload_pack_config(const char *var, const char *value,
+                             const struct config_context *ctx,
+                             void *cb_data)
 {
        struct upload_pack_data *data = cb_data;
 
@@ -1329,7 +1358,7 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data)
                else
                        data->allow_uor &= ~ALLOW_ANY_SHA1;
        } else if (!strcmp("uploadpack.keepalive", var)) {
-               data->keepalive = git_config_int(var, value);
+               data->keepalive = git_config_int(var, value, ctx->kvi);
                if (!data->keepalive)
                        data->keepalive = -1;
        } else if (!strcmp("uploadpack.allowfilter", var)) {
@@ -1344,13 +1373,15 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data)
                data->advertise_sid = git_config_bool(var, value);
        }
 
-       if (parse_object_filter_config(var, value, data) < 0)
+       if (parse_object_filter_config(var, value, ctx->kvi, data) < 0)
                return -1;
 
        return parse_hide_refs_config(var, value, "uploadpack", &data->hidden_refs);
 }
 
-static int upload_pack_protected_config(const char *var, const char *value, void *cb_data)
+static int upload_pack_protected_config(const char *var, const char *value,
+                                       const struct config_context *ctx UNUSED,
+                                       void *cb_data)
 {
        struct upload_pack_data *data = cb_data;
 
@@ -1386,7 +1417,7 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
                if (advertise_refs)
                        data.no_done = 1;
                head_ref_namespaced(send_ref, &data);
-               for_each_namespaced_ref(send_ref, &data);
+               for_each_namespaced_ref_1(send_ref, &data);
                if (!data.sent_capabilities) {
                        const char *refname = "capabilities^{}";
                        write_v0_ref(&data, refname, refname, null_oid());
@@ -1400,7 +1431,7 @@ void upload_pack(const int advertise_refs, const int stateless_rpc,
                packet_flush(1);
        } else {
                head_ref_namespaced(check_ref, &data);
-               for_each_namespaced_ref(check_ref, &data);
+               for_each_namespaced_ref_1(check_ref, &data);
        }
 
        if (!advertise_refs) {
@@ -1465,7 +1496,7 @@ static int parse_want(struct packet_writer *writer, const char *line,
 
 static int parse_want_ref(struct packet_writer *writer, const char *line,
                          struct string_list *wanted_refs,
-                         struct string_list *hidden_refs,
+                         struct strvec *hidden_refs,
                          struct object_array *want_obj)
 {
        const char *refname_nons;
diff --git a/url.c b/url.c
index 2e1a9f6feec96b055a9415748eb721937461c07f..282b12495ae7d4af9db51a76017af6065b924d3a 100644 (file)
--- a/url.c
+++ b/url.c
@@ -1,5 +1,5 @@
 #include "git-compat-util.h"
-#include "hex.h"
+#include "hex-ll.h"
 #include "strbuf.h"
 #include "url.h"
 
index eba0bdd77fe75bc4c0f836d88f9b7e8c4b91c995..1d0254abacbc3f393062351bc55ccd9bef32051a 100644 (file)
@@ -1,6 +1,6 @@
 #include "git-compat-util.h"
 #include "gettext.h"
-#include "hex.h"
+#include "hex-ll.h"
 #include "strbuf.h"
 #include "urlmatch.h"
 
@@ -551,7 +551,8 @@ static int cmp_matches(const struct urlmatch_item *a,
        return 0;
 }
 
-int urlmatch_config_entry(const char *var, const char *value, void *cb)
+int urlmatch_config_entry(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb)
 {
        struct string_list_item *item;
        struct urlmatch_config *collect = cb;
@@ -565,7 +566,7 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
 
        if (!skip_prefix(var, collect->section, &key) || *(key++) != '.') {
                if (collect->cascade_fn)
-                       return collect->cascade_fn(var, value, cb);
+                       return collect->cascade_fn(var, value, ctx, cb);
                return 0; /* not interested */
        }
        dot = strrchr(key, '.');
@@ -609,7 +610,7 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
        strbuf_addstr(&synthkey, collect->section);
        strbuf_addch(&synthkey, '.');
        strbuf_addstr(&synthkey, key);
-       retval = collect->collect_fn(synthkey.buf, value, collect->cb);
+       retval = collect->collect_fn(synthkey.buf, value, ctx, collect->cb);
 
        strbuf_release(&synthkey);
        return retval;
index 9f40b00bfb82b1f32bf75e60538be145bbe9d116..5ba85cea1396dd10d18849eb9e6de85c9750403a 100644 (file)
@@ -2,6 +2,7 @@
 #define URL_MATCH_H
 
 #include "string-list.h"
+#include "config.h"
 
 struct url_info {
        /* normalized url on success, must be freed, otherwise NULL */
@@ -48,8 +49,8 @@ struct urlmatch_config {
        const char *key;
 
        void *cb;
-       int (*collect_fn)(const char *var, const char *value, void *cb);
-       int (*cascade_fn)(const char *var, const char *value, void *cb);
+       config_fn_t collect_fn;
+       config_fn_t cascade_fn;
        /*
         * Compare the two matches, the one just discovered and the existing
         * best match and return a negative value if the found item is to be
@@ -70,7 +71,8 @@ struct urlmatch_config {
        .vars = STRING_LIST_INIT_DUP, \
 }
 
-int urlmatch_config_entry(const char *var, const char *value, void *cb);
+int urlmatch_config_entry(const char *var, const char *value,
+                         const struct config_context *ctx, void *cb);
 void urlmatch_config_release(struct urlmatch_config *config);
 
 #endif /* URL_MATCH_H */
diff --git a/usage.c b/usage.c
index 46d99f8bd43a2456bf59337fab2101463c66b54b..09f0ed509b79c5a162f06a7f4cb5c5296d36be56 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -6,7 +6,6 @@
 #include "git-compat-util.h"
 #include "gettext.h"
 #include "trace2.h"
-#include "wrapper.h"
 
 static void vreportf(const char *prefix, const char *err, va_list params)
 {
index 664c7c140256bb089d3e3920828ead185dfedd01..e399543823bdf2c0c8f24fb87f7622ac4d8a366b 100644 (file)
@@ -1,5 +1,4 @@
 #include "git-compat-util.h"
-#include "alloc.h"
 #include "config.h"
 #include "userdiff.h"
 #include "attr.h"
index 74cc7c43f0f8f20431471f7b9a0c949c719ce7cd..45e676cbca6314d1b65c11e76f754898f060dfda 100644 (file)
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "config.h"
+#include "strbuf.h"
 #include "string-list.h"
 #include "versioncmp.h"
 
index 24ff7dfdc28a43a0f2b8535fd417b84eb0bede42..65002a7220adc2e60aafe6a29555df1cee167ad0 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -3,8 +3,9 @@
 #include "hex.h"
 #include "walker.h"
 #include "repository.h"
-#include "object-store.h"
+#include "object-store-ll.h"
 #include "commit.h"
+#include "strbuf.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "tag.h"
index b5ee71c5ebda499899e5f64209611f0484359867..a56a6c2a3d136d31019520fdae68fc46c428194d 100644 (file)
@@ -1,8 +1,8 @@
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "alloc.h"
 #include "environment.h"
 #include "gettext.h"
+#include "path.h"
 #include "repository.h"
 #include "refs.h"
 #include "setup.h"
@@ -11,7 +11,6 @@
 #include "dir.h"
 #include "wt-status.h"
 #include "config.h"
-#include "wrapper.h"
 
 void free_worktrees(struct worktree **worktrees)
 {
@@ -582,8 +581,10 @@ static void repair_gitfile(struct worktree *wt,
        strbuf_release(&dotgit);
 }
 
-static void repair_noop(int iserr, const char *path, const char *msg,
-                       void *cb_data)
+static void repair_noop(int iserr UNUSED,
+                       const char *path UNUSED,
+                       const char *msg UNUSED,
+                       void *cb_data UNUSED)
 {
        /* nothing */
 }
@@ -806,7 +807,7 @@ int init_worktree_config(struct repository *r)
         * If the extension is already enabled, then we can skip the
         * upgrade process.
         */
-       if (repository_format_worktree_config)
+       if (r->repository_format_worktree_config)
                return 0;
        if ((res = git_config_set_gently("extensions.worktreeConfig", "true")))
                return error(_("failed to set extensions.worktreeConfig setting"));
@@ -835,7 +836,7 @@ int init_worktree_config(struct repository *r)
         * Relocate that value to avoid breaking all worktrees with this
         * upgrade to worktree config.
         */
-       if (!git_configset_get_value(&cs, "core.worktree", &core_worktree)) {
+       if (!git_configset_get_value(&cs, "core.worktree", &core_worktree, NULL)) {
                if ((res = move_config_setting("core.worktree", core_worktree,
                                               common_config_file,
                                               main_worktree_file)))
@@ -846,7 +847,7 @@ int init_worktree_config(struct repository *r)
         * Ensure that we use worktree config for the remaining lifetime
         * of the current process.
         */
-       repository_format_worktree_config = 1;
+       r->repository_format_worktree_config = 1;
 
 cleanup:
        git_configset_clear(&cs);
index 67f5f5dbe199f8362cad205a19f968687cb2906b..7da15a56da614ce82ca1d6a5c6e2277b444f1063 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -3,21 +3,16 @@
  */
 #include "git-compat-util.h"
 #include "abspath.h"
-#include "config.h"
+#include "parse.h"
 #include "gettext.h"
-#include "object.h"
 #include "repository.h"
 #include "strbuf.h"
 #include "trace2.h"
-#include "wrapper.h"
-
-static intmax_t count_fsync_writeout_only;
-static intmax_t count_fsync_hardware_flush;
 
 #ifdef HAVE_RTLGENRANDOM
 /* This is required to get access to RtlGenRandom. */
 #define SystemFunction036 NTAPI SystemFunction036
-#include <NTSecAPI.h>
+#include <ntsecapi.h>
 #undef SystemFunction036
 #endif
 
@@ -552,7 +547,7 @@ int git_fsync(int fd, enum fsync_action action)
 {
        switch (action) {
        case FSYNC_WRITEOUT_ONLY:
-               count_fsync_writeout_only += 1;
+               trace2_counter_add(TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY, 1);
 
 #ifdef __APPLE__
                /*
@@ -584,7 +579,7 @@ int git_fsync(int fd, enum fsync_action action)
                return -1;
 
        case FSYNC_HARDWARE_FLUSH:
-               count_fsync_hardware_flush += 1;
+               trace2_counter_add(TRACE2_COUNTER_ID_FSYNC_HARDWARE_FLUSH, 1);
 
                /*
                 * On macOS, a special fcntl is required to really flush the
@@ -601,18 +596,6 @@ 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)
-{
-       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)
 {
        int err;
@@ -648,11 +631,6 @@ int rmdir_or_warn(const char *file)
        return warn_if_unremovable("rmdir", file, rmdir(file));
 }
 
-int remove_or_warn(unsigned int mode, const char *file)
-{
-       return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
-}
-
 static int access_error_is_ok(int err, unsigned flag)
 {
        return (is_missing_file_error(err) ||
@@ -835,3 +813,13 @@ int csprng_bytes(void *buf, size_t len)
        return 0;
 #endif
 }
+
+uint32_t git_rand(void)
+{
+       uint32_t result;
+
+       if (csprng_bytes(&result, sizeof(result)) < 0)
+               die(_("unable to get random bytes"));
+
+       return result;
+}
index f0c7d0616d6905c3c6b049262dbe56137be9fa8d..1b2b047ea069272052b13371c31ca06924231cc9 100644 (file)
--- a/wrapper.h
+++ b/wrapper.h
@@ -1,6 +1,42 @@
 #ifndef WRAPPER_H
 #define WRAPPER_H
 
+char *xstrdup(const char *str);
+void *xmalloc(size_t size);
+void *xmallocz(size_t size);
+void *xmallocz_gently(size_t size);
+void *xmemdupz(const void *data, size_t len);
+char *xstrndup(const char *str, size_t len);
+void *xrealloc(void *ptr, size_t size);
+void *xcalloc(size_t nmemb, size_t size);
+void xsetenv(const char *name, const char *value, int overwrite);
+void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
+const char *mmap_os_err(void);
+void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset);
+int xopen(const char *path, int flags, ...);
+ssize_t xread(int fd, void *buf, size_t len);
+ssize_t xwrite(int fd, const void *buf, size_t len);
+ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
+int xdup(int fd);
+FILE *xfopen(const char *path, const char *mode);
+FILE *xfdopen(int fd, const char *mode);
+int xmkstemp(char *temp_filename);
+int xmkstemp_mode(char *temp_filename, int mode);
+char *xgetcwd(void);
+FILE *fopen_for_writing(const char *path);
+FILE *fopen_or_warn(const char *path, const char *mode);
+
+/*
+ * Like strncmp, but only return zero if s is NUL-terminated and exactly len
+ * characters long.  If it is not, consider it greater than t.
+ */
+int xstrncmpz(const char *s, const char *t, size_t len);
+
+__attribute__((format (printf, 3, 4)))
+int xsnprintf(char *dst, size_t max, const char *fmt, ...);
+
+int xgethostname(char *buf, size_t len);
+
 /* set default permissions by passing mode arguments to open(2) */
 int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
 int git_mkstemp_mode(char *pattern, int mode);
@@ -33,4 +69,75 @@ void write_file(const char *path, const char *fmt, ...);
 /* Return 1 if the file is empty or does not exists, 0 otherwise. */
 int is_empty_or_missing_file(const char *filename);
 
+enum fsync_action {
+       FSYNC_WRITEOUT_ONLY,
+       FSYNC_HARDWARE_FLUSH
+};
+
+/*
+ * Issues an fsync against the specified file according to the specified mode.
+ *
+ * FSYNC_WRITEOUT_ONLY attempts to use interfaces available on some operating
+ * systems to flush the OS cache without issuing a flush command to the storage
+ * controller. If those interfaces are unavailable, the function fails with
+ * ENOSYS.
+ *
+ * FSYNC_HARDWARE_FLUSH does an OS writeout and hardware flush to ensure that
+ * changes are durable. It is not expected to fail.
+ */
+int git_fsync(int fd, enum fsync_action action);
+
+/*
+ * Preserves errno, prints a message, but gives no warning for ENOENT.
+ * Returns 0 on success, which includes trying to unlink an object that does
+ * not exist.
+ */
+int unlink_or_warn(const char *path);
+ /*
+  * Tries to unlink file.  Returns 0 if unlink succeeded
+  * or the file already didn't exist.  Returns -1 and
+  * appends a message to err suitable for
+  * 'error("%s", err->buf)' on error.
+  */
+int unlink_or_msg(const char *file, struct strbuf *err);
+/*
+ * Preserves errno, prints a message, but gives no warning for ENOENT.
+ * Returns 0 on success, which includes trying to remove a directory that does
+ * not exist.
+ */
+int rmdir_or_warn(const char *path);
+
+/*
+ * Call access(2), but warn for any error except "missing file"
+ * (ENOENT or ENOTDIR).
+ */
+#define ACCESS_EACCES_OK (1U << 0)
+int access_or_warn(const char *path, int mode, unsigned flag);
+int access_or_die(const char *path, int mode, unsigned flag);
+
+/* Warn on an inaccessible file if errno indicates this is an error */
+int warn_on_fopen_errors(const char *path);
+
+/*
+ * Open with O_NOFOLLOW, or equivalent. Note that the fallback equivalent
+ * may be racy. Do not use this as protection against an attacker who can
+ * simultaneously create paths.
+ */
+int open_nofollow(const char *path, int flags);
+
+void sleep_millisec(int millisec);
+
+/*
+ * Generate len bytes from the system cryptographically secure PRNG.
+ * Returns 0 on success and -1 on error, setting errno.  The inability to
+ * satisfy the full request is an error.
+ */
+int csprng_bytes(void *buf, size_t len);
+
+/*
+ * Returns a random uint32_t, uniformly distributed across all possible
+ * values.
+ */
+uint32_t git_rand(void);
+
 #endif /* WRAPPER_H */
index cc9e0787a1de50e9032a06d4036835bc9d1b35b9..42a2dc73cd3f18638445780e7fa9aa9b67ba871c 100644 (file)
@@ -1,7 +1,6 @@
 #include "git-compat-util.h"
-#include "config.h"
+#include "parse.h"
 #include "run-command.h"
-#include "wrapper.h"
 #include "write-or-die.h"
 
 /*
index 068b76ef6d9644c6f1e1576e425ac5339845e004..9f45bf69490e6fa4939948aadb63e7201d0e868e 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "advice.h"
 #include "wt-status.h"
 #include "object.h"
@@ -7,8 +7,10 @@
 #include "diff.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hash.h"
 #include "hex.h"
 #include "object-name.h"
+#include "path.h"
 #include "revision.h"
 #include "diffcore.h"
 #include "quote.h"
@@ -18,6 +20,7 @@
 #include "refs.h"
 #include "submodule.h"
 #include "column.h"
+#include "read-cache.h"
 #include "setup.h"
 #include "strbuf.h"
 #include "trace.h"
@@ -672,7 +675,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
        rev.diffopt.flags.recursive = 1;
 
        copy_pathspec(&rev.prune_data, &s->pathspec);
-       run_diff_index(&rev, 1);
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
        release_revisions(&rev);
 }
 
@@ -736,7 +739,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
                        ps.max_depth = -1;
 
                        strbuf_add(&base, ce->name, ce->ce_namelen);
-                       read_tree_at(istate->repo, tree, &base, &ps,
+                       read_tree_at(istate->repo, tree, &base, 0, &ps,
                                     add_file_to_list, s);
                        continue;
                }
@@ -1024,7 +1027,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom
        if (s->display_comment_prefix) {
                size_t len;
                summary_content = strbuf_detach(&summary, &len);
-               strbuf_add_commented_lines(&summary, summary_content, len);
+               strbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);
                free(summary_content);
        }
 
@@ -1099,8 +1102,8 @@ void wt_status_append_cut_line(struct strbuf *buf)
 {
        const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
 
-       strbuf_commented_addf(buf, "%s", cut_line);
-       strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+       strbuf_commented_addf(buf, comment_line_char, "%s", cut_line);
+       strbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);
 }
 
 void wt_status_add_cut_line(FILE *fp)
@@ -1153,7 +1156,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
                rev.diffopt.a_prefix = "c/";
                rev.diffopt.b_prefix = "i/";
        } /* else use prefix as per user config */
-       run_diff_index(&rev, 1);
+       run_diff_index(&rev, DIFF_INDEX_CACHED);
        if (s->verbose > 1 &&
            wt_status_check_worktree_changes(s, &dirty_submodules)) {
                status_printf_ln(s, c,
@@ -1183,7 +1186,8 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
 
        t_begin = getnanotime();
 
-       if (!format_tracking_info(branch, &sb, s->ahead_behind_flags))
+       if (!format_tracking_info(branch, &sb, s->ahead_behind_flags,
+                                 !s->commit_template))
                return;
 
        if (advice_enabled(ADVICE_STATUS_AHEAD_BEHIND_WARNING) &&
@@ -1790,10 +1794,10 @@ void wt_status_get_state(struct repository *r,
                oidcpy(&state->revert_head_oid, &oid);
        }
        if (!sequencer_get_last_command(r, &action)) {
-               if (action == REPLAY_PICK) {
+               if (action == REPLAY_PICK && !state->cherry_pick_in_progress) {
                        state->cherry_pick_in_progress = 1;
                        oidcpy(&state->cherry_pick_head_oid, null_oid());
-               } else {
+               } else if (action == REPLAY_REVERT && !state->revert_in_progress) {
                        state->revert_in_progress = 1;
                        oidcpy(&state->revert_head_oid, null_oid());
                }
@@ -2576,8 +2580,8 @@ int has_unstaged_changes(struct repository *r, int ignore_submodules)
        }
        rev_info.diffopt.flags.quick = 1;
        diff_setup_done(&rev_info.diffopt);
-       result = run_diff_files(&rev_info, 0);
-       result = diff_result_code(&rev_info.diffopt, result);
+       run_diff_files(&rev_info, 0);
+       result = diff_result_code(&rev_info.diffopt);
        release_revisions(&rev_info);
        return result;
 }
@@ -2610,8 +2614,8 @@ int has_uncommitted_changes(struct repository *r,
        }
 
        diff_setup_done(&rev_info.diffopt);
-       result = run_diff_index(&rev_info, 1);
-       result = diff_result_code(&rev_info.diffopt, result);
+       run_diff_index(&rev_info, DIFF_INDEX_CACHED);
+       result = diff_result_code(&rev_info.diffopt);
        release_revisions(&rev_info);
        return result;
 }
@@ -2651,8 +2655,12 @@ int require_clean_work_tree(struct repository *r,
        }
 
        if (err) {
-               if (hint)
+               if (hint) {
+                       if (!*hint)
+                               BUG("empty hint passed to require_clean_work_tree();"
+                                   " use NULL instead");
                        error("%s", hint);
+               }
                if (!gently)
                        exit(128);
        }
index 0460e03f5edd3538ff6ef6ff46d146aec1d06611..adcea109fa9a54eaa96c67c1b5e8a1689af253af 100644 (file)
@@ -1,7 +1,8 @@
 #include "git-compat-util.h"
 #include "config.h"
 #include "hex.h"
-#include "object-store.h"
+#include "object-store-ll.h"
+#include "strbuf.h"
 #include "xdiff-interface.h"
 #include "xdiff/xtypes.h"
 #include "xdiff/xdiffi.h"
@@ -307,7 +308,8 @@ int xdiff_compare_lines(const char *l1, long s1,
 
 int git_xmerge_style = -1;
 
-int git_xmerge_config(const char *var, const char *value, void *cb)
+int git_xmerge_config(const char *var, const char *value,
+                     const struct config_context *ctx, void *cb)
 {
        if (!strcmp(var, "merge.conflictstyle")) {
                if (!value)
@@ -327,5 +329,5 @@ int git_xmerge_config(const char *var, const char *value, void *cb)
                            value, var);
                return 0;
        }
-       return git_default_config(var, value, cb);
+       return git_default_config(var, value, ctx, cb);
 }
index 733c364d26c7bfd3e080bd1b64cbe84abbf33a7c..e6f80df04627ccfe1b3777fe380ef3aa5188769e 100644 (file)
@@ -50,7 +50,9 @@ int buffer_is_binary(const char *ptr, unsigned long size);
 
 void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);
 void xdiff_clear_find_func(xdemitconf_t *xecfg);
-int git_xmerge_config(const char *var, const char *value, void *cb);
+struct config_context;
+int git_xmerge_config(const char *var, const char *value,
+                     const struct config_context *ctx, void *cb);
 extern int git_xmerge_style;
 
 /*